LibreOffice Module sdext (master) 1
pdfioutdev_gpl.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include "pdfioutdev_gpl.hxx"
21#include "pnghelper.hxx"
22
23#include <stdlib.h>
24#include <stdio.h>
25#include <assert.h>
26#include <math.h>
27
28#include <memory>
29#include <vector>
30
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
43
44#ifdef _WIN32
45# define snprintf _snprintf
46
47#if defined __GNUC__
48#pragma GCC diagnostic warning "-Wformat"
49#pragma GCC diagnostic warning "-Wformat-extra-args"
50#endif
51#endif
52
53/* SYNC STREAMS
54 ============
55
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.
64 */
65
66namespace pdfi
67{
68
70static double normalize( double val )
71{
72 return fabs(val) < 0.0000001 ? 0.0 : val;
73}
74
75namespace
76{
77
80std::vector<char> lcl_escapeLineFeeds(const char* const i_pStr)
81{
82 size_t nLength(strlen(i_pStr));
83 std::vector<char> aBuffer;
84 aBuffer.reserve(2*nLength+1);
85
86 const char* pRead = i_pStr;
87 while( nLength-- )
88 {
89 if( *pRead == '\r' )
90 {
91 aBuffer.push_back('\\');
92 aBuffer.push_back('r');
93 }
94 else if( *pRead == '\n' )
95 {
96 aBuffer.push_back('\\');
97 aBuffer.push_back('n');
98 }
99 else if( *pRead == '\\' )
100 {
101 aBuffer.push_back('\\');
102 aBuffer.push_back('\\');
103 }
104 else
105 aBuffer.push_back(*pRead);
106 pRead++;
107 }
108 aBuffer.push_back(0);
109
110 return aBuffer;
111}
112
113}
114
116#define WRITE_BUFFER_SIZE 1024
117
119#define WRITE_BUFFER_INITIAL_CAPACITY (1024*100)
120
121static void initBuf(OutputBuffer& io_rBuffer)
122{
123 io_rBuffer.reserve(WRITE_BUFFER_INITIAL_CAPACITY);
124}
125
126static void writeBinaryBuffer( const OutputBuffer& rBuffer )
127{
128 // ---sync point--- see SYNC STREAMS above
129 fflush(stdout);
130
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
136
137 // ---sync point--- see SYNC STREAMS above
138 fflush(g_binary_out);
139}
140
141static bool ExtractJpegData(Stream* str, OutputBuffer& outBuf)
142{
143 int bytesToMarker = 0;
144 int bytesToLen = -1;
145 bool collectBytes = false;
146 int startOfScan = 0;
147 int b1 = -1;
148 for (; ; )
149 {
150 const int b2 = b1;
151 b1 = str->getChar();
152
153 if (b1 == -1)
154 return false;
155
156 if (collectBytes)
157 {
158 outBuf.push_back(static_cast<Output_t>(b1));
159
160 bytesToMarker--;
161 bytesToLen--;
162 }
163
164 if (bytesToMarker == 0)
165 {
166 if (startOfScan == 1)
167 {
168 bytesToMarker = -1;
169 startOfScan = 2;
170 }
171 else if (b2 == 0xFF)
172 {
173 if (b1 == 0xD8)
174 {
175 collectBytes = true;
176 bytesToMarker = 2;
177
178 outBuf.push_back(Output_t(0xFF));
179 outBuf.push_back(Output_t(0xD8));
180 }
181 else
182 {
183 bytesToLen = 2;
184 }
185 if (b1 == 0xDA)
186 {
187 startOfScan = 1;
188 }
189 }
190 else if (collectBytes)
191 {
192 return false;
193 }
194 }
195
196 if (bytesToLen == 0)
197 {
198 bytesToMarker = b2 * 256 + b1;
199 }
200
201 if (startOfScan == 2)
202 if ((b2 == 0xFF) && (b1 == 0xD9))
203 return true;
204 }
205}
206
207static void writeJpeg_( OutputBuffer& o_rOutputBuf, Stream* str )
208{
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();
216
217 o_rOutputBuf.clear();
218 ExtractJpegData(str, o_rOutputBuf);
219
220 printf( " JPEG %d", static_cast<int>(o_rOutputBuf.size()) );
221 printf("\n");
222
223 str->close();
224}
225
226static void writePbm_(OutputBuffer& o_rOutputBuf, Stream* str, int width, int height, bool bInvert )
227{
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;
240
241 const int header_size = 3+nOutLen+1;
242 const int size = height * ((width + 7) / 8);
243
244 printf( " PBM %d", size + header_size );
245 printf("\n");
246
247 // trim buffer to exact header length
248 o_rOutputBuf.resize(header_size);
249
250 // initialize stream
251 str->reset();
252
253 // copy the raw stream
254 if( bInvert )
255 {
256 for( int i=0; i<size; ++i)
257 o_rOutputBuf.push_back(static_cast<char>(str->getChar() ^ 0xff));
258 }
259 else
260 {
261 for( int i=0; i<size; ++i)
262 o_rOutputBuf.push_back(static_cast<char>(str->getChar()));
263 }
264
265 str->close();
266}
267
268static void writePpm_( OutputBuffer& o_rOutputBuf,
269 Stream* str,
270 int width,
271 int height,
272 GfxImageColorMap* colorMap )
273{
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;
290
291 const int header_size = 3+nOutLen+5;
292 const int size = width*height*3 + header_size;
293
294 printf( " PPM %d", size );
295 printf("\n");
296
297 // trim buffer to exact header size
298 o_rOutputBuf.resize(header_size);
299
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();
309
310 for( int y=0; y<height; ++y)
311 {
312 p = imgStr->getLine();
313 for( int x=0; x<width; ++x)
314 {
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));
319
320 p +=colorMap->getNumPixelComps();
321 }
322 }
323}
324
325// call this only for 1 bit image streams !
326static 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 )
333{
334 o_rOutputBuf.clear();
335
336 // get png image
337 PngHelper::createPng( o_rOutputBuf, str, width, height, zeroColor, oneColor, bIsMask );
338
339 printf( " PNG %d", static_cast<int>(o_rOutputBuf.size()) );
340 printf("\n");
341}
342
343static 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 )
348{
349 o_rOutputBuf.clear();
350
351 // get png image
352 PngHelper::createPng( o_rOutputBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap );
353
354 printf( " PNG %d", static_cast<int>(o_rOutputBuf.size()) );
355 printf("\n");
356}
357
358static 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 )
363{
364 o_rOutputBuf.clear();
365
366 // get png image
367 PngHelper::createPng( o_rOutputBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert );
368
369 printf( " PNG %d", static_cast<int>(o_rOutputBuf.size()) );
370 printf("\n");
371}
372
373// stolen from ImageOutputDev.cc
374static void writeMask_( OutputBuffer& o_rOutputBuf, Stream* str, int width, int height, bool bInvert )
375{
376 if( str->getKind() == strDCT )
377 writeJpeg_(o_rOutputBuf, str);
378 else
379 writePbm_(o_rOutputBuf, str, width, height, bInvert );
380}
381
382static void writeImage_( OutputBuffer& o_rOutputBuf,
383 Stream* str,
384 int width,
385 int height,
386 GfxImageColorMap* colorMap )
387{
388 // dump JPEG file
389 if( str->getKind() == strDCT &&
390 (colorMap->getNumPixelComps() == 1 ||
391 colorMap->getNumPixelComps() == 3) )
392 {
393 writeJpeg_(o_rOutputBuf, str);
394 }
395 else if (colorMap->getNumPixelComps() == 1 &&
396 colorMap->getBits() == 1)
397 {
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 )
403 {
404 unsigned char nIndex = 0;
405 colorMap->getRGB( &nIndex, &zeroColor );
406 nIndex = 1;
407 colorMap->getRGB( &nIndex, &oneColor );
408 }
409 writePng_( o_rOutputBuf, str, width, height, zeroColor, oneColor, false);
410 }
411 else
412 writePpm_( o_rOutputBuf, str, width, height, colorMap );
413}
414
415// forwarders
416
417
418static void writeImageLF( OutputBuffer& o_rOutputBuf,
419 Stream* str,
420 int width,
421 int height,
422 GfxImageColorMap* colorMap ) { writeImage_(o_rOutputBuf,str,width,height,colorMap); }
423static void writeMaskLF( OutputBuffer& o_rOutputBuf,
424 Stream* str,
425 int width,
426 int height,
427 bool bInvert ) { writeMask_(o_rOutputBuf,str,width,height,bInvert); }
428
429
430int PDFOutDev::parseFont( long long nNewId, GfxFont* gfxFont, const GfxState* state ) const
431{
432 FontAttributes aNewFont;
433 int nSize = 0;
434
435#if POPPLER_CHECK_VERSION(20, 12, 0)
436 std::string familyName = gfxFont->getNameWithoutSubsetTag();
437#else
438#if POPPLER_CHECK_VERSION(0, 71, 0) // GooString::toStr()
439 std::string familyName = gfxFont->getName()->toStr();
440#else
441 const GooString* gooString = gfxFont->getName();
442 std::string familyName = std::string(gooString->getCString(), gooString->getLength());
443#endif
444 if (familyName.length() > 7 && familyName.at(6) == '+')
445 {
446 familyName = familyName.substr(7);
447 }
448#endif
449 if( familyName != "" )
450 {
451 aNewFont.familyName.clear();
452#if POPPLER_CHECK_VERSION(0, 83, 0) // GooString::append(const std::string&)
453 aNewFont.familyName.append( familyName );
454#else
455 aNewFont.familyName.append( familyName.c_str() );
456#endif
457 }
458 else
459 {
460 aNewFont.familyName.clear();
461 aNewFont.familyName.append( "Arial" );
462 }
463
464 aNewFont.maFontWeight = gfxFont->getWeight();
465 aNewFont.isItalic = gfxFont->isItalic();
466#if POPPLER_CHECK_VERSION(0, 83, 0) // const added to getTransformedFontSize
467 aNewFont.size = state->getTransformedFontSize();
468#else
469 aNewFont.size = const_cast<GfxState*>(state)->getTransformedFontSize();
470#endif
471 aNewFont.isUnderline = false;
472
473 if( gfxFont->getType() == fontTrueType || gfxFont->getType() == fontType1 )
474 {
475 // TODO(P3): Unfortunately, need to read stream twice, since
476 // we must write byte count to stdout before
477#if POPPLER_CHECK_VERSION(22, 6, 0)
478 std::optional<std::vector<unsigned char>> pBuf = gfxFont->readEmbFontFile( m_pDoc->getXRef() );
479 if ( pBuf )
480 {
481 aNewFont.isEmbedded = true;
482 nSize = pBuf->size();
483 }
484#else
485 char* pBuf = gfxFont->readEmbFontFile( m_pDoc->getXRef(), &nSize );
486 if( pBuf )
487 {
488 aNewFont.isEmbedded = true;
489 gfree(pBuf);
490 }
491#endif
492 }
493
494 m_aFontMap[ nNewId ] = aNewFont;
495 return nSize;
496}
497
498void PDFOutDev::writeFontFile( GfxFont* gfxFont ) const
499{
500 if( gfxFont->getType() != fontTrueType && gfxFont->getType() != fontType1 )
501 return;
502
503 int nSize = 0;
504#if POPPLER_CHECK_VERSION(22, 6, 0)
505 std::optional<std::vector<unsigned char>> pBuf = gfxFont->readEmbFontFile( m_pDoc->getXRef() );
506 if ( pBuf )
507 nSize = pBuf->size();
508 if ( nSize == 0 )
509 return;
510#else
511 char* pBuf = gfxFont->readEmbFontFile( m_pDoc->getXRef(), &nSize );
512 if( !pBuf )
513 return;
514#endif
515
516 // ---sync point--- see SYNC STREAMS above
517 fflush(stdout);
518
519#if POPPLER_CHECK_VERSION(22, 6, 0)
520 if( fwrite(pBuf->data(), sizeof(*pBuf->data()), nSize, g_binary_out) != static_cast<size_t>(nSize) )
521 {
522 exit(1); // error
523 }
524 // ---sync point--- see SYNC STREAMS above
525 fflush(g_binary_out);
526#else
527 if( fwrite(pBuf, sizeof(char), nSize, g_binary_out) != static_cast<size_t>(nSize) )
528 {
529 gfree(pBuf);
530 exit(1); // error
531 }
532 // ---sync point--- see SYNC STREAMS above
533 fflush(g_binary_out);
534 gfree(pBuf);
535#endif
536}
537
538#if POPPLER_CHECK_VERSION(0, 83, 0)
539void PDFOutDev::printPath( const GfxPath* pPath )
540#else
541void PDFOutDev::printPath( GfxPath* pPath )
542#endif
543{
544 int nSubPaths = pPath ? pPath->getNumSubpaths() : 0;
545 for( int i=0; i<nSubPaths; i++ )
546 {
547#if POPPLER_CHECK_VERSION(0, 83, 0)
548 const
549#endif
550 GfxSubpath* pSub = pPath->getSubpath( i );
551 const int nPoints = pSub->getNumPoints();
552
553 printf( " subpath %d", pSub->isClosed() );
554
555 for( int n=0; n<nPoints; ++n )
556 {
557 printf( " %f %f %d",
558 normalize(pSub->getX(n)),
559 normalize(pSub->getY(n)),
560 pSub->getCurve(n) );
561 }
562 }
563}
564
565PDFOutDev::PDFOutDev( PDFDoc* pDoc ) :
566 m_pDoc( pDoc ),
567 m_pUtf8Map( new UnicodeMap("UTF-8", true, &mapUTF8) ),
568 m_bSkipImages(false)
569{
570}
572{
573}
574
575void PDFOutDev::startPage(int /*pageNum*/, GfxState* state
576#if POPPLER_CHECK_VERSION(0, 23, 0) || POPPLER_CHECK_VERSION(0, 24, 0)
577 , XRef* /*xref*/
578#endif
579)
580{
581 assert(state);
582 printf("startPage %f %f\n",
583 normalize(state->getPageWidth()),
584 normalize(state->getPageHeight()));
585}
586
588{
589 printf("endPage\n");
590}
591
592#if POPPLER_CHECK_VERSION(0, 19, 0)
593void PDFOutDev::processLink(AnnotLink *link)
594#elif POPPLER_CHECK_VERSION(0, 17, 0)
595void PDFOutDev::processLink(AnnotLink *link, Catalog *)
596#else
597void PDFOutDev::processLink(Link* link, Catalog*)
598#endif
599{
600 assert(link);
601
602 double x1,x2,y1,y2;
603 link->getRect( &x1, &y1, &x2, &y2 );
604
605 LinkAction* pAction = link->getAction();
606 if (!(pAction && pAction->getKind() == actionURI))
607 return;
608
609#if POPPLER_CHECK_VERSION(0, 86, 0)
610 const char* pURI = static_cast<LinkURI*>(pAction)->getURI().c_str();
611#elif POPPLER_CHECK_VERSION(0, 72, 0)
612 const char* pURI = static_cast<LinkURI*>(pAction)->getURI()->c_str();
613#else
614 const char* pURI = static_cast<LinkURI*>(pAction)->getURI()->getCString();
615#endif
616
617 std::vector<char> aEsc( lcl_escapeLineFeeds(pURI) );
618
619 printf( "drawLink %f %f %f %f %s\n",
620 normalize(x1),
621 normalize(y1),
622 normalize(x2),
623 normalize(y2),
624 aEsc.data() );
625}
626
627void PDFOutDev::saveState(GfxState*)
628{
629 printf( "saveState\n" );
630}
631
633{
634 printf( "restoreState\n" );
635}
636
637#if POPPLER_CHECK_VERSION(0, 71, 0)
638void PDFOutDev::setDefaultCTM(const double *pMat)
639#else
640void PDFOutDev::setDefaultCTM(double *pMat)
641#endif
642{
643 assert(pMat);
644
645 OutputDev::setDefaultCTM(pMat);
646
647 printf( "updateCtm %f %f %f %f %f %f\n",
648 normalize(pMat[0]),
649 normalize(pMat[1]),
650 normalize(pMat[2]),
651 normalize(pMat[3]),
652 normalize(pMat[4]),
653 normalize(pMat[5]) );
654}
655
656void PDFOutDev::updateCTM(GfxState* state,
657 double, double,
658 double, double,
659 double, double)
660{
661 assert(state);
662
663 const double* const pMat = state->getCTM();
664 assert(pMat);
665
666 printf( "updateCtm %f %f %f %f %f %f\n",
667 normalize(pMat[0]),
668 normalize(pMat[1]),
669 normalize(pMat[2]),
670 normalize(pMat[3]),
671 normalize(pMat[4]),
672 normalize(pMat[5]) );
673}
674
675void PDFOutDev::updateLineDash(GfxState *state)
676{
677 if (m_bSkipImages)
678 return;
679 assert(state);
680
681 double* dashArray; int arrayLen; double startOffset;
682 state->getLineDash(&dashArray, &arrayLen, &startOffset);
683
684 printf( "updateLineDash" );
685 if( arrayLen && dashArray )
686 {
687 printf( " %f %d", normalize(startOffset), arrayLen );
688 for( int i=0; i<arrayLen; ++i )
689 printf( " %f", normalize(*dashArray++) );
690 }
691 printf( "\n" );
692}
693
694void PDFOutDev::updateFlatness(GfxState *state)
695{
696 if (m_bSkipImages)
697 return;
698 assert(state);
699 printf( "updateFlatness %d\n", state->getFlatness() );
700}
701
702void PDFOutDev::updateLineJoin(GfxState *state)
703{
704 if (m_bSkipImages)
705 return;
706 assert(state);
707 printf( "updateLineJoin %d\n", state->getLineJoin() );
708}
709
710void PDFOutDev::updateLineCap(GfxState *state)
711{
712 if (m_bSkipImages)
713 return;
714 assert(state);
715 printf( "updateLineCap %d\n", state->getLineCap() );
716}
717
718void PDFOutDev::updateMiterLimit(GfxState *state)
719{
720 if (m_bSkipImages)
721 return;
722 assert(state);
723 printf( "updateMiterLimit %f\n", normalize(state->getMiterLimit()) );
724}
725
726void PDFOutDev::updateLineWidth(GfxState *state)
727{
728 if (m_bSkipImages)
729 return;
730 assert(state);
731 printf( "updateLineWidth %f\n", normalize(state->getLineWidth()) );
732}
733
734void PDFOutDev::updateFillColor(GfxState *state)
735{
736 if (m_bSkipImages)
737 return;
738 assert(state);
739
740 GfxRGB aRGB;
741 state->getFillRGB( &aRGB );
742
743 printf( "updateFillColor %f %f %f %f\n",
744 normalize(colToDbl(aRGB.r)),
745 normalize(colToDbl(aRGB.g)),
746 normalize(colToDbl(aRGB.b)),
747 normalize(state->getFillOpacity()) );
748}
749
750void PDFOutDev::updateStrokeColor(GfxState *state)
751{
752 if (m_bSkipImages)
753 return;
754 assert(state);
755
756 GfxRGB aRGB;
757 state->getStrokeRGB( &aRGB );
758
759 printf( "updateStrokeColor %f %f %f %f\n",
760 normalize(colToDbl(aRGB.r)),
761 normalize(colToDbl(aRGB.g)),
762 normalize(colToDbl(aRGB.b)),
763 normalize(state->getFillOpacity()) );
764}
765
766void PDFOutDev::updateFillOpacity(GfxState *state)
767{
768 if (m_bSkipImages)
769 return;
770 updateFillColor(state);
771}
772
774{
775 if (m_bSkipImages)
776 return;
777 updateStrokeColor(state);
778}
779
781{
782}
783
784void PDFOutDev::updateFont(GfxState *state)
785{
786 assert(state);
787
788#if POPPLER_CHECK_VERSION(22, 6, 0)
789 GfxFont *gfxFont = state->getFont().get();
790#else
791 GfxFont *gfxFont = state->getFont();
792#endif
793 if( !gfxFont )
794 return;
795
796 FontAttributes aFont;
797 int nEmbedSize=0;
798
799#if POPPLER_CHECK_VERSION(0, 64, 0)
800 const
801#endif
802 Ref* pID = gfxFont->getID();
803 // TODO(Q3): Portability problem
804 long long fontID = static_cast<long long>(pID->gen) << 32 | static_cast<long long>(pID->num);
805 std::unordered_map< long long, FontAttributes >::const_iterator it =
806 m_aFontMap.find( fontID );
807 if( it == m_aFontMap.end() )
808 {
809 nEmbedSize = parseFont( fontID, gfxFont, state );
810 it = m_aFontMap.find( fontID );
811 }
812
813 printf( "updateFont" );
814 if( it != m_aFontMap.end() )
815 {
816 // conflating this with printf below crashes under Windoze
817 printf( " %lld", fontID );
818
819 aFont = it->second;
820
821#if POPPLER_CHECK_VERSION(0, 72, 0)
822 std::vector<char> aEsc( lcl_escapeLineFeeds(aFont.familyName.c_str()) );
823#else
824 std::vector<char> aEsc( lcl_escapeLineFeeds(aFont.familyName.getCString()) );
825#endif
826 printf( " %d %d %d %d %f %d %s",
827 aFont.isEmbedded,
828 aFont.maFontWeight,
829 aFont.isItalic,
830 aFont.isUnderline,
831 normalize(state->getTransformedFontSize()),
832 nEmbedSize,
833 aEsc.data() );
834 }
835 printf( "\n" );
836
837 if (nEmbedSize)
838 {
839 writeFontFile(gfxFont);
840 }
841}
842
843void PDFOutDev::updateRender(GfxState *state)
844{
845 assert(state);
846
847 printf( "setTextRenderMode %d\n", state->getRender() );
848}
849
850void PDFOutDev::stroke(GfxState *state)
851{
852 if (m_bSkipImages)
853 return;
854 assert(state);
855
856 printf( "strokePath" );
857 printPath( state->getPath() );
858 printf( "\n" );
859}
860
861void PDFOutDev::fill(GfxState *state)
862{
863 if (m_bSkipImages)
864 return;
865 assert(state);
866
867 printf( "fillPath" );
868 printPath( state->getPath() );
869 printf( "\n" );
870}
871
872void PDFOutDev::eoFill(GfxState *state)
873{
874 if (m_bSkipImages)
875 return;
876 assert(state);
877
878 printf( "eoFillPath" );
879 printPath( state->getPath() );
880 printf( "\n" );
881}
882
883void PDFOutDev::clip(GfxState *state)
884{
885 if (m_bSkipImages)
886 return;
887 assert(state);
888
889 printf( "clipPath" );
890 printPath( state->getPath() );
891 printf( "\n" );
892}
893
894void PDFOutDev::eoClip(GfxState *state)
895{
896 if (m_bSkipImages)
897 return;
898 assert(state);
899
900 printf( "eoClipPath" );
901 printPath( state->getPath() );
902 printf( "\n" );
903}
904
925#if POPPLER_CHECK_VERSION(0, 82, 0)
926void PDFOutDev::drawChar(GfxState *state, double x, double y,
927 double dx, double dy,
928 double originX, double originY,
929 CharCode, int /*nBytes*/, const Unicode *u, int uLen)
930{
931#else
932void PDFOutDev::drawChar(GfxState *state, double x, double y,
933 double dx, double dy,
934 double originX, double originY,
935 CharCode, int /*nBytes*/, Unicode *u, int uLen)
936{
937#endif
938 assert(state);
939
940 if( u == nullptr )
941 return;
942
943 // Fix for tdf#96080
944 if (uLen == 4 && u[0] == '\t' && u[1] == '\r' && u[2] == ' ' && u[3] == 0xA0)
945 {
946 u += 2;
947 uLen = 1;
948 }
949
950 double csdx = 0.0;
951 double csdy = 0.0;
952 if (state->getFont()->getWMode())
953 {
954 csdy = state->getCharSpace();
955 if (*u == ' ')
956 csdy += state->getWordSpace();
957 }
958 else
959 {
960 csdx = state->getCharSpace();
961 if (*u == ' ')
962 csdx += state->getWordSpace();
963 csdx *= state->getHorizScaling();
964 }
965
966 double cstdx = 0.0;
967 double cstdy = 0.0;
968 state->textTransformDelta(csdx, csdy, &cstdx, &cstdy);
969
970 const double fontSize = state->getFontSize();
971
972 const double aPositionX(x-originX);
973 const double aPositionY(y-originY);
974
975 const double* pTextMat=state->getTextMat();
976 printf( "drawChar %f %f %f %f %f %f %f %f %f ",
977 normalize(aPositionX),
978 normalize(aPositionY),
979 normalize(aPositionX + dx - cstdx),
980 normalize(aPositionY + dy - cstdy),
981 normalize(pTextMat[0]),
982 normalize(pTextMat[2]),
983 normalize(pTextMat[1]),
984 normalize(pTextMat[3]),
985 normalize(fontSize)
986 );
987
988 // silence spurious warning
989#if POPPLER_CHECK_VERSION(0, 62, 0)
990 (void)&mapUTF16;
991#else
992 (void)&mapUCS2;
993#endif
994
995 char buf[9];
996 for( int i=0; i<uLen; ++i )
997 {
998 buf[ m_pUtf8Map->mapUnicode(u[i], buf, sizeof(buf)-1) ] = 0;
999 std::vector<char> aEsc( lcl_escapeLineFeeds(buf) );
1000 printf( "%s", aEsc.data() );
1001 }
1002
1003 printf( "\n" );
1004}
1005
1006#if POPPLER_CHECK_VERSION(0, 64, 0)
1007void PDFOutDev::drawString(GfxState*, const GooString* /*s*/)
1008#else
1009void PDFOutDev::drawString(GfxState*, GooString* /*s*/)
1010#endif
1011{
1012 // TODO(F3): NYI
1013}
1014
1016{
1017 printf( "endTextObject\n" );
1018}
1019
1020void PDFOutDev::drawImageMask(GfxState* pState, Object*, Stream* str,
1021 int width, int height, poppler_bool invert,
1022 poppler_bool /*interpolate*/,
1023 poppler_bool /*inlineImg*/ )
1024{
1025 if (m_bSkipImages)
1026 return;
1028
1029 printf( "drawMask %d %d %d", width, height, invert );
1030
1031 int bitsPerComponent = 1;
1032 StreamColorSpaceMode csMode = streamCSNone;
1033 str->getImageParams( &bitsPerComponent, &csMode );
1034 if( bitsPerComponent == 1 && (csMode == streamCSNone || csMode == streamCSDeviceGray) )
1035 {
1036 GfxRGB oneColor = { dblToCol( 1.0 ), dblToCol( 1.0 ), dblToCol( 1.0 ) };
1037 GfxRGB zeroColor = { dblToCol( 0.0 ), dblToCol( 0.0 ), dblToCol( 0.0 ) };
1038 pState->getFillColorSpace()->getRGB( pState->getFillColor(), &zeroColor );
1039 if( invert )
1040 writePng_( aBuf, str, width, height, oneColor, zeroColor, true );
1041 else
1042 writePng_( aBuf, str, width, height, zeroColor, oneColor, true );
1043 }
1044 else
1045 writeMaskLF(aBuf, str, width, height, invert);
1047}
1048
1049#if POPPLER_CHECK_VERSION(0, 82, 0)
1050void PDFOutDev::drawImage(GfxState*, Object*, Stream* str,
1051 int width, int height, GfxImageColorMap* colorMap,
1052 poppler_bool /*interpolate*/,
1053 const int* maskColors, poppler_bool /*inlineImg*/ )
1054{
1055#else
1056void PDFOutDev::drawImage(GfxState*, Object*, Stream* str,
1057 int width, int height, GfxImageColorMap* colorMap,
1058 poppler_bool /*interpolate*/,
1059 int* maskColors, poppler_bool /*inlineImg*/ )
1060{
1061#endif
1062 if (m_bSkipImages)
1063 return;
1065 OutputBuffer aMaskBuf;
1066
1067 printf( "drawImage %d %d", width, height );
1068
1069 if( maskColors )
1070 {
1071 // write mask colors. nBytes must be even - first half is
1072 // lower bound values, second half upper bound values
1073 if( colorMap->getColorSpace()->getMode() == csIndexed )
1074 {
1075 aMaskBuf.push_back( static_cast<char>(maskColors[0]) );
1076 aMaskBuf.push_back( static_cast<char>(maskColors[gfxColorMaxComps]) );
1077 }
1078 else
1079 {
1080 GfxRGB aMinRGB;
1081 colorMap->getColorSpace()->getRGB(
1082#if POPPLER_CHECK_VERSION(0, 82, 0)
1083 reinterpret_cast<const GfxColor*>(maskColors),
1084#else
1085 reinterpret_cast<GfxColor*>(maskColors),
1086#endif
1087 &aMinRGB );
1088
1089 GfxRGB aMaxRGB;
1090 colorMap->getColorSpace()->getRGB(
1091#if POPPLER_CHECK_VERSION(0, 82, 0)
1092 reinterpret_cast<const GfxColor*>(maskColors)+gfxColorMaxComps,
1093#else
1094 reinterpret_cast<GfxColor*>(maskColors)+gfxColorMaxComps,
1095#endif
1096 &aMaxRGB );
1097
1098 aMaskBuf.push_back( colToByte(aMinRGB.r) );
1099 aMaskBuf.push_back( colToByte(aMinRGB.g) );
1100 aMaskBuf.push_back( colToByte(aMinRGB.b) );
1101 aMaskBuf.push_back( colToByte(aMaxRGB.r) );
1102 aMaskBuf.push_back( colToByte(aMaxRGB.g) );
1103 aMaskBuf.push_back( colToByte(aMaxRGB.b) );
1104 }
1105 }
1106
1107 printf( " %d", static_cast<int>(aMaskBuf.size()) );
1108 writeImageLF( aBuf, str, width, height, colorMap );
1110 writeBinaryBuffer(aMaskBuf);
1111}
1112
1113void PDFOutDev::drawMaskedImage(GfxState*, Object*, Stream* str,
1114 int width, int height,
1115 GfxImageColorMap* colorMap,
1116 poppler_bool /*interpolate*/,
1117 Stream* maskStr,
1118 int maskWidth, int maskHeight,
1119 poppler_bool maskInvert, poppler_bool /*maskInterpolate*/
1120 )
1121{
1122 if (m_bSkipImages)
1123 return;
1125 printf( "drawImage %d %d 0", width, height );
1126 writePng_( aBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert );
1128}
1129
1130void PDFOutDev::drawSoftMaskedImage(GfxState*, Object*, Stream* str,
1131 int width, int height,
1132 GfxImageColorMap* colorMap,
1133 poppler_bool /*interpolate*/,
1134 Stream* maskStr,
1135 int maskWidth, int maskHeight,
1136 GfxImageColorMap* maskColorMap
1137 , poppler_bool /*maskInterpolate*/
1138 )
1139{
1140 if (m_bSkipImages)
1141 return;
1143 printf( "drawImage %d %d 0", width, height );
1144 writePng_( aBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap );
1146}
1147
1148void PDFOutDev::setPageNum( int nNumPages )
1149{
1150 // TODO(F3): printf might format int locale-dependent!
1151 printf("setPageNum %d\n", nNumPages);
1152}
1153
1154void PDFOutDev::setSkipImages( bool bSkipImages )
1155{
1156 m_bSkipImages = bSkipImages;
1157}
1158
1159}
1160
1161/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual void endPage() override
virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, poppler_bool interpolate, Stream *maskStr, int maskWidth, int maskHeight, poppler_bool maskInvert, poppler_bool maskInterpolate) override
virtual void updateRender(GfxState *state) override
virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, poppler_bool interpolate, Stream *maskStr, int maskWidth, int maskHeight, GfxImageColorMap *maskColorMap, poppler_bool maskInterpolate) override
virtual void endTextObject(GfxState *state) override
virtual void clip(GfxState *state) override
virtual void updateLineWidth(GfxState *state) override
virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, poppler_bool invert, poppler_bool interpolate, poppler_bool inlineImg) override
std::unique_ptr< UnicodeMap > m_pUtf8Map
void setSkipImages(bool bSkipImages)
virtual void updateLineJoin(GfxState *state) override
virtual void updateLineDash(GfxState *state) override
virtual void saveState(GfxState *state) override
int parseFont(long long nNewId, GfxFont *pFont, const GfxState *state) const
virtual void updateBlendMode(GfxState *state) override
PDFOutDev(PDFDoc *pDoc)
void writeFontFile(GfxFont *gfxFont) const
virtual void eoClip(GfxState *state) override
static void printPath(GfxPath *pPath)
virtual void setDefaultCTM(double *ctm) override
virtual void drawString(GfxState *state, GooString *s) override
virtual void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, poppler_bool interpolate, int *maskColors, poppler_bool inlineImg) override
virtual void processLink(Link *link, Catalog *catalog) override
virtual void updateFillColor(GfxState *state) override
virtual void fill(GfxState *state) override
virtual void stroke(GfxState *state) override
virtual void restoreState(GfxState *state) override
virtual void eoFill(GfxState *state) override
virtual void updateStrokeColor(GfxState *state) override
static void setPageNum(int nNumPages)
virtual void updateLineCap(GfxState *state) override
virtual void updateCTM(GfxState *state, double m11, double m12, double m21, double m22, double m31, double m32) override
virtual ~PDFOutDev() override
virtual void updateFont(GfxState *state) override
virtual void updateStrokeOpacity(GfxState *state) override
std::unordered_map< long long, FontAttributes > m_aFontMap
virtual void updateFlatness(GfxState *state) override
virtual void updateFillOpacity(GfxState *state) override
virtual void updateMiterLimit(GfxState *state) override
virtual void startPage(int pageNum, GfxState *state) override
virtual void drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, CharCode code, int nBytes, Unicode *u, int uLen) override
Output one glyph.
static void createPng(OutputBuffer &o_rOutputBuf, Stream *str, int width, int height, GfxRGB const &zeroColor, GfxRGB const &oneColor, bool bIsMask)
Definition: pnghelper.cxx:178
float u
float y
float x
sal_Int32 nIndex
void * p
sal_Int64 n
aBuf
size
int i
GBool poppler_bool
static void writePbm_(OutputBuffer &o_rOutputBuf, Stream *str, int width, int height, bool bInvert)
static void writeBinaryBuffer(const OutputBuffer &rBuffer)
static void writeMask_(OutputBuffer &o_rOutputBuf, Stream *str, int width, int height, bool bInvert)
static double normalize(double val)
cut off very small numbers & clamp value to zero
static void writePpm_(OutputBuffer &o_rOutputBuf, Stream *str, int width, int height, GfxImageColorMap *colorMap)
static void writePng_(OutputBuffer &o_rOutputBuf, Stream *str, int width, int height, GfxRGB const &zeroColor, GfxRGB const &oneColor, bool bIsMask)
static void writeImageLF(OutputBuffer &o_rOutputBuf, Stream *str, int width, int height, GfxImageColorMap *colorMap)
static void writeMaskLF(OutputBuffer &o_rOutputBuf, Stream *str, int width, int height, bool bInvert)
static void writeJpeg_(OutputBuffer &o_rOutputBuf, Stream *str)
static bool ExtractJpegData(Stream *str, OutputBuffer &outBuf)
static void initBuf(OutputBuffer &io_rBuffer)
static void writeImage_(OutputBuffer &o_rOutputBuf, Stream *str, int width, int height, GfxImageColorMap *colorMap)
int fontID
#define WRITE_BUFFER_SIZE
for the temp char buffer the header gets snprintfed in
#define WRITE_BUFFER_INITIAL_CAPACITY
for the initial std::vector capacity when copying stream from xpdf
std::vector< Output_t > OutputBuffer
FILE * g_binary_out
Definition: wrapper_gpl.cxx:31
#define POPPLER_CHECK_VERSION(major, minor, micro)
unsigned char Output_t
GfxFont::Weight maFontWeight
std::unique_ptr< char[]> aBuffer
Definition: wrapper.cxx:971
sal_Int32 nLength