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 
66 namespace pdfi
67 {
68 
70 static double normalize( double val )
71 {
72  return fabs(val) < 0.0000001 ? 0.0 : val;
73 }
74 
75 namespace
76 {
77 
80 std::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 
121 static void initBuf(OutputBuffer& io_rBuffer)
122 {
123  io_rBuffer.reserve(WRITE_BUFFER_INITIAL_CAPACITY);
124 }
125 
126 static 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 
141 static 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 
207 static 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 
226 static 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 
268 static 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 !
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 )
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 
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 )
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 
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 )
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
374 static 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 
382 static 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 
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); }
428 
429 
430 int PDFOutDev::parseFont( long long nNewId, GfxFont* gfxFont, 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  std::string familyName = gfxFont->getName()->toStr();
439  if (familyName.length() > 7 && familyName.at(6) == '+')
440  {
441  familyName = familyName.substr(7);
442  }
443 #endif
444  if( familyName != "" )
445  {
446  aNewFont.familyName.clear();
447 #if POPPLER_CHECK_VERSION(0, 74, 0) // at least 0.73 doesn't have GooString::append(const std::string&)
448  aNewFont.familyName.append( familyName );
449 #else
450  aNewFont.familyName.append( familyName.c_str() );
451 #endif
452  }
453  else
454  {
455  aNewFont.familyName.clear();
456  aNewFont.familyName.append( "Arial" );
457  }
458 
459  aNewFont.isBold = gfxFont->isBold();
460  aNewFont.isItalic = gfxFont->isItalic();
461  aNewFont.size = state->getTransformedFontSize();
462  aNewFont.isUnderline = false;
463 
464  if( gfxFont->getType() == fontTrueType || gfxFont->getType() == fontType1 )
465  {
466  // TODO(P3): Unfortunately, need to read stream twice, since
467  // we must write byte count to stdout before
468  char* pBuf = gfxFont->readEmbFontFile( m_pDoc->getXRef(), &nSize );
469  if( pBuf )
470  {
471  aNewFont.isEmbedded = true;
472  gfree(pBuf);
473  }
474  }
475 
476  m_aFontMap[ nNewId ] = aNewFont;
477  return nSize;
478 }
479 
480 void PDFOutDev::writeFontFile( GfxFont* gfxFont ) const
481 {
482  if( gfxFont->getType() != fontTrueType && gfxFont->getType() != fontType1 )
483  return;
484 
485  int nSize = 0;
486  char* pBuf = gfxFont->readEmbFontFile( m_pDoc->getXRef(), &nSize );
487  if( !pBuf )
488  return;
489 
490  // ---sync point--- see SYNC STREAMS above
491  fflush(stdout);
492 
493  if( fwrite(pBuf, sizeof(char), nSize, g_binary_out) != static_cast<size_t>(nSize) )
494  {
495  gfree(pBuf);
496  exit(1); // error
497  }
498  // ---sync point--- see SYNC STREAMS above
499  fflush(g_binary_out);
500  gfree(pBuf);
501 }
502 
503 #if POPPLER_CHECK_VERSION(0, 83, 0)
504 void PDFOutDev::printPath( const GfxPath* pPath )
505 #else
506 void PDFOutDev::printPath( GfxPath* pPath )
507 #endif
508 {
509  int nSubPaths = pPath ? pPath->getNumSubpaths() : 0;
510  for( int i=0; i<nSubPaths; i++ )
511  {
512 #if POPPLER_CHECK_VERSION(0, 83, 0)
513  const
514 #endif
515  GfxSubpath* pSub = pPath->getSubpath( i );
516  const int nPoints = pSub->getNumPoints();
517 
518  printf( " subpath %d", pSub->isClosed() );
519 
520  for( int n=0; n<nPoints; ++n )
521  {
522  printf( " %f %f %d",
523  normalize(pSub->getX(n)),
524  normalize(pSub->getY(n)),
525  pSub->getCurve(n) );
526  }
527  }
528 }
529 
530 PDFOutDev::PDFOutDev( PDFDoc* pDoc ) :
531  m_pDoc( pDoc ),
532  m_aFontMap(),
533  m_pUtf8Map( new UnicodeMap("UTF-8", true, &mapUTF8) ),
534  m_bSkipImages(false)
535 {
536 }
538 {
539 }
540 
541 void PDFOutDev::startPage(int /*pageNum*/, GfxState* state
542 #if POPPLER_CHECK_VERSION(0, 23, 0) || POPPLER_CHECK_VERSION(0, 24, 0)
543  , XRef* /*xref*/
544 #endif
545 )
546 {
547  assert(state);
548  printf("startPage %f %f\n",
549  normalize(state->getPageWidth()),
550  normalize(state->getPageHeight()));
551 }
552 
554 {
555  printf("endPage\n");
556 }
557 
558 #if POPPLER_CHECK_VERSION(0, 19, 0)
559 void PDFOutDev::processLink(AnnotLink *link)
560 #elif POPPLER_CHECK_VERSION(0, 17, 0)
561 void PDFOutDev::processLink(AnnotLink *link, Catalog *)
562 #else
563 void PDFOutDev::processLink(Link* link, Catalog*)
564 #endif
565 {
566  assert(link);
567 
568  double x1,x2,y1,y2;
569  link->getRect( &x1, &y1, &x2, &y2 );
570 
571  LinkAction* pAction = link->getAction();
572  if (!(pAction && pAction->getKind() == actionURI))
573  return;
574 
575 #if POPPLER_CHECK_VERSION(0, 86, 0)
576  const char* pURI = static_cast<LinkURI*>(pAction)->getURI().c_str();
577 #elif POPPLER_CHECK_VERSION(0, 72, 0)
578  const char* pURI = static_cast<LinkURI*>(pAction)->getURI()->c_str();
579 #else
580  const char* pURI = static_cast<LinkURI*>(pAction)->getURI()->getCString();
581 #endif
582 
583  std::vector<char> aEsc( lcl_escapeLineFeeds(pURI) );
584 
585  printf( "drawLink %f %f %f %f %s\n",
586  normalize(x1),
587  normalize(y1),
588  normalize(x2),
589  normalize(y2),
590  aEsc.data() );
591 }
592 
593 void PDFOutDev::saveState(GfxState*)
594 {
595  printf( "saveState\n" );
596 }
597 
598 void PDFOutDev::restoreState(GfxState*)
599 {
600  printf( "restoreState\n" );
601 }
602 
603 #if POPPLER_CHECK_VERSION(0, 71, 0)
604 void PDFOutDev::setDefaultCTM(const double *pMat)
605 #else
606 void PDFOutDev::setDefaultCTM(double *pMat)
607 #endif
608 {
609  assert(pMat);
610 
611  OutputDev::setDefaultCTM(pMat);
612 
613  printf( "updateCtm %f %f %f %f %f %f\n",
614  normalize(pMat[0]),
615  normalize(pMat[1]),
616  normalize(pMat[2]),
617  normalize(pMat[3]),
618  normalize(pMat[4]),
619  normalize(pMat[5]) );
620 }
621 
622 void PDFOutDev::updateCTM(GfxState* state,
623  double, double,
624  double, double,
625  double, double)
626 {
627  assert(state);
628 
629  const double* const pMat = state->getCTM();
630  assert(pMat);
631 
632  printf( "updateCtm %f %f %f %f %f %f\n",
633  normalize(pMat[0]),
634  normalize(pMat[1]),
635  normalize(pMat[2]),
636  normalize(pMat[3]),
637  normalize(pMat[4]),
638  normalize(pMat[5]) );
639 }
640 
641 void PDFOutDev::updateLineDash(GfxState *state)
642 {
643  if (m_bSkipImages)
644  return;
645  assert(state);
646 
647  double* dashArray; int arrayLen; double startOffset;
648  state->getLineDash(&dashArray, &arrayLen, &startOffset);
649 
650  printf( "updateLineDash" );
651  if( arrayLen && dashArray )
652  {
653  printf( " %f %d", normalize(startOffset), arrayLen );
654  for( int i=0; i<arrayLen; ++i )
655  printf( " %f", normalize(*dashArray++) );
656  }
657  printf( "\n" );
658 }
659 
660 void PDFOutDev::updateFlatness(GfxState *state)
661 {
662  if (m_bSkipImages)
663  return;
664  assert(state);
665  printf( "updateFlatness %d\n", state->getFlatness() );
666 }
667 
668 void PDFOutDev::updateLineJoin(GfxState *state)
669 {
670  if (m_bSkipImages)
671  return;
672  assert(state);
673  printf( "updateLineJoin %d\n", state->getLineJoin() );
674 }
675 
676 void PDFOutDev::updateLineCap(GfxState *state)
677 {
678  if (m_bSkipImages)
679  return;
680  assert(state);
681  printf( "updateLineCap %d\n", state->getLineCap() );
682 }
683 
684 void PDFOutDev::updateMiterLimit(GfxState *state)
685 {
686  if (m_bSkipImages)
687  return;
688  assert(state);
689  printf( "updateMiterLimit %f\n", normalize(state->getMiterLimit()) );
690 }
691 
692 void PDFOutDev::updateLineWidth(GfxState *state)
693 {
694  if (m_bSkipImages)
695  return;
696  assert(state);
697  printf( "updateLineWidth %f\n", normalize(state->getLineWidth()) );
698 }
699 
700 void PDFOutDev::updateFillColor(GfxState *state)
701 {
702  if (m_bSkipImages)
703  return;
704  assert(state);
705 
706  GfxRGB aRGB;
707  state->getFillRGB( &aRGB );
708 
709  printf( "updateFillColor %f %f %f %f\n",
710  normalize(colToDbl(aRGB.r)),
711  normalize(colToDbl(aRGB.g)),
712  normalize(colToDbl(aRGB.b)),
713  normalize(state->getFillOpacity()) );
714 }
715 
716 void PDFOutDev::updateStrokeColor(GfxState *state)
717 {
718  if (m_bSkipImages)
719  return;
720  assert(state);
721 
722  GfxRGB aRGB;
723  state->getStrokeRGB( &aRGB );
724 
725  printf( "updateStrokeColor %f %f %f %f\n",
726  normalize(colToDbl(aRGB.r)),
727  normalize(colToDbl(aRGB.g)),
728  normalize(colToDbl(aRGB.b)),
729  normalize(state->getFillOpacity()) );
730 }
731 
732 void PDFOutDev::updateFillOpacity(GfxState *state)
733 {
734  if (m_bSkipImages)
735  return;
736  updateFillColor(state);
737 }
738 
739 void PDFOutDev::updateStrokeOpacity(GfxState *state)
740 {
741  if (m_bSkipImages)
742  return;
743  updateStrokeColor(state);
744 }
745 
747 {
748 }
749 
750 void PDFOutDev::updateFont(GfxState *state)
751 {
752  assert(state);
753 
754  GfxFont *gfxFont = state->getFont();
755  if( !gfxFont )
756  return;
757 
758  FontAttributes aFont;
759  int nEmbedSize=0;
760 
761 #if POPPLER_CHECK_VERSION(0, 64, 0)
762  const
763 #endif
764  Ref* pID = gfxFont->getID();
765  // TODO(Q3): Portability problem
766  long long fontID = static_cast<long long>(pID->gen) << 32 | static_cast<long long>(pID->num);
767  std::unordered_map< long long, FontAttributes >::const_iterator it =
768  m_aFontMap.find( fontID );
769  if( it == m_aFontMap.end() )
770  {
771  nEmbedSize = parseFont( fontID, gfxFont, state );
772  it = m_aFontMap.find( fontID );
773  }
774 
775  printf( "updateFont" );
776  if( it != m_aFontMap.end() )
777  {
778  // conflating this with printf below crashes under Windoze
779  printf( " %lld", fontID );
780 
781  aFont = it->second;
782 
783 #if POPPLER_CHECK_VERSION(0, 72, 0)
784  std::vector<char> aEsc( lcl_escapeLineFeeds(aFont.familyName.c_str()) );
785 #else
786  std::vector<char> aEsc( lcl_escapeLineFeeds(aFont.familyName.getCString()) );
787 #endif
788  printf( " %d %d %d %d %f %d %s",
789  aFont.isEmbedded,
790  aFont.isBold,
791  aFont.isItalic,
792  aFont.isUnderline,
793  normalize(state->getTransformedFontSize()),
794  nEmbedSize,
795  aEsc.data() );
796  }
797  printf( "\n" );
798 }
799 
800 void PDFOutDev::updateRender(GfxState *state)
801 {
802  assert(state);
803 
804  printf( "setTextRenderMode %d\n", state->getRender() );
805 }
806 
807 void PDFOutDev::stroke(GfxState *state)
808 {
809  if (m_bSkipImages)
810  return;
811  assert(state);
812 
813  printf( "strokePath" );
814  printPath( state->getPath() );
815  printf( "\n" );
816 }
817 
818 void PDFOutDev::fill(GfxState *state)
819 {
820  if (m_bSkipImages)
821  return;
822  assert(state);
823 
824  printf( "fillPath" );
825  printPath( state->getPath() );
826  printf( "\n" );
827 }
828 
829 void PDFOutDev::eoFill(GfxState *state)
830 {
831  if (m_bSkipImages)
832  return;
833  assert(state);
834 
835  printf( "eoFillPath" );
836  printPath( state->getPath() );
837  printf( "\n" );
838 }
839 
840 void PDFOutDev::clip(GfxState *state)
841 {
842  if (m_bSkipImages)
843  return;
844  assert(state);
845 
846  printf( "clipPath" );
847  printPath( state->getPath() );
848  printf( "\n" );
849 }
850 
851 void PDFOutDev::eoClip(GfxState *state)
852 {
853  if (m_bSkipImages)
854  return;
855  assert(state);
856 
857  printf( "eoClipPath" );
858  printPath( state->getPath() );
859  printf( "\n" );
860 }
861 
882 #if POPPLER_CHECK_VERSION(0, 82, 0)
883 void PDFOutDev::drawChar(GfxState *state, double x, double y,
884  double dx, double dy,
885  double originX, double originY,
886  CharCode, int /*nBytes*/, const Unicode *u, int uLen)
887 {
888 #else
889 void PDFOutDev::drawChar(GfxState *state, double x, double y,
890  double dx, double dy,
891  double originX, double originY,
892  CharCode, int /*nBytes*/, Unicode *u, int uLen)
893 {
894 #endif
895  assert(state);
896 
897  if( u == nullptr )
898  return;
899 
900  // Fix for tdf#96080
901  if (uLen == 4 && u[0] == '\t' && u[1] == '\r' && u[2] == ' ' && u[3] == 0xA0)
902  {
903  u += 2;
904  uLen = 1;
905  }
906 
907  double csdx = 0.0;
908  double csdy = 0.0;
909  if (state->getFont()->getWMode())
910  {
911  csdy = state->getCharSpace();
912  if (*u == ' ')
913  csdy += state->getWordSpace();
914  }
915  else
916  {
917  csdx = state->getCharSpace();
918  if (*u == ' ')
919  csdx += state->getWordSpace();
920  csdx *= state->getHorizScaling();
921  }
922 
923  double cstdx = 0.0;
924  double cstdy = 0.0;
925  state->textTransformDelta(csdx, csdy, &cstdx, &cstdy);
926 
927  const double fontSize = state->getFontSize();
928 
929  const double aPositionX(x-originX);
930  const double aPositionY(y-originY);
931 
932  const double* pTextMat=state->getTextMat();
933  printf( "drawChar %f %f %f %f %f %f %f %f %f ",
934  normalize(aPositionX),
935  normalize(aPositionY),
936  normalize(aPositionX + dx - cstdx),
937  normalize(aPositionY + dy - cstdy),
938  normalize(pTextMat[0]),
939  normalize(pTextMat[2]),
940  normalize(pTextMat[1]),
941  normalize(pTextMat[3]),
942  normalize(fontSize)
943  );
944 
945  // silence spurious warning
946 #if POPPLER_CHECK_VERSION(0, 62, 0)
947  (void)&mapUTF16;
948 #else
949  (void)&mapUCS2;
950 #endif
951 
952  char buf[9];
953  for( int i=0; i<uLen; ++i )
954  {
955  buf[ m_pUtf8Map->mapUnicode(u[i], buf, sizeof(buf)-1) ] = 0;
956  std::vector<char> aEsc( lcl_escapeLineFeeds(buf) );
957  printf( "%s", aEsc.data() );
958  }
959 
960  printf( "\n" );
961 }
962 
963 #if POPPLER_CHECK_VERSION(0, 64, 0)
964 void PDFOutDev::drawString(GfxState*, const GooString* /*s*/)
965 #else
966 void PDFOutDev::drawString(GfxState*, GooString* /*s*/)
967 #endif
968 {
969  // TODO(F3): NYI
970 }
971 
973 {
974  printf( "endTextObject\n" );
975 }
976 
977 void PDFOutDev::drawImageMask(GfxState* pState, Object*, Stream* str,
978  int width, int height, poppler_bool invert,
979  poppler_bool /*interpolate*/,
980  poppler_bool /*inlineImg*/ )
981 {
982  if (m_bSkipImages)
983  return;
984  OutputBuffer aBuf; initBuf(aBuf);
985 
986  printf( "drawMask %d %d %d", width, height, invert );
987 
988  int bitsPerComponent = 1;
989  StreamColorSpaceMode csMode = streamCSNone;
990  str->getImageParams( &bitsPerComponent, &csMode );
991  if( bitsPerComponent == 1 && (csMode == streamCSNone || csMode == streamCSDeviceGray) )
992  {
993  GfxRGB oneColor = { dblToCol( 1.0 ), dblToCol( 1.0 ), dblToCol( 1.0 ) };
994  GfxRGB zeroColor = { dblToCol( 0.0 ), dblToCol( 0.0 ), dblToCol( 0.0 ) };
995  pState->getFillColorSpace()->getRGB( pState->getFillColor(), &zeroColor );
996  if( invert )
997  writePng_( aBuf, str, width, height, oneColor, zeroColor, true );
998  else
999  writePng_( aBuf, str, width, height, zeroColor, oneColor, true );
1000  }
1001  else
1002  writeMaskLF(aBuf, str, width, height, invert);
1003  writeBinaryBuffer(aBuf);
1004 }
1005 
1006 #if POPPLER_CHECK_VERSION(0, 82, 0)
1007 void PDFOutDev::drawImage(GfxState*, Object*, Stream* str,
1008  int width, int height, GfxImageColorMap* colorMap,
1009  poppler_bool /*interpolate*/,
1010  const int* maskColors, poppler_bool /*inlineImg*/ )
1011 {
1012 #else
1013 void PDFOutDev::drawImage(GfxState*, Object*, Stream* str,
1014  int width, int height, GfxImageColorMap* colorMap,
1015  poppler_bool /*interpolate*/,
1016  int* maskColors, poppler_bool /*inlineImg*/ )
1017 {
1018 #endif
1019  if (m_bSkipImages)
1020  return;
1021  OutputBuffer aBuf; initBuf(aBuf);
1022  OutputBuffer aMaskBuf;
1023 
1024  printf( "drawImage %d %d", width, height );
1025 
1026  if( maskColors )
1027  {
1028  // write mask colors. nBytes must be even - first half is
1029  // lower bound values, second half upper bound values
1030  if( colorMap->getColorSpace()->getMode() == csIndexed )
1031  {
1032  aMaskBuf.push_back( static_cast<char>(maskColors[0]) );
1033  aMaskBuf.push_back( static_cast<char>(maskColors[gfxColorMaxComps]) );
1034  }
1035  else
1036  {
1037  GfxRGB aMinRGB;
1038  colorMap->getColorSpace()->getRGB(
1039 #if POPPLER_CHECK_VERSION(0, 82, 0)
1040  reinterpret_cast<const GfxColor*>(maskColors),
1041 #else
1042  reinterpret_cast<GfxColor*>(maskColors),
1043 #endif
1044  &aMinRGB );
1045 
1046  GfxRGB aMaxRGB;
1047  colorMap->getColorSpace()->getRGB(
1048 #if POPPLER_CHECK_VERSION(0, 82, 0)
1049  reinterpret_cast<const GfxColor*>(maskColors)+gfxColorMaxComps,
1050 #else
1051  reinterpret_cast<GfxColor*>(maskColors)+gfxColorMaxComps,
1052 #endif
1053  &aMaxRGB );
1054 
1055  aMaskBuf.push_back( colToByte(aMinRGB.r) );
1056  aMaskBuf.push_back( colToByte(aMinRGB.g) );
1057  aMaskBuf.push_back( colToByte(aMinRGB.b) );
1058  aMaskBuf.push_back( colToByte(aMaxRGB.r) );
1059  aMaskBuf.push_back( colToByte(aMaxRGB.g) );
1060  aMaskBuf.push_back( colToByte(aMaxRGB.b) );
1061  }
1062  }
1063 
1064  printf( " %d", static_cast<int>(aMaskBuf.size()) );
1065  writeImageLF( aBuf, str, width, height, colorMap );
1066  writeBinaryBuffer(aBuf);
1067  writeBinaryBuffer(aMaskBuf);
1068 }
1069 
1070 void PDFOutDev::drawMaskedImage(GfxState*, Object*, Stream* str,
1071  int width, int height,
1072  GfxImageColorMap* colorMap,
1073  poppler_bool /*interpolate*/,
1074  Stream* maskStr,
1075  int maskWidth, int maskHeight,
1076  poppler_bool maskInvert, poppler_bool /*maskInterpolate*/
1077  )
1078 {
1079  if (m_bSkipImages)
1080  return;
1081  OutputBuffer aBuf; initBuf(aBuf);
1082  printf( "drawImage %d %d 0", width, height );
1083  writePng_( aBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert );
1084  writeBinaryBuffer( aBuf );
1085 }
1086 
1087 void PDFOutDev::drawSoftMaskedImage(GfxState*, Object*, Stream* str,
1088  int width, int height,
1089  GfxImageColorMap* colorMap,
1090  poppler_bool /*interpolate*/,
1091  Stream* maskStr,
1092  int maskWidth, int maskHeight,
1093  GfxImageColorMap* maskColorMap
1094  , poppler_bool /*maskInterpolate*/
1095  )
1096 {
1097  if (m_bSkipImages)
1098  return;
1099  OutputBuffer aBuf; initBuf(aBuf);
1100  printf( "drawImage %d %d 0", width, height );
1101  writePng_( aBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap );
1102  writeBinaryBuffer( aBuf );
1103 }
1104 
1105 void PDFOutDev::setPageNum( int nNumPages )
1106 {
1107  // TODO(F3): printf might format int locale-dependent!
1108  printf("setPageNum %d\n", nNumPages);
1109 }
1110 
1111 void PDFOutDev::setSkipImages( bool bSkipImages )
1112 {
1113  m_bSkipImages = bSkipImages;
1114 }
1115 
1116 }
1117 
1118 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static void writeJpeg_(OutputBuffer &o_rOutputBuf, Stream *str)
virtual void updateLineCap(GfxState *state) override
virtual void updateCTM(GfxState *state, double m11, double m12, double m21, double m22, double m31, double m32) override
#define WRITE_BUFFER_SIZE
for the temp char buffer the header gets snprintfed in
FILE * g_binary_out
Definition: wrapper_gpl.cxx:31
static void writePpm_(OutputBuffer &o_rOutputBuf, Stream *str, int width, int height, GfxImageColorMap *colorMap)
sal_Int32 nIndex
virtual void setDefaultCTM(double *ctm) override
virtual void updateLineDash(GfxState *state) override
virtual void updateFillColor(GfxState *state) override
virtual void startPage(int pageNum, GfxState *state) override
virtual void clip(GfxState *state) override
virtual ~PDFOutDev() override
sal_Int64 n
static void writeBinaryBuffer(const OutputBuffer &rBuffer)
aBuf
static void initBuf(OutputBuffer &io_rBuffer)
std::unordered_map< long long, FontAttributes > m_aFontMap
static void writePbm_(OutputBuffer &o_rOutputBuf, Stream *str, int width, int height, bool bInvert)
virtual void updateMiterLimit(GfxState *state) 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
float x
virtual void eoFill(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
#define WRITE_BUFFER_INITIAL_CAPACITY
for the initial std::vector capacity when copying stream from xpdf
static void writeImageLF(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)
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 setPageNum(int nNumPages)
virtual void stroke(GfxState *state) override
virtual void eoClip(GfxState *state) override
virtual void updateFlatness(GfxState *state) override
virtual void fill(GfxState *state) override
virtual void updateStrokeColor(GfxState *state) override
float y
static double normalize(double val)
cut off very small numbers & clamp value to zero
static void printPath(GfxPath *pPath)
int i
PDFOutDev(PDFDoc *pDoc)
virtual void processLink(Link *link, Catalog *catalog) override
size
virtual void restoreState(GfxState *state) override
virtual void drawString(GfxState *state, GooString *s) override
virtual void updateLineJoin(GfxState *state) override
virtual void updateFont(GfxState *state) override
unsigned char Output_t
std::vector< Output_t > OutputBuffer
static bool ExtractJpegData(Stream *str, OutputBuffer &outBuf)
void setSkipImages(bool bSkipImages)
static void createPng(OutputBuffer &o_rOutputBuf, Stream *str, int width, int height, GfxRGB const &zeroColor, GfxRGB const &oneColor, bool bIsMask)
Definition: pnghelper.cxx:178
std::unique_ptr< char[]> aBuffer
Definition: wrapper.cxx:846
virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, poppler_bool invert, poppler_bool interpolate, poppler_bool inlineImg) 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
#define POPPLER_CHECK_VERSION(major, minor, micro)
virtual void updateStrokeOpacity(GfxState *state) override
virtual void updateBlendMode(GfxState *state) override
void * p
virtual void endPage() override
virtual void endTextObject(GfxState *state) override
void writeFontFile(GfxFont *gfxFont) const
virtual void updateLineWidth(GfxState *state) override
int fontID
virtual void updateFillOpacity(GfxState *state) override
GBool poppler_bool
static void writeMask_(OutputBuffer &o_rOutputBuf, Stream *str, int width, int height, bool bInvert)
sal_Int32 nLength
static void writeMaskLF(OutputBuffer &o_rOutputBuf, Stream *str, int width, int height, bool bInvert)
static void writeImage_(OutputBuffer &o_rOutputBuf, Stream *str, int width, int height, GfxImageColorMap *colorMap)
std::unique_ptr< UnicodeMap > m_pUtf8Map
virtual void updateRender(GfxState *state) override
virtual void saveState(GfxState *state) override
FontMapType m_aFontMap
Definition: wrapper.cxx:152
int parseFont(long long nNewId, GfxFont *pFont, GfxState *state) const
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo