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