Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / generic / print / bitmap_gfx.cxx
blobca6495ff8d5644d4011ad0527812f458740f0e38
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 .
20 #include "psputil.hxx"
22 #include "generic/printergfx.hxx"
23 #include "vcl/strhelper.hxx"
25 namespace psp {
27 const sal_uInt32 nLineLength = 80;
28 const sal_uInt32 nBufferSize = 16384;
32 * Bitmap compression / Hex encoding / Ascii85 Encoding
36 PrinterBmp::~PrinterBmp()
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()
56 /* HexEncoder */
58 class HexEncoder : public ByteEncoder
60 private:
62 osl::File* mpFile;
63 sal_uInt32 mnColumn;
64 sal_uInt32 mnOffset;
65 sal_Char mpFileBuffer[nBufferSize + 16];
67 public:
69 HexEncoder (osl::File* pFile);
70 virtual ~HexEncoder ();
71 void WriteAscii (sal_uInt8 nByte);
72 virtual void EncodeByte (sal_uInt8 nByte) SAL_OVERRIDE;
73 void FlushLine ();
76 HexEncoder::HexEncoder (osl::File* pFile) :
77 mpFile (pFile),
78 mnColumn (0),
79 mnOffset (0)
82 HexEncoder::~HexEncoder ()
84 FlushLine ();
85 if (mnColumn > 0)
86 WritePS (mpFile, "\n");
89 void
90 HexEncoder::WriteAscii (sal_uInt8 nByte)
92 sal_uInt32 nOff = psp::getHexValueOf (nByte, mpFileBuffer + mnOffset);
93 mnColumn += nOff;
94 mnOffset += nOff;
96 if (mnColumn >= nLineLength)
98 mnOffset += psp::appendStr ("\n", mpFileBuffer + mnOffset);
99 mnColumn = 0;
101 if (mnOffset >= nBufferSize)
102 FlushLine ();
105 void
106 HexEncoder::EncodeByte (sal_uInt8 nByte)
108 WriteAscii (nByte);
111 void
112 HexEncoder::FlushLine ()
114 if (mnOffset > 0)
116 WritePS (mpFile, mpFileBuffer, mnOffset);
117 mnOffset = 0;
121 /* Ascii85 encoder, is abi compatible with HexEncoder but writes a ~> to
122 indicate end of data EOD */
124 class Ascii85Encoder : public ByteEncoder
126 private:
128 osl::File* mpFile;
129 sal_uInt32 mnByte;
130 sal_uInt8 mpByteBuffer[4];
132 sal_uInt32 mnColumn;
133 sal_uInt32 mnOffset;
134 sal_Char mpFileBuffer[nBufferSize + 16];
136 inline void PutByte (sal_uInt8 nByte);
137 inline void PutEOD ();
138 void ConvertToAscii85 ();
139 void FlushLine ();
141 public:
143 Ascii85Encoder (osl::File* pFile);
144 virtual ~Ascii85Encoder ();
145 virtual void EncodeByte (sal_uInt8 nByte) SAL_OVERRIDE;
146 void WriteAscii (sal_uInt8 nByte);
149 Ascii85Encoder::Ascii85Encoder (osl::File* pFile) :
150 mpFile (pFile),
151 mnByte (0),
152 mnColumn (0),
153 mnOffset (0)
156 inline void
157 Ascii85Encoder::PutByte (sal_uInt8 nByte)
159 mpByteBuffer [mnByte++] = nByte;
162 inline void
163 Ascii85Encoder::PutEOD ()
165 WritePS (mpFile, "~>\n");
168 void
169 Ascii85Encoder::ConvertToAscii85 ()
171 if (mnByte < 4)
172 std::memset (mpByteBuffer + mnByte, 0, (4 - mnByte) * sizeof(sal_uInt8));
174 sal_uInt32 nByteValue = mpByteBuffer[0] * 256 * 256 * 256
175 + mpByteBuffer[1] * 256 * 256
176 + mpByteBuffer[2] * 256
177 + mpByteBuffer[3];
179 if (nByteValue == 0 && mnByte == 4)
181 /* special case of 4 Bytes in row */
182 mpFileBuffer [mnOffset] = 'z';
184 mnOffset += 1;
185 mnColumn += 1;
187 else
189 /* real ascii85 encoding */
190 mpFileBuffer [mnOffset + 4] = (nByteValue % 85) + 33;
191 nByteValue /= 85;
192 mpFileBuffer [mnOffset + 3] = (nByteValue % 85) + 33;
193 nByteValue /= 85;
194 mpFileBuffer [mnOffset + 2] = (nByteValue % 85) + 33;
195 nByteValue /= 85;
196 mpFileBuffer [mnOffset + 1] = (nByteValue % 85) + 33;
197 nByteValue /= 85;
198 mpFileBuffer [mnOffset + 0] = (nByteValue % 85) + 33;
200 mnColumn += (mnByte + 1);
201 mnOffset += (mnByte + 1);
203 /* insert a newline if necessary */
204 if (mnColumn > nLineLength)
206 sal_uInt32 nEolOff = mnColumn - nLineLength;
207 sal_uInt32 nBufOff = mnOffset - nEolOff;
209 std::memmove (mpFileBuffer + nBufOff + 1, mpFileBuffer + nBufOff, nEolOff);
210 mpFileBuffer[ nBufOff ] = '\n';
212 mnOffset++;
213 mnColumn = nEolOff;
217 mnByte = 0;
220 void
221 Ascii85Encoder::WriteAscii (sal_uInt8 nByte)
223 PutByte (nByte);
224 if (mnByte == 4)
225 ConvertToAscii85 ();
227 if (mnColumn >= nLineLength)
229 mnOffset += psp::appendStr ("\n", mpFileBuffer + mnOffset);
230 mnColumn = 0;
232 if (mnOffset >= nBufferSize)
233 FlushLine ();
236 void
237 Ascii85Encoder::EncodeByte (sal_uInt8 nByte)
239 WriteAscii (nByte);
242 void
243 Ascii85Encoder::FlushLine ()
245 if (mnOffset > 0)
247 WritePS (mpFile, mpFileBuffer, mnOffset);
248 mnOffset = 0;
252 Ascii85Encoder::~Ascii85Encoder ()
254 if (mnByte > 0)
255 ConvertToAscii85 ();
256 if (mnOffset > 0)
257 FlushLine ();
258 PutEOD ();
261 /* LZW encoder */
263 class LZWEncoder : public Ascii85Encoder
265 private:
267 struct LZWCTreeNode
269 LZWCTreeNode* mpBrother; // next node with same parent
270 LZWCTreeNode* mpFirstChild; // first son
271 sal_uInt16 mnCode; // code for the string
272 sal_uInt16 mnValue; // pixelvalue
275 LZWCTreeNode* mpTable; // LZW compression data
276 LZWCTreeNode* mpPrefix; // the compression is as same as the TIFF compression
277 sal_uInt16 mnDataSize;
278 sal_uInt16 mnClearCode;
279 sal_uInt16 mnEOICode;
280 sal_uInt16 mnTableSize;
281 sal_uInt16 mnCodeSize;
282 sal_uInt32 mnOffset;
283 sal_uInt32 mdwShift;
285 void WriteBits (sal_uInt16 nCode, sal_uInt16 nCodeLen);
287 public:
289 LZWEncoder (osl::File* pOutputFile);
290 virtual ~LZWEncoder ();
292 virtual void EncodeByte (sal_uInt8 nByte) SAL_OVERRIDE;
295 LZWEncoder::LZWEncoder(osl::File* pOutputFile) :
296 Ascii85Encoder (pOutputFile)
298 mnDataSize = 8;
300 mnClearCode = 1 << mnDataSize;
301 mnEOICode = mnClearCode + 1;
302 mnTableSize = mnEOICode + 1;
303 mnCodeSize = mnDataSize + 1;
305 mnOffset = 32; // free bits in dwShift
306 mdwShift = 0;
308 mpTable = new LZWCTreeNode[ 4096 ];
310 for (sal_uInt32 i = 0; i < 4096; i++)
312 mpTable[i].mpBrother = NULL;
313 mpTable[i].mpFirstChild = NULL;
314 mpTable[i].mnCode = i;
315 mpTable[i].mnValue = (sal_uInt8)mpTable[i].mnCode;
318 mpPrefix = NULL;
320 WriteBits( mnClearCode, mnCodeSize );
323 LZWEncoder::~LZWEncoder()
325 if (mpPrefix)
326 WriteBits (mpPrefix->mnCode, mnCodeSize);
328 WriteBits (mnEOICode, mnCodeSize);
330 delete[] mpTable;
333 void
334 LZWEncoder::WriteBits (sal_uInt16 nCode, sal_uInt16 nCodeLen)
336 mdwShift |= (nCode << (mnOffset - nCodeLen));
337 mnOffset -= nCodeLen;
338 while (mnOffset < 24)
340 WriteAscii ((sal_uInt8)(mdwShift >> 24));
341 mdwShift <<= 8;
342 mnOffset += 8;
344 if (nCode == 257 && mnOffset != 32)
345 WriteAscii ((sal_uInt8)(mdwShift >> 24));
348 void
349 LZWEncoder::EncodeByte (sal_uInt8 nByte )
351 LZWCTreeNode* p;
352 sal_uInt16 i;
353 sal_uInt8 nV;
355 if (!mpPrefix)
357 mpPrefix = mpTable + nByte;
359 else
361 nV = nByte;
362 for (p = mpPrefix->mpFirstChild; p != NULL; p = p->mpBrother)
364 if (p->mnValue == nV)
365 break;
368 if (p != NULL)
370 mpPrefix = p;
372 else
374 WriteBits (mpPrefix->mnCode, mnCodeSize);
376 if (mnTableSize == 409)
378 WriteBits (mnClearCode, mnCodeSize);
380 for (i = 0; i < mnClearCode; i++)
381 mpTable[i].mpFirstChild = NULL;
383 mnCodeSize = mnDataSize + 1;
384 mnTableSize = mnEOICode + 1;
386 else
388 if(mnTableSize == (sal_uInt16)((1 << mnCodeSize) - 1))
389 mnCodeSize++;
391 p = mpTable + (mnTableSize++);
392 p->mpBrother = mpPrefix->mpFirstChild;
393 mpPrefix->mpFirstChild = p;
394 p->mnValue = nV;
395 p->mpFirstChild = NULL;
398 mpPrefix = mpTable + nV;
405 * bitmap handling routines
409 void
410 PrinterGfx::DrawBitmap (const Rectangle& rDest, const Rectangle& rSrc,
411 const PrinterBmp& rBitmap)
413 double fScaleX = (double)rDest.GetWidth();
414 double fScaleY = (double)rDest.GetHeight();
415 if(rSrc.GetWidth() > 0)
417 fScaleX = (double)rDest.GetWidth() / (double)rSrc.GetWidth();
419 if(rSrc.GetHeight() > 0)
421 fScaleY = (double)rDest.GetHeight() / (double)rSrc.GetHeight();
423 PSGSave ();
424 PSTranslate (rDest.BottomLeft());
425 PSScale (fScaleX, fScaleY);
427 if (mnPSLevel >= 2)
429 if (rBitmap.GetDepth() == 1)
431 DrawPS2MonoImage (rBitmap, rSrc);
433 else
434 if (rBitmap.GetDepth() == 8 && mbColor)
436 // if the palette is larger than the image itself print it as a truecolor
437 // image to save diskspace. This is important for printing transparent
438 // bitmaps that are disassembled into small pieces
439 sal_Int32 nImageSz = rSrc.GetWidth() * rSrc.GetHeight();
440 sal_Int32 nPaletteSz = rBitmap.GetPaletteEntryCount();
441 if ((nImageSz < nPaletteSz) || (nImageSz < 24) )
442 DrawPS2TrueColorImage (rBitmap, rSrc);
443 else
444 DrawPS2PaletteImage (rBitmap, rSrc);
446 else
447 if (rBitmap.GetDepth() == 24 && mbColor)
449 DrawPS2TrueColorImage (rBitmap, rSrc);
451 else
453 DrawPS2GrayImage (rBitmap, rSrc);
456 else
458 DrawPS1GrayImage (rBitmap, rSrc);
461 PSGRestore ();
466 * Implementation: PS Level 1
470 void
471 PrinterGfx::DrawPS1GrayImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
473 sal_uInt32 nWidth = rArea.GetWidth();
474 sal_uInt32 nHeight = rArea.GetHeight();
476 sal_Char pGrayImage [512];
477 sal_Int32 nChar = 0;
479 // image header
480 nChar += psp::getValueOf (nWidth, pGrayImage + nChar);
481 nChar += psp::appendStr (" ", pGrayImage + nChar);
482 nChar += psp::getValueOf (nHeight, pGrayImage + nChar);
483 nChar += psp::appendStr (" 8 ", pGrayImage + nChar);
484 nChar += psp::appendStr ("[ 1 0 0 1 0 ", pGrayImage + nChar);
485 nChar += psp::getValueOf (nHeight, pGrayImage + nChar);
486 nChar += psp::appendStr ("]", pGrayImage + nChar);
487 nChar += psp::appendStr (" {currentfile ", pGrayImage + nChar);
488 nChar += psp::getValueOf (nWidth, pGrayImage + nChar);
489 nChar += psp::appendStr (" string readhexstring pop}\n", pGrayImage + nChar);
490 nChar += psp::appendStr ("image\n", pGrayImage + nChar);
492 WritePS (mpPageBody, pGrayImage);
494 // image body
495 std::unique_ptr<HexEncoder> xEncoder(new HexEncoder (mpPageBody));
497 for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
499 for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
501 unsigned char nByte = rBitmap.GetPixelGray (nRow, nColumn);
502 xEncoder->EncodeByte (nByte);
506 xEncoder.reset();
508 WritePS (mpPageBody, "\n");
513 * Implementation: PS Level 2
517 void
518 PrinterGfx::writePS2ImageHeader (const Rectangle& rArea, psp::ImageType nType)
520 sal_Int32 nChar = 0;
521 sal_Char pImage [512];
523 sal_Int32 nDictType = 0;
524 switch (nType)
526 case psp::TrueColorImage: nDictType = 0; break;
527 case psp::PaletteImage: nDictType = 1; break;
528 case psp::GrayScaleImage: nDictType = 2; break;
529 case psp::MonochromeImage: nDictType = 3; break;
530 default: break;
532 sal_Int32 nCompressType = mbCompressBmp ? 1 : 0;
534 nChar += psp::getValueOf (rArea.GetWidth(), pImage + nChar);
535 nChar += psp::appendStr (" ", pImage + nChar);
536 nChar += psp::getValueOf (rArea.GetHeight(), pImage + nChar);
537 nChar += psp::appendStr (" ", pImage + nChar);
538 nChar += psp::getValueOf (nDictType, pImage + nChar);
539 nChar += psp::appendStr (" ", pImage + nChar);
540 nChar += psp::getValueOf (nCompressType, pImage + nChar);
541 nChar += psp::appendStr (" psp_imagedict image\n", pImage + nChar);
543 WritePS (mpPageBody, pImage);
546 void
547 PrinterGfx::writePS2Colorspace(const PrinterBmp& rBitmap, psp::ImageType nType)
549 switch (nType)
551 case psp::GrayScaleImage:
553 WritePS (mpPageBody, "/DeviceGray setcolorspace\n");
554 break;
556 case psp::TrueColorImage:
558 WritePS (mpPageBody, "/DeviceRGB setcolorspace\n");
559 break;
561 case psp::MonochromeImage:
562 case psp::PaletteImage:
565 sal_Int32 nChar = 0;
566 sal_Char pImage [4096];
568 const sal_uInt32 nSize = rBitmap.GetPaletteEntryCount();
570 nChar += psp::appendStr ("[/Indexed /DeviceRGB ", pImage + nChar);
571 nChar += psp::getValueOf (nSize - 1, pImage + nChar);
572 if (mbCompressBmp)
573 nChar += psp::appendStr ("\npsp_lzwstring\n", pImage + nChar);
574 else
575 nChar += psp::appendStr ("\npsp_ascii85string\n", pImage + nChar);
576 WritePS (mpPageBody, pImage);
578 std::unique_ptr<ByteEncoder> xEncoder(mbCompressBmp ? new LZWEncoder(mpPageBody)
579 : new Ascii85Encoder(mpPageBody));
580 for (sal_uInt32 i = 0; i < nSize; i++)
582 PrinterColor aColor = rBitmap.GetPaletteColor(i);
584 xEncoder->EncodeByte (aColor.GetRed());
585 xEncoder->EncodeByte (aColor.GetGreen());
586 xEncoder->EncodeByte (aColor.GetBlue());
588 xEncoder.reset();
590 WritePS (mpPageBody, "pop ] setcolorspace\n");
592 break;
593 default: break;
597 void
598 PrinterGfx::DrawPS2GrayImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
600 writePS2Colorspace(rBitmap, psp::GrayScaleImage);
601 writePS2ImageHeader(rArea, psp::GrayScaleImage);
603 std::unique_ptr<ByteEncoder> xEncoder(mbCompressBmp ? new LZWEncoder(mpPageBody)
604 : new Ascii85Encoder(mpPageBody));
606 for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
608 for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
610 unsigned char nByte = rBitmap.GetPixelGray (nRow, nColumn);
611 xEncoder->EncodeByte (nByte);
616 void
617 PrinterGfx::DrawPS2MonoImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
619 writePS2Colorspace(rBitmap, psp::MonochromeImage);
620 writePS2ImageHeader(rArea, psp::MonochromeImage);
622 std::unique_ptr<ByteEncoder> xEncoder(mbCompressBmp ? new LZWEncoder(mpPageBody)
623 : new Ascii85Encoder(mpPageBody));
625 for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
627 long nBitPos = 0;
628 unsigned char nByte = 0;
630 for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
632 unsigned char nBit = rBitmap.GetPixelIdx (nRow, nColumn);
633 nByte |= nBit << (7 - nBitPos);
635 if (++nBitPos == 8)
637 xEncoder->EncodeByte (nByte);
638 nBitPos = 0;
639 nByte = 0;
642 // keep the row byte aligned
643 if (nBitPos != 0)
644 xEncoder->EncodeByte (nByte);
648 void
649 PrinterGfx::DrawPS2PaletteImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
651 writePS2Colorspace(rBitmap, psp::PaletteImage);
652 writePS2ImageHeader(rArea, psp::PaletteImage);
654 std::unique_ptr<ByteEncoder> xEncoder(mbCompressBmp ? new LZWEncoder(mpPageBody)
655 : new Ascii85Encoder(mpPageBody));
657 for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
659 for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
661 unsigned char nByte = rBitmap.GetPixelIdx (nRow, nColumn);
662 xEncoder->EncodeByte (nByte);
667 void
668 PrinterGfx::DrawPS2TrueColorImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
670 writePS2Colorspace(rBitmap, psp::TrueColorImage);
671 writePS2ImageHeader(rArea, psp::TrueColorImage);
673 std::unique_ptr<ByteEncoder> xEncoder(mbCompressBmp ? new LZWEncoder(mpPageBody)
674 : new Ascii85Encoder(mpPageBody));
676 for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
678 for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
680 PrinterColor aColor = rBitmap.GetPixelRGB (nRow, nColumn);
681 xEncoder->EncodeByte (aColor.GetRed());
682 xEncoder->EncodeByte (aColor.GetGreen());
683 xEncoder->EncodeByte (aColor.GetBlue());
688 } /* namespace psp */
690 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */