vcl: allow for overriding the default PDF rendering resolution
[LibreOffice.git] / sdext / source / pdfimport / xpdfwrapper / pdfioutdev_gpl.cxx
blob16ad04bf660a615239bcb28b3877cc5f793b4b93
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "pdfioutdev_gpl.hxx"
21 #include "pnghelper.hxx"
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <assert.h>
26 #include <math.h>
28 #include <memory>
29 #include <vector>
31 // sigh, UTF8.h was removed in poppler-0.21.0 and put back in 0.21.1, then renamed to UnicodeMapFuncs.h in 0.62.0
32 // FIXME: we can't use #if POPPLER_CHECK_VERSION(0, 21, 0) && !POPPLER_CHECK_VERSION(0, 21, 1)
33 // because the internal poppler does not provide poppler-version.h and the macro always returns 0
34 #if POPPLER_CHECK_VERSION(0, 62, 0)
35 #include <UnicodeMapFuncs.h>
36 #elif POPPLER_CHECK_VERSION(0, 21, 1)
37 #include <UTF8.h>
38 #elif POPPLER_CHECK_VERSION(0, 21, 0)
39 #include "UTF.h"
40 #else
41 #include "UTF8.h"
42 #endif
44 #ifdef _WIN32
45 # define snprintf _snprintf
47 #if defined __GNUC__
48 #pragma GCC diagnostic warning "-Wformat"
49 #pragma GCC diagnostic warning "-Wformat-extra-args"
50 #endif
51 #endif
53 /* SYNC STREAMS
54 ============
56 We stream human-readable tokens to stdout, and binary data (fonts,
57 bitmaps) to g_binary_out. Another process reads from those pipes, and
58 there lies the rub: things can deadlock, if the two involved
59 processes access the pipes in different order. At any point in
60 time, both processes must access the same pipe. To ensure this,
61 data must be flushed to the OS before writing to a different pipe,
62 otherwise not-yet-written data will leave the reading process
63 waiting on the wrong pipe.
66 namespace pdfi
69 /// cut off very small numbers & clamp value to zero
70 static double normalize( double val )
72 return fabs(val) < 0.0000001 ? 0.0 : val;
75 namespace
78 /** Escapes line-ending characters (\n and \r) in input string.
80 std::vector<char> lcl_escapeLineFeeds(const char* const i_pStr)
82 size_t nLength(strlen(i_pStr));
83 std::vector<char> aBuffer;
84 aBuffer.reserve(2*nLength+1);
86 const char* pRead = i_pStr;
87 while( nLength-- )
89 if( *pRead == '\r' )
91 aBuffer.push_back('\\');
92 aBuffer.push_back('r');
94 else if( *pRead == '\n' )
96 aBuffer.push_back('\\');
97 aBuffer.push_back('n');
99 else if( *pRead == '\\' )
101 aBuffer.push_back('\\');
102 aBuffer.push_back('\\');
104 else
105 aBuffer.push_back(*pRead);
106 pRead++;
108 aBuffer.push_back(0);
110 return aBuffer;
115 /// for the temp char buffer the header gets snprintfed in
116 #define WRITE_BUFFER_SIZE 1024
118 /// for the initial std::vector capacity when copying stream from xpdf
119 #define WRITE_BUFFER_INITIAL_CAPACITY (1024*100)
121 static void initBuf(OutputBuffer& io_rBuffer)
123 io_rBuffer.reserve(WRITE_BUFFER_INITIAL_CAPACITY);
126 static void writeBinaryBuffer( const OutputBuffer& rBuffer )
128 // ---sync point--- see SYNC STREAMS above
129 fflush(stdout);
131 // put buffer to stderr
132 if( !rBuffer.empty() )
133 if( fwrite(rBuffer.data(), sizeof(char),
134 rBuffer.size(), g_binary_out) != static_cast<size_t>(rBuffer.size()) )
135 exit(1); // error
137 // ---sync point--- see SYNC STREAMS above
138 fflush(g_binary_out);
141 static bool ExtractJpegData(Stream* str, OutputBuffer& outBuf)
143 int bytesToMarker = 0;
144 int bytesToLen = -1;
145 bool collectBytes = false;
146 int startOfScan = 0;
147 int b1 = -1;
148 for (; ; )
150 const int b2 = b1;
151 b1 = str->getChar();
153 if (b1 == -1)
154 return false;
156 if (collectBytes)
158 outBuf.push_back(static_cast<Output_t>(b1));
160 bytesToMarker--;
161 bytesToLen--;
164 if (bytesToMarker == 0)
166 if (startOfScan == 1)
168 bytesToMarker = -1;
169 startOfScan = 2;
171 else if (b2 == 0xFF)
173 if (b1 == 0xD8)
175 collectBytes = true;
176 bytesToMarker = 2;
178 outBuf.push_back(Output_t(0xFF));
179 outBuf.push_back(Output_t(0xD8));
181 else
183 bytesToLen = 2;
185 if (b1 == 0xDA)
187 startOfScan = 1;
190 else if (collectBytes)
192 return false;
196 if (bytesToLen == 0)
198 bytesToMarker = b2 * 256 + b1;
201 if (startOfScan == 2)
202 if ((b2 == 0xFF) && (b1 == 0xD9))
203 return true;
207 static void writeJpeg_( OutputBuffer& o_rOutputBuf, Stream* str )
209 // dump JPEG file as-is
210 #if POPPLER_CHECK_VERSION(0, 17, 3)
211 str = str->getNextStream();
212 #else
213 str = ((DCTStream *)str)->getRawStream();
214 #endif
215 str->reset();
217 o_rOutputBuf.clear();
218 ExtractJpegData(str, o_rOutputBuf);
220 printf( " JPEG %d", static_cast<int>(o_rOutputBuf.size()) );
221 printf("\n");
223 str->close();
226 static void writePbm_(OutputBuffer& o_rOutputBuf, Stream* str, int width, int height, bool bInvert )
228 // write as PBM (char by char, to avoid stdlib lineend messing)
229 o_rOutputBuf.clear();
230 o_rOutputBuf.resize(WRITE_BUFFER_SIZE);
231 o_rOutputBuf[0] = 'P';
232 o_rOutputBuf[1] = '4';
233 o_rOutputBuf[2] = 0x0A;
234 char *pAsCharPtr = reinterpret_cast<char *>(&o_rOutputBuf[3]);
235 int nOutLen = snprintf(pAsCharPtr, WRITE_BUFFER_SIZE-10, "%d %d", width, height);
236 if( nOutLen < 0 )
237 nOutLen = WRITE_BUFFER_SIZE-10;
238 o_rOutputBuf[3+nOutLen] =0x0A;
239 o_rOutputBuf[3+nOutLen+1]=0;
241 const int header_size = 3+nOutLen+1;
242 const int size = height * ((width + 7) / 8);
244 printf( " PBM %d", size + header_size );
245 printf("\n");
247 // trim buffer to exact header length
248 o_rOutputBuf.resize(header_size);
250 // initialize stream
251 str->reset();
253 // copy the raw stream
254 if( bInvert )
256 for( int i=0; i<size; ++i)
257 o_rOutputBuf.push_back(static_cast<char>(str->getChar() ^ 0xff));
259 else
261 for( int i=0; i<size; ++i)
262 o_rOutputBuf.push_back(static_cast<char>(str->getChar()));
265 str->close();
268 static void writePpm_( OutputBuffer& o_rOutputBuf,
269 Stream* str,
270 int width,
271 int height,
272 GfxImageColorMap* colorMap )
274 // write as PPM (char by char, to avoid stdlib lineend messing)
275 o_rOutputBuf.clear();
276 o_rOutputBuf.resize(WRITE_BUFFER_SIZE);
277 o_rOutputBuf[0] = 'P';
278 o_rOutputBuf[1] = '6';
279 o_rOutputBuf[2] = '\n';
280 char *pAsCharPtr = reinterpret_cast<char *>(&o_rOutputBuf[3]);
281 int nOutLen = snprintf(pAsCharPtr, WRITE_BUFFER_SIZE-10, "%d %d", width, height);
282 if( nOutLen < 0 )
283 nOutLen = WRITE_BUFFER_SIZE-10;
284 o_rOutputBuf[3+nOutLen] ='\n';
285 o_rOutputBuf[3+nOutLen+1]='2';
286 o_rOutputBuf[3+nOutLen+2]='5';
287 o_rOutputBuf[3+nOutLen+3]='5';
288 o_rOutputBuf[3+nOutLen+4]='\n';
289 o_rOutputBuf[3+nOutLen+5]=0;
291 const int header_size = 3+nOutLen+5;
292 const int size = width*height*3 + header_size;
294 printf( " PPM %d", size );
295 printf("\n");
297 // trim buffer to exact header size
298 o_rOutputBuf.resize(header_size);
300 // initialize stream
301 unsigned char *p;
302 GfxRGB rgb;
303 std::unique_ptr<ImageStream> imgStr(
304 new ImageStream(str,
305 width,
306 colorMap->getNumPixelComps(),
307 colorMap->getBits()));
308 imgStr->reset();
310 for( int y=0; y<height; ++y)
312 p = imgStr->getLine();
313 for( int x=0; x<width; ++x)
315 colorMap->getRGB(p, &rgb);
316 o_rOutputBuf.push_back(colToByte(rgb.r));
317 o_rOutputBuf.push_back(colToByte(rgb.g));
318 o_rOutputBuf.push_back(colToByte(rgb.b));
320 p +=colorMap->getNumPixelComps();
325 // call this only for 1 bit image streams !
326 static void writePng_( OutputBuffer& o_rOutputBuf,
327 Stream* str,
328 int width,
329 int height,
330 GfxRGB const & zeroColor,
331 GfxRGB const & oneColor,
332 bool bIsMask )
334 o_rOutputBuf.clear();
336 // get png image
337 PngHelper::createPng( o_rOutputBuf, str, width, height, zeroColor, oneColor, bIsMask );
339 printf( " PNG %d", static_cast<int>(o_rOutputBuf.size()) );
340 printf("\n");
343 static void writePng_( OutputBuffer& o_rOutputBuf,
344 Stream* str,
345 int width, int height, GfxImageColorMap* colorMap,
346 Stream* maskStr,
347 int maskWidth, int maskHeight, GfxImageColorMap* maskColorMap )
349 o_rOutputBuf.clear();
351 // get png image
352 PngHelper::createPng( o_rOutputBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap );
354 printf( " PNG %d", static_cast<int>(o_rOutputBuf.size()) );
355 printf("\n");
358 static void writePng_( OutputBuffer& o_rOutputBuf,
359 Stream* str,
360 int width, int height, GfxImageColorMap* colorMap,
361 Stream* maskStr,
362 int maskWidth, int maskHeight, bool maskInvert )
364 o_rOutputBuf.clear();
366 // get png image
367 PngHelper::createPng( o_rOutputBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert );
369 printf( " PNG %d", static_cast<int>(o_rOutputBuf.size()) );
370 printf("\n");
373 // stolen from ImageOutputDev.cc
374 static void writeMask_( OutputBuffer& o_rOutputBuf, Stream* str, int width, int height, bool bInvert )
376 if( str->getKind() == strDCT )
377 writeJpeg_(o_rOutputBuf, str);
378 else
379 writePbm_(o_rOutputBuf, str, width, height, bInvert );
382 static void writeImage_( OutputBuffer& o_rOutputBuf,
383 Stream* str,
384 int width,
385 int height,
386 GfxImageColorMap* colorMap )
388 // dump JPEG file
389 if( str->getKind() == strDCT &&
390 (colorMap->getNumPixelComps() == 1 ||
391 colorMap->getNumPixelComps() == 3) )
393 writeJpeg_(o_rOutputBuf, str);
395 else if (colorMap->getNumPixelComps() == 1 &&
396 colorMap->getBits() == 1)
398 // this is a two color bitmap, write a png
399 // provide default colors
400 GfxRGB zeroColor = { 0, 0, 0 },
401 oneColor = { byteToCol( 0xff ), byteToCol( 0xff ), byteToCol( 0xff ) };
402 if( colorMap->getColorSpace()->getMode() == csIndexed || colorMap->getColorSpace()->getMode() == csDeviceGray )
404 unsigned char nIndex = 0;
405 colorMap->getRGB( &nIndex, &zeroColor );
406 nIndex = 1;
407 colorMap->getRGB( &nIndex, &oneColor );
409 writePng_( o_rOutputBuf, str, width, height, zeroColor, oneColor, false);
411 else
412 writePpm_( o_rOutputBuf, str, width, height, colorMap );
415 // forwarders
418 static void writeImageLF( OutputBuffer& o_rOutputBuf,
419 Stream* str,
420 int width,
421 int height,
422 GfxImageColorMap* colorMap ) { writeImage_(o_rOutputBuf,str,width,height,colorMap); }
423 static void writeMaskLF( OutputBuffer& o_rOutputBuf,
424 Stream* str,
425 int width,
426 int height,
427 bool bInvert ) { writeMask_(o_rOutputBuf,str,width,height,bInvert); }
430 int PDFOutDev::parseFont( long long nNewId, GfxFont* gfxFont, GfxState* state ) const
432 FontAttributes aNewFont;
433 int nSize = 0;
435 #if POPPLER_CHECK_VERSION(0, 64, 0)
436 const
437 #endif
438 GooString* pFamily = gfxFont->getName();
439 if( pFamily )
441 aNewFont.familyName.clear();
442 aNewFont.familyName.append( gfxFont->getName() );
444 else
446 aNewFont.familyName.clear();
447 aNewFont.familyName.append( "Arial" );
450 aNewFont.isBold = gfxFont->isBold();
451 aNewFont.isItalic = gfxFont->isItalic();
452 aNewFont.size = state->getTransformedFontSize();
453 aNewFont.isUnderline = false;
455 if( gfxFont->getType() == fontTrueType || gfxFont->getType() == fontType1 )
457 // TODO(P3): Unfortunately, need to read stream twice, since
458 // we must write byte count to stdout before
459 char* pBuf = gfxFont->readEmbFontFile( m_pDoc->getXRef(), &nSize );
460 if( pBuf )
462 aNewFont.isEmbedded = true;
463 gfree(pBuf);
467 m_aFontMap[ nNewId ] = aNewFont;
468 return nSize;
471 void PDFOutDev::writeFontFile( GfxFont* gfxFont ) const
473 if( gfxFont->getType() != fontTrueType && gfxFont->getType() != fontType1 )
474 return;
476 int nSize = 0;
477 char* pBuf = gfxFont->readEmbFontFile( m_pDoc->getXRef(), &nSize );
478 if( !pBuf )
479 return;
481 // ---sync point--- see SYNC STREAMS above
482 fflush(stdout);
484 if( fwrite(pBuf, sizeof(char), nSize, g_binary_out) != static_cast<size_t>(nSize) )
486 gfree(pBuf);
487 exit(1); // error
489 // ---sync point--- see SYNC STREAMS above
490 fflush(g_binary_out);
491 gfree(pBuf);
494 #if POPPLER_CHECK_VERSION(0, 83, 0)
495 void PDFOutDev::printPath( const GfxPath* pPath )
496 #else
497 void PDFOutDev::printPath( GfxPath* pPath )
498 #endif
500 int nSubPaths = pPath ? pPath->getNumSubpaths() : 0;
501 for( int i=0; i<nSubPaths; i++ )
503 #if POPPLER_CHECK_VERSION(0, 83, 0)
504 const
505 #endif
506 GfxSubpath* pSub = pPath->getSubpath( i );
507 const int nPoints = pSub->getNumPoints();
509 printf( " subpath %d", pSub->isClosed() );
511 for( int n=0; n<nPoints; ++n )
513 printf( " %f %f %d",
514 normalize(pSub->getX(n)),
515 normalize(pSub->getY(n)),
516 pSub->getCurve(n) );
521 PDFOutDev::PDFOutDev( PDFDoc* pDoc ) :
522 m_pDoc( pDoc ),
523 m_aFontMap(),
524 m_pUtf8Map( new UnicodeMap("UTF-8", true, &mapUTF8) ),
525 m_bSkipImages(false)
528 PDFOutDev::~PDFOutDev()
532 void PDFOutDev::startPage(int /*pageNum*/, GfxState* state
533 #if POPPLER_CHECK_VERSION(0, 23, 0) || POPPLER_CHECK_VERSION(0, 24, 0)
534 , XRef* /*xref*/
535 #endif
538 assert(state);
539 printf("startPage %f %f\n",
540 normalize(state->getPageWidth()),
541 normalize(state->getPageHeight()));
544 void PDFOutDev::endPage()
546 printf("endPage\n");
549 #if POPPLER_CHECK_VERSION(0, 19, 0)
550 void PDFOutDev::processLink(AnnotLink *link)
551 #elif POPPLER_CHECK_VERSION(0, 17, 0)
552 void PDFOutDev::processLink(AnnotLink *link, Catalog *)
553 #else
554 void PDFOutDev::processLink(Link* link, Catalog*)
555 #endif
557 assert(link);
559 double x1,x2,y1,y2;
560 link->getRect( &x1, &y1, &x2, &y2 );
562 LinkAction* pAction = link->getAction();
563 if (!(pAction && pAction->getKind() == actionURI))
564 return;
566 #if POPPLER_CHECK_VERSION(0, 86, 0)
567 const char* pURI = static_cast<LinkURI*>(pAction)->getURI().c_str();
568 #elif POPPLER_CHECK_VERSION(0, 72, 0)
569 const char* pURI = static_cast<LinkURI*>(pAction)->getURI()->c_str();
570 #else
571 const char* pURI = static_cast<LinkURI*>(pAction)->getURI()->getCString();
572 #endif
574 std::vector<char> aEsc( lcl_escapeLineFeeds(pURI) );
576 printf( "drawLink %f %f %f %f %s\n",
577 normalize(x1),
578 normalize(y1),
579 normalize(x2),
580 normalize(y2),
581 aEsc.data() );
584 void PDFOutDev::saveState(GfxState*)
586 printf( "saveState\n" );
589 void PDFOutDev::restoreState(GfxState*)
591 printf( "restoreState\n" );
594 #if POPPLER_CHECK_VERSION(0, 71, 0)
595 void PDFOutDev::setDefaultCTM(const double *pMat)
596 #else
597 void PDFOutDev::setDefaultCTM(double *pMat)
598 #endif
600 assert(pMat);
602 OutputDev::setDefaultCTM(pMat);
604 printf( "updateCtm %f %f %f %f %f %f\n",
605 normalize(pMat[0]),
606 normalize(pMat[1]),
607 normalize(pMat[2]),
608 normalize(pMat[3]),
609 normalize(pMat[4]),
610 normalize(pMat[5]) );
613 void PDFOutDev::updateCTM(GfxState* state,
614 double, double,
615 double, double,
616 double, double)
618 assert(state);
620 const double* const pMat = state->getCTM();
621 assert(pMat);
623 printf( "updateCtm %f %f %f %f %f %f\n",
624 normalize(pMat[0]),
625 normalize(pMat[1]),
626 normalize(pMat[2]),
627 normalize(pMat[3]),
628 normalize(pMat[4]),
629 normalize(pMat[5]) );
632 void PDFOutDev::updateLineDash(GfxState *state)
634 if (m_bSkipImages)
635 return;
636 assert(state);
638 double* dashArray; int arrayLen; double startOffset;
639 state->getLineDash(&dashArray, &arrayLen, &startOffset);
641 printf( "updateLineDash" );
642 if( arrayLen && dashArray )
644 printf( " %f %d", normalize(startOffset), arrayLen );
645 for( int i=0; i<arrayLen; ++i )
646 printf( " %f", normalize(*dashArray++) );
648 printf( "\n" );
651 void PDFOutDev::updateFlatness(GfxState *state)
653 if (m_bSkipImages)
654 return;
655 assert(state);
656 printf( "updateFlatness %d\n", state->getFlatness() );
659 void PDFOutDev::updateLineJoin(GfxState *state)
661 if (m_bSkipImages)
662 return;
663 assert(state);
664 printf( "updateLineJoin %d\n", state->getLineJoin() );
667 void PDFOutDev::updateLineCap(GfxState *state)
669 if (m_bSkipImages)
670 return;
671 assert(state);
672 printf( "updateLineCap %d\n", state->getLineCap() );
675 void PDFOutDev::updateMiterLimit(GfxState *state)
677 if (m_bSkipImages)
678 return;
679 assert(state);
680 printf( "updateMiterLimit %f\n", normalize(state->getMiterLimit()) );
683 void PDFOutDev::updateLineWidth(GfxState *state)
685 if (m_bSkipImages)
686 return;
687 assert(state);
688 printf( "updateLineWidth %f\n", normalize(state->getLineWidth()) );
691 void PDFOutDev::updateFillColor(GfxState *state)
693 if (m_bSkipImages)
694 return;
695 assert(state);
697 GfxRGB aRGB;
698 state->getFillRGB( &aRGB );
700 printf( "updateFillColor %f %f %f %f\n",
701 normalize(colToDbl(aRGB.r)),
702 normalize(colToDbl(aRGB.g)),
703 normalize(colToDbl(aRGB.b)),
704 normalize(state->getFillOpacity()) );
707 void PDFOutDev::updateStrokeColor(GfxState *state)
709 if (m_bSkipImages)
710 return;
711 assert(state);
713 GfxRGB aRGB;
714 state->getStrokeRGB( &aRGB );
716 printf( "updateStrokeColor %f %f %f %f\n",
717 normalize(colToDbl(aRGB.r)),
718 normalize(colToDbl(aRGB.g)),
719 normalize(colToDbl(aRGB.b)),
720 normalize(state->getFillOpacity()) );
723 void PDFOutDev::updateFillOpacity(GfxState *state)
725 if (m_bSkipImages)
726 return;
727 updateFillColor(state);
730 void PDFOutDev::updateStrokeOpacity(GfxState *state)
732 if (m_bSkipImages)
733 return;
734 updateStrokeColor(state);
737 void PDFOutDev::updateBlendMode(GfxState*)
741 void PDFOutDev::updateFont(GfxState *state)
743 assert(state);
745 GfxFont *gfxFont = state->getFont();
746 if( !gfxFont )
747 return;
749 FontAttributes aFont;
750 int nEmbedSize=0;
752 #if POPPLER_CHECK_VERSION(0, 64, 0)
753 const
754 #endif
755 Ref* pID = gfxFont->getID();
756 // TODO(Q3): Portability problem
757 long long fontID = static_cast<long long>(pID->gen) << 32 | static_cast<long long>(pID->num);
758 std::unordered_map< long long, FontAttributes >::const_iterator it =
759 m_aFontMap.find( fontID );
760 if( it == m_aFontMap.end() )
762 nEmbedSize = parseFont( fontID, gfxFont, state );
763 it = m_aFontMap.find( fontID );
766 printf( "updateFont" );
767 if( it != m_aFontMap.end() )
769 // conflating this with printf below crashes under Windoze
770 printf( " %lld", fontID );
772 aFont = it->second;
774 #if POPPLER_CHECK_VERSION(0, 72, 0)
775 std::vector<char> aEsc( lcl_escapeLineFeeds(aFont.familyName.c_str()) );
776 #else
777 std::vector<char> aEsc( lcl_escapeLineFeeds(aFont.familyName.getCString()) );
778 #endif
779 printf( " %d %d %d %d %f %d %s",
780 aFont.isEmbedded,
781 aFont.isBold,
782 aFont.isItalic,
783 aFont.isUnderline,
784 normalize(state->getTransformedFontSize()),
785 nEmbedSize,
786 aEsc.data() );
788 printf( "\n" );
790 if( nEmbedSize )
791 writeFontFile(gfxFont);
794 void PDFOutDev::updateRender(GfxState *state)
796 assert(state);
798 printf( "setTextRenderMode %d\n", state->getRender() );
801 void PDFOutDev::stroke(GfxState *state)
803 if (m_bSkipImages)
804 return;
805 assert(state);
807 printf( "strokePath" );
808 printPath( state->getPath() );
809 printf( "\n" );
812 void PDFOutDev::fill(GfxState *state)
814 if (m_bSkipImages)
815 return;
816 assert(state);
818 printf( "fillPath" );
819 printPath( state->getPath() );
820 printf( "\n" );
823 void PDFOutDev::eoFill(GfxState *state)
825 if (m_bSkipImages)
826 return;
827 assert(state);
829 printf( "eoFillPath" );
830 printPath( state->getPath() );
831 printf( "\n" );
834 void PDFOutDev::clip(GfxState *state)
836 if (m_bSkipImages)
837 return;
838 assert(state);
840 printf( "clipPath" );
841 printPath( state->getPath() );
842 printf( "\n" );
845 void PDFOutDev::eoClip(GfxState *state)
847 if (m_bSkipImages)
848 return;
849 assert(state);
851 printf( "eoClipPath" );
852 printPath( state->getPath() );
853 printf( "\n" );
856 /** Output one glyph
859 @param dx
860 horizontal skip for character (already scaled with font size) +
861 inter-char space: cursor is shifted by this amount for next char
863 @param dy
864 vertical skip for character (zero for horizontal writing mode):
865 cursor is shifted by this amount for next char
867 @param originX
868 local offset of character (zero for horizontal writing mode). not
869 taken into account for output pos updates. Used for vertical writing.
871 @param originY
872 local offset of character (zero for horizontal writing mode). not
873 taken into account for output pos updates. Used for vertical writing.
876 #if POPPLER_CHECK_VERSION(0, 82, 0)
877 void PDFOutDev::drawChar(GfxState *state, double x, double y,
878 double dx, double dy,
879 double originX, double originY,
880 CharCode, int /*nBytes*/, const Unicode *u, int uLen)
882 #else
883 void PDFOutDev::drawChar(GfxState *state, double x, double y,
884 double dx, double dy,
885 double originX, double originY,
886 CharCode, int /*nBytes*/, Unicode *u, int uLen)
888 #endif
889 assert(state);
891 if( u == nullptr )
892 return;
894 // Fix for tdf#96080
895 if (uLen == 4 && u[0] == '\t' && u[1] == '\r' && u[2] == ' ' && u[3] == 0xA0)
897 u += 2;
898 uLen = 1;
901 double csdx = 0.0;
902 double csdy = 0.0;
903 if (state->getFont()->getWMode())
905 csdy = state->getCharSpace();
906 if (*u == ' ')
907 csdy += state->getWordSpace();
909 else
911 csdx = state->getCharSpace();
912 if (*u == ' ')
913 csdx += state->getWordSpace();
914 csdx *= state->getHorizScaling();
917 double cstdx = 0.0;
918 double cstdy = 0.0;
919 state->textTransformDelta(csdx, csdy, &cstdx, &cstdy);
921 const double fontSize = state->getFontSize();
923 const double aPositionX(x-originX);
924 const double aPositionY(y-originY);
926 const double* pTextMat=state->getTextMat();
927 printf( "drawChar %f %f %f %f %f %f %f %f %f ",
928 normalize(aPositionX),
929 normalize(aPositionY),
930 normalize(aPositionX + dx - cstdx),
931 normalize(aPositionY + dy - cstdy),
932 normalize(pTextMat[0]),
933 normalize(pTextMat[2]),
934 normalize(pTextMat[1]),
935 normalize(pTextMat[3]),
936 normalize(fontSize)
939 // silence spurious warning
940 #if POPPLER_CHECK_VERSION(0, 62, 0)
941 (void)&mapUTF16;
942 #else
943 (void)&mapUCS2;
944 #endif
946 char buf[9];
947 for( int i=0; i<uLen; ++i )
949 buf[ m_pUtf8Map->mapUnicode(u[i], buf, sizeof(buf)-1) ] = 0;
950 std::vector<char> aEsc( lcl_escapeLineFeeds(buf) );
951 printf( "%s", aEsc.data() );
954 printf( "\n" );
957 #if POPPLER_CHECK_VERSION(0, 64, 0)
958 void PDFOutDev::drawString(GfxState*, const GooString* /*s*/)
959 #else
960 void PDFOutDev::drawString(GfxState*, GooString* /*s*/)
961 #endif
963 // TODO(F3): NYI
966 void PDFOutDev::endTextObject(GfxState*)
968 printf( "endTextObject\n" );
971 void PDFOutDev::drawImageMask(GfxState* pState, Object*, Stream* str,
972 int width, int height, poppler_bool invert,
973 poppler_bool /*interpolate*/,
974 poppler_bool /*inlineImg*/ )
976 if (m_bSkipImages)
977 return;
978 OutputBuffer aBuf; initBuf(aBuf);
980 printf( "drawMask %d %d %d", width, height, invert );
982 int bitsPerComponent = 1;
983 StreamColorSpaceMode csMode = streamCSNone;
984 str->getImageParams( &bitsPerComponent, &csMode );
985 if( bitsPerComponent == 1 && (csMode == streamCSNone || csMode == streamCSDeviceGray) )
987 GfxRGB oneColor = { dblToCol( 1.0 ), dblToCol( 1.0 ), dblToCol( 1.0 ) };
988 GfxRGB zeroColor = { dblToCol( 0.0 ), dblToCol( 0.0 ), dblToCol( 0.0 ) };
989 pState->getFillColorSpace()->getRGB( pState->getFillColor(), &zeroColor );
990 if( invert )
991 writePng_( aBuf, str, width, height, oneColor, zeroColor, true );
992 else
993 writePng_( aBuf, str, width, height, zeroColor, oneColor, true );
995 else
996 writeMaskLF(aBuf, str, width, height, invert);
997 writeBinaryBuffer(aBuf);
1000 #if POPPLER_CHECK_VERSION(0, 82, 0)
1001 void PDFOutDev::drawImage(GfxState*, Object*, Stream* str,
1002 int width, int height, GfxImageColorMap* colorMap,
1003 poppler_bool /*interpolate*/,
1004 const int* maskColors, poppler_bool /*inlineImg*/ )
1006 #else
1007 void PDFOutDev::drawImage(GfxState*, Object*, Stream* str,
1008 int width, int height, GfxImageColorMap* colorMap,
1009 poppler_bool /*interpolate*/,
1010 int* maskColors, poppler_bool /*inlineImg*/ )
1012 #endif
1013 if (m_bSkipImages)
1014 return;
1015 OutputBuffer aBuf; initBuf(aBuf);
1016 OutputBuffer aMaskBuf;
1018 printf( "drawImage %d %d", width, height );
1020 if( maskColors )
1022 // write mask colors. nBytes must be even - first half is
1023 // lower bound values, second half upper bound values
1024 if( colorMap->getColorSpace()->getMode() == csIndexed )
1026 aMaskBuf.push_back( static_cast<char>(maskColors[0]) );
1027 aMaskBuf.push_back( static_cast<char>(maskColors[gfxColorMaxComps]) );
1029 else
1031 GfxRGB aMinRGB;
1032 colorMap->getColorSpace()->getRGB(
1033 #if POPPLER_CHECK_VERSION(0, 82, 0)
1034 reinterpret_cast<const GfxColor*>(maskColors),
1035 #else
1036 reinterpret_cast<GfxColor*>(maskColors),
1037 #endif
1038 &aMinRGB );
1040 GfxRGB aMaxRGB;
1041 colorMap->getColorSpace()->getRGB(
1042 #if POPPLER_CHECK_VERSION(0, 82, 0)
1043 reinterpret_cast<const GfxColor*>(maskColors)+gfxColorMaxComps,
1044 #else
1045 reinterpret_cast<GfxColor*>(maskColors)+gfxColorMaxComps,
1046 #endif
1047 &aMaxRGB );
1049 aMaskBuf.push_back( colToByte(aMinRGB.r) );
1050 aMaskBuf.push_back( colToByte(aMinRGB.g) );
1051 aMaskBuf.push_back( colToByte(aMinRGB.b) );
1052 aMaskBuf.push_back( colToByte(aMaxRGB.r) );
1053 aMaskBuf.push_back( colToByte(aMaxRGB.g) );
1054 aMaskBuf.push_back( colToByte(aMaxRGB.b) );
1058 printf( " %d", static_cast<int>(aMaskBuf.size()) );
1059 writeImageLF( aBuf, str, width, height, colorMap );
1060 writeBinaryBuffer(aBuf);
1061 writeBinaryBuffer(aMaskBuf);
1064 void PDFOutDev::drawMaskedImage(GfxState*, Object*, Stream* str,
1065 int width, int height,
1066 GfxImageColorMap* colorMap,
1067 poppler_bool /*interpolate*/,
1068 Stream* maskStr,
1069 int maskWidth, int maskHeight,
1070 poppler_bool maskInvert, poppler_bool /*maskInterpolate*/
1073 if (m_bSkipImages)
1074 return;
1075 OutputBuffer aBuf; initBuf(aBuf);
1076 printf( "drawImage %d %d 0", width, height );
1077 writePng_( aBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert );
1078 writeBinaryBuffer( aBuf );
1081 void PDFOutDev::drawSoftMaskedImage(GfxState*, Object*, Stream* str,
1082 int width, int height,
1083 GfxImageColorMap* colorMap,
1084 poppler_bool /*interpolate*/,
1085 Stream* maskStr,
1086 int maskWidth, int maskHeight,
1087 GfxImageColorMap* maskColorMap
1088 , poppler_bool /*maskInterpolate*/
1091 if (m_bSkipImages)
1092 return;
1093 OutputBuffer aBuf; initBuf(aBuf);
1094 printf( "drawImage %d %d 0", width, height );
1095 writePng_( aBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap );
1096 writeBinaryBuffer( aBuf );
1099 void PDFOutDev::setPageNum( int nNumPages )
1101 // TODO(F3): printf might format int locale-dependent!
1102 printf("setPageNum %d\n", nNumPages);
1105 void PDFOutDev::setSkipImages( bool bSkipImages )
1107 m_bSkipImages = bSkipImages;
1112 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */