1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 #if defined __GNUC__ || defined __clang__
24 # pragma GCC diagnostic push
25 # pragma GCC diagnostic ignored "-Wunused-parameter"
26 #elif defined _MSC_VER
28 #pragma warning(disable : 4100) // unreferenced formal parameter
29 #pragma warning(disable : 4121) // alignment of a member was sensitive to packing in Gfx.h/Operator
33 #include <splash/SplashBitmap.h>
34 #include <SplashOutputDev.h>
35 #if defined __GNUC__ || defined __clang__
36 # pragma GCC diagnostic pop
37 #elif defined _MSC_VER
50 // 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
51 // FIXME: we can't use #if POPPLER_CHECK_VERSION(0, 21, 0) && !POPPLER_CHECK_VERSION(0, 21, 1)
52 // because the internal poppler does not provide poppler-version.h and the macro always returns 0
53 #if POPPLER_CHECK_VERSION(0, 62, 0)
54 #include <UnicodeMapFuncs.h>
55 #elif POPPLER_CHECK_VERSION(0, 21, 1)
57 #elif POPPLER_CHECK_VERSION(0, 21, 0)
64 # define snprintf _snprintf
67 #pragma GCC diagnostic warning "-Wformat"
68 #pragma GCC diagnostic warning "-Wformat-extra-args"
75 We stream human-readable tokens to stdout, and binary data (fonts,
76 bitmaps) to g_binary_out. Another process reads from those pipes, and
77 there lies the rub: things can deadlock, if the two involved
78 processes access the pipes in different order. At any point in
79 time, both processes must access the same pipe. To ensure this,
80 data must be flushed to the OS before writing to a different pipe,
81 otherwise not-yet-written data will leave the reading process
82 waiting on the wrong pipe.
88 /// cut off very small numbers & clamp value to zero
89 static double normalize( double val
)
91 return fabs(val
) < 0.0000001 ? 0.0 : val
;
97 /** Escapes line-ending characters (\n and \r) in input string.
99 std::vector
<char> lcl_escapeLineFeeds(const char* const i_pStr
)
101 size_t nLength(strlen(i_pStr
));
102 std::vector
<char> aBuffer
;
103 aBuffer
.reserve(2*nLength
+1);
105 const char* pRead
= i_pStr
;
110 aBuffer
.push_back('\\');
111 aBuffer
.push_back('r');
113 else if( *pRead
== '\n' )
115 aBuffer
.push_back('\\');
116 aBuffer
.push_back('n');
118 else if( *pRead
== '\\' )
120 aBuffer
.push_back('\\');
121 aBuffer
.push_back('\\');
124 aBuffer
.push_back(*pRead
);
127 aBuffer
.push_back(0);
134 /// for the temp char buffer the header gets snprintfed in
135 #define WRITE_BUFFER_SIZE 1024
137 /// for the initial std::vector capacity when copying stream from xpdf
138 #define WRITE_BUFFER_INITIAL_CAPACITY (1024*100)
140 static void initBuf(OutputBuffer
& io_rBuffer
)
142 io_rBuffer
.reserve(WRITE_BUFFER_INITIAL_CAPACITY
);
145 static void writeBinaryBuffer( const OutputBuffer
& rBuffer
)
147 // ---sync point--- see SYNC STREAMS above
150 // put buffer to stderr
151 if( !rBuffer
.empty() )
152 if( fwrite(rBuffer
.data(), sizeof(char),
153 rBuffer
.size(), g_binary_out
) != static_cast<size_t>(rBuffer
.size()) )
156 // ---sync point--- see SYNC STREAMS above
157 fflush(g_binary_out
);
160 static bool ExtractJpegData(Stream
* str
, OutputBuffer
& outBuf
)
162 int bytesToMarker
= 0;
164 bool collectBytes
= false;
177 outBuf
.push_back(static_cast<Output_t
>(b1
));
183 if (bytesToMarker
== 0)
185 if (startOfScan
== 1)
197 outBuf
.push_back(Output_t(0xFF));
198 outBuf
.push_back(Output_t(0xD8));
209 else if (collectBytes
)
217 bytesToMarker
= b2
* 256 + b1
;
220 if (startOfScan
== 2)
221 if ((b2
== 0xFF) && (b1
== 0xD9))
226 static void writeJpeg_( OutputBuffer
& o_rOutputBuf
, Stream
* str
)
228 // dump JPEG file as-is
229 #if POPPLER_CHECK_VERSION(0, 17, 3)
230 str
= str
->getNextStream();
232 str
= ((DCTStream
*)str
)->getRawStream();
236 o_rOutputBuf
.clear();
237 ExtractJpegData(str
, o_rOutputBuf
);
239 printf( " JPEG %d", static_cast<int>(o_rOutputBuf
.size()) );
245 static void writePbm_(OutputBuffer
& o_rOutputBuf
, Stream
* str
, int width
, int height
, bool bInvert
)
247 // write as PBM (char by char, to avoid stdlib lineend messing)
248 o_rOutputBuf
.clear();
249 o_rOutputBuf
.resize(WRITE_BUFFER_SIZE
);
250 o_rOutputBuf
[0] = 'P';
251 o_rOutputBuf
[1] = '4';
252 o_rOutputBuf
[2] = 0x0A;
253 char *pAsCharPtr
= reinterpret_cast<char *>(&o_rOutputBuf
[3]);
254 int nOutLen
= snprintf(pAsCharPtr
, WRITE_BUFFER_SIZE
-10, "%d %d", width
, height
);
256 nOutLen
= WRITE_BUFFER_SIZE
-10;
257 o_rOutputBuf
[3+nOutLen
] =0x0A;
258 o_rOutputBuf
[3+nOutLen
+1]=0;
260 const int header_size
= 3+nOutLen
+1;
261 const int size
= height
* ((width
+ 7) / 8);
263 printf( " PBM %d", size
+ header_size
);
266 // trim buffer to exact header length
267 o_rOutputBuf
.resize(header_size
);
272 // copy the raw stream
275 for( int i
=0; i
<size
; ++i
)
276 o_rOutputBuf
.push_back(static_cast<char>(str
->getChar() ^ 0xff));
280 for( int i
=0; i
<size
; ++i
)
281 o_rOutputBuf
.push_back(static_cast<char>(str
->getChar()));
287 static void writePpm_( OutputBuffer
& o_rOutputBuf
,
291 GfxImageColorMap
* colorMap
)
293 // write as PPM (char by char, to avoid stdlib lineend messing)
294 o_rOutputBuf
.clear();
295 o_rOutputBuf
.resize(WRITE_BUFFER_SIZE
);
296 o_rOutputBuf
[0] = 'P';
297 o_rOutputBuf
[1] = '6';
298 o_rOutputBuf
[2] = '\n';
299 char *pAsCharPtr
= reinterpret_cast<char *>(&o_rOutputBuf
[3]);
300 int nOutLen
= snprintf(pAsCharPtr
, WRITE_BUFFER_SIZE
-10, "%d %d", width
, height
);
302 nOutLen
= WRITE_BUFFER_SIZE
-10;
303 o_rOutputBuf
[3+nOutLen
] ='\n';
304 o_rOutputBuf
[3+nOutLen
+1]='2';
305 o_rOutputBuf
[3+nOutLen
+2]='5';
306 o_rOutputBuf
[3+nOutLen
+3]='5';
307 o_rOutputBuf
[3+nOutLen
+4]='\n';
308 o_rOutputBuf
[3+nOutLen
+5]=0;
310 const int header_size
= 3+nOutLen
+5;
311 const int size
= width
*height
*3 + header_size
;
313 printf( " PPM %d", size
);
316 // trim buffer to exact header size
317 o_rOutputBuf
.resize(header_size
);
322 std::unique_ptr
<ImageStream
> imgStr(
325 colorMap
->getNumPixelComps(),
326 colorMap
->getBits()));
329 for( int y
=0; y
<height
; ++y
)
331 p
= imgStr
->getLine();
332 for( int x
=0; x
<width
; ++x
)
334 colorMap
->getRGB(p
, &rgb
);
335 o_rOutputBuf
.push_back(colToByte(rgb
.r
));
336 o_rOutputBuf
.push_back(colToByte(rgb
.g
));
337 o_rOutputBuf
.push_back(colToByte(rgb
.b
));
339 p
+=colorMap
->getNumPixelComps();
344 // call this only for 1 bit image streams !
345 static void writePng_( OutputBuffer
& o_rOutputBuf
,
349 GfxRGB
const & zeroColor
,
350 GfxRGB
const & oneColor
,
353 o_rOutputBuf
.clear();
356 PngHelper::createPng( o_rOutputBuf
, str
, width
, height
, zeroColor
, oneColor
, bIsMask
);
358 printf( " PNG %d", static_cast<int>(o_rOutputBuf
.size()) );
362 static void writePng_( OutputBuffer
& o_rOutputBuf
,
364 int width
, int height
, GfxImageColorMap
* colorMap
,
366 int maskWidth
, int maskHeight
, GfxImageColorMap
* maskColorMap
)
368 o_rOutputBuf
.clear();
371 PngHelper::createPng( o_rOutputBuf
, str
, width
, height
, colorMap
, maskStr
, maskWidth
, maskHeight
, maskColorMap
);
373 printf( " PNG %d", static_cast<int>(o_rOutputBuf
.size()) );
377 static void writePng_( OutputBuffer
& o_rOutputBuf
,
379 int width
, int height
, GfxImageColorMap
* colorMap
,
381 int maskWidth
, int maskHeight
, bool maskInvert
)
383 o_rOutputBuf
.clear();
386 PngHelper::createPng( o_rOutputBuf
, str
, width
, height
, colorMap
, maskStr
, maskWidth
, maskHeight
, maskInvert
);
388 printf( " PNG %d", static_cast<int>(o_rOutputBuf
.size()) );
392 // stolen from ImageOutputDev.cc
393 static void writeMask_( OutputBuffer
& o_rOutputBuf
, Stream
* str
, int width
, int height
, bool bInvert
)
395 if( str
->getKind() == strDCT
)
396 writeJpeg_(o_rOutputBuf
, str
);
398 writePbm_(o_rOutputBuf
, str
, width
, height
, bInvert
);
401 static void writeImage_( OutputBuffer
& o_rOutputBuf
,
405 GfxImageColorMap
* colorMap
)
408 if( str
->getKind() == strDCT
&&
409 (colorMap
->getNumPixelComps() == 1 ||
410 colorMap
->getNumPixelComps() == 3) )
412 writeJpeg_(o_rOutputBuf
, str
);
414 else if (colorMap
->getNumPixelComps() == 1 &&
415 colorMap
->getBits() == 1)
417 // this is a two color bitmap, write a png
418 // provide default colors
419 GfxRGB zeroColor
= { 0, 0, 0 },
420 oneColor
= { byteToCol( 0xff ), byteToCol( 0xff ), byteToCol( 0xff ) };
421 if( colorMap
->getColorSpace()->getMode() == csIndexed
|| colorMap
->getColorSpace()->getMode() == csDeviceGray
)
423 unsigned char nIndex
= 0;
424 colorMap
->getRGB( &nIndex
, &zeroColor
);
426 colorMap
->getRGB( &nIndex
, &oneColor
);
428 writePng_( o_rOutputBuf
, str
, width
, height
, zeroColor
, oneColor
, false);
431 writePpm_( o_rOutputBuf
, str
, width
, height
, colorMap
);
435 static void writeImageLF( OutputBuffer
& o_rOutputBuf
,
439 GfxImageColorMap
* colorMap
) { writeImage_(o_rOutputBuf
,str
,width
,height
,colorMap
); }
440 static void writeMaskLF( OutputBuffer
& o_rOutputBuf
,
444 bool bInvert
) { writeMask_(o_rOutputBuf
,str
,width
,height
,bInvert
); }
446 // Vertically flip the bitmap
447 static void flipSplashBitmap(SplashBitmap
*pBitmap
)
449 if (pBitmap
->getRowSize() <= 0)
452 auto nBitmapHeight
= static_cast<size_t>(pBitmap
->getHeight());
453 auto nRowSize
= static_cast<size_t>(pBitmap
->getRowSize());
454 auto nAlphaRowSize
= static_cast<size_t>(pBitmap
->getAlphaRowSize());
456 std::unique_ptr
<unsigned char[]> aTmpRow(new unsigned char[nRowSize
]);
457 std::unique_ptr
<unsigned char[]> aTmpAlphaRow(new unsigned char[nAlphaRowSize
]);
459 auto pBitmapData
= pBitmap
->getDataPtr();
460 auto pAlphaData
= pBitmap
->getAlphaPtr();
462 // Set up pairs of pointers working from each end of the bitmap
463 auto pCurRowA
= pBitmapData
;
464 auto pCurAlphaA
= pAlphaData
;
465 auto pCurRowB
= pBitmapData
+nRowSize
*(nBitmapHeight
-1);
466 auto pCurAlphaB
= pAlphaData
+nAlphaRowSize
*(nBitmapHeight
-1);
468 for (size_t nCur
= 0;
469 nCur
< nBitmapHeight
/2;
470 nCur
++, pCurRowA
+=nRowSize
, pCurRowB
-=nRowSize
,
471 pCurAlphaA
+=nAlphaRowSize
, pCurAlphaB
-=nAlphaRowSize
)
473 memcpy(aTmpRow
.get(), pCurRowA
, nRowSize
);
474 memcpy(pCurRowA
, pCurRowB
, nRowSize
);
475 memcpy(pCurRowB
, aTmpRow
.get(), nRowSize
);
477 memcpy(aTmpAlphaRow
.get(), pCurAlphaA
, nAlphaRowSize
);
478 memcpy(pCurAlphaA
, pCurAlphaB
, nAlphaRowSize
);
479 memcpy(pCurAlphaB
, aTmpAlphaRow
.get(), nAlphaRowSize
);
483 int PDFOutDev::parseFont( long long nNewId
, GfxFont
* gfxFont
, const GfxState
* state
) const
485 FontAttributes aNewFont
;
488 #if POPPLER_CHECK_VERSION(20, 12, 0)
489 std::string familyName
= gfxFont
->getNameWithoutSubsetTag();
491 #if POPPLER_CHECK_VERSION(0, 71, 0) // GooString::toStr()
492 std::string familyName
= gfxFont
->getName()->toStr();
494 const GooString
* gooString
= gfxFont
->getName();
495 std::string familyName
= std::string(gooString
->getCString(), gooString
->getLength());
497 if (familyName
.length() > 7 && familyName
.at(6) == '+')
499 familyName
= familyName
.substr(7);
502 if( familyName
!= "" )
504 aNewFont
.familyName
.clear();
505 #if POPPLER_CHECK_VERSION(0, 83, 0) // GooString::append(const std::string&)
506 aNewFont
.familyName
.append( familyName
);
508 aNewFont
.familyName
.append( familyName
.c_str() );
513 aNewFont
.familyName
.clear();
514 aNewFont
.familyName
.append( "Arial" );
517 aNewFont
.maFontWeight
= gfxFont
->getWeight();
518 aNewFont
.isItalic
= gfxFont
->isItalic();
519 #if POPPLER_CHECK_VERSION(0, 83, 0) // const added to getTransformedFontSize
520 aNewFont
.size
= state
->getTransformedFontSize();
522 aNewFont
.size
= const_cast<GfxState
*>(state
)->getTransformedFontSize();
524 aNewFont
.isUnderline
= false;
526 if( gfxFont
->getType() == fontTrueType
|| gfxFont
->getType() == fontType1
)
528 // TODO(P3): Unfortunately, need to read stream twice, since
529 // we must write byte count to stdout before
530 #if POPPLER_CHECK_VERSION(22, 6, 0)
531 std::optional
<std::vector
<unsigned char>> pBuf
= gfxFont
->readEmbFontFile( m_pDoc
->getXRef() );
534 aNewFont
.isEmbedded
= true;
535 nSize
= pBuf
->size();
538 char* pBuf
= gfxFont
->readEmbFontFile( m_pDoc
->getXRef(), &nSize
);
541 aNewFont
.isEmbedded
= true;
547 m_aFontMap
[ nNewId
] = aNewFont
;
551 void PDFOutDev::writeFontFile( GfxFont
* gfxFont
) const
553 if( gfxFont
->getType() != fontTrueType
&& gfxFont
->getType() != fontType1
)
557 #if POPPLER_CHECK_VERSION(22, 6, 0)
558 std::optional
<std::vector
<unsigned char>> pBuf
= gfxFont
->readEmbFontFile( m_pDoc
->getXRef() );
560 nSize
= pBuf
->size();
564 char* pBuf
= gfxFont
->readEmbFontFile( m_pDoc
->getXRef(), &nSize
);
569 // ---sync point--- see SYNC STREAMS above
572 #if POPPLER_CHECK_VERSION(22, 6, 0)
573 if( fwrite(pBuf
->data(), sizeof(*pBuf
->data()), nSize
, g_binary_out
) != static_cast<size_t>(nSize
) )
577 // ---sync point--- see SYNC STREAMS above
578 fflush(g_binary_out
);
580 if( fwrite(pBuf
, sizeof(char), nSize
, g_binary_out
) != static_cast<size_t>(nSize
) )
585 // ---sync point--- see SYNC STREAMS above
586 fflush(g_binary_out
);
591 #if POPPLER_CHECK_VERSION(0, 83, 0)
592 void PDFOutDev::printPath( const GfxPath
* pPath
)
594 void PDFOutDev::printPath( GfxPath
* pPath
)
597 int nSubPaths
= pPath
? pPath
->getNumSubpaths() : 0;
598 for( int i
=0; i
<nSubPaths
; i
++ )
600 #if POPPLER_CHECK_VERSION(0, 83, 0)
603 GfxSubpath
* pSub
= pPath
->getSubpath( i
);
604 const int nPoints
= pSub
->getNumPoints();
606 printf( " subpath %d", pSub
->isClosed() );
608 for( int n
=0; n
<nPoints
; ++n
)
611 normalize(pSub
->getX(n
)),
612 normalize(pSub
->getY(n
)),
618 PDFOutDev::PDFOutDev( PDFDoc
* pDoc
) :
620 m_pUtf8Map( new UnicodeMap("UTF-8", true, &mapUTF8
) ),
624 PDFOutDev::~PDFOutDev()
628 void PDFOutDev::startPage(int /*pageNum*/, GfxState
* state
629 #if POPPLER_CHECK_VERSION(0, 23, 0)
635 printf("startPage %f %f\n",
636 normalize(state
->getPageWidth()),
637 normalize(state
->getPageHeight()));
640 void PDFOutDev::endPage()
645 #if POPPLER_CHECK_VERSION(0, 19, 0)
646 void PDFOutDev::processLink(AnnotLink
*link
)
647 #elif POPPLER_CHECK_VERSION(0, 17, 0)
648 void PDFOutDev::processLink(AnnotLink
*link
, Catalog
*)
650 void PDFOutDev::processLink(Link
* link
, Catalog
*)
656 link
->getRect( &x1
, &y1
, &x2
, &y2
);
658 LinkAction
* pAction
= link
->getAction();
659 if (!(pAction
&& pAction
->getKind() == actionURI
))
662 #if POPPLER_CHECK_VERSION(0, 86, 0)
663 const char* pURI
= static_cast<LinkURI
*>(pAction
)->getURI().c_str();
664 #elif POPPLER_CHECK_VERSION(0, 72, 0)
665 const char* pURI
= static_cast<LinkURI
*>(pAction
)->getURI()->c_str();
667 const char* pURI
= static_cast<LinkURI
*>(pAction
)->getURI()->getCString();
670 std::vector
<char> aEsc( lcl_escapeLineFeeds(pURI
) );
672 printf( "drawLink %f %f %f %f %s\n",
680 void PDFOutDev::saveState(GfxState
*)
682 printf( "saveState\n" );
685 void PDFOutDev::restoreState(GfxState
*)
687 printf( "restoreState\n" );
690 #if POPPLER_CHECK_VERSION(0, 71, 0)
691 void PDFOutDev::setDefaultCTM(const double *pMat
)
693 void PDFOutDev::setDefaultCTM(double *pMat
)
698 OutputDev::setDefaultCTM(pMat
);
700 printf( "updateCtm %f %f %f %f %f %f\n",
706 normalize(pMat
[5]) );
709 void PDFOutDev::updateCTM(GfxState
* state
,
716 const double* const pMat
= state
->getCTM();
719 printf( "updateCtm %f %f %f %f %f %f\n",
725 normalize(pMat
[5]) );
728 void PDFOutDev::updateLineDash(GfxState
*state
)
734 int arrayLen
; double startOffset
;
735 #if POPPLER_CHECK_VERSION(22, 9, 0)
736 const std::vector
<double> &dash
= state
->getLineDash(&startOffset
);
737 const double* dashArray
= dash
.data();
738 arrayLen
= dash
.size();
741 state
->getLineDash(&dashArray
, &arrayLen
, &startOffset
);
744 printf( "updateLineDash" );
745 if( arrayLen
&& dashArray
)
747 printf( " %f %d", normalize(startOffset
), arrayLen
);
748 for( int i
=0; i
<arrayLen
; ++i
)
749 printf( " %f", normalize(*dashArray
++) );
754 void PDFOutDev::updateFlatness(GfxState
*state
)
759 printf( "updateFlatness %d\n", state
->getFlatness() );
762 void PDFOutDev::updateLineJoin(GfxState
*state
)
767 printf( "updateLineJoin %d\n", state
->getLineJoin() );
770 void PDFOutDev::updateLineCap(GfxState
*state
)
775 printf( "updateLineCap %d\n", state
->getLineCap() );
778 void PDFOutDev::updateMiterLimit(GfxState
*state
)
783 printf( "updateMiterLimit %f\n", normalize(state
->getMiterLimit()) );
786 void PDFOutDev::updateLineWidth(GfxState
*state
)
791 printf( "updateLineWidth %f\n", normalize(state
->getLineWidth()) );
794 void PDFOutDev::updateFillColor(GfxState
*state
)
801 state
->getFillRGB( &aRGB
);
803 printf( "updateFillColor %f %f %f %f\n",
804 normalize(colToDbl(aRGB
.r
)),
805 normalize(colToDbl(aRGB
.g
)),
806 normalize(colToDbl(aRGB
.b
)),
807 normalize(state
->getFillOpacity()) );
810 void PDFOutDev::updateStrokeColor(GfxState
*state
)
817 state
->getStrokeRGB( &aRGB
);
819 printf( "updateStrokeColor %f %f %f %f\n",
820 normalize(colToDbl(aRGB
.r
)),
821 normalize(colToDbl(aRGB
.g
)),
822 normalize(colToDbl(aRGB
.b
)),
823 normalize(state
->getFillOpacity()) );
826 void PDFOutDev::updateFillOpacity(GfxState
*state
)
830 updateFillColor(state
);
833 void PDFOutDev::updateStrokeOpacity(GfxState
*state
)
837 updateStrokeColor(state
);
840 void PDFOutDev::updateBlendMode(GfxState
*)
844 void PDFOutDev::updateFont(GfxState
*state
)
848 #if POPPLER_CHECK_VERSION(22, 6, 0)
849 GfxFont
*gfxFont
= state
->getFont().get();
851 GfxFont
*gfxFont
= state
->getFont();
856 FontAttributes aFont
;
859 #if POPPLER_CHECK_VERSION(0, 64, 0)
862 Ref
* pID
= gfxFont
->getID();
863 // TODO(Q3): Portability problem
864 long long fontID
= static_cast<long long>(pID
->gen
) << 32 | static_cast<long long>(pID
->num
);
865 std::unordered_map
< long long, FontAttributes
>::const_iterator it
=
866 m_aFontMap
.find( fontID
);
867 if( it
== m_aFontMap
.end() )
869 nEmbedSize
= parseFont( fontID
, gfxFont
, state
);
870 it
= m_aFontMap
.find( fontID
);
873 printf( "updateFont" );
874 if( it
!= m_aFontMap
.end() )
876 // conflating this with printf below crashes under Windoze
877 printf( " %lld", fontID
);
881 #if POPPLER_CHECK_VERSION(0, 72, 0)
882 std::vector
<char> aEsc( lcl_escapeLineFeeds(aFont
.familyName
.c_str()) );
884 std::vector
<char> aEsc( lcl_escapeLineFeeds(aFont
.familyName
.getCString()) );
886 printf( " %d %d %d %d %f %d %s",
891 normalize(state
->getTransformedFontSize()),
899 writeFontFile(gfxFont
);
903 void PDFOutDev::updateRender(GfxState
*state
)
907 printf( "setTextRenderMode %d\n", state
->getRender() );
910 void PDFOutDev::stroke(GfxState
*state
)
916 printf( "strokePath" );
917 printPath( state
->getPath() );
921 void PDFOutDev::fill(GfxState
*state
)
927 printf( "fillPath" );
928 printPath( state
->getPath() );
932 void PDFOutDev::eoFill(GfxState
*state
)
938 printf( "eoFillPath" );
939 printPath( state
->getPath() );
943 void PDFOutDev::clip(GfxState
*state
)
949 printf( "clipPath" );
950 printPath( state
->getPath() );
954 void PDFOutDev::eoClip(GfxState
*state
)
960 printf( "eoClipPath" );
961 printPath( state
->getPath() );
965 void PDFOutDev::clipToStrokePath(GfxState
*state
)
971 printf( "clipToStrokePath" );
972 printPath( state
->getPath() );
980 horizontal skip for character (already scaled with font size) +
981 inter-char space: cursor is shifted by this amount for next char
984 vertical skip for character (zero for horizontal writing mode):
985 cursor is shifted by this amount for next char
988 local offset of character (zero for horizontal writing mode). not
989 taken into account for output pos updates. Used for vertical writing.
992 local offset of character (zero for horizontal writing mode). not
993 taken into account for output pos updates. Used for vertical writing.
996 #if POPPLER_CHECK_VERSION(0, 82, 0)
997 void PDFOutDev::drawChar(GfxState
*state
, double x
, double y
,
998 double dx
, double dy
,
999 double originX
, double originY
,
1000 CharCode
, int /*nBytes*/, const Unicode
*u
, int uLen
)
1003 void PDFOutDev::drawChar(GfxState
*state
, double x
, double y
,
1004 double dx
, double dy
,
1005 double originX
, double originY
,
1006 CharCode
, int /*nBytes*/, Unicode
*u
, int uLen
)
1014 // Fix for tdf#96080
1015 if (uLen
== 4 && u
[0] == '\t' && u
[1] == '\r' && u
[2] == ' ' && u
[3] == 0xA0)
1023 if (!state
->getFont() || !state
->getFont()->getWMode())
1025 csdx
= state
->getCharSpace();
1027 csdx
+= state
->getWordSpace();
1028 csdx
*= state
->getHorizScaling();
1032 csdy
= state
->getCharSpace();
1034 csdy
+= state
->getWordSpace();
1039 state
->textTransformDelta(csdx
, csdy
, &cstdx
, &cstdy
);
1041 const double fontSize
= state
->getFontSize();
1043 const double aPositionX(x
-originX
);
1044 const double aPositionY(y
-originY
);
1046 const double* pTextMat
=state
->getTextMat();
1047 printf( "drawChar %f %f %f %f %f %f %f %f %f ",
1048 normalize(aPositionX
),
1049 normalize(aPositionY
),
1050 normalize(aPositionX
+ dx
- cstdx
),
1051 normalize(aPositionY
+ dy
- cstdy
),
1052 normalize(pTextMat
[0]),
1053 normalize(pTextMat
[2]),
1054 normalize(pTextMat
[1]),
1055 normalize(pTextMat
[3]),
1059 // silence spurious warning
1060 #if POPPLER_CHECK_VERSION(0, 62, 0)
1067 for( int i
=0; i
<uLen
; ++i
)
1069 buf
[ m_pUtf8Map
->mapUnicode(u
[i
], buf
, sizeof(buf
)-1) ] = 0;
1070 std::vector
<char> aEsc( lcl_escapeLineFeeds(buf
) );
1071 printf( "%s", aEsc
.data() );
1077 #if POPPLER_CHECK_VERSION(0, 64, 0)
1078 void PDFOutDev::drawString(GfxState
*, const GooString
* /*s*/)
1080 void PDFOutDev::drawString(GfxState
*, GooString
* /*s*/)
1086 void PDFOutDev::endTextObject(GfxState
*)
1088 printf( "endTextObject\n" );
1091 void PDFOutDev::drawImageMask(GfxState
* pState
, Object
*, Stream
* str
,
1092 int width
, int height
, poppler_bool invert
,
1093 poppler_bool
/*interpolate*/,
1094 poppler_bool
/*inlineImg*/ )
1098 OutputBuffer aBuf
; initBuf(aBuf
);
1100 printf( "drawMask %d %d %d", width
, height
, invert
);
1102 int bitsPerComponent
= 1;
1103 StreamColorSpaceMode csMode
= streamCSNone
;
1104 str
->getImageParams( &bitsPerComponent
, &csMode
);
1105 if( bitsPerComponent
== 1 && (csMode
== streamCSNone
|| csMode
== streamCSDeviceGray
) )
1107 GfxRGB oneColor
= { dblToCol( 1.0 ), dblToCol( 1.0 ), dblToCol( 1.0 ) };
1108 GfxRGB zeroColor
= { dblToCol( 0.0 ), dblToCol( 0.0 ), dblToCol( 0.0 ) };
1109 pState
->getFillColorSpace()->getRGB( pState
->getFillColor(), &zeroColor
);
1111 writePng_( aBuf
, str
, width
, height
, oneColor
, zeroColor
, true );
1113 writePng_( aBuf
, str
, width
, height
, zeroColor
, oneColor
, true );
1116 writeMaskLF(aBuf
, str
, width
, height
, invert
);
1117 writeBinaryBuffer(aBuf
);
1120 #if POPPLER_CHECK_VERSION(0, 82, 0)
1121 void PDFOutDev::drawImage(GfxState
*, Object
*, Stream
* str
,
1122 int width
, int height
, GfxImageColorMap
* colorMap
,
1123 poppler_bool
/*interpolate*/,
1124 const int* maskColors
, poppler_bool
/*inlineImg*/ )
1127 void PDFOutDev::drawImage(GfxState
*, Object
*, Stream
* str
,
1128 int width
, int height
, GfxImageColorMap
* colorMap
,
1129 poppler_bool
/*interpolate*/,
1130 int* maskColors
, poppler_bool
/*inlineImg*/ )
1135 OutputBuffer aBuf
; initBuf(aBuf
);
1136 OutputBuffer aMaskBuf
;
1138 printf( "drawImage %d %d", width
, height
);
1142 // write mask colors. nBytes must be even - first half is
1143 // lower bound values, second half upper bound values
1144 if( colorMap
->getColorSpace()->getMode() == csIndexed
)
1146 aMaskBuf
.push_back( static_cast<char>(maskColors
[0]) );
1147 aMaskBuf
.push_back( static_cast<char>(maskColors
[gfxColorMaxComps
]) );
1152 colorMap
->getColorSpace()->getRGB(
1153 #if POPPLER_CHECK_VERSION(0, 82, 0)
1154 reinterpret_cast<const GfxColor
*>(maskColors
),
1156 reinterpret_cast<GfxColor
*>(maskColors
),
1161 colorMap
->getColorSpace()->getRGB(
1162 #if POPPLER_CHECK_VERSION(0, 82, 0)
1163 reinterpret_cast<const GfxColor
*>(maskColors
)+gfxColorMaxComps
,
1165 reinterpret_cast<GfxColor
*>(maskColors
)+gfxColorMaxComps
,
1169 aMaskBuf
.push_back( colToByte(aMinRGB
.r
) );
1170 aMaskBuf
.push_back( colToByte(aMinRGB
.g
) );
1171 aMaskBuf
.push_back( colToByte(aMinRGB
.b
) );
1172 aMaskBuf
.push_back( colToByte(aMaxRGB
.r
) );
1173 aMaskBuf
.push_back( colToByte(aMaxRGB
.g
) );
1174 aMaskBuf
.push_back( colToByte(aMaxRGB
.b
) );
1178 printf( " %d", static_cast<int>(aMaskBuf
.size()) );
1179 writeImageLF( aBuf
, str
, width
, height
, colorMap
);
1180 writeBinaryBuffer(aBuf
);
1181 writeBinaryBuffer(aMaskBuf
);
1184 void PDFOutDev::drawMaskedImage(GfxState
*, Object
*, Stream
* str
,
1185 int width
, int height
,
1186 GfxImageColorMap
* colorMap
,
1187 poppler_bool
/*interpolate*/,
1189 int maskWidth
, int maskHeight
,
1190 poppler_bool maskInvert
, poppler_bool
/*maskInterpolate*/
1195 OutputBuffer aBuf
; initBuf(aBuf
);
1196 printf( "drawImage %d %d 0", width
, height
);
1197 writePng_( aBuf
, str
, width
, height
, colorMap
, maskStr
, maskWidth
, maskHeight
, maskInvert
);
1198 writeBinaryBuffer( aBuf
);
1201 void PDFOutDev::drawSoftMaskedImage(GfxState
*, Object
*, Stream
* str
,
1202 int width
, int height
,
1203 GfxImageColorMap
* colorMap
,
1204 poppler_bool
/*interpolate*/,
1206 int maskWidth
, int maskHeight
,
1207 GfxImageColorMap
* maskColorMap
1208 , poppler_bool
/*maskInterpolate*/
1213 OutputBuffer aBuf
; initBuf(aBuf
);
1214 printf( "drawImage %d %d 0", width
, height
);
1215 writePng_( aBuf
, str
, width
, height
, colorMap
, maskStr
, maskWidth
, maskHeight
, maskColorMap
);
1216 writeBinaryBuffer( aBuf
);
1219 void PDFOutDev::setPageNum( int nNumPages
)
1221 // TODO(F3): printf might format int locale-dependent!
1222 printf("setPageNum %d\n", nNumPages
);
1225 void PDFOutDev::setSkipImages( bool bSkipImages
)
1227 m_bSkipImages
= bSkipImages
;
1230 #if POPPLER_CHECK_VERSION(21, 3, 0)
1231 poppler_bool
PDFOutDev::tilingPatternFill(GfxState
*state
, Gfx
*, Catalog
*,
1232 GfxTilingPattern
*tPat
, const double *mat
,
1233 int x0
, int y0
, int x1
, int y1
,
1234 double xStep
, double yStep
)
1236 const double *pBbox
= tPat
->getBBox();
1237 const int nPaintType
= tPat
->getPaintType();
1238 Dict
*pResDict
= tPat
->getResDict();
1239 Object
*aStr
= tPat
->getContentStream();
1240 double nWidth
= pBbox
[2] - pBbox
[0];
1241 double nHeight
= pBbox
[3] - pBbox
[1];
1243 // If our wrapper is skipping images then we don't need to do anything
1244 // but return 'true' so that Poppler doesn't do the slow method
1248 // Copied from the Cairo output dev; I think this is patterns
1249 // with gaps, let poppler do the slow method for now.
1250 if (xStep
!= nWidth
|| yStep
!= nHeight
)
1253 printf( "tilingPatternFill %d %d %d %d %f %f "
1255 "%f %f %f %f %f %f", // No ending space!
1257 x0
, y0
, x1
, y1
, normalize(xStep
), normalize(yStep
),
1261 normalize(mat
[0]), normalize(mat
[1]),
1262 normalize(mat
[2]), normalize(mat
[3]),
1263 normalize(mat
[4]), normalize(mat
[5])
1272 const int nDPI
= 72; // GfxState seems to have 72.0 as magic for some reason
1273 auto pSplashGfxState
= new GfxState(nDPI
, nDPI
, &aBox
, 0, false);
1274 auto pSplashOut
= new SplashOutputDev(splashModeRGB8
, 1, false, nullptr);
1275 pSplashOut
->setEnableFreeType(false);
1276 pSplashOut
->startDoc(m_pDoc
);
1277 pSplashOut
->startPage(0 /* pageNum */, pSplashGfxState
, nullptr /* xref */);
1279 auto pSplashGfx
= new Gfx(m_pDoc
, pSplashOut
, pResDict
, &aBox
, nullptr);
1280 pSplashGfx
->display(aStr
);
1281 std::unique_ptr
<SplashBitmap
> pSplashBitmap(pSplashOut
->takeBitmap());
1282 // Poppler tells us to free the splash device immediately after taking the
1284 delete pSplashGfxState
;
1288 // Add a vertical flip, we can't do this in LO for an image filled poly
1289 flipSplashBitmap(pSplashBitmap
.get());
1291 auto nBitmapWidth
= static_cast<size_t>(pSplashBitmap
->getWidth());
1292 auto nBitmapHeight
= static_cast<size_t>(pSplashBitmap
->getHeight());
1294 char *pBitmapData
= reinterpret_cast<char *>(pSplashBitmap
->getDataPtr());
1295 if (nPaintType
== 2)
1297 // My understanding is Type 2 fills are just bitmaps of *what* to fill
1298 // in the current fill colour.
1299 // sending it to LO as a flat colour image with the alpha map is easiest
1301 unsigned char r
,g
,b
;
1302 state
->getFillColorSpace()->getRGB(state
->getFillColor(), &aCurFill
);
1303 r
= colToByte(aCurFill
.r
);
1304 g
= colToByte(aCurFill
.g
);
1305 b
= colToByte(aCurFill
.b
);
1307 for(size_t i
=0; i
< (nBitmapWidth
* nBitmapHeight
* 3); i
+=3)
1309 pBitmapData
[i
] = r
;
1310 pBitmapData
[i
+1] = g
;
1311 pBitmapData
[i
+2] = b
;
1315 std::unique_ptr
<MemStream
> pRgbStr(new MemStream(pBitmapData
, 0,
1316 nBitmapWidth
* nBitmapHeight
* 3, Object(objNull
)));
1317 std::unique_ptr
<MemStream
> pAlphaStr(new MemStream(reinterpret_cast<char *>(pSplashBitmap
->getAlphaPtr()),
1318 0, nBitmapWidth
* nBitmapHeight
, Object(objNull
)));
1319 auto aDecode
= Object(objNull
);
1320 std::unique_ptr
<GfxImageColorMap
> pRgbIdentityColorMap(new GfxImageColorMap(8, &aDecode
,
1321 new GfxDeviceRGBColorSpace()));
1322 std::unique_ptr
<GfxImageColorMap
> pGrayIdentityColorMap(new GfxImageColorMap(8, &aDecode
,
1323 new GfxDeviceGrayColorSpace()));
1325 OutputBuffer aBuf
; initBuf(aBuf
);
1326 writePng_(aBuf
, pRgbStr
.get(), nBitmapWidth
, nBitmapHeight
, pRgbIdentityColorMap
.get(),
1327 pAlphaStr
.get(), nBitmapWidth
, nBitmapHeight
, pGrayIdentityColorMap
.get());
1328 writeBinaryBuffer(aBuf
);
1330 // If we return false here we can fall back to the slow path
1334 // This could be implemented for earlier versions, but the interface keeps
1335 // changing a little; not having it is only a problem for inputs with
1340 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */