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