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