Bump version to 4.1-6
[LibreOffice.git] / vcl / generic / print / bitmap_gfx.cxx
blob31ea82fe58a190b0a636249b9b849f7184cf7dae
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "psputil.hxx"
23 #include "generic/printergfx.hxx"
24 #include "vcl/strhelper.hxx"
26 namespace psp {
28 const sal_uInt32 nLineLength = 80;
29 const sal_uInt32 nBufferSize = 16384;
33 * Bitmap compression / Hex encoding / Ascii85 Encoding
37 PrinterBmp::~PrinterBmp ()
38 { /* dont need this, but C50 does */ }
40 /* virtual base class */
42 class ByteEncoder
44 private:
46 public:
48 virtual void EncodeByte (sal_uInt8 nByte) = 0;
49 virtual ~ByteEncoder () = 0;
52 ByteEncoder::~ByteEncoder ()
53 { /* dont need this, but the C50 does */ }
55 /* HexEncoder */
57 class HexEncoder : public ByteEncoder
59 private:
61 osl::File* mpFile;
62 sal_uInt32 mnColumn;
63 sal_uInt32 mnOffset;
64 sal_Char mpFileBuffer[nBufferSize + 16];
66 HexEncoder (); /* dont use */
68 public:
70 HexEncoder (osl::File* pFile);
71 virtual ~HexEncoder ();
72 void WriteAscii (sal_uInt8 nByte);
73 virtual void EncodeByte (sal_uInt8 nByte);
74 void FlushLine ();
77 HexEncoder::HexEncoder (osl::File* pFile) :
78 mpFile (pFile),
79 mnColumn (0),
80 mnOffset (0)
83 HexEncoder::~HexEncoder ()
85 FlushLine ();
86 if (mnColumn > 0)
87 WritePS (mpFile, "\n");
90 void
91 HexEncoder::WriteAscii (sal_uInt8 nByte)
93 sal_uInt32 nOff = psp::getHexValueOf (nByte, mpFileBuffer + mnOffset);
94 mnColumn += nOff;
95 mnOffset += nOff;
97 if (mnColumn >= nLineLength)
99 mnOffset += psp::appendStr ("\n", mpFileBuffer + mnOffset);
100 mnColumn = 0;
102 if (mnOffset >= nBufferSize)
103 FlushLine ();
106 void
107 HexEncoder::EncodeByte (sal_uInt8 nByte)
109 WriteAscii (nByte);
112 void
113 HexEncoder::FlushLine ()
115 if (mnOffset > 0)
117 WritePS (mpFile, mpFileBuffer, mnOffset);
118 mnOffset = 0;
122 /* Ascii85 encoder, is abi compatible with HexEncoder but writes a ~> to
123 indicate end of data EOD */
125 class Ascii85Encoder : public ByteEncoder
127 private:
129 osl::File* mpFile;
130 sal_uInt32 mnByte;
131 sal_uInt8 mpByteBuffer[4];
133 sal_uInt32 mnColumn;
134 sal_uInt32 mnOffset;
135 sal_Char mpFileBuffer[nBufferSize + 16];
137 Ascii85Encoder (); /* dont use */
139 inline void PutByte (sal_uInt8 nByte);
140 inline void PutEOD ();
141 void ConvertToAscii85 ();
142 void FlushLine ();
144 public:
146 Ascii85Encoder (osl::File* pFile);
147 virtual ~Ascii85Encoder ();
148 virtual void EncodeByte (sal_uInt8 nByte);
149 void WriteAscii (sal_uInt8 nByte);
152 Ascii85Encoder::Ascii85Encoder (osl::File* pFile) :
153 mpFile (pFile),
154 mnByte (0),
155 mnColumn (0),
156 mnOffset (0)
159 inline void
160 Ascii85Encoder::PutByte (sal_uInt8 nByte)
162 mpByteBuffer [mnByte++] = nByte;
165 inline void
166 Ascii85Encoder::PutEOD ()
168 WritePS (mpFile, "~>\n");
171 void
172 Ascii85Encoder::ConvertToAscii85 ()
174 if (mnByte < 4)
175 std::memset (mpByteBuffer + mnByte, 0, (4 - mnByte) * sizeof(sal_uInt8));
177 sal_uInt32 nByteValue = mpByteBuffer[0] * 256 * 256 * 256
178 + mpByteBuffer[1] * 256 * 256
179 + mpByteBuffer[2] * 256
180 + mpByteBuffer[3];
182 if (nByteValue == 0 && mnByte == 4)
184 /* special case of 4 Bytes in row */
185 mpFileBuffer [mnOffset] = 'z';
187 mnOffset += 1;
188 mnColumn += 1;
190 else
192 /* real ascii85 encoding */
193 mpFileBuffer [mnOffset + 4] = (nByteValue % 85) + 33;
194 nByteValue /= 85;
195 mpFileBuffer [mnOffset + 3] = (nByteValue % 85) + 33;
196 nByteValue /= 85;
197 mpFileBuffer [mnOffset + 2] = (nByteValue % 85) + 33;
198 nByteValue /= 85;
199 mpFileBuffer [mnOffset + 1] = (nByteValue % 85) + 33;
200 nByteValue /= 85;
201 mpFileBuffer [mnOffset + 0] = (nByteValue % 85) + 33;
203 mnColumn += (mnByte + 1);
204 mnOffset += (mnByte + 1);
206 /* insert a newline if necessary */
207 if (mnColumn > nLineLength)
209 sal_uInt32 nEolOff = mnColumn - nLineLength;
210 sal_uInt32 nBufOff = mnOffset - nEolOff;
212 std::memmove (mpFileBuffer + nBufOff + 1, mpFileBuffer + nBufOff, nEolOff);
213 mpFileBuffer[ nBufOff ] = '\n';
215 mnOffset++;
216 mnColumn = nEolOff;
220 mnByte = 0;
223 void
224 Ascii85Encoder::WriteAscii (sal_uInt8 nByte)
226 PutByte (nByte);
227 if (mnByte == 4)
228 ConvertToAscii85 ();
230 if (mnColumn >= nLineLength)
232 mnOffset += psp::appendStr ("\n", mpFileBuffer + mnOffset);
233 mnColumn = 0;
235 if (mnOffset >= nBufferSize)
236 FlushLine ();
239 void
240 Ascii85Encoder::EncodeByte (sal_uInt8 nByte)
242 WriteAscii (nByte);
245 void
246 Ascii85Encoder::FlushLine ()
248 if (mnOffset > 0)
250 WritePS (mpFile, mpFileBuffer, mnOffset);
251 mnOffset = 0;
255 Ascii85Encoder::~Ascii85Encoder ()
257 if (mnByte > 0)
258 ConvertToAscii85 ();
259 if (mnOffset > 0)
260 FlushLine ();
261 PutEOD ();
264 /* LZW encoder */
266 class LZWEncoder : public Ascii85Encoder
268 private:
270 struct LZWCTreeNode
272 LZWCTreeNode* mpBrother; // next node with same parent
273 LZWCTreeNode* mpFirstChild; // first son
274 sal_uInt16 mnCode; // code for the string
275 sal_uInt16 mnValue; // pixelvalue
278 LZWCTreeNode* mpTable; // LZW compression data
279 LZWCTreeNode* mpPrefix; // the compression is as same as the TIFF compression
280 sal_uInt16 mnDataSize;
281 sal_uInt16 mnClearCode;
282 sal_uInt16 mnEOICode;
283 sal_uInt16 mnTableSize;
284 sal_uInt16 mnCodeSize;
285 sal_uInt32 mnOffset;
286 sal_uInt32 mdwShift;
288 LZWEncoder ();
289 void WriteBits (sal_uInt16 nCode, sal_uInt16 nCodeLen);
291 public:
293 LZWEncoder (osl::File* pOutputFile);
294 ~LZWEncoder ();
296 virtual void EncodeByte (sal_uInt8 nByte);
299 LZWEncoder::LZWEncoder(osl::File* pOutputFile) :
300 Ascii85Encoder (pOutputFile)
302 mnDataSize = 8;
304 mnClearCode = 1 << mnDataSize;
305 mnEOICode = mnClearCode + 1;
306 mnTableSize = mnEOICode + 1;
307 mnCodeSize = mnDataSize + 1;
309 mnOffset = 32; // free bits in dwShift
310 mdwShift = 0;
312 mpTable = new LZWCTreeNode[ 4096 ];
314 for (sal_uInt32 i = 0; i < 4096; i++)
316 mpTable[i].mpBrother = NULL;
317 mpTable[i].mpFirstChild = NULL;
318 mpTable[i].mnCode = i;
319 mpTable[i].mnValue = (sal_uInt8)mpTable[i].mnCode;
322 mpPrefix = NULL;
324 WriteBits( mnClearCode, mnCodeSize );
327 LZWEncoder::~LZWEncoder()
329 if (mpPrefix)
330 WriteBits (mpPrefix->mnCode, mnCodeSize);
332 WriteBits (mnEOICode, mnCodeSize);
334 delete[] mpTable;
337 void
338 LZWEncoder::WriteBits (sal_uInt16 nCode, sal_uInt16 nCodeLen)
340 mdwShift |= (nCode << (mnOffset - nCodeLen));
341 mnOffset -= nCodeLen;
342 while (mnOffset < 24)
344 WriteAscii ((sal_uInt8)(mdwShift >> 24));
345 mdwShift <<= 8;
346 mnOffset += 8;
348 if (nCode == 257 && mnOffset != 32)
349 WriteAscii ((sal_uInt8)(mdwShift >> 24));
352 void
353 LZWEncoder::EncodeByte (sal_uInt8 nByte )
355 LZWCTreeNode* p;
356 sal_uInt16 i;
357 sal_uInt8 nV;
359 if (!mpPrefix)
361 mpPrefix = mpTable + nByte;
363 else
365 nV = nByte;
366 for (p = mpPrefix->mpFirstChild; p != NULL; p = p->mpBrother)
368 if (p->mnValue == nV)
369 break;
372 if (p != NULL)
374 mpPrefix = p;
376 else
378 WriteBits (mpPrefix->mnCode, mnCodeSize);
380 if (mnTableSize == 409)
382 WriteBits (mnClearCode, mnCodeSize);
384 for (i = 0; i < mnClearCode; i++)
385 mpTable[i].mpFirstChild = NULL;
387 mnCodeSize = mnDataSize + 1;
388 mnTableSize = mnEOICode + 1;
390 else
392 if(mnTableSize == (sal_uInt16)((1 << mnCodeSize) - 1))
393 mnCodeSize++;
395 p = mpTable + (mnTableSize++);
396 p->mpBrother = mpPrefix->mpFirstChild;
397 mpPrefix->mpFirstChild = p;
398 p->mnValue = nV;
399 p->mpFirstChild = NULL;
402 mpPrefix = mpTable + nV;
409 * bitmap handling routines
413 void
414 PrinterGfx::DrawBitmap (const Rectangle& rDest, const Rectangle& rSrc,
415 const PrinterBmp& rBitmap)
417 double fScaleX = (double)rDest.GetWidth() / (double)rSrc.GetWidth();
418 double fScaleY = (double)rDest.GetHeight() / (double)rSrc.GetHeight();
420 PSGSave ();
421 PSTranslate (rDest.BottomLeft());
422 PSScale (fScaleX, fScaleY);
424 if (mnPSLevel >= 2)
426 if (rBitmap.GetDepth() == 1)
428 DrawPS2MonoImage (rBitmap, rSrc);
430 else
431 if (rBitmap.GetDepth() == 8 && mbColor)
433 // if the palette is larger than the image itself print it as a truecolor
434 // image to save diskspace. This is important for printing transparent
435 // bitmaps that are disassembled into small pieces
436 sal_Int32 nImageSz = rSrc.GetWidth() * rSrc.GetHeight();
437 sal_Int32 nPaletteSz = rBitmap.GetPaletteEntryCount();
438 if ((nImageSz < nPaletteSz) || (nImageSz < 24) )
439 DrawPS2TrueColorImage (rBitmap, rSrc);
440 else
441 DrawPS2PaletteImage (rBitmap, rSrc);
443 else
444 if (rBitmap.GetDepth() == 24 && mbColor)
446 DrawPS2TrueColorImage (rBitmap, rSrc);
448 else
450 DrawPS2GrayImage (rBitmap, rSrc);
453 else
455 DrawPS1GrayImage (rBitmap, rSrc);
458 PSGRestore ();
463 * Implementation: PS Level 1
467 void
468 PrinterGfx::DrawPS1GrayImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
470 sal_uInt32 nWidth = rArea.GetWidth();
471 sal_uInt32 nHeight = rArea.GetHeight();
473 sal_Char pGrayImage [512];
474 sal_Int32 nChar = 0;
476 // image header
477 nChar += psp::getValueOf (nWidth, pGrayImage + nChar);
478 nChar += psp::appendStr (" ", pGrayImage + nChar);
479 nChar += psp::getValueOf (nHeight, pGrayImage + nChar);
480 nChar += psp::appendStr (" 8 ", pGrayImage + nChar);
481 nChar += psp::appendStr ("[ 1 0 0 1 0 ", pGrayImage + nChar);
482 nChar += psp::getValueOf (nHeight, pGrayImage + nChar);
483 nChar += psp::appendStr ("]", pGrayImage + nChar);
484 nChar += psp::appendStr (" {currentfile ", pGrayImage + nChar);
485 nChar += psp::getValueOf (nWidth, pGrayImage + nChar);
486 nChar += psp::appendStr (" string readhexstring pop}\n", pGrayImage + nChar);
487 nChar += psp::appendStr ("image\n", pGrayImage + nChar);
489 WritePS (mpPageBody, pGrayImage);
491 // image body
492 HexEncoder* pEncoder = new HexEncoder (mpPageBody);
494 for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
496 for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
498 sal_uChar nByte = rBitmap.GetPixelGray (nRow, nColumn);
499 pEncoder->EncodeByte (nByte);
503 delete pEncoder;
505 WritePS (mpPageBody, "\n");
510 * Implementation: PS Level 2
514 void
515 PrinterGfx::writePS2ImageHeader (const Rectangle& rArea, psp::ImageType nType)
517 sal_Int32 nChar = 0;
518 sal_Char pImage [512];
520 sal_Int32 nDictType = 0;
521 switch (nType)
523 case psp::TrueColorImage: nDictType = 0; break;
524 case psp::PaletteImage: nDictType = 1; break;
525 case psp::GrayScaleImage: nDictType = 2; break;
526 case psp::MonochromeImage: nDictType = 3; break;
527 default: break;
529 sal_Int32 nCompressType = mbCompressBmp ? 1 : 0;
531 nChar += psp::getValueOf (rArea.GetWidth(), pImage + nChar);
532 nChar += psp::appendStr (" ", pImage + nChar);
533 nChar += psp::getValueOf (rArea.GetHeight(), pImage + nChar);
534 nChar += psp::appendStr (" ", pImage + nChar);
535 nChar += psp::getValueOf (nDictType, pImage + nChar);
536 nChar += psp::appendStr (" ", pImage + nChar);
537 nChar += psp::getValueOf (nCompressType, pImage + nChar);
538 nChar += psp::appendStr (" psp_imagedict image\n", pImage + nChar);
540 WritePS (mpPageBody, pImage);
543 void
544 PrinterGfx::writePS2Colorspace(const PrinterBmp& rBitmap, psp::ImageType nType)
546 switch (nType)
548 case psp::GrayScaleImage:
550 WritePS (mpPageBody, "/DeviceGray setcolorspace\n");
551 break;
553 case psp::TrueColorImage:
555 WritePS (mpPageBody, "/DeviceRGB setcolorspace\n");
556 break;
558 case psp::MonochromeImage:
559 case psp::PaletteImage:
562 sal_Int32 nChar = 0;
563 sal_Char pImage [4096];
565 const sal_uInt32 nSize = rBitmap.GetPaletteEntryCount();
567 nChar += psp::appendStr ("[/Indexed /DeviceRGB ", pImage + nChar);
568 nChar += psp::getValueOf (nSize - 1, pImage + nChar);
569 if (mbCompressBmp)
570 nChar += psp::appendStr ("\npsp_lzwstring\n", pImage + nChar);
571 else
572 nChar += psp::appendStr ("\npsp_ascii85string\n", pImage + nChar);
573 WritePS (mpPageBody, pImage);
575 ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
576 : new Ascii85Encoder(mpPageBody);
577 for (sal_uInt32 i = 0; i < nSize; i++)
579 PrinterColor aColor = rBitmap.GetPaletteColor(i);
581 pEncoder->EncodeByte (aColor.GetRed());
582 pEncoder->EncodeByte (aColor.GetGreen());
583 pEncoder->EncodeByte (aColor.GetBlue());
585 delete pEncoder;
587 WritePS (mpPageBody, "pop ] setcolorspace\n");
589 break;
590 default: break;
594 void
595 PrinterGfx::DrawPS2GrayImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
597 writePS2Colorspace(rBitmap, psp::GrayScaleImage);
598 writePS2ImageHeader(rArea, psp::GrayScaleImage);
600 ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
601 : new Ascii85Encoder(mpPageBody);
603 for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
605 for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
607 sal_uChar nByte = rBitmap.GetPixelGray (nRow, nColumn);
608 pEncoder->EncodeByte (nByte);
612 delete pEncoder;
615 void
616 PrinterGfx::DrawPS2MonoImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
618 writePS2Colorspace(rBitmap, psp::MonochromeImage);
619 writePS2ImageHeader(rArea, psp::MonochromeImage);
621 ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
622 : new Ascii85Encoder(mpPageBody);
624 for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
626 long nBitPos = 0;
627 sal_uChar nBit = 0;
628 sal_uChar nByte = 0;
630 for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
632 nBit = rBitmap.GetPixelIdx (nRow, nColumn);
633 nByte |= nBit << (7 - nBitPos);
635 if (++nBitPos == 8)
637 pEncoder->EncodeByte (nByte);
638 nBitPos = 0;
639 nByte = 0;
642 // keep the row byte aligned
643 if (nBitPos != 0)
644 pEncoder->EncodeByte (nByte);
647 delete pEncoder;
650 void
651 PrinterGfx::DrawPS2PaletteImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
653 writePS2Colorspace(rBitmap, psp::PaletteImage);
654 writePS2ImageHeader(rArea, psp::PaletteImage);
656 ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
657 : new Ascii85Encoder(mpPageBody);
659 for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
661 for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
663 sal_uChar nByte = rBitmap.GetPixelIdx (nRow, nColumn);
664 pEncoder->EncodeByte (nByte);
668 delete pEncoder;
671 void
672 PrinterGfx::DrawPS2TrueColorImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
674 writePS2Colorspace(rBitmap, psp::TrueColorImage);
675 writePS2ImageHeader(rArea, psp::TrueColorImage);
677 ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
678 : new Ascii85Encoder(mpPageBody);
680 for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
682 for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
684 PrinterColor aColor = rBitmap.GetPixelRGB (nRow, nColumn);
685 pEncoder->EncodeByte (aColor.GetRed());
686 pEncoder->EncodeByte (aColor.GetGreen());
687 pEncoder->EncodeByte (aColor.GetBlue());
691 delete pEncoder;
694 } /* namespace psp */
696 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */