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