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