merge the formfield patch from ooo-build
[ooovba.git] / vcl / unx / source / printergfx / bitmap_gfx.cxx
blobb78ba18b97c5674481a90b0d33e312cd169bb7a4
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: bitmap_gfx.cxx,v $
10 * $Revision: 1.13 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
34 #include "psputil.hxx"
36 #include "vcl/printergfx.hxx"
37 #include "vcl/strhelper.hxx"
39 namespace psp {
41 const sal_uInt32 nLineLength = 80;
42 const sal_uInt32 nBufferSize = 16384;
46 * Bitmap compression / Hex encoding / Ascii85 Encoding
50 PrinterBmp::~PrinterBmp ()
51 { /* dont need this, but C50 does */ }
53 /* virtual base class */
55 class ByteEncoder
57 private:
59 public:
61 virtual void EncodeByte (sal_uInt8 nByte) = 0;
62 virtual ~ByteEncoder () = 0;
65 ByteEncoder::~ByteEncoder ()
66 { /* dont need this, but the C50 does */ }
68 /* HexEncoder */
70 class HexEncoder : public ByteEncoder
72 private:
74 osl::File* mpFile;
75 sal_uInt32 mnColumn;
76 sal_uInt32 mnOffset;
77 sal_Char mpFileBuffer[nBufferSize + 16];
79 HexEncoder (); /* dont use */
81 public:
83 HexEncoder (osl::File* pFile);
84 virtual ~HexEncoder ();
85 void WriteAscii (sal_uInt8 nByte);
86 virtual void EncodeByte (sal_uInt8 nByte);
87 void FlushLine ();
90 HexEncoder::HexEncoder (osl::File* pFile) :
91 mpFile (pFile),
92 mnColumn (0),
93 mnOffset (0)
96 HexEncoder::~HexEncoder ()
98 FlushLine ();
99 if (mnColumn > 0)
100 WritePS (mpFile, "\n");
103 void
104 HexEncoder::WriteAscii (sal_uInt8 nByte)
106 sal_uInt32 nOff = psp::getHexValueOf (nByte, mpFileBuffer + mnOffset);
107 mnColumn += nOff;
108 mnOffset += nOff;
110 if (mnColumn >= nLineLength)
112 mnOffset += psp::appendStr ("\n", mpFileBuffer + mnOffset);
113 mnColumn = 0;
115 if (mnOffset >= nBufferSize)
116 FlushLine ();
119 void
120 HexEncoder::EncodeByte (sal_uInt8 nByte)
122 WriteAscii (nByte);
125 void
126 HexEncoder::FlushLine ()
128 if (mnOffset > 0)
130 WritePS (mpFile, mpFileBuffer, mnOffset);
131 mnOffset = 0;
135 /* Ascii85 encoder, is abi compatible with HexEncoder but writes a ~> to
136 indicate end of data EOD */
138 class Ascii85Encoder : public ByteEncoder
140 private:
142 osl::File* mpFile;
143 sal_uInt32 mnByte;
144 sal_uInt8 mpByteBuffer[4];
146 sal_uInt32 mnColumn;
147 sal_uInt32 mnOffset;
148 sal_Char mpFileBuffer[nBufferSize + 16];
150 Ascii85Encoder (); /* dont use */
152 inline void PutByte (sal_uInt8 nByte);
153 inline void PutEOD ();
154 void ConvertToAscii85 ();
155 void FlushLine ();
157 public:
159 Ascii85Encoder (osl::File* pFile);
160 virtual ~Ascii85Encoder ();
161 virtual void EncodeByte (sal_uInt8 nByte);
162 void WriteAscii (sal_uInt8 nByte);
165 Ascii85Encoder::Ascii85Encoder (osl::File* pFile) :
166 mpFile (pFile),
167 mnByte (0),
168 mnColumn (0),
169 mnOffset (0)
172 inline void
173 Ascii85Encoder::PutByte (sal_uInt8 nByte)
175 mpByteBuffer [mnByte++] = nByte;
178 inline void
179 Ascii85Encoder::PutEOD ()
181 WritePS (mpFile, "~>\n");
184 void
185 Ascii85Encoder::ConvertToAscii85 ()
187 if (mnByte < 4)
188 std::memset (mpByteBuffer + mnByte, 0, (4 - mnByte) * sizeof(sal_uInt8));
190 sal_uInt32 nByteValue = mpByteBuffer[0] * 256 * 256 * 256
191 + mpByteBuffer[1] * 256 * 256
192 + mpByteBuffer[2] * 256
193 + mpByteBuffer[3];
195 if (nByteValue == 0 && mnByte == 4)
197 /* special case of 4 Bytes in row */
198 mpFileBuffer [mnOffset] = 'z';
200 mnOffset += 1;
201 mnColumn += 1;
203 else
205 /* real ascii85 encoding */
206 mpFileBuffer [mnOffset + 4] = (nByteValue % 85) + 33;
207 nByteValue /= 85;
208 mpFileBuffer [mnOffset + 3] = (nByteValue % 85) + 33;
209 nByteValue /= 85;
210 mpFileBuffer [mnOffset + 2] = (nByteValue % 85) + 33;
211 nByteValue /= 85;
212 mpFileBuffer [mnOffset + 1] = (nByteValue % 85) + 33;
213 nByteValue /= 85;
214 mpFileBuffer [mnOffset + 0] = (nByteValue % 85) + 33;
216 mnColumn += (mnByte + 1);
217 mnOffset += (mnByte + 1);
219 /* insert a newline if necessary */
220 if (mnColumn > nLineLength)
222 sal_uInt32 nEolOff = mnColumn - nLineLength;
223 sal_uInt32 nBufOff = mnOffset - nEolOff;
225 std::memmove (mpFileBuffer + nBufOff + 1, mpFileBuffer + nBufOff, nEolOff);
226 mpFileBuffer[ nBufOff ] = '\n';
228 mnOffset++;
229 mnColumn = nEolOff;
233 mnByte = 0;
236 void
237 Ascii85Encoder::WriteAscii (sal_uInt8 nByte)
239 PutByte (nByte);
240 if (mnByte == 4)
241 ConvertToAscii85 ();
243 if (mnColumn >= nLineLength)
245 mnOffset += psp::appendStr ("\n", mpFileBuffer + mnOffset);
246 mnColumn = 0;
248 if (mnOffset >= nBufferSize)
249 FlushLine ();
252 void
253 Ascii85Encoder::EncodeByte (sal_uInt8 nByte)
255 WriteAscii (nByte);
258 void
259 Ascii85Encoder::FlushLine ()
261 if (mnOffset > 0)
263 WritePS (mpFile, mpFileBuffer, mnOffset);
264 mnOffset = 0;
268 Ascii85Encoder::~Ascii85Encoder ()
270 if (mnByte > 0)
271 ConvertToAscii85 ();
272 if (mnOffset > 0)
273 FlushLine ();
274 PutEOD ();
277 /* LZW encoder */
279 class LZWEncoder : public Ascii85Encoder
281 private:
283 struct LZWCTreeNode
285 LZWCTreeNode* mpBrother; // next node with same parent
286 LZWCTreeNode* mpFirstChild; // first son
287 sal_uInt16 mnCode; // code for the string
288 sal_uInt16 mnValue; // pixelvalue
291 LZWCTreeNode* mpTable; // LZW compression data
292 LZWCTreeNode* mpPrefix; // the compression is as same as the TIFF compression
293 sal_uInt16 mnDataSize;
294 sal_uInt16 mnClearCode;
295 sal_uInt16 mnEOICode;
296 sal_uInt16 mnTableSize;
297 sal_uInt16 mnCodeSize;
298 sal_uInt32 mnOffset;
299 sal_uInt32 mdwShift;
301 LZWEncoder ();
302 void WriteBits (sal_uInt16 nCode, sal_uInt16 nCodeLen);
304 public:
306 LZWEncoder (osl::File* pOutputFile);
307 ~LZWEncoder ();
309 virtual void EncodeByte (sal_uInt8 nByte);
312 LZWEncoder::LZWEncoder(osl::File* pOutputFile) :
313 Ascii85Encoder (pOutputFile)
315 mnDataSize = 8;
317 mnClearCode = 1 << mnDataSize;
318 mnEOICode = mnClearCode + 1;
319 mnTableSize = mnEOICode + 1;
320 mnCodeSize = mnDataSize + 1;
322 mnOffset = 32; // free bits in dwShift
323 mdwShift = 0;
325 mpTable = new LZWCTreeNode[ 4096 ];
327 for (sal_uInt32 i = 0; i < 4096; i++)
329 mpTable[i].mpBrother = NULL;
330 mpTable[i].mpFirstChild = NULL;
331 mpTable[i].mnCode = i;
332 mpTable[i].mnValue = (sal_uInt8)mpTable[i].mnCode;
335 mpPrefix = NULL;
337 WriteBits( mnClearCode, mnCodeSize );
340 LZWEncoder::~LZWEncoder()
342 if (mpPrefix)
343 WriteBits (mpPrefix->mnCode, mnCodeSize);
345 WriteBits (mnEOICode, mnCodeSize);
347 delete[] mpTable;
350 void
351 LZWEncoder::WriteBits (sal_uInt16 nCode, sal_uInt16 nCodeLen)
353 mdwShift |= (nCode << (mnOffset - nCodeLen));
354 mnOffset -= nCodeLen;
355 while (mnOffset < 24)
357 WriteAscii ((sal_uInt8)(mdwShift >> 24));
358 mdwShift <<= 8;
359 mnOffset += 8;
361 if (nCode == 257 && mnOffset != 32)
362 WriteAscii ((sal_uInt8)(mdwShift >> 24));
365 void
366 LZWEncoder::EncodeByte (sal_uInt8 nByte )
368 LZWCTreeNode* p;
369 sal_uInt16 i;
370 sal_uInt8 nV;
372 if (!mpPrefix)
374 mpPrefix = mpTable + nByte;
376 else
378 nV = nByte;
379 for (p = mpPrefix->mpFirstChild; p != NULL; p = p->mpBrother)
381 if (p->mnValue == nV)
382 break;
385 if (p != NULL)
387 mpPrefix = p;
389 else
391 WriteBits (mpPrefix->mnCode, mnCodeSize);
393 if (mnTableSize == 409)
395 WriteBits (mnClearCode, mnCodeSize);
397 for (i = 0; i < mnClearCode; i++)
398 mpTable[i].mpFirstChild = NULL;
400 mnCodeSize = mnDataSize + 1;
401 mnTableSize = mnEOICode + 1;
403 else
405 if(mnTableSize == (sal_uInt16)((1 << mnCodeSize) - 1))
406 mnCodeSize++;
408 p = mpTable + (mnTableSize++);
409 p->mpBrother = mpPrefix->mpFirstChild;
410 mpPrefix->mpFirstChild = p;
411 p->mnValue = nV;
412 p->mpFirstChild = NULL;
415 mpPrefix = mpTable + nV;
422 * bitmap handling routines
426 void
427 PrinterGfx::DrawBitmap (const Rectangle& rDest, const Rectangle& rSrc,
428 const PrinterBmp& rBitmap)
430 double fScaleX = (double)rDest.GetWidth() / (double)rSrc.GetWidth();
431 double fScaleY = (double)rDest.GetHeight() / (double)rSrc.GetHeight();
433 PSGSave ();
434 PSTranslate (rDest.BottomLeft());
435 PSScale (fScaleX, fScaleY);
437 if (mnPSLevel >= 2)
439 if (rBitmap.GetDepth() == 1)
441 DrawPS2MonoImage (rBitmap, rSrc);
443 else
444 if (rBitmap.GetDepth() == 8 && mbColor)
446 // if the palette is larger than the image itself print it as a truecolor
447 // image to save diskspace. This is important for printing transparent
448 // bitmaps that are disassembled into small pieces
449 sal_Int32 nImageSz = rSrc.GetWidth() * rSrc.GetHeight();
450 sal_Int32 nPaletteSz = rBitmap.GetPaletteEntryCount();
451 if ((nImageSz < nPaletteSz) || (nImageSz < 24) )
452 DrawPS2TrueColorImage (rBitmap, rSrc);
453 else
454 DrawPS2PaletteImage (rBitmap, rSrc);
456 else
457 if (rBitmap.GetDepth() == 24 && mbColor)
459 DrawPS2TrueColorImage (rBitmap, rSrc);
461 else
463 DrawPS2GrayImage (rBitmap, rSrc);
466 else
468 DrawPS1GrayImage (rBitmap, rSrc);
471 PSGRestore ();
474 /* XXX does not work XXX */
475 void
476 PrinterGfx::DrawBitmap (const Rectangle& rDest, const Rectangle& rSrc,
477 const PrinterBmp& /*rBitmap*/, const PrinterBmp& /*rTransBitmap*/)
479 double fScaleX = (double)rDest.GetWidth() / (double)rSrc.GetWidth();
480 double fScaleY = (double)rDest.GetHeight() / (double)rSrc.GetHeight();
482 PSGSave ();
483 PSTranslate (rDest.BottomLeft());
484 PSScale (fScaleX, fScaleY);
485 PSGRestore ();
488 /* XXX does not work XXX */
489 void
490 PrinterGfx::DrawMask (const Rectangle& rDest, const Rectangle& rSrc,
491 const PrinterBmp &/*rBitmap*/, PrinterColor& /*rMaskColor*/)
493 double fScaleX = (double)rDest.GetWidth() / (double)rSrc.GetWidth();
494 double fScaleY = (double)rDest.GetHeight() / (double)rSrc.GetHeight();
496 PSGSave ();
497 PSTranslate (rDest.BottomLeft());
498 PSScale (fScaleX, fScaleY);
499 PSGRestore ();
504 * Implementation: PS Level 1
508 void
509 PrinterGfx::DrawPS1GrayImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
511 sal_uInt32 nWidth = rArea.GetWidth();
512 sal_uInt32 nHeight = rArea.GetHeight();
514 sal_Char pGrayImage [512];
515 sal_Int32 nChar = 0;
517 // image header
518 nChar += psp::getValueOf (nWidth, pGrayImage + nChar);
519 nChar += psp::appendStr (" ", pGrayImage + nChar);
520 nChar += psp::getValueOf (nHeight, pGrayImage + nChar);
521 nChar += psp::appendStr (" 8 ", pGrayImage + nChar);
522 nChar += psp::appendStr ("[ 1 0 0 1 0 ", pGrayImage + nChar);
523 nChar += psp::getValueOf (nHeight, pGrayImage + nChar);
524 nChar += psp::appendStr ("]", pGrayImage + nChar);
525 nChar += psp::appendStr (" {currentfile ", pGrayImage + nChar);
526 nChar += psp::getValueOf (nWidth, pGrayImage + nChar);
527 nChar += psp::appendStr (" string readhexstring pop}\n", pGrayImage + nChar);
528 nChar += psp::appendStr ("image\n", pGrayImage + nChar);
530 WritePS (mpPageBody, pGrayImage);
532 // image body
533 HexEncoder* pEncoder = new HexEncoder (mpPageBody);
535 for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
537 for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
539 sal_uChar nByte = rBitmap.GetPixelGray (nRow, nColumn);
540 pEncoder->EncodeByte (nByte);
544 delete pEncoder;
546 WritePS (mpPageBody, "\n");
551 * Implementation: PS Level 2
555 void
556 PrinterGfx::writePS2ImageHeader (const Rectangle& rArea, psp::ImageType nType)
558 sal_Int32 nChar = 0;
559 sal_Char pImage [512];
561 sal_Int32 nDictType = 0;
562 switch (nType)
564 case psp::TrueColorImage: nDictType = 0; break;
565 case psp::PaletteImage: nDictType = 1; break;
566 case psp::GrayScaleImage: nDictType = 2; break;
567 case psp::MonochromeImage: nDictType = 3; break;
568 default: break;
570 sal_Int32 nCompressType = mbCompressBmp ? 1 : 0;
572 nChar += psp::getValueOf (rArea.GetWidth(), pImage + nChar);
573 nChar += psp::appendStr (" ", pImage + nChar);
574 nChar += psp::getValueOf (rArea.GetHeight(), pImage + nChar);
575 nChar += psp::appendStr (" ", pImage + nChar);
576 nChar += psp::getValueOf (nDictType, pImage + nChar);
577 nChar += psp::appendStr (" ", pImage + nChar);
578 nChar += psp::getValueOf (nCompressType, pImage + nChar);
579 nChar += psp::appendStr (" psp_imagedict image\n", pImage + nChar);
581 WritePS (mpPageBody, pImage);
584 void
585 PrinterGfx::writePS2Colorspace(const PrinterBmp& rBitmap, psp::ImageType nType)
587 switch (nType)
589 case psp::GrayScaleImage:
591 WritePS (mpPageBody, "/DeviceGray setcolorspace\n");
592 break;
594 case psp::TrueColorImage:
596 WritePS (mpPageBody, "/DeviceRGB setcolorspace\n");
597 break;
599 case psp::MonochromeImage:
600 case psp::PaletteImage:
603 sal_Int32 nChar = 0;
604 sal_Char pImage [4096];
606 const sal_uInt32 nSize = rBitmap.GetPaletteEntryCount();
608 nChar += psp::appendStr ("[/Indexed /DeviceRGB ", pImage + nChar);
609 nChar += psp::getValueOf (nSize - 1, pImage + nChar);
610 if (mbCompressBmp)
611 nChar += psp::appendStr ("\npsp_lzwstring\n", pImage + nChar);
612 else
613 nChar += psp::appendStr ("\npsp_ascii85string\n", pImage + nChar);
614 WritePS (mpPageBody, pImage);
616 ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
617 : new Ascii85Encoder(mpPageBody);
618 for (sal_uInt32 i = 0; i < nSize; i++)
620 PrinterColor aColor = rBitmap.GetPaletteColor(i);
622 pEncoder->EncodeByte (aColor.GetRed());
623 pEncoder->EncodeByte (aColor.GetGreen());
624 pEncoder->EncodeByte (aColor.GetBlue());
626 delete pEncoder;
628 WritePS (mpPageBody, "pop ] setcolorspace\n");
630 break;
631 default: break;
635 void
636 PrinterGfx::DrawPS2GrayImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
638 writePS2Colorspace(rBitmap, psp::GrayScaleImage);
639 writePS2ImageHeader(rArea, psp::GrayScaleImage);
641 ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
642 : new Ascii85Encoder(mpPageBody);
644 for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
646 for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
648 sal_uChar nByte = rBitmap.GetPixelGray (nRow, nColumn);
649 pEncoder->EncodeByte (nByte);
653 delete pEncoder;
656 void
657 PrinterGfx::DrawPS2MonoImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
659 writePS2Colorspace(rBitmap, psp::MonochromeImage);
660 writePS2ImageHeader(rArea, psp::MonochromeImage);
662 ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
663 : new Ascii85Encoder(mpPageBody);
665 for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
667 long nBitPos = 0;
668 sal_uChar nBit = 0;
669 sal_uChar nByte = 0;
671 for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
673 nBit = rBitmap.GetPixelIdx (nRow, nColumn);
674 nByte |= nBit << (7 - nBitPos);
676 if (++nBitPos == 8)
678 pEncoder->EncodeByte (nByte);
679 nBitPos = 0;
680 nByte = 0;
683 // keep the row byte aligned
684 if (nBitPos != 0)
685 pEncoder->EncodeByte (nByte);
688 delete pEncoder;
691 void
692 PrinterGfx::DrawPS2PaletteImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
694 writePS2Colorspace(rBitmap, psp::PaletteImage);
695 writePS2ImageHeader(rArea, psp::PaletteImage);
697 ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
698 : new Ascii85Encoder(mpPageBody);
700 for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
702 for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
704 sal_uChar nByte = rBitmap.GetPixelIdx (nRow, nColumn);
705 pEncoder->EncodeByte (nByte);
709 delete pEncoder;
712 void
713 PrinterGfx::DrawPS2TrueColorImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
715 writePS2Colorspace(rBitmap, psp::TrueColorImage);
716 writePS2ImageHeader(rArea, psp::TrueColorImage);
718 ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
719 : new Ascii85Encoder(mpPageBody);
721 for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
723 for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
725 PrinterColor aColor = rBitmap.GetPixelRGB (nRow, nColumn);
726 pEncoder->EncodeByte (aColor.GetRed());
727 pEncoder->EncodeByte (aColor.GetGreen());
728 pEncoder->EncodeByte (aColor.GetBlue());
732 delete pEncoder;
735 } /* namespace psp */