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 .
22 #include <vcl/graph.hxx>
23 #include <vcl/BitmapTools.hxx>
24 #include <tools/stream.hxx>
25 #include <filter/PcxReader.hxx>
27 class FilterConfigItem
;
29 //============================ PCXReader ==================================
37 SvStream
& m_rPCX
; // the PCX file to read
39 std::unique_ptr
<vcl::bitmap::RawBitmap
> mpBitmap
;
40 std::vector
<Color
> mvPalette
;
41 sal_uInt8 nVersion
; // PCX-Version
42 sal_uInt8 nEncoding
; // compression type
43 sal_uInt16 nBitsPerPlanePix
; // bits per plane per pixel
44 sal_uInt16 nPlanes
; // no of planes
45 sal_uInt16 nBytesPerPlaneLin
; // bytes per plane line
47 sal_uInt32 nWidth
, nHeight
; // dimension in pixel
48 sal_uInt16 nResX
, nResY
; // resolution in pixel per inch or 0,0
49 sal_uInt16 nDestBitsPerPixel
; // bits per pixel in destination bitmap 1,4,8 or 24
50 std::unique_ptr
<sal_uInt8
[]>
52 bool bStatus
; // from now on do not read status from stream ( SJ )
56 void ImplReadPalette( unsigned int nCol
);
57 void ImplReadHeader();
60 explicit PCXReader(SvStream
&rStream
);
61 bool ReadPCX(Graphic
& rGraphic
);
62 // Reads a PCX file from the stream and fills the GDIMetaFile
67 //=================== methods of PCXReader ==============================
69 PCXReader::PCXReader(SvStream
&rStream
)
75 , nBytesPerPlaneLin(0)
80 , nDestBitsPerPixel(0)
81 , pPalette(new sal_uInt8
[ 768 ])
86 bool PCXReader::ReadPCX(Graphic
& rGraphic
)
88 if ( m_rPCX
.GetError() )
91 m_rPCX
.SetEndian(SvStreamEndian::LITTLE
);
99 // sanity check there is enough data before trying allocation
100 if (bStatus
&& nBytesPerPlaneLin
> m_rPCX
.remainingSize() / nPlanes
)
108 bStatus
= !o3tl::checked_multiply(nWidth
, nHeight
, nResult
) && nResult
<= SAL_MAX_INT32
/2/3;
111 // Write BMP header and conditionally (maybe invalid for now) color palette:
114 mpBitmap
.reset( new vcl::bitmap::RawBitmap( Size( nWidth
, nHeight
), 24 ) );
116 if ( nDestBitsPerPixel
<= 8 )
118 sal_uInt16 nColors
= 1 << nDestBitsPerPixel
;
119 sal_uInt8
* pPal
= pPalette
.get();
120 mvPalette
.resize( nColors
);
121 for ( sal_uInt16 i
= 0; i
< nColors
; i
++, pPal
+= 3 )
123 mvPalette
[i
] = Color( pPal
[ 0 ], pPal
[ 1 ], pPal
[ 2 ] );
130 // If an extended color palette exists at the end of the file, then read it and
131 // and write again in palette:
132 if ( nDestBitsPerPixel
== 8 && bStatus
)
134 sal_uInt8
* pPal
= pPalette
.get();
136 ImplReadPalette(256);
137 mvPalette
.resize( 256 );
138 for ( sal_uInt16 i
= 0; i
< 256; i
++, pPal
+= 3 )
140 mvPalette
[i
] = Color( pPal
[ 0 ], pPal
[ 1 ], pPal
[ 2 ] );
146 rGraphic
= vcl::bitmap::CreateFromData(std::move(*mpBitmap
));
153 void PCXReader::ImplReadHeader()
156 m_rPCX
.ReadUChar( nbyte
).ReadUChar( nVersion
).ReadUChar( nEncoding
);
157 if ( nbyte
!=0x0a || (nVersion
!= 0 && nVersion
!= 2 && nVersion
!= 3 && nVersion
!= 5) || nEncoding
> 1 )
164 m_rPCX
.ReadUChar( nbyte
); nBitsPerPlanePix
= static_cast<sal_uInt16
>(nbyte
);
165 sal_uInt16
nMinX(0),nMinY(0),nMaxX(0),nMaxY(0);
166 m_rPCX
.ReadUInt16( nMinX
).ReadUInt16( nMinY
).ReadUInt16( nMaxX
).ReadUInt16( nMaxY
);
168 if ((nMinX
> nMaxX
) || (nMinY
> nMaxY
))
174 nWidth
= nMaxX
-nMinX
+1;
175 nHeight
= nMaxY
-nMinY
+1;
177 m_rPCX
.ReadUInt16( nResX
);
178 m_rPCX
.ReadUInt16( nResY
);
179 if ( nResX
>= nWidth
|| nResY
>= nHeight
|| ( nResX
!= nResY
) )
182 ImplReadPalette( 16 );
186 m_rPCX
.ReadUChar( nbyte
); nPlanes
= static_cast<sal_uInt16
>(nbyte
);
187 sal_uInt16
nushort(0);
188 m_rPCX
.ReadUInt16( nushort
); nBytesPerPlaneLin
= nushort
;
189 sal_uInt16 nPaletteInfo
;
190 m_rPCX
.ReadUInt16( nPaletteInfo
);
192 m_rPCX
.SeekRel( 58 );
194 nDestBitsPerPixel
= nBitsPerPlanePix
* nPlanes
;
195 if (nDestBitsPerPixel
== 2 || nDestBitsPerPixel
== 3) nDestBitsPerPixel
= 4;
197 if ( ( nDestBitsPerPixel
!= 1 && nDestBitsPerPixel
!= 4 && nDestBitsPerPixel
!= 8 && nDestBitsPerPixel
!= 24 )
198 || nPlanes
> 4 || nBytesPerPlaneLin
< ( ( nWidth
* nBitsPerPlanePix
+7 ) >> 3 ) )
204 // If the bitmap has only 2 colors, the palette is most often invalid and it is always(?)
205 // a black and white image:
206 if ( nPlanes
== 1 && nBitsPerPlanePix
== 1 )
208 pPalette
[ 0 ] = pPalette
[ 1 ] = pPalette
[ 2 ] = 0x00;
209 pPalette
[ 3 ] = pPalette
[ 4 ] = pPalette
[ 5 ] = 0xff;
213 void PCXReader::ImplReadBody()
215 std::unique_ptr
<sal_uInt8
[]> pPlane
[ 4 ];
217 sal_uInt32 i
, ny
, nLastPercent
= 0, nPercent
;
218 sal_uInt16 nCount
, nx
;
219 sal_uInt8 nDat
= 0, nCol
= 0;
221 for (sal_uInt16 np
= 0; np
< nPlanes
; ++np
)
222 pPlane
[np
].reset(new sal_uInt8
[nBytesPerPlaneLin
]());
225 for ( ny
= 0; ny
< nHeight
; ny
++ )
232 nPercent
= ny
* 60 / nHeight
+ 10;
233 if ( ny
== 0 || nLastPercent
+ 4 <= nPercent
)
235 nLastPercent
= nPercent
;
237 for (sal_uInt16 np
= 0; np
< nPlanes
; ++np
)
240 m_rPCX
.ReadBytes( static_cast<void *>(pPlane
[ np
].get()), nBytesPerPlaneLin
);
243 pDest
= pPlane
[ np
].get();
244 nx
= nBytesPerPlaneLin
;
245 while ( nCount
> 0 && nx
> 0)
251 while (nx
> 0 && m_rPCX
.good())
253 m_rPCX
.ReadUChar( nDat
);
254 if ( ( nDat
& 0xc0 ) == 0xc0 )
256 nCount
=static_cast<sal_uInt64
>(nDat
) & 0x003f;
257 m_rPCX
.ReadUChar( nDat
);
287 sal_uInt8
*pSource1
= pPlane
[ 0 ].get();
288 sal_uInt8
*pSource2
= pPlane
[ 1 ].get();
289 sal_uInt8
*pSource3
= pPlane
[ 2 ].get();
290 sal_uInt8
*pSource4
= pPlane
[ 3 ].get();
291 switch ( nBitsPerPlanePix
+ ( nPlanes
<< 8 ) )
295 for ( i
= 0; i
< nWidth
; i
++ )
297 sal_uInt32 nShift
= ( i
& 7 ) ^ 7;
299 mpBitmap
->SetPixel( ny
, i
, mvPalette
[*(pSource1
++) & 1] );
301 mpBitmap
->SetPixel( ny
, i
, mvPalette
[(*pSource1
>> nShift
) & 1] );
306 for ( i
= 0; i
< nWidth
; i
++ )
311 nCol
= *pSource1
>> 6;
314 nCol
= ( *pSource1
>> 4 ) & 0x03 ;
317 nCol
= ( *pSource1
>> 2 ) & 0x03;
320 nCol
= ( *pSource1
++ ) & 0x03;
323 mpBitmap
->SetPixel( ny
, i
, mvPalette
[nCol
] );
328 for ( i
= 0; i
< nWidth
; i
++ )
330 mpBitmap
->SetPixel( ny
, i
, mvPalette
[*pSource1
++] );
335 for ( i
= 0; i
< nWidth
; i
++ )
337 sal_uInt32 nShift
= ( i
& 7 ) ^ 7;
340 nCol
= ( *pSource1
++ & 1) + ( ( *pSource2
++ << 1 ) & 2 ) + ( ( *pSource3
++ << 2 ) & 4 );
341 mpBitmap
->SetPixel( ny
, i
, mvPalette
[nCol
] );
345 nCol
= sal::static_int_cast
< sal_uInt8
>(
346 ( ( *pSource1
>> nShift
) & 1) + ( ( ( *pSource2
>> nShift
) << 1 ) & 2 ) +
347 ( ( ( *pSource3
>> nShift
) << 2 ) & 4 ));
348 mpBitmap
->SetPixel( ny
, i
, mvPalette
[nCol
] );
354 for ( i
= 0; i
< nWidth
; i
++ )
356 sal_uInt32 nShift
= ( i
& 7 ) ^ 7;
359 nCol
= ( *pSource1
++ & 1) + ( ( *pSource2
++ << 1 ) & 2 ) + ( ( *pSource3
++ << 2 ) & 4 ) +
360 ( ( *pSource4
++ << 3 ) & 8 );
361 mpBitmap
->SetPixel( ny
, i
, mvPalette
[nCol
] );
365 nCol
= sal::static_int_cast
< sal_uInt8
>(
366 ( ( *pSource1
>> nShift
) & 1) + ( ( ( *pSource2
>> nShift
) << 1 ) & 2 ) +
367 ( ( ( *pSource3
>> nShift
) << 2 ) & 4 ) + ( ( ( *pSource4
>> nShift
) << 3 ) & 8 ));
368 mpBitmap
->SetPixel( ny
, i
, mvPalette
[nCol
] );
374 for ( i
= 0; i
< nWidth
; i
++ )
376 mpBitmap
->SetPixel( ny
, i
, Color( *pSource1
++, *pSource2
++, *pSource3
++ ) );
387 void PCXReader::ImplReadPalette( unsigned int nCol
)
390 sal_uInt8
* pPtr
= pPalette
.get();
391 for ( unsigned int i
= 0; i
< nCol
; i
++ )
393 m_rPCX
.ReadUChar( r
).ReadUChar( g
).ReadUChar( b
);
400 //================== GraphicImport - the exported function ================
402 bool ImportPcxGraphic(SvStream
& rStream
, Graphic
& rGraphic
)
404 PCXReader
aPCXReader(rStream
);
405 bool bRetValue
= aPCXReader
.ReadPCX(rGraphic
);
407 rStream
.SetError( SVSTREAM_FILEFORMAT_ERROR
);
411 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */