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 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_vcl.hxx" 26 27 #include "psputil.hxx" 28 29 #include "printergfx.hxx" 30 #include "vcl/strhelper.hxx" 31 32 namespace psp { 33 34 const sal_uInt32 nLineLength = 80; 35 const sal_uInt32 nBufferSize = 16384; 36 37 /* 38 * 39 * Bitmap compression / Hex encoding / Ascii85 Encoding 40 * 41 */ 42 43 PrinterBmp::~PrinterBmp () 44 { /* dont need this, but C50 does */ } 45 46 /* virtual base class */ 47 48 class ByteEncoder 49 { 50 private: 51 52 public: 53 54 virtual void EncodeByte (sal_uInt8 nByte) = 0; 55 virtual ~ByteEncoder () = 0; 56 }; 57 58 ByteEncoder::~ByteEncoder () 59 { /* dont need this, but the C50 does */ } 60 61 /* HexEncoder */ 62 63 class HexEncoder : public ByteEncoder 64 { 65 private: 66 67 osl::File* mpFile; 68 sal_uInt32 mnColumn; 69 sal_uInt32 mnOffset; 70 sal_Char mpFileBuffer[nBufferSize + 16]; 71 72 HexEncoder (); /* dont use */ 73 74 public: 75 76 HexEncoder (osl::File* pFile); 77 virtual ~HexEncoder (); 78 void WriteAscii (sal_uInt8 nByte); 79 virtual void EncodeByte (sal_uInt8 nByte); 80 void FlushLine (); 81 }; 82 83 HexEncoder::HexEncoder (osl::File* pFile) : 84 mpFile (pFile), 85 mnColumn (0), 86 mnOffset (0) 87 {} 88 89 HexEncoder::~HexEncoder () 90 { 91 FlushLine (); 92 if (mnColumn > 0) 93 WritePS (mpFile, "\n"); 94 } 95 96 void 97 HexEncoder::WriteAscii (sal_uInt8 nByte) 98 { 99 sal_uInt32 nOff = psp::getHexValueOf (nByte, mpFileBuffer + mnOffset); 100 mnColumn += nOff; 101 mnOffset += nOff; 102 103 if (mnColumn >= nLineLength) 104 { 105 mnOffset += psp::appendStr ("\n", mpFileBuffer + mnOffset); 106 mnColumn = 0; 107 } 108 if (mnOffset >= nBufferSize) 109 FlushLine (); 110 } 111 112 void 113 HexEncoder::EncodeByte (sal_uInt8 nByte) 114 { 115 WriteAscii (nByte); 116 } 117 118 void 119 HexEncoder::FlushLine () 120 { 121 if (mnOffset > 0) 122 { 123 WritePS (mpFile, mpFileBuffer, mnOffset); 124 mnOffset = 0; 125 } 126 } 127 128 /* Ascii85 encoder, is abi compatible with HexEncoder but writes a ~> to 129 indicate end of data EOD */ 130 131 class Ascii85Encoder : public ByteEncoder 132 { 133 private: 134 135 osl::File* mpFile; 136 sal_uInt32 mnByte; 137 sal_uInt8 mpByteBuffer[4]; 138 139 sal_uInt32 mnColumn; 140 sal_uInt32 mnOffset; 141 sal_Char mpFileBuffer[nBufferSize + 16]; 142 143 Ascii85Encoder (); /* dont use */ 144 145 inline void PutByte (sal_uInt8 nByte); 146 inline void PutEOD (); 147 void ConvertToAscii85 (); 148 void FlushLine (); 149 150 public: 151 152 Ascii85Encoder (osl::File* pFile); 153 virtual ~Ascii85Encoder (); 154 virtual void EncodeByte (sal_uInt8 nByte); 155 void WriteAscii (sal_uInt8 nByte); 156 }; 157 158 Ascii85Encoder::Ascii85Encoder (osl::File* pFile) : 159 mpFile (pFile), 160 mnByte (0), 161 mnColumn (0), 162 mnOffset (0) 163 {} 164 165 inline void 166 Ascii85Encoder::PutByte (sal_uInt8 nByte) 167 { 168 mpByteBuffer [mnByte++] = nByte; 169 } 170 171 inline void 172 Ascii85Encoder::PutEOD () 173 { 174 WritePS (mpFile, "~>\n"); 175 } 176 177 void 178 Ascii85Encoder::ConvertToAscii85 () 179 { 180 if (mnByte < 4) 181 std::memset (mpByteBuffer + mnByte, 0, (4 - mnByte) * sizeof(sal_uInt8)); 182 183 sal_uInt32 nByteValue = mpByteBuffer[0] * 256 * 256 * 256 184 + mpByteBuffer[1] * 256 * 256 185 + mpByteBuffer[2] * 256 186 + mpByteBuffer[3]; 187 188 if (nByteValue == 0 && mnByte == 4) 189 { 190 /* special case of 4 Bytes in row */ 191 mpFileBuffer [mnOffset] = 'z'; 192 193 mnOffset += 1; 194 mnColumn += 1; 195 } 196 else 197 { 198 /* real ascii85 encoding */ 199 mpFileBuffer [mnOffset + 4] = (nByteValue % 85) + 33; 200 nByteValue /= 85; 201 mpFileBuffer [mnOffset + 3] = (nByteValue % 85) + 33; 202 nByteValue /= 85; 203 mpFileBuffer [mnOffset + 2] = (nByteValue % 85) + 33; 204 nByteValue /= 85; 205 mpFileBuffer [mnOffset + 1] = (nByteValue % 85) + 33; 206 nByteValue /= 85; 207 mpFileBuffer [mnOffset + 0] = (nByteValue % 85) + 33; 208 209 mnColumn += (mnByte + 1); 210 mnOffset += (mnByte + 1); 211 212 /* insert a newline if necessary */ 213 if (mnColumn > nLineLength) 214 { 215 sal_uInt32 nEolOff = mnColumn - nLineLength; 216 sal_uInt32 nBufOff = mnOffset - nEolOff; 217 218 std::memmove (mpFileBuffer + nBufOff + 1, mpFileBuffer + nBufOff, nEolOff); 219 mpFileBuffer[ nBufOff ] = '\n'; 220 221 mnOffset++; 222 mnColumn = nEolOff; 223 } 224 } 225 226 mnByte = 0; 227 } 228 229 void 230 Ascii85Encoder::WriteAscii (sal_uInt8 nByte) 231 { 232 PutByte (nByte); 233 if (mnByte == 4) 234 ConvertToAscii85 (); 235 236 if (mnColumn >= nLineLength) 237 { 238 mnOffset += psp::appendStr ("\n", mpFileBuffer + mnOffset); 239 mnColumn = 0; 240 } 241 if (mnOffset >= nBufferSize) 242 FlushLine (); 243 } 244 245 void 246 Ascii85Encoder::EncodeByte (sal_uInt8 nByte) 247 { 248 WriteAscii (nByte); 249 } 250 251 void 252 Ascii85Encoder::FlushLine () 253 { 254 if (mnOffset > 0) 255 { 256 WritePS (mpFile, mpFileBuffer, mnOffset); 257 mnOffset = 0; 258 } 259 } 260 261 Ascii85Encoder::~Ascii85Encoder () 262 { 263 if (mnByte > 0) 264 ConvertToAscii85 (); 265 if (mnOffset > 0) 266 FlushLine (); 267 PutEOD (); 268 } 269 270 /* LZW encoder */ 271 272 class LZWEncoder : public Ascii85Encoder 273 { 274 private: 275 276 struct LZWCTreeNode 277 { 278 LZWCTreeNode* mpBrother; // next node with same parent 279 LZWCTreeNode* mpFirstChild; // first son 280 sal_uInt16 mnCode; // code for the string 281 sal_uInt16 mnValue; // pixelvalue 282 }; 283 284 LZWCTreeNode* mpTable; // LZW compression data 285 LZWCTreeNode* mpPrefix; // the compression is as same as the TIFF compression 286 sal_uInt16 mnDataSize; 287 sal_uInt16 mnClearCode; 288 sal_uInt16 mnEOICode; 289 sal_uInt16 mnTableSize; 290 sal_uInt16 mnCodeSize; 291 sal_uInt32 mnOffset; 292 sal_uInt32 mdwShift; 293 294 LZWEncoder (); 295 void WriteBits (sal_uInt16 nCode, sal_uInt16 nCodeLen); 296 297 public: 298 299 LZWEncoder (osl::File* pOutputFile); 300 ~LZWEncoder (); 301 302 virtual void EncodeByte (sal_uInt8 nByte); 303 }; 304 305 LZWEncoder::LZWEncoder(osl::File* pOutputFile) : 306 Ascii85Encoder (pOutputFile) 307 { 308 mnDataSize = 8; 309 310 mnClearCode = 1 << mnDataSize; 311 mnEOICode = mnClearCode + 1; 312 mnTableSize = mnEOICode + 1; 313 mnCodeSize = mnDataSize + 1; 314 315 mnOffset = 32; // free bits in dwShift 316 mdwShift = 0; 317 318 mpTable = new LZWCTreeNode[ 4096 ]; 319 320 for (sal_uInt32 i = 0; i < 4096; i++) 321 { 322 mpTable[i].mpBrother = NULL; 323 mpTable[i].mpFirstChild = NULL; 324 mpTable[i].mnCode = i; 325 mpTable[i].mnValue = (sal_uInt8)mpTable[i].mnCode; 326 } 327 328 mpPrefix = NULL; 329 330 WriteBits( mnClearCode, mnCodeSize ); 331 } 332 333 LZWEncoder::~LZWEncoder() 334 { 335 if (mpPrefix) 336 WriteBits (mpPrefix->mnCode, mnCodeSize); 337 338 WriteBits (mnEOICode, mnCodeSize); 339 340 delete[] mpTable; 341 } 342 343 void 344 LZWEncoder::WriteBits (sal_uInt16 nCode, sal_uInt16 nCodeLen) 345 { 346 mdwShift |= (nCode << (mnOffset - nCodeLen)); 347 mnOffset -= nCodeLen; 348 while (mnOffset < 24) 349 { 350 WriteAscii ((sal_uInt8)(mdwShift >> 24)); 351 mdwShift <<= 8; 352 mnOffset += 8; 353 } 354 if (nCode == 257 && mnOffset != 32) 355 WriteAscii ((sal_uInt8)(mdwShift >> 24)); 356 } 357 358 void 359 LZWEncoder::EncodeByte (sal_uInt8 nByte ) 360 { 361 LZWCTreeNode* p; 362 sal_uInt16 i; 363 sal_uInt8 nV; 364 365 if (!mpPrefix) 366 { 367 mpPrefix = mpTable + nByte; 368 } 369 else 370 { 371 nV = nByte; 372 for (p = mpPrefix->mpFirstChild; p != NULL; p = p->mpBrother) 373 { 374 if (p->mnValue == nV) 375 break; 376 } 377 378 if (p != NULL) 379 { 380 mpPrefix = p; 381 } 382 else 383 { 384 WriteBits (mpPrefix->mnCode, mnCodeSize); 385 386 if (mnTableSize == 409) 387 { 388 WriteBits (mnClearCode, mnCodeSize); 389 390 for (i = 0; i < mnClearCode; i++) 391 mpTable[i].mpFirstChild = NULL; 392 393 mnCodeSize = mnDataSize + 1; 394 mnTableSize = mnEOICode + 1; 395 } 396 else 397 { 398 if(mnTableSize == (sal_uInt16)((1 << mnCodeSize) - 1)) 399 mnCodeSize++; 400 401 p = mpTable + (mnTableSize++); 402 p->mpBrother = mpPrefix->mpFirstChild; 403 mpPrefix->mpFirstChild = p; 404 p->mnValue = nV; 405 p->mpFirstChild = NULL; 406 } 407 408 mpPrefix = mpTable + nV; 409 } 410 } 411 } 412 413 /* 414 * 415 * bitmap handling routines 416 * 417 */ 418 419 void 420 PrinterGfx::DrawBitmap (const Rectangle& rDest, const Rectangle& rSrc, 421 const PrinterBmp& rBitmap) 422 { 423 double fScaleX = (double)rDest.GetWidth() / (double)rSrc.GetWidth(); 424 double fScaleY = (double)rDest.GetHeight() / (double)rSrc.GetHeight(); 425 426 PSGSave (); 427 PSTranslate (rDest.BottomLeft()); 428 PSScale (fScaleX, fScaleY); 429 430 if (mnPSLevel >= 2) 431 { 432 if (rBitmap.GetDepth() == 1) 433 { 434 DrawPS2MonoImage (rBitmap, rSrc); 435 } 436 else 437 if (rBitmap.GetDepth() == 8 && mbColor) 438 { 439 // if the palette is larger than the image itself print it as a truecolor 440 // image to save diskspace. This is important for printing transparent 441 // bitmaps that are disassembled into small pieces 442 sal_Int32 nImageSz = rSrc.GetWidth() * rSrc.GetHeight(); 443 sal_Int32 nPaletteSz = rBitmap.GetPaletteEntryCount(); 444 if ((nImageSz < nPaletteSz) || (nImageSz < 24) ) 445 DrawPS2TrueColorImage (rBitmap, rSrc); 446 else 447 DrawPS2PaletteImage (rBitmap, rSrc); 448 } 449 else 450 if (rBitmap.GetDepth() == 24 && mbColor) 451 { 452 DrawPS2TrueColorImage (rBitmap, rSrc); 453 } 454 else 455 { 456 DrawPS2GrayImage (rBitmap, rSrc); 457 } 458 } 459 else 460 { 461 DrawPS1GrayImage (rBitmap, rSrc); 462 } 463 464 PSGRestore (); 465 } 466 467 /* XXX does not work XXX */ 468 void 469 PrinterGfx::DrawBitmap (const Rectangle& rDest, const Rectangle& rSrc, 470 const PrinterBmp& /*rBitmap*/, const PrinterBmp& /*rTransBitmap*/) 471 { 472 double fScaleX = (double)rDest.GetWidth() / (double)rSrc.GetWidth(); 473 double fScaleY = (double)rDest.GetHeight() / (double)rSrc.GetHeight(); 474 475 PSGSave (); 476 PSTranslate (rDest.BottomLeft()); 477 PSScale (fScaleX, fScaleY); 478 PSGRestore (); 479 } 480 481 /* XXX does not work XXX */ 482 void 483 PrinterGfx::DrawMask (const Rectangle& rDest, const Rectangle& rSrc, 484 const PrinterBmp &/*rBitmap*/, PrinterColor& /*rMaskColor*/) 485 { 486 double fScaleX = (double)rDest.GetWidth() / (double)rSrc.GetWidth(); 487 double fScaleY = (double)rDest.GetHeight() / (double)rSrc.GetHeight(); 488 489 PSGSave (); 490 PSTranslate (rDest.BottomLeft()); 491 PSScale (fScaleX, fScaleY); 492 PSGRestore (); 493 } 494 495 /* 496 * 497 * Implementation: PS Level 1 498 * 499 */ 500 501 void 502 PrinterGfx::DrawPS1GrayImage (const PrinterBmp& rBitmap, const Rectangle& rArea) 503 { 504 sal_uInt32 nWidth = rArea.GetWidth(); 505 sal_uInt32 nHeight = rArea.GetHeight(); 506 507 sal_Char pGrayImage [512]; 508 sal_Int32 nChar = 0; 509 510 // image header 511 nChar += psp::getValueOf (nWidth, pGrayImage + nChar); 512 nChar += psp::appendStr (" ", pGrayImage + nChar); 513 nChar += psp::getValueOf (nHeight, pGrayImage + nChar); 514 nChar += psp::appendStr (" 8 ", pGrayImage + nChar); 515 nChar += psp::appendStr ("[ 1 0 0 1 0 ", pGrayImage + nChar); 516 nChar += psp::getValueOf (nHeight, pGrayImage + nChar); 517 nChar += psp::appendStr ("]", pGrayImage + nChar); 518 nChar += psp::appendStr (" {currentfile ", pGrayImage + nChar); 519 nChar += psp::getValueOf (nWidth, pGrayImage + nChar); 520 nChar += psp::appendStr (" string readhexstring pop}\n", pGrayImage + nChar); 521 nChar += psp::appendStr ("image\n", pGrayImage + nChar); 522 523 WritePS (mpPageBody, pGrayImage); 524 525 // image body 526 HexEncoder* pEncoder = new HexEncoder (mpPageBody); 527 528 for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++) 529 { 530 for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++) 531 { 532 sal_uChar nByte = rBitmap.GetPixelGray (nRow, nColumn); 533 pEncoder->EncodeByte (nByte); 534 } 535 } 536 537 delete pEncoder; 538 539 WritePS (mpPageBody, "\n"); 540 } 541 542 /* 543 * 544 * Implementation: PS Level 2 545 * 546 */ 547 548 void 549 PrinterGfx::writePS2ImageHeader (const Rectangle& rArea, psp::ImageType nType) 550 { 551 sal_Int32 nChar = 0; 552 sal_Char pImage [512]; 553 554 sal_Int32 nDictType = 0; 555 switch (nType) 556 { 557 case psp::TrueColorImage: nDictType = 0; break; 558 case psp::PaletteImage: nDictType = 1; break; 559 case psp::GrayScaleImage: nDictType = 2; break; 560 case psp::MonochromeImage: nDictType = 3; break; 561 default: break; 562 } 563 sal_Int32 nCompressType = mbCompressBmp ? 1 : 0; 564 565 nChar += psp::getValueOf (rArea.GetWidth(), pImage + nChar); 566 nChar += psp::appendStr (" ", pImage + nChar); 567 nChar += psp::getValueOf (rArea.GetHeight(), pImage + nChar); 568 nChar += psp::appendStr (" ", pImage + nChar); 569 nChar += psp::getValueOf (nDictType, pImage + nChar); 570 nChar += psp::appendStr (" ", pImage + nChar); 571 nChar += psp::getValueOf (nCompressType, pImage + nChar); 572 nChar += psp::appendStr (" psp_imagedict image\n", pImage + nChar); 573 574 WritePS (mpPageBody, pImage); 575 } 576 577 void 578 PrinterGfx::writePS2Colorspace(const PrinterBmp& rBitmap, psp::ImageType nType) 579 { 580 switch (nType) 581 { 582 case psp::GrayScaleImage: 583 584 WritePS (mpPageBody, "/DeviceGray setcolorspace\n"); 585 break; 586 587 case psp::TrueColorImage: 588 589 WritePS (mpPageBody, "/DeviceRGB setcolorspace\n"); 590 break; 591 592 case psp::MonochromeImage: 593 case psp::PaletteImage: 594 { 595 596 sal_Int32 nChar = 0; 597 sal_Char pImage [4096]; 598 599 const sal_uInt32 nSize = rBitmap.GetPaletteEntryCount(); 600 601 nChar += psp::appendStr ("[/Indexed /DeviceRGB ", pImage + nChar); 602 nChar += psp::getValueOf (nSize - 1, pImage + nChar); 603 if (mbCompressBmp) 604 nChar += psp::appendStr ("\npsp_lzwstring\n", pImage + nChar); 605 else 606 nChar += psp::appendStr ("\npsp_ascii85string\n", pImage + nChar); 607 WritePS (mpPageBody, pImage); 608 609 ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody) 610 : new Ascii85Encoder(mpPageBody); 611 for (sal_uInt32 i = 0; i < nSize; i++) 612 { 613 PrinterColor aColor = rBitmap.GetPaletteColor(i); 614 615 pEncoder->EncodeByte (aColor.GetRed()); 616 pEncoder->EncodeByte (aColor.GetGreen()); 617 pEncoder->EncodeByte (aColor.GetBlue()); 618 } 619 delete pEncoder; 620 621 WritePS (mpPageBody, "pop ] setcolorspace\n"); 622 } 623 break; 624 default: break; 625 } 626 } 627 628 void 629 PrinterGfx::DrawPS2GrayImage (const PrinterBmp& rBitmap, const Rectangle& rArea) 630 { 631 writePS2Colorspace(rBitmap, psp::GrayScaleImage); 632 writePS2ImageHeader(rArea, psp::GrayScaleImage); 633 634 ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody) 635 : new Ascii85Encoder(mpPageBody); 636 637 for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++) 638 { 639 for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++) 640 { 641 sal_uChar nByte = rBitmap.GetPixelGray (nRow, nColumn); 642 pEncoder->EncodeByte (nByte); 643 } 644 } 645 646 delete pEncoder; 647 } 648 649 void 650 PrinterGfx::DrawPS2MonoImage (const PrinterBmp& rBitmap, const Rectangle& rArea) 651 { 652 writePS2Colorspace(rBitmap, psp::MonochromeImage); 653 writePS2ImageHeader(rArea, psp::MonochromeImage); 654 655 ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody) 656 : new Ascii85Encoder(mpPageBody); 657 658 for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++) 659 { 660 long nBitPos = 0; 661 sal_uChar nBit = 0; 662 sal_uChar nByte = 0; 663 664 for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++) 665 { 666 nBit = rBitmap.GetPixelIdx (nRow, nColumn); 667 nByte |= nBit << (7 - nBitPos); 668 669 if (++nBitPos == 8) 670 { 671 pEncoder->EncodeByte (nByte); 672 nBitPos = 0; 673 nByte = 0; 674 } 675 } 676 // keep the row byte aligned 677 if (nBitPos != 0) 678 pEncoder->EncodeByte (nByte); 679 } 680 681 delete pEncoder; 682 } 683 684 void 685 PrinterGfx::DrawPS2PaletteImage (const PrinterBmp& rBitmap, const Rectangle& rArea) 686 { 687 writePS2Colorspace(rBitmap, psp::PaletteImage); 688 writePS2ImageHeader(rArea, psp::PaletteImage); 689 690 ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody) 691 : new Ascii85Encoder(mpPageBody); 692 693 for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++) 694 { 695 for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++) 696 { 697 sal_uChar nByte = rBitmap.GetPixelIdx (nRow, nColumn); 698 pEncoder->EncodeByte (nByte); 699 } 700 } 701 702 delete pEncoder; 703 } 704 705 void 706 PrinterGfx::DrawPS2TrueColorImage (const PrinterBmp& rBitmap, const Rectangle& rArea) 707 { 708 writePS2Colorspace(rBitmap, psp::TrueColorImage); 709 writePS2ImageHeader(rArea, psp::TrueColorImage); 710 711 ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody) 712 : new Ascii85Encoder(mpPageBody); 713 714 for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++) 715 { 716 for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++) 717 { 718 PrinterColor aColor = rBitmap.GetPixelRGB (nRow, nColumn); 719 pEncoder->EncodeByte (aColor.GetRed()); 720 pEncoder->EncodeByte (aColor.GetGreen()); 721 pEncoder->EncodeByte (aColor.GetBlue()); 722 } 723 } 724 725 delete pEncoder; 726 } 727 728 } /* namespace psp */ 729