1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: bitmap_gfx.cxx,v $
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"
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 */
61 virtual void EncodeByte (sal_uInt8 nByte
) = 0;
62 virtual ~ByteEncoder () = 0;
65 ByteEncoder::~ByteEncoder ()
66 { /* dont need this, but the C50 does */ }
70 class HexEncoder
: public ByteEncoder
77 sal_Char mpFileBuffer
[nBufferSize
+ 16];
79 HexEncoder (); /* dont use */
83 HexEncoder (osl::File
* pFile
);
84 virtual ~HexEncoder ();
85 void WriteAscii (sal_uInt8 nByte
);
86 virtual void EncodeByte (sal_uInt8 nByte
);
90 HexEncoder::HexEncoder (osl::File
* pFile
) :
96 HexEncoder::~HexEncoder ()
100 WritePS (mpFile
, "\n");
104 HexEncoder::WriteAscii (sal_uInt8 nByte
)
106 sal_uInt32 nOff
= psp::getHexValueOf (nByte
, mpFileBuffer
+ mnOffset
);
110 if (mnColumn
>= nLineLength
)
112 mnOffset
+= psp::appendStr ("\n", mpFileBuffer
+ mnOffset
);
115 if (mnOffset
>= nBufferSize
)
120 HexEncoder::EncodeByte (sal_uInt8 nByte
)
126 HexEncoder::FlushLine ()
130 WritePS (mpFile
, mpFileBuffer
, mnOffset
);
135 /* Ascii85 encoder, is abi compatible with HexEncoder but writes a ~> to
136 indicate end of data EOD */
138 class Ascii85Encoder
: public ByteEncoder
144 sal_uInt8 mpByteBuffer
[4];
148 sal_Char mpFileBuffer
[nBufferSize
+ 16];
150 Ascii85Encoder (); /* dont use */
152 inline void PutByte (sal_uInt8 nByte
);
153 inline void PutEOD ();
154 void ConvertToAscii85 ();
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
) :
173 Ascii85Encoder::PutByte (sal_uInt8 nByte
)
175 mpByteBuffer
[mnByte
++] = nByte
;
179 Ascii85Encoder::PutEOD ()
181 WritePS (mpFile
, "~>\n");
185 Ascii85Encoder::ConvertToAscii85 ()
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
195 if (nByteValue
== 0 && mnByte
== 4)
197 /* special case of 4 Bytes in row */
198 mpFileBuffer
[mnOffset
] = 'z';
205 /* real ascii85 encoding */
206 mpFileBuffer
[mnOffset
+ 4] = (nByteValue
% 85) + 33;
208 mpFileBuffer
[mnOffset
+ 3] = (nByteValue
% 85) + 33;
210 mpFileBuffer
[mnOffset
+ 2] = (nByteValue
% 85) + 33;
212 mpFileBuffer
[mnOffset
+ 1] = (nByteValue
% 85) + 33;
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';
237 Ascii85Encoder::WriteAscii (sal_uInt8 nByte
)
243 if (mnColumn
>= nLineLength
)
245 mnOffset
+= psp::appendStr ("\n", mpFileBuffer
+ mnOffset
);
248 if (mnOffset
>= nBufferSize
)
253 Ascii85Encoder::EncodeByte (sal_uInt8 nByte
)
259 Ascii85Encoder::FlushLine ()
263 WritePS (mpFile
, mpFileBuffer
, mnOffset
);
268 Ascii85Encoder::~Ascii85Encoder ()
279 class LZWEncoder
: public Ascii85Encoder
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
;
302 void WriteBits (sal_uInt16 nCode
, sal_uInt16 nCodeLen
);
306 LZWEncoder (osl::File
* pOutputFile
);
309 virtual void EncodeByte (sal_uInt8 nByte
);
312 LZWEncoder::LZWEncoder(osl::File
* pOutputFile
) :
313 Ascii85Encoder (pOutputFile
)
317 mnClearCode
= 1 << mnDataSize
;
318 mnEOICode
= mnClearCode
+ 1;
319 mnTableSize
= mnEOICode
+ 1;
320 mnCodeSize
= mnDataSize
+ 1;
322 mnOffset
= 32; // free bits in dwShift
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
;
337 WriteBits( mnClearCode
, mnCodeSize
);
340 LZWEncoder::~LZWEncoder()
343 WriteBits (mpPrefix
->mnCode
, mnCodeSize
);
345 WriteBits (mnEOICode
, mnCodeSize
);
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));
361 if (nCode
== 257 && mnOffset
!= 32)
362 WriteAscii ((sal_uInt8
)(mdwShift
>> 24));
366 LZWEncoder::EncodeByte (sal_uInt8 nByte
)
374 mpPrefix
= mpTable
+ nByte
;
379 for (p
= mpPrefix
->mpFirstChild
; p
!= NULL
; p
= p
->mpBrother
)
381 if (p
->mnValue
== nV
)
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;
405 if(mnTableSize
== (sal_uInt16
)((1 << mnCodeSize
) - 1))
408 p
= mpTable
+ (mnTableSize
++);
409 p
->mpBrother
= mpPrefix
->mpFirstChild
;
410 mpPrefix
->mpFirstChild
= p
;
412 p
->mpFirstChild
= NULL
;
415 mpPrefix
= mpTable
+ nV
;
422 * bitmap handling routines
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();
434 PSTranslate (rDest
.BottomLeft());
435 PSScale (fScaleX
, fScaleY
);
439 if (rBitmap
.GetDepth() == 1)
441 DrawPS2MonoImage (rBitmap
, rSrc
);
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
);
454 DrawPS2PaletteImage (rBitmap
, rSrc
);
457 if (rBitmap
.GetDepth() == 24 && mbColor
)
459 DrawPS2TrueColorImage (rBitmap
, rSrc
);
463 DrawPS2GrayImage (rBitmap
, rSrc
);
468 DrawPS1GrayImage (rBitmap
, rSrc
);
474 /* XXX does not work XXX */
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();
483 PSTranslate (rDest
.BottomLeft());
484 PSScale (fScaleX
, fScaleY
);
488 /* XXX does not work XXX */
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();
497 PSTranslate (rDest
.BottomLeft());
498 PSScale (fScaleX
, fScaleY
);
504 * Implementation: PS Level 1
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];
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
);
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
);
546 WritePS (mpPageBody
, "\n");
551 * Implementation: PS Level 2
556 PrinterGfx::writePS2ImageHeader (const Rectangle
& rArea
, psp::ImageType nType
)
559 sal_Char pImage
[512];
561 sal_Int32 nDictType
= 0;
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;
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
);
585 PrinterGfx::writePS2Colorspace(const PrinterBmp
& rBitmap
, psp::ImageType nType
)
589 case psp::GrayScaleImage
:
591 WritePS (mpPageBody
, "/DeviceGray setcolorspace\n");
594 case psp::TrueColorImage
:
596 WritePS (mpPageBody
, "/DeviceRGB setcolorspace\n");
599 case psp::MonochromeImage
:
600 case psp::PaletteImage
:
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
);
611 nChar
+= psp::appendStr ("\npsp_lzwstring\n", pImage
+ nChar
);
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());
628 WritePS (mpPageBody
, "pop ] setcolorspace\n");
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
);
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
++)
671 for (long nColumn
= rArea
.Left(); nColumn
<= rArea
.Right(); nColumn
++)
673 nBit
= rBitmap
.GetPixelIdx (nRow
, nColumn
);
674 nByte
|= nBit
<< (7 - nBitPos
);
678 pEncoder
->EncodeByte (nByte
);
683 // keep the row byte aligned
685 pEncoder
->EncodeByte (nByte
);
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
);
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());
735 } /* namespace psp */