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 .
20 #include "psputil.hxx"
22 #include "generic/printergfx.hxx"
23 #include "vcl/strhelper.hxx"
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 */
48 virtual void EncodeByte (sal_uInt8 nByte
) = 0;
49 virtual ~ByteEncoder () = 0;
52 ByteEncoder::~ByteEncoder()
58 class HexEncoder
: public ByteEncoder
65 sal_Char mpFileBuffer
[nBufferSize
+ 16];
69 HexEncoder (osl::File
* pFile
);
70 virtual ~HexEncoder ();
71 void WriteAscii (sal_uInt8 nByte
);
72 virtual void EncodeByte (sal_uInt8 nByte
) SAL_OVERRIDE
;
76 HexEncoder::HexEncoder (osl::File
* pFile
) :
82 HexEncoder::~HexEncoder ()
86 WritePS (mpFile
, "\n");
90 HexEncoder::WriteAscii (sal_uInt8 nByte
)
92 sal_uInt32 nOff
= psp::getHexValueOf (nByte
, mpFileBuffer
+ mnOffset
);
96 if (mnColumn
>= nLineLength
)
98 mnOffset
+= psp::appendStr ("\n", mpFileBuffer
+ mnOffset
);
101 if (mnOffset
>= nBufferSize
)
106 HexEncoder::EncodeByte (sal_uInt8 nByte
)
112 HexEncoder::FlushLine ()
116 WritePS (mpFile
, mpFileBuffer
, mnOffset
);
121 /* Ascii85 encoder, is abi compatible with HexEncoder but writes a ~> to
122 indicate end of data EOD */
124 class Ascii85Encoder
: public ByteEncoder
130 sal_uInt8 mpByteBuffer
[4];
134 sal_Char mpFileBuffer
[nBufferSize
+ 16];
136 inline void PutByte (sal_uInt8 nByte
);
137 inline void PutEOD ();
138 void ConvertToAscii85 ();
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
) :
157 Ascii85Encoder::PutByte (sal_uInt8 nByte
)
159 mpByteBuffer
[mnByte
++] = nByte
;
163 Ascii85Encoder::PutEOD ()
165 WritePS (mpFile
, "~>\n");
169 Ascii85Encoder::ConvertToAscii85 ()
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
179 if (nByteValue
== 0 && mnByte
== 4)
181 /* special case of 4 Bytes in row */
182 mpFileBuffer
[mnOffset
] = 'z';
189 /* real ascii85 encoding */
190 mpFileBuffer
[mnOffset
+ 4] = (nByteValue
% 85) + 33;
192 mpFileBuffer
[mnOffset
+ 3] = (nByteValue
% 85) + 33;
194 mpFileBuffer
[mnOffset
+ 2] = (nByteValue
% 85) + 33;
196 mpFileBuffer
[mnOffset
+ 1] = (nByteValue
% 85) + 33;
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';
221 Ascii85Encoder::WriteAscii (sal_uInt8 nByte
)
227 if (mnColumn
>= nLineLength
)
229 mnOffset
+= psp::appendStr ("\n", mpFileBuffer
+ mnOffset
);
232 if (mnOffset
>= nBufferSize
)
237 Ascii85Encoder::EncodeByte (sal_uInt8 nByte
)
243 Ascii85Encoder::FlushLine ()
247 WritePS (mpFile
, mpFileBuffer
, mnOffset
);
252 Ascii85Encoder::~Ascii85Encoder ()
263 class LZWEncoder
: public Ascii85Encoder
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
;
285 void WriteBits (sal_uInt16 nCode
, sal_uInt16 nCodeLen
);
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
)
300 mnClearCode
= 1 << mnDataSize
;
301 mnEOICode
= mnClearCode
+ 1;
302 mnTableSize
= mnEOICode
+ 1;
303 mnCodeSize
= mnDataSize
+ 1;
305 mnOffset
= 32; // free bits in dwShift
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
;
320 WriteBits( mnClearCode
, mnCodeSize
);
323 LZWEncoder::~LZWEncoder()
326 WriteBits (mpPrefix
->mnCode
, mnCodeSize
);
328 WriteBits (mnEOICode
, mnCodeSize
);
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));
344 if (nCode
== 257 && mnOffset
!= 32)
345 WriteAscii ((sal_uInt8
)(mdwShift
>> 24));
349 LZWEncoder::EncodeByte (sal_uInt8 nByte
)
357 mpPrefix
= mpTable
+ nByte
;
362 for (p
= mpPrefix
->mpFirstChild
; p
!= NULL
; p
= p
->mpBrother
)
364 if (p
->mnValue
== nV
)
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;
388 if(mnTableSize
== (sal_uInt16
)((1 << mnCodeSize
) - 1))
391 p
= mpTable
+ (mnTableSize
++);
392 p
->mpBrother
= mpPrefix
->mpFirstChild
;
393 mpPrefix
->mpFirstChild
= p
;
395 p
->mpFirstChild
= NULL
;
398 mpPrefix
= mpTable
+ nV
;
405 * bitmap handling routines
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();
424 PSTranslate (rDest
.BottomLeft());
425 PSScale (fScaleX
, fScaleY
);
429 if (rBitmap
.GetDepth() == 1)
431 DrawPS2MonoImage (rBitmap
, rSrc
);
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
);
444 DrawPS2PaletteImage (rBitmap
, rSrc
);
447 if (rBitmap
.GetDepth() == 24 && mbColor
)
449 DrawPS2TrueColorImage (rBitmap
, rSrc
);
453 DrawPS2GrayImage (rBitmap
, rSrc
);
458 DrawPS1GrayImage (rBitmap
, rSrc
);
466 * Implementation: PS Level 1
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];
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
);
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
);
508 WritePS (mpPageBody
, "\n");
513 * Implementation: PS Level 2
518 PrinterGfx::writePS2ImageHeader (const Rectangle
& rArea
, psp::ImageType nType
)
521 sal_Char pImage
[512];
523 sal_Int32 nDictType
= 0;
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;
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
);
547 PrinterGfx::writePS2Colorspace(const PrinterBmp
& rBitmap
, psp::ImageType nType
)
551 case psp::GrayScaleImage
:
553 WritePS (mpPageBody
, "/DeviceGray setcolorspace\n");
556 case psp::TrueColorImage
:
558 WritePS (mpPageBody
, "/DeviceRGB setcolorspace\n");
561 case psp::MonochromeImage
:
562 case psp::PaletteImage
:
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
);
573 nChar
+= psp::appendStr ("\npsp_lzwstring\n", pImage
+ nChar
);
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());
590 WritePS (mpPageBody
, "pop ] setcolorspace\n");
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
);
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
++)
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
);
637 xEncoder
->EncodeByte (nByte
);
642 // keep the row byte aligned
644 xEncoder
->EncodeByte (nByte
);
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
);
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: */