Line data Source code
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 <boost/shared_array.hpp>
29 :
30 : #if defined _MSC_VER
31 : #pragma warning(push, 1)
32 : #endif
33 :
34 : // sigh, UTF8.h was removed in poppler-0.21.0 and put back in 0.21.1
35 : // FIXME: we can't use #if POPPLER_CHECK_VERSION(0, 21, 0) && !POPPLER_CHECK_VERSION(0, 21, 1)
36 : // because the internal poppler does not provide poppler-version.h and the macro always returns 0
37 : #if POPPLER_CHECK_VERSION(0, 21, 1)
38 : #include "UTF8.h"
39 : #elif POPPLER_CHECK_VERSION(0, 21, 0)
40 : #include "UTF.h"
41 : #else
42 : #include "UTF8.h"
43 : #endif
44 :
45 : #if defined _MSC_VER
46 : #pragma warning(pop)
47 : #endif
48 :
49 : #ifdef WNT
50 : # define snprintf _snprintf
51 :
52 : #if defined __GNUC__
53 : #pragma GCC diagnostic warning "-Wformat"
54 : #pragma GCC diagnostic warning "-Wformat-extra-args"
55 : #endif
56 : #endif
57 :
58 : /* SYNC STREAMS
59 : ============
60 :
61 : We stream human-readble tokens to stdout, and binary data (fonts,
62 : bitmaps) to g_binary_out. Another process reads from those pipes, and
63 : there lies the rub: things can deadlock, if the two involved
64 : processes access the pipes in different order. At any point in
65 : time, both processes must access the same pipe. To ensure this,
66 : data must be flushed to the OS before writing to a different pipe,
67 : otherwise not-yet-written data will leave the reading process
68 : waiting on the wrong pipe.
69 : */
70 :
71 : namespace pdfi
72 : {
73 :
74 : /// cut off very small numbers & clamp value to zero
75 4088 : inline double normalize( double val )
76 : {
77 4088 : return fabs(val) < 0.0000001 ? 0.0 : val;
78 : }
79 :
80 : namespace
81 : {
82 :
83 : /** Escapes line-ending characters (\n and \r) in input string.
84 : */
85 428 : boost::shared_array<char> lcl_escapeLineFeeds(const char* const i_pStr)
86 : {
87 428 : size_t nLength(strlen(i_pStr));
88 428 : char* pBuffer = new char[2*nLength+1];
89 :
90 428 : const char* pRead = i_pStr;
91 428 : char* pWrite = pBuffer;
92 1866 : while( nLength-- )
93 : {
94 1010 : if( *pRead == '\r' )
95 : {
96 0 : *pWrite++ = '\\';
97 0 : *pWrite++ = 'r';
98 : }
99 1010 : else if( *pRead == '\n' )
100 : {
101 0 : *pWrite++ = '\\';
102 0 : *pWrite++ = 'n';
103 : }
104 1010 : else if( *pRead == '\\' )
105 : {
106 0 : *pWrite++ = '\\';
107 0 : *pWrite++ = '\\';
108 : }
109 : else
110 1010 : *pWrite++ = *pRead;
111 1010 : pRead++;
112 : }
113 428 : *pWrite++ = 0;
114 :
115 428 : return boost::shared_array<char>(pBuffer);
116 : }
117 :
118 : }
119 :
120 : /// for the temp char buffer the header gets snprintfed in
121 : #define WRITE_BUFFER_SIZE 1024
122 :
123 : /// for the initial std::vector capacity when copying stream from xpdf
124 : #define WRITE_BUFFER_INITIAL_CAPACITY (1024*100)
125 :
126 4 : void initBuf(OutputBuffer& io_rBuffer)
127 : {
128 4 : io_rBuffer.reserve(WRITE_BUFFER_INITIAL_CAPACITY);
129 4 : }
130 :
131 7 : void writeBinaryBuffer( const OutputBuffer& rBuffer )
132 : {
133 : // ---sync point--- see SYNC STREAMS above
134 7 : fflush(stdout);
135 :
136 : // put buffer to stderr
137 7 : if( !rBuffer.empty() )
138 8 : if( fwrite(&rBuffer[0], sizeof(char),
139 8 : rBuffer.size(), g_binary_out) != (size_t)rBuffer.size() )
140 0 : exit(1); // error
141 :
142 : // ---sync point--- see SYNC STREAMS above
143 7 : fflush(g_binary_out);
144 7 : }
145 :
146 3 : bool ExtractJpegData(Stream* str, OutputBuffer& outBuf)
147 : {
148 3 : int bytesToMarker = 0;
149 3 : int bytesToLen = -1;
150 3 : bool collectBytes = false;
151 3 : int startOfScan = 0;
152 3 : int b1 = -1;
153 : for (; ; )
154 : {
155 132387 : const int b2 = b1;
156 132387 : b1 = str->getChar();
157 :
158 132387 : if (b1 == -1)
159 0 : return false;
160 :
161 132387 : if (collectBytes)
162 : {
163 132381 : outBuf.push_back((Output_t)b1);
164 :
165 132381 : bytesToMarker--;
166 132381 : bytesToLen--;
167 : }
168 :
169 132387 : if (bytesToMarker == 0)
170 : {
171 30 : if (startOfScan == 1)
172 : {
173 3 : bytesToMarker = -1;
174 3 : startOfScan = 2;
175 : }
176 27 : else if (b2 == 0xFF)
177 : {
178 24 : if (b1 == 0xD8)
179 : {
180 3 : collectBytes = true;
181 3 : bytesToMarker = 2;
182 :
183 3 : outBuf.push_back((Output_t)0xFF);
184 3 : outBuf.push_back((Output_t)0xD8);
185 : }
186 : else
187 : {
188 21 : bytesToLen = 2;
189 : }
190 24 : if (b1 == 0xDA)
191 : {
192 3 : startOfScan = 1;
193 : }
194 : }
195 3 : else if (collectBytes)
196 : {
197 0 : return false;
198 : }
199 : }
200 :
201 132387 : if (bytesToLen == 0)
202 : {
203 21 : bytesToMarker = b2 * 256 + b1;
204 : }
205 :
206 132387 : if (startOfScan == 2)
207 131631 : if ((b2 == 0xFF) && (b1 == 0xD9))
208 3 : return true;
209 132384 : }
210 : }
211 :
212 3 : void writeJpeg_( OutputBuffer& o_rOutputBuf, Stream* str, bool bWithLinefeed )
213 : {
214 : // dump JPEG file as-is
215 : #if POPPLER_CHECK_VERSION(0, 17, 3)
216 3 : str = str->getNextStream();
217 : #else
218 : str = ((DCTStream *)str)->getRawStream();
219 : #endif
220 3 : str->reset();
221 :
222 3 : o_rOutputBuf.clear();
223 3 : ExtractJpegData(str, o_rOutputBuf);
224 :
225 3 : printf( " JPEG %d", (int)o_rOutputBuf.size() );
226 3 : if( bWithLinefeed )
227 3 : printf("\n");
228 :
229 3 : str->close();
230 3 : }
231 :
232 0 : void writePbm_(OutputBuffer& o_rOutputBuf, Stream* str, int width, int height, bool bWithLinefeed, bool bInvert )
233 : {
234 : // write as PBM (char by char, to avoid stdlib lineend messing)
235 0 : o_rOutputBuf.clear();
236 0 : o_rOutputBuf.resize(WRITE_BUFFER_SIZE);
237 0 : o_rOutputBuf[0] = 'P';
238 0 : o_rOutputBuf[1] = '4';
239 0 : o_rOutputBuf[2] = 0x0A;
240 0 : char *pAsCharPtr = reinterpret_cast<char *>(&o_rOutputBuf[3]);
241 0 : int nOutLen = snprintf(pAsCharPtr, WRITE_BUFFER_SIZE-10, "%d %d", width, height);
242 0 : if( nOutLen < 0 )
243 0 : nOutLen = WRITE_BUFFER_SIZE-10;
244 0 : o_rOutputBuf[3+nOutLen] =0x0A;
245 0 : o_rOutputBuf[3+nOutLen+1]=0;
246 :
247 0 : const int header_size = 3+nOutLen+1;
248 0 : const int size = height * ((width + 7) / 8);
249 :
250 0 : printf( " PBM %d", size + header_size );
251 0 : if( bWithLinefeed )
252 0 : printf("\n");
253 :
254 : // trim buffer to exact header length
255 0 : o_rOutputBuf.resize(header_size);
256 :
257 : // initialize stream
258 0 : str->reset();
259 :
260 : // copy the raw stream
261 0 : if( bInvert )
262 : {
263 0 : for( int i=0; i<size; ++i)
264 0 : o_rOutputBuf.push_back(static_cast<char>(str->getChar() ^ 0xff));
265 : }
266 : else
267 : {
268 0 : for( int i=0; i<size; ++i)
269 0 : o_rOutputBuf.push_back(static_cast<char>(str->getChar()));
270 : }
271 :
272 0 : str->close();
273 0 : }
274 :
275 0 : void writePpm_( OutputBuffer& o_rOutputBuf,
276 : Stream* str,
277 : int width,
278 : int height,
279 : GfxImageColorMap* colorMap,
280 : bool bWithLinefeed )
281 : {
282 : // write as PPM (char by char, to avoid stdlib lineend messing)
283 0 : o_rOutputBuf.clear();
284 0 : o_rOutputBuf.resize(WRITE_BUFFER_SIZE);
285 0 : o_rOutputBuf[0] = 'P';
286 0 : o_rOutputBuf[1] = '6';
287 0 : o_rOutputBuf[2] = '\n';
288 0 : char *pAsCharPtr = reinterpret_cast<char *>(&o_rOutputBuf[3]);
289 0 : int nOutLen = snprintf(pAsCharPtr, WRITE_BUFFER_SIZE-10, "%d %d", width, height);
290 0 : if( nOutLen < 0 )
291 0 : nOutLen = WRITE_BUFFER_SIZE-10;
292 0 : o_rOutputBuf[3+nOutLen] ='\n';
293 0 : o_rOutputBuf[3+nOutLen+1]='2';
294 0 : o_rOutputBuf[3+nOutLen+2]='5';
295 0 : o_rOutputBuf[3+nOutLen+3]='5';
296 0 : o_rOutputBuf[3+nOutLen+4]='\n';
297 0 : o_rOutputBuf[3+nOutLen+5]=0;
298 :
299 0 : const int header_size = 3+nOutLen+5;
300 0 : const int size = width*height*3 + header_size;
301 :
302 0 : printf( " PPM %d", size );
303 0 : if( bWithLinefeed )
304 0 : printf("\n");
305 :
306 : // trim buffer to exact header size
307 0 : o_rOutputBuf.resize(header_size);
308 :
309 : // initialize stream
310 : Guchar *p;
311 : GfxRGB rgb;
312 : ImageStream* imgStr =
313 : new ImageStream(str,
314 : width,
315 : colorMap->getNumPixelComps(),
316 0 : colorMap->getBits());
317 0 : imgStr->reset();
318 :
319 0 : for( int y=0; y<height; ++y)
320 : {
321 0 : p = imgStr->getLine();
322 0 : for( int x=0; x<width; ++x)
323 : {
324 0 : colorMap->getRGB(p, &rgb);
325 0 : o_rOutputBuf.push_back(colToByte(rgb.r));
326 0 : o_rOutputBuf.push_back(colToByte(rgb.g));
327 0 : o_rOutputBuf.push_back(colToByte(rgb.b));
328 :
329 0 : p +=colorMap->getNumPixelComps();
330 : }
331 : }
332 :
333 0 : delete imgStr;
334 :
335 0 : }
336 :
337 : // call this only for 1 bit image streams !
338 0 : void writePng_( OutputBuffer& o_rOutputBuf,
339 : Stream* str,
340 : int width,
341 : int height,
342 : GfxRGB& zeroColor,
343 : GfxRGB& oneColor,
344 : bool bIsMask,
345 : bool bWithLinefeed )
346 : {
347 0 : o_rOutputBuf.clear();
348 :
349 : // get png image
350 0 : PngHelper::createPng( o_rOutputBuf, str, width, height, zeroColor, oneColor, bIsMask );
351 :
352 0 : printf( " PNG %d", (int)o_rOutputBuf.size() );
353 0 : if( bWithLinefeed )
354 0 : printf("\n");
355 0 : }
356 :
357 1 : void writePng_( OutputBuffer& o_rOutputBuf,
358 : Stream* str,
359 : int width, int height, GfxImageColorMap* colorMap,
360 : Stream* maskStr,
361 : int maskWidth, int maskHeight, GfxImageColorMap* maskColorMap,
362 : bool bWithLinefeed )
363 : {
364 1 : o_rOutputBuf.clear();
365 :
366 : // get png image
367 1 : PngHelper::createPng( o_rOutputBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap );
368 :
369 1 : printf( " PNG %d", (int)o_rOutputBuf.size() );
370 1 : if( bWithLinefeed )
371 1 : printf("\n");
372 1 : }
373 :
374 0 : void writePng_( OutputBuffer& o_rOutputBuf,
375 : Stream* str,
376 : int width, int height, GfxImageColorMap* colorMap,
377 : Stream* maskStr,
378 : int maskWidth, int maskHeight, bool maskInvert,
379 : bool bWithLinefeed )
380 : {
381 0 : o_rOutputBuf.clear();
382 :
383 : // get png image
384 0 : PngHelper::createPng( o_rOutputBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert );
385 :
386 0 : printf( " PNG %d", (int)o_rOutputBuf.size() );
387 0 : if( bWithLinefeed )
388 0 : printf("\n");
389 0 : }
390 :
391 : // stolen from ImageOutputDev.cc
392 0 : void writeMask_( OutputBuffer& o_rOutputBuf, Stream* str, int width, int height, bool bWithLinefeed, bool bInvert )
393 : {
394 0 : if( str->getKind() == strDCT )
395 0 : writeJpeg_(o_rOutputBuf, str, bWithLinefeed);
396 : else
397 0 : writePbm_(o_rOutputBuf, str, width, height, bWithLinefeed, bInvert );
398 0 : }
399 :
400 3 : void writeImage_( OutputBuffer& o_rOutputBuf,
401 : Stream* str,
402 : int width,
403 : int height,
404 : GfxImageColorMap* colorMap,
405 : bool bWithLinefeed )
406 : {
407 : // dump JPEG file
408 9 : if( str->getKind() == strDCT &&
409 6 : (colorMap->getNumPixelComps() == 1 ||
410 3 : colorMap->getNumPixelComps() == 3) )
411 : {
412 3 : writeJpeg_(o_rOutputBuf, str, bWithLinefeed);
413 : }
414 0 : else if (colorMap->getNumPixelComps() == 1 &&
415 0 : colorMap->getBits() == 1)
416 : {
417 : // this is a two color bitmap, write a png
418 : // provide default colors
419 0 : GfxRGB zeroColor = { 0, 0, 0 },
420 0 : oneColor = { byteToCol( 0xff ), byteToCol( 0xff ), byteToCol( 0xff ) };
421 0 : if( colorMap->getColorSpace()->getMode() == csIndexed || colorMap->getColorSpace()->getMode() == csDeviceGray )
422 : {
423 0 : Guchar nIndex = 0;
424 0 : colorMap->getRGB( &nIndex, &zeroColor );
425 0 : nIndex = 1;
426 0 : colorMap->getRGB( &nIndex, &oneColor );
427 : }
428 0 : writePng_( o_rOutputBuf, str, width, height, zeroColor, oneColor, false, bWithLinefeed );
429 : }
430 : else
431 0 : writePpm_( o_rOutputBuf, str, width, height, colorMap, bWithLinefeed );
432 3 : }
433 :
434 : // forwarders
435 :
436 :
437 3 : inline void writeImageLF( OutputBuffer& o_rOutputBuf,
438 : Stream* str,
439 : int width,
440 : int height,
441 3 : GfxImageColorMap* colorMap ) { writeImage_(o_rOutputBuf,str,width,height,colorMap,true); }
442 0 : inline void writeMaskLF( OutputBuffer& o_rOutputBuf,
443 : Stream* str,
444 : int width,
445 : int height,
446 0 : bool bInvert ) { writeMask_(o_rOutputBuf,str,width,height,true,bInvert); }
447 :
448 :
449 :
450 :
451 11 : int PDFOutDev::parseFont( long long nNewId, GfxFont* gfxFont, GfxState* state ) const
452 : {
453 11 : FontAttributes aNewFont;
454 11 : int nSize = 0;
455 :
456 11 : GooString* pFamily = gfxFont->getName();
457 11 : if( pFamily )
458 : {
459 11 : aNewFont.familyName.clear();
460 11 : aNewFont.familyName.append( gfxFont->getName() );
461 : }
462 : else
463 : {
464 0 : aNewFont.familyName.clear();
465 0 : aNewFont.familyName.append( "Arial" );
466 : }
467 :
468 11 : aNewFont.isBold = gfxFont->isBold();
469 11 : aNewFont.isItalic = gfxFont->isItalic();
470 11 : aNewFont.size = state->getTransformedFontSize();
471 11 : aNewFont.isUnderline = false;
472 :
473 11 : 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 11 : char* pBuf = gfxFont->readEmbFontFile( m_pDoc->getXRef(), &nSize );
478 11 : if( pBuf )
479 : {
480 11 : aNewFont.isEmbedded = true;
481 11 : gfree(pBuf);
482 : }
483 : }
484 :
485 11 : m_aFontMap[ nNewId ] = aNewFont;
486 11 : return nSize;
487 : }
488 :
489 11 : void PDFOutDev::writeFontFile( GfxFont* gfxFont ) const
490 : {
491 11 : if( gfxFont->getType() != fontTrueType && gfxFont->getType() != fontType1 )
492 0 : return;
493 :
494 11 : int nSize = 0;
495 11 : char* pBuf = gfxFont->readEmbFontFile( m_pDoc->getXRef(), &nSize );
496 11 : if( !pBuf )
497 0 : return;
498 :
499 : // ---sync point--- see SYNC STREAMS above
500 11 : fflush(stdout);
501 :
502 11 : if( fwrite(pBuf, sizeof(char), nSize, g_binary_out) != (size_t)nSize )
503 : {
504 0 : gfree(pBuf);
505 0 : exit(1); // error
506 : }
507 : // ---sync point--- see SYNC STREAMS above
508 11 : fflush(g_binary_out);
509 11 : gfree(pBuf);
510 : }
511 :
512 18 : void PDFOutDev::printPath( GfxPath* pPath )
513 : {
514 18 : int nSubPaths = pPath ? pPath->getNumSubpaths() : 0;
515 36 : for( int i=0; i<nSubPaths; i++ )
516 : {
517 18 : GfxSubpath* pSub = pPath->getSubpath( i );
518 18 : const int nPoints = pSub->getNumPoints();
519 :
520 18 : printf( " subpath %d", pSub->isClosed() );
521 :
522 114 : for( int n=0; n<nPoints; ++n )
523 : {
524 : printf( " %f %f %d",
525 : normalize(pSub->getX(n)),
526 : normalize(pSub->getY(n)),
527 96 : pSub->getCurve(n) );
528 : }
529 : }
530 18 : }
531 :
532 5 : PDFOutDev::PDFOutDev( PDFDoc* pDoc ) :
533 : m_pDoc( pDoc ),
534 : m_aFontMap(),
535 5 : m_pUtf8Map( new UnicodeMap("UTF-8", gTrue, &mapUTF8) ),
536 10 : m_bSkipImages(false)
537 : {
538 5 : }
539 10 : PDFOutDev::~PDFOutDev()
540 : {
541 5 : delete m_pUtf8Map;
542 5 : }
543 :
544 5 : void PDFOutDev::startPage(int /*pageNum*/, GfxState* state
545 : #if POPPLER_CHECK_VERSION(0, 23, 0) || POPPLER_CHECK_VERSION(0, 24, 0)
546 : , XRef* /*xref*/
547 : #endif
548 : )
549 : {
550 : assert(state);
551 : printf("startPage %f %f\n",
552 : normalize(state->getPageWidth()),
553 5 : normalize(state->getPageHeight()));
554 5 : }
555 :
556 5 : void PDFOutDev::endPage()
557 : {
558 5 : printf("endPage\n");
559 5 : }
560 :
561 : #if POPPLER_CHECK_VERSION(0, 19, 0)
562 3 : void PDFOutDev::processLink(AnnotLink *link)
563 : #elif POPPLER_CHECK_VERSION(0, 17, 0)
564 : void PDFOutDev::processLink(AnnotLink *link, Catalog *)
565 : #else
566 : void PDFOutDev::processLink(Link* link, Catalog*)
567 : #endif
568 : {
569 : assert(link);
570 :
571 : double x1,x2,y1,y2;
572 3 : link->getRect( &x1, &y1, &x2, &y2 );
573 :
574 3 : LinkAction* pAction = link->getAction();
575 3 : if (pAction && pAction->getKind() == actionURI)
576 : {
577 3 : const char* pURI = static_cast<LinkURI*>(pAction)->getURI()->getCString();
578 :
579 3 : boost::shared_array<char> pEsc( lcl_escapeLineFeeds(pURI) );
580 :
581 : printf( "drawLink %f %f %f %f %s\n",
582 : normalize(x1),
583 : normalize(y1),
584 : normalize(x2),
585 : normalize(y2),
586 3 : pEsc.get() );
587 : }
588 3 : }
589 :
590 58 : void PDFOutDev::saveState(GfxState*)
591 : {
592 58 : printf( "saveState\n" );
593 58 : }
594 :
595 58 : void PDFOutDev::restoreState(GfxState*)
596 : {
597 58 : printf( "restoreState\n" );
598 58 : }
599 :
600 5 : void PDFOutDev::setDefaultCTM(double *pMat)
601 : {
602 : assert(pMat);
603 :
604 5 : OutputDev::setDefaultCTM(pMat);
605 :
606 : printf( "updateCtm %f %f %f %f %f %f\n",
607 : normalize(pMat[0]),
608 5 : normalize(pMat[1]),
609 5 : normalize(pMat[2]),
610 5 : normalize(pMat[3]),
611 5 : normalize(pMat[4]),
612 25 : normalize(pMat[5]) );
613 5 : }
614 :
615 5 : void PDFOutDev::updateCTM(GfxState* state,
616 : double, double,
617 : double, double,
618 : double, double)
619 : {
620 : assert(state);
621 :
622 5 : const double* const pMat = state->getCTM();
623 : assert(pMat);
624 :
625 : printf( "updateCtm %f %f %f %f %f %f\n",
626 : normalize(pMat[0]),
627 5 : normalize(pMat[1]),
628 5 : normalize(pMat[2]),
629 5 : normalize(pMat[3]),
630 5 : normalize(pMat[4]),
631 25 : normalize(pMat[5]) );
632 5 : }
633 :
634 8 : void PDFOutDev::updateLineDash(GfxState *state)
635 : {
636 8 : if (m_bSkipImages)
637 9 : return;
638 : assert(state);
639 :
640 : double* dashArray; int arrayLen; double startOffset;
641 7 : state->getLineDash(&dashArray, &arrayLen, &startOffset);
642 :
643 7 : printf( "updateLineDash" );
644 7 : if( arrayLen && dashArray )
645 : {
646 3 : printf( " %f %d", normalize(startOffset), arrayLen );
647 15 : for( int i=0; i<arrayLen; ++i )
648 12 : printf( " %f", normalize(*dashArray++) );
649 : }
650 7 : printf( "\n" );
651 : }
652 :
653 5 : void PDFOutDev::updateFlatness(GfxState *state)
654 : {
655 5 : if (m_bSkipImages)
656 6 : return;
657 : assert(state);
658 4 : printf( "updateFlatness %d\n", state->getFlatness() );
659 : }
660 :
661 11 : void PDFOutDev::updateLineJoin(GfxState *state)
662 : {
663 11 : if (m_bSkipImages)
664 12 : return;
665 : assert(state);
666 10 : printf( "updateLineJoin %d\n", state->getLineJoin() );
667 : }
668 :
669 11 : void PDFOutDev::updateLineCap(GfxState *state)
670 : {
671 11 : if (m_bSkipImages)
672 12 : return;
673 : assert(state);
674 10 : printf( "updateLineCap %d\n", state->getLineCap() );
675 : }
676 :
677 5 : void PDFOutDev::updateMiterLimit(GfxState *state)
678 : {
679 5 : if (m_bSkipImages)
680 6 : return;
681 : assert(state);
682 4 : printf( "updateMiterLimit %f\n", normalize(state->getMiterLimit()) );
683 : }
684 :
685 16 : void PDFOutDev::updateLineWidth(GfxState *state)
686 : {
687 16 : if (m_bSkipImages)
688 18 : return;
689 : assert(state);
690 14 : printf( "updateLineWidth %f\n", normalize(state->getLineWidth()) );
691 : }
692 :
693 47 : void PDFOutDev::updateFillColor(GfxState *state)
694 : {
695 47 : if (m_bSkipImages)
696 49 : return;
697 : assert(state);
698 :
699 : GfxRGB aRGB;
700 45 : state->getFillRGB( &aRGB );
701 :
702 : printf( "updateFillColor %f %f %f %f\n",
703 : normalize(colToDbl(aRGB.r)),
704 : normalize(colToDbl(aRGB.g)),
705 : normalize(colToDbl(aRGB.b)),
706 45 : normalize(state->getFillOpacity()) );
707 : }
708 :
709 15 : void PDFOutDev::updateStrokeColor(GfxState *state)
710 : {
711 15 : if (m_bSkipImages)
712 16 : return;
713 : assert(state);
714 :
715 : GfxRGB aRGB;
716 14 : state->getStrokeRGB( &aRGB );
717 :
718 : printf( "updateStrokeColor %f %f %f %f\n",
719 : normalize(colToDbl(aRGB.r)),
720 : normalize(colToDbl(aRGB.g)),
721 : normalize(colToDbl(aRGB.b)),
722 14 : normalize(state->getFillOpacity()) );
723 : }
724 :
725 5 : void PDFOutDev::updateFillOpacity(GfxState *state)
726 : {
727 5 : if (m_bSkipImages)
728 6 : return;
729 4 : updateFillColor(state);
730 : }
731 :
732 5 : void PDFOutDev::updateStrokeOpacity(GfxState *state)
733 : {
734 5 : if (m_bSkipImages)
735 6 : return;
736 4 : updateStrokeColor(state);
737 : }
738 :
739 5 : void PDFOutDev::updateBlendMode(GfxState*)
740 : {
741 5 : }
742 :
743 40 : void PDFOutDev::updateFont(GfxState *state)
744 : {
745 : assert(state);
746 :
747 40 : GfxFont *gfxFont = state->getFont();
748 40 : if( gfxFont )
749 : {
750 35 : FontAttributes aFont;
751 35 : int nEmbedSize=0;
752 :
753 35 : Ref* pID = gfxFont->getID();
754 : // TODO(Q3): Portability problem
755 35 : long long fontID = (long long)pID->gen << 32 | (long long)pID->num;
756 : std::unordered_map< long long, FontAttributes >::const_iterator it =
757 35 : m_aFontMap.find( fontID );
758 35 : if( it == m_aFontMap.end() )
759 : {
760 11 : nEmbedSize = parseFont( fontID, gfxFont, state );
761 11 : it = m_aFontMap.find( fontID );
762 : }
763 :
764 35 : printf( "updateFont" );
765 35 : if( it != m_aFontMap.end() )
766 : {
767 : // conflating this with printf below crashes under Windoze
768 35 : printf( " %lld", fontID );
769 :
770 35 : aFont = it->second;
771 :
772 35 : boost::shared_array<char> pEsc( lcl_escapeLineFeeds(aFont.familyName.getCString()) );
773 : printf( " %d %d %d %d %f %d %s",
774 : aFont.isEmbedded,
775 : aFont.isBold,
776 : aFont.isItalic,
777 : aFont.isUnderline,
778 : normalize(state->getTransformedFontSize()),
779 : nEmbedSize,
780 35 : pEsc.get() );
781 : }
782 35 : printf( "\n" );
783 :
784 35 : if( nEmbedSize )
785 11 : writeFontFile(gfxFont);
786 : }
787 40 : }
788 :
789 0 : void PDFOutDev::updateRender(GfxState *state)
790 : {
791 : assert(state);
792 :
793 0 : printf( "setTextRenderMode %d\n", state->getRender() );
794 0 : }
795 :
796 6 : void PDFOutDev::stroke(GfxState *state)
797 : {
798 6 : if (m_bSkipImages)
799 6 : return;
800 : assert(state);
801 :
802 6 : printf( "strokePath" );
803 6 : printPath( state->getPath() );
804 6 : printf( "\n" );
805 : }
806 :
807 0 : void PDFOutDev::fill(GfxState *state)
808 : {
809 0 : if (m_bSkipImages)
810 0 : return;
811 : assert(state);
812 :
813 0 : printf( "fillPath" );
814 0 : printPath( state->getPath() );
815 0 : printf( "\n" );
816 : }
817 :
818 3 : void PDFOutDev::eoFill(GfxState *state)
819 : {
820 3 : if (m_bSkipImages)
821 3 : return;
822 : assert(state);
823 :
824 3 : printf( "eoFillPath" );
825 3 : printPath( state->getPath() );
826 3 : printf( "\n" );
827 : }
828 :
829 5 : void PDFOutDev::clip(GfxState *state)
830 : {
831 5 : if (m_bSkipImages)
832 6 : return;
833 : assert(state);
834 :
835 4 : printf( "clipPath" );
836 4 : printPath( state->getPath() );
837 4 : printf( "\n" );
838 : }
839 :
840 7 : void PDFOutDev::eoClip(GfxState *state)
841 : {
842 7 : if (m_bSkipImages)
843 9 : return;
844 : assert(state);
845 :
846 5 : printf( "eoClipPath" );
847 5 : printPath( state->getPath() );
848 5 : printf( "\n" );
849 : }
850 :
851 : /** Output one glyph
852 :
853 :
854 : @param dx
855 : horizontal skip for character (already scaled with font size) +
856 : inter-char space: cursor is shifted by this amount for next char
857 :
858 : @param dy
859 : vertical skip for character (zero for horizontal writing mode):
860 : cursor is shifted by this amount for next char
861 :
862 : @param originX
863 : local offset of character (zero for horizontal writing mode). not
864 : taken into account for output pos updates. Used for vertical writing.
865 :
866 : @param originY
867 : local offset of character (zero for horizontal writing mode). not
868 : taken into account for output pos updates. Used for vertical writing.
869 : */
870 390 : void PDFOutDev::drawChar(GfxState *state, double x, double y,
871 : double dx, double dy,
872 : double originX, double originY,
873 : CharCode, int /*nBytes*/, Unicode *u, int uLen)
874 : {
875 : assert(state);
876 :
877 390 : if( u == NULL )
878 390 : return;
879 :
880 390 : double csdx = 0.0;
881 390 : double csdy = 0.0;
882 390 : if (state->getFont()->getWMode())
883 : {
884 0 : csdy = state->getCharSpace();
885 0 : if (*u == ' ')
886 0 : csdy += state->getWordSpace();
887 : }
888 : else
889 : {
890 390 : csdx = state->getCharSpace();
891 390 : if (*u == ' ')
892 56 : csdx += state->getWordSpace();
893 390 : csdx *= state->getHorizScaling();
894 : }
895 :
896 390 : double cstdx = 0.0;
897 390 : double cstdy = 0.0;
898 390 : state->textTransformDelta(csdx, csdy, &cstdx, &cstdy);
899 :
900 390 : const double fontSize = state->getFontSize();
901 :
902 390 : const double aPositionX(x-originX);
903 390 : const double aPositionY(y-originY);
904 :
905 390 : const double* pTextMat=state->getTextMat();
906 : printf( "drawChar %f %f %f %f %f %f %f %f %f ",
907 : normalize(aPositionX),
908 : normalize(aPositionY),
909 390 : normalize(aPositionX + dx - cstdx),
910 390 : normalize(aPositionY + dy - cstdy),
911 : normalize(pTextMat[0]),
912 390 : normalize(pTextMat[2]),
913 390 : normalize(pTextMat[1]),
914 390 : normalize(pTextMat[3]),
915 : normalize(fontSize)
916 2340 : );
917 :
918 : // silence spurious warning
919 : (void)&mapUCS2;
920 :
921 : char buf[9];
922 780 : for( int i=0; i<uLen; ++i )
923 : {
924 390 : buf[ m_pUtf8Map->mapUnicode(u[i], buf, sizeof(buf)-1) ] = 0;
925 390 : boost::shared_array<char> pEsc( lcl_escapeLineFeeds(buf) );
926 390 : printf( "%s", pEsc.get() );
927 390 : }
928 :
929 390 : printf( "\n" );
930 : }
931 :
932 0 : void PDFOutDev::drawString(GfxState*, GooString* /*s*/)
933 : {
934 : // TODO(F3): NYI
935 0 : }
936 :
937 35 : void PDFOutDev::endTextObject(GfxState*)
938 : {
939 35 : printf( "endTextObject\n" );
940 35 : }
941 :
942 0 : void PDFOutDev::drawImageMask(GfxState* pState, Object*, Stream* str,
943 : int width, int height, GBool invert,
944 : #if POPPLER_CHECK_VERSION(0, 12, 0)
945 : GBool /*interpolate*/,
946 : #endif
947 : GBool /*inlineImg*/ )
948 : {
949 0 : if (m_bSkipImages)
950 0 : return;
951 0 : OutputBuffer aBuf; initBuf(aBuf);
952 :
953 0 : printf( "drawMask %d %d %d", width, height, invert );
954 :
955 0 : int bitsPerComponent = 1;
956 0 : StreamColorSpaceMode csMode = streamCSNone;
957 0 : str->getImageParams( &bitsPerComponent, &csMode );
958 0 : if( bitsPerComponent == 1 && (csMode == streamCSNone || csMode == streamCSDeviceGray) )
959 : {
960 0 : GfxRGB oneColor = { dblToCol( 1.0 ), dblToCol( 1.0 ), dblToCol( 1.0 ) };
961 0 : GfxRGB zeroColor = { dblToCol( 0.0 ), dblToCol( 0.0 ), dblToCol( 0.0 ) };
962 0 : pState->getFillColorSpace()->getRGB( pState->getFillColor(), &zeroColor );
963 0 : if( invert )
964 0 : writePng_( aBuf, str, width, height, oneColor, zeroColor, true, true );
965 : else
966 0 : writePng_( aBuf, str, width, height, zeroColor, oneColor, true, true );
967 : }
968 : else
969 0 : writeMaskLF(aBuf, str, width, height, invert);
970 0 : writeBinaryBuffer(aBuf);
971 : }
972 :
973 3 : void PDFOutDev::drawImage(GfxState*, Object*, Stream* str,
974 : int width, int height, GfxImageColorMap* colorMap,
975 : #if POPPLER_CHECK_VERSION(0, 12, 0)
976 : GBool /*interpolate*/,
977 : #endif
978 : int* maskColors, GBool /*inlineImg*/ )
979 : {
980 3 : if (m_bSkipImages)
981 3 : return;
982 3 : OutputBuffer aBuf; initBuf(aBuf);
983 6 : OutputBuffer aMaskBuf;
984 :
985 3 : printf( "drawImage %d %d", width, height );
986 :
987 3 : if( maskColors )
988 : {
989 : // write mask colors. nBytes must be even - first half is
990 : // lower bound values, second half upper bound values
991 0 : if( colorMap->getColorSpace()->getMode() == csIndexed )
992 : {
993 0 : aMaskBuf.push_back( (char)maskColors[0] );
994 0 : aMaskBuf.push_back( (char)maskColors[gfxColorMaxComps] );
995 : }
996 : else
997 : {
998 : GfxRGB aMinRGB;
999 0 : colorMap->getColorSpace()->getRGB(
1000 : reinterpret_cast<GfxColor*>(maskColors),
1001 0 : &aMinRGB );
1002 :
1003 : GfxRGB aMaxRGB;
1004 0 : colorMap->getColorSpace()->getRGB(
1005 : reinterpret_cast<GfxColor*>(maskColors)+gfxColorMaxComps,
1006 0 : &aMaxRGB );
1007 :
1008 0 : aMaskBuf.push_back( colToByte(aMinRGB.r) );
1009 0 : aMaskBuf.push_back( colToByte(aMinRGB.g) );
1010 0 : aMaskBuf.push_back( colToByte(aMinRGB.b) );
1011 0 : aMaskBuf.push_back( colToByte(aMaxRGB.r) );
1012 0 : aMaskBuf.push_back( colToByte(aMaxRGB.g) );
1013 0 : aMaskBuf.push_back( colToByte(aMaxRGB.b) );
1014 : }
1015 : }
1016 :
1017 3 : printf( " %d", (int)aMaskBuf.size() );
1018 3 : writeImageLF( aBuf, str, width, height, colorMap );
1019 3 : writeBinaryBuffer(aBuf);
1020 6 : writeBinaryBuffer(aMaskBuf);
1021 : }
1022 :
1023 0 : void PDFOutDev::drawMaskedImage(GfxState*, Object*, Stream* str,
1024 : int width, int height,
1025 : GfxImageColorMap* colorMap,
1026 : #if POPPLER_CHECK_VERSION(0, 12, 0)
1027 : GBool /*interpolate*/,
1028 : #endif
1029 : Stream* maskStr,
1030 : int maskWidth, int maskHeight,
1031 : GBool maskInvert
1032 : #if POPPLER_CHECK_VERSION(0, 12, 0)
1033 : , GBool /*maskInterpolate*/
1034 : #endif
1035 : )
1036 : {
1037 0 : if (m_bSkipImages)
1038 0 : return;
1039 0 : OutputBuffer aBuf; initBuf(aBuf);
1040 0 : printf( "drawImage %d %d 0", width, height );
1041 0 : writePng_( aBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert, true );
1042 0 : writeBinaryBuffer( aBuf );
1043 : }
1044 :
1045 2 : void PDFOutDev::drawSoftMaskedImage(GfxState*, Object*, Stream* str,
1046 : int width, int height,
1047 : GfxImageColorMap* colorMap,
1048 : #if POPPLER_CHECK_VERSION(0, 12, 0)
1049 : GBool /*interpolate*/,
1050 : #endif
1051 : Stream* maskStr,
1052 : int maskWidth, int maskHeight,
1053 : GfxImageColorMap* maskColorMap
1054 : #if POPPLER_CHECK_VERSION(0, 12, 0)
1055 : , GBool /*maskInterpolate*/
1056 : #endif
1057 : )
1058 : {
1059 2 : if (m_bSkipImages)
1060 3 : return;
1061 1 : OutputBuffer aBuf; initBuf(aBuf);
1062 1 : printf( "drawImage %d %d 0", width, height );
1063 1 : writePng_( aBuf, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap, true );
1064 1 : writeBinaryBuffer( aBuf );
1065 : }
1066 :
1067 5 : void PDFOutDev::setPageNum( int nNumPages )
1068 : {
1069 : // TODO(F3): printf might format int locale-dependent!
1070 5 : printf("setPageNum %d\n", nNumPages);
1071 5 : }
1072 :
1073 1 : void PDFOutDev::setSkipImages( bool bSkipImages )
1074 : {
1075 1 : m_bSkipImages = bSkipImages;
1076 1 : }
1077 :
1078 : }
1079 :
1080 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|