1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
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 */
48 virtual void EncodeByte (sal_uInt8 nByte
) = 0;
49 virtual ~ByteEncoder () = 0;
52 ByteEncoder::~ByteEncoder ()
53 { /* dont need this, but the C50 does */ }
57 class HexEncoder
: public ByteEncoder
64 sal_Char mpFileBuffer
[nBufferSize
+ 16];
66 HexEncoder (); /* dont use */
70 HexEncoder (osl::File
* pFile
);
71 virtual ~HexEncoder ();
72 void WriteAscii (sal_uInt8 nByte
);
73 virtual void EncodeByte (sal_uInt8 nByte
);
77 HexEncoder::HexEncoder (osl::File
* pFile
) :
83 HexEncoder::~HexEncoder ()
87 WritePS (mpFile
, "\n");
91 HexEncoder::WriteAscii (sal_uInt8 nByte
)
93 sal_uInt32 nOff
= psp::getHexValueOf (nByte
, mpFileBuffer
+ mnOffset
);
97 if (mnColumn
>= nLineLength
)
99 mnOffset
+= psp::appendStr ("\n", mpFileBuffer
+ mnOffset
);
102 if (mnOffset
>= nBufferSize
)
107 HexEncoder::EncodeByte (sal_uInt8 nByte
)
113 HexEncoder::FlushLine ()
117 WritePS (mpFile
, mpFileBuffer
, mnOffset
);
122 /* Ascii85 encoder, is abi compatible with HexEncoder but writes a ~> to
123 indicate end of data EOD */
125 class Ascii85Encoder
: public ByteEncoder
131 sal_uInt8 mpByteBuffer
[4];
135 sal_Char mpFileBuffer
[nBufferSize
+ 16];
137 Ascii85Encoder (); /* dont use */
139 inline void PutByte (sal_uInt8 nByte
);
140 inline void PutEOD ();
141 void ConvertToAscii85 ();
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
) :
160 Ascii85Encoder::PutByte (sal_uInt8 nByte
)
162 mpByteBuffer
[mnByte
++] = nByte
;
166 Ascii85Encoder::PutEOD ()
168 WritePS (mpFile
, "~>\n");
172 Ascii85Encoder::ConvertToAscii85 ()
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
182 if (nByteValue
== 0 && mnByte
== 4)
184 /* special case of 4 Bytes in row */
185 mpFileBuffer
[mnOffset
] = 'z';
192 /* real ascii85 encoding */
193 mpFileBuffer
[mnOffset
+ 4] = (nByteValue
% 85) + 33;
195 mpFileBuffer
[mnOffset
+ 3] = (nByteValue
% 85) + 33;
197 mpFileBuffer
[mnOffset
+ 2] = (nByteValue
% 85) + 33;
199 mpFileBuffer
[mnOffset
+ 1] = (nByteValue
% 85) + 33;
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';
224 Ascii85Encoder::WriteAscii (sal_uInt8 nByte
)
230 if (mnColumn
>= nLineLength
)
232 mnOffset
+= psp::appendStr ("\n", mpFileBuffer
+ mnOffset
);
235 if (mnOffset
>= nBufferSize
)
240 Ascii85Encoder::EncodeByte (sal_uInt8 nByte
)
246 Ascii85Encoder::FlushLine ()
250 WritePS (mpFile
, mpFileBuffer
, mnOffset
);
255 Ascii85Encoder::~Ascii85Encoder ()
266 class LZWEncoder
: public Ascii85Encoder
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
;
289 void WriteBits (sal_uInt16 nCode
, sal_uInt16 nCodeLen
);
293 LZWEncoder (osl::File
* pOutputFile
);
296 virtual void EncodeByte (sal_uInt8 nByte
);
299 LZWEncoder::LZWEncoder(osl::File
* pOutputFile
) :
300 Ascii85Encoder (pOutputFile
)
304 mnClearCode
= 1 << mnDataSize
;
305 mnEOICode
= mnClearCode
+ 1;
306 mnTableSize
= mnEOICode
+ 1;
307 mnCodeSize
= mnDataSize
+ 1;
309 mnOffset
= 32; // free bits in dwShift
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
;
324 WriteBits( mnClearCode
, mnCodeSize
);
327 LZWEncoder::~LZWEncoder()
330 WriteBits (mpPrefix
->mnCode
, mnCodeSize
);
332 WriteBits (mnEOICode
, mnCodeSize
);
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));
348 if (nCode
== 257 && mnOffset
!= 32)
349 WriteAscii ((sal_uInt8
)(mdwShift
>> 24));
353 LZWEncoder::EncodeByte (sal_uInt8 nByte
)
361 mpPrefix
= mpTable
+ nByte
;
366 for (p
= mpPrefix
->mpFirstChild
; p
!= NULL
; p
= p
->mpBrother
)
368 if (p
->mnValue
== nV
)
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;
392 if(mnTableSize
== (sal_uInt16
)((1 << mnCodeSize
) - 1))
395 p
= mpTable
+ (mnTableSize
++);
396 p
->mpBrother
= mpPrefix
->mpFirstChild
;
397 mpPrefix
->mpFirstChild
= p
;
399 p
->mpFirstChild
= NULL
;
402 mpPrefix
= mpTable
+ nV
;
409 * bitmap handling routines
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();
421 PSTranslate (rDest
.BottomLeft());
422 PSScale (fScaleX
, fScaleY
);
426 if (rBitmap
.GetDepth() == 1)
428 DrawPS2MonoImage (rBitmap
, rSrc
);
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
);
441 DrawPS2PaletteImage (rBitmap
, rSrc
);
444 if (rBitmap
.GetDepth() == 24 && mbColor
)
446 DrawPS2TrueColorImage (rBitmap
, rSrc
);
450 DrawPS2GrayImage (rBitmap
, rSrc
);
455 DrawPS1GrayImage (rBitmap
, rSrc
);
463 * Implementation: PS Level 1
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];
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
);
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
);
505 WritePS (mpPageBody
, "\n");
510 * Implementation: PS Level 2
515 PrinterGfx::writePS2ImageHeader (const Rectangle
& rArea
, psp::ImageType nType
)
518 sal_Char pImage
[512];
520 sal_Int32 nDictType
= 0;
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;
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
);
544 PrinterGfx::writePS2Colorspace(const PrinterBmp
& rBitmap
, psp::ImageType nType
)
548 case psp::GrayScaleImage
:
550 WritePS (mpPageBody
, "/DeviceGray setcolorspace\n");
553 case psp::TrueColorImage
:
555 WritePS (mpPageBody
, "/DeviceRGB setcolorspace\n");
558 case psp::MonochromeImage
:
559 case psp::PaletteImage
:
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
);
570 nChar
+= psp::appendStr ("\npsp_lzwstring\n", pImage
+ nChar
);
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());
587 WritePS (mpPageBody
, "pop ] setcolorspace\n");
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
);
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
++)
630 for (long nColumn
= rArea
.Left(); nColumn
<= rArea
.Right(); nColumn
++)
632 nBit
= rBitmap
.GetPixelIdx (nRow
, nColumn
);
633 nByte
|= nBit
<< (7 - nBitPos
);
637 pEncoder
->EncodeByte (nByte
);
642 // keep the row byte aligned
644 pEncoder
->EncodeByte (nByte
);
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
);
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());
694 } /* namespace psp */
696 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */