1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_filter.hxx"
26
27 #include <vcl/graph.hxx>
28 #include <vcl/bmpacc.hxx>
29 #include <svtools/fltcall.hxx>
30
31 //============================ PCXReader ==================================
32
33 class PCXReader {
34
35 private:
36
37 SvStream* pPCX; // Die einzulesende PCX-Datei
38
39 Bitmap aBmp;
40 BitmapWriteAccess* pAcc;
41 sal_uInt8 nVersion; // PCX-Version
42 sal_uInt8 nEncoding; // Art der Komprimierung
43 sal_uLong nBitsPerPlanePix; // Bits Pro Ebene pro Pixel
44 sal_uLong nPlanes; // Anzahl Ebenen
45 sal_uLong nBytesPerPlaneLin; // Bytes in einer Ebenen pro Zeile
46 sal_uInt16 nPaletteInfo;
47
48 sal_uLong nWidth, nHeight; // Bildausmass in Pixeln
49 sal_uInt16 nResX, nResY; // Aufloesung in Pixel pro Inch oder 0,0
50 sal_uInt16 nDestBitsPerPixel; // Bits pro Pixel der Zielbitmap 1,4,8 oder 24
51 sal_uInt8* pPalette; //
52 sal_Bool nStatus; // status nun nicht mehr am stream abfragen ( SJ )
53
54
55 sal_Bool Callback( sal_uInt16 nPercent );
56 void ImplReadBody();
57 void ImplReadPalette( sal_uLong nCol );
58 void ImplReadHeader();
59
60 public:
61 PCXReader();
62 ~PCXReader();
63 sal_Bool ReadPCX( SvStream & rPCX, Graphic & rGraphic );
64 // Liesst aus dem Stream eine PCX-Datei und fuellt das GDIMetaFile
65 };
66
67 //=================== Methoden von PCXReader ==============================
68
PCXReader()69 PCXReader::PCXReader() :
70 pAcc ( NULL )
71 {
72 pPalette = new sal_uInt8[ 768 ];
73 }
74
~PCXReader()75 PCXReader::~PCXReader()
76 {
77 delete[] pPalette;
78 }
79
Callback(sal_uInt16)80 sal_Bool PCXReader::Callback( sal_uInt16 /*nPercent*/ )
81 {
82 /*
83 if (pCallback!=NULL) {
84 if (((*pCallback)(pCallerData,nPercent))==sal_True) {
85 nStatus = sal_False;
86 return sal_True;
87 }
88 }
89 */
90 return sal_False;
91 }
92
ReadPCX(SvStream & rPCX,Graphic & rGraphic)93 sal_Bool PCXReader::ReadPCX( SvStream & rPCX, Graphic & rGraphic )
94 {
95 if ( rPCX.GetError() )
96 return sal_False;
97
98 sal_uLong* pDummy = new sal_uLong; delete pDummy; // damit unter OS/2
99 // das richtige (Tools-)new
100 // verwendet wird, da es sonst
101 // in dieser DLL nur Vector-news
102 // gibt;
103
104 pPCX = &rPCX;
105 pPCX->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN);
106
107 // Kopf einlesen:
108
109 nStatus = sal_True;
110
111 ImplReadHeader();
112
113 // BMP-Header und ggf. (eventuell zunaechst ungueltige) Farbpalette schreiben:
114 if ( nStatus )
115 {
116 aBmp = Bitmap( Size( nWidth, nHeight ), nDestBitsPerPixel );
117 pAcc = aBmp.AcquireWriteAccess();
118 if ( !pAcc )
119 return sal_False;
120
121 if ( nDestBitsPerPixel <= 8 )
122 {
123 sal_uInt16 nColors = 1 << nDestBitsPerPixel;
124 sal_uInt8* pPal = pPalette;
125 pAcc->SetPaletteEntryCount( nColors );
126 for ( sal_uInt16 i = 0; i < nColors; i++, pPal += 3 )
127 {
128 pAcc->SetPaletteColor( i, BitmapColor ( pPal[ 0 ], pPal[ 1 ], pPal[ 2 ] ) );
129 }
130 }
131 // Bitmap-Daten einlesen
132 ImplReadBody();
133
134 // Wenn erweiterte Farbpalette am Ende von PCX, dann diese einlesen, und nochmals
135 // in Palette schreiben:
136 if ( nDestBitsPerPixel == 8 && nStatus )
137 {
138 sal_uInt8* pPal = pPalette;
139 pPCX->SeekRel(1);
140 ImplReadPalette(256);
141 pAcc->SetPaletteEntryCount( 256 );
142 for ( sal_uInt16 i = 0; i < 256; i++, pPal += 3 )
143 {
144 pAcc->SetPaletteColor( i, BitmapColor ( pPal[ 0 ], pPal[ 1 ], pPal[ 2 ] ) );
145 }
146 }
147 /*
148 // Aufloesung einstellen:
149 if (nResX!=0 && nResY!=0) {
150 MapMode aMapMode(MAP_INCH,Point(0,0),Fraction(1,nResX),Fraction(1,nResY));
151 rBitmap.SetPrefMapMode(aMapMode);
152 rBitmap.SetPrefSize(Size(nWidth,nHeight));
153 }
154 */ if ( nStatus && pAcc )
155 {
156 aBmp.ReleaseAccess( pAcc ), pAcc = NULL;
157 rGraphic = aBmp;
158 return sal_True;
159 }
160 }
161 return sal_False;
162 }
163
ImplReadHeader()164 void PCXReader::ImplReadHeader()
165 {
166 sal_uInt8 nbyte;
167 sal_uInt16 nushort;
168 sal_uInt16 nMinX,nMinY,nMaxX,nMaxY;
169
170 *pPCX >> nbyte >> nVersion >> nEncoding;
171 if ( nbyte!=0x0a || (nVersion != 0 && nVersion != 2 && nVersion != 3 && nVersion != 5) || nEncoding > 1 )
172 {
173 nStatus = sal_False;
174 return;
175 }
176
177 *pPCX >> nbyte; nBitsPerPlanePix = (sal_uLong)nbyte;
178 *pPCX >> nMinX >> nMinY >> nMaxX >> nMaxY;
179
180 if ((nMinX > nMaxX) || (nMinY > nMaxY))
181 {
182 nStatus = sal_False;
183 return;
184 }
185
186 nWidth = nMaxX-nMinX+1;
187 nHeight = nMaxY-nMinY+1;
188
189 *pPCX >> nResX;
190 *pPCX >> nResY;
191 if ( nResX >= nWidth || nResY >= nHeight || ( nResX != nResY ) )
192 nResX = nResY = 0;
193
194 ImplReadPalette( 16 );
195
196 pPCX->SeekRel( 1 );
197 *pPCX >> nbyte; nPlanes = (sal_uLong)nbyte;
198 *pPCX >> nushort; nBytesPerPlaneLin = (sal_uLong)nushort;
199 *pPCX >> nPaletteInfo;
200
201 pPCX->SeekRel( 58 );
202
203 nDestBitsPerPixel = (sal_uInt16)( nBitsPerPlanePix * nPlanes );
204 if (nDestBitsPerPixel == 2 || nDestBitsPerPixel == 3) nDestBitsPerPixel = 4;
205
206 if ( ( nDestBitsPerPixel != 1 && nDestBitsPerPixel != 4 && nDestBitsPerPixel != 8 && nDestBitsPerPixel != 24 )
207 || nPlanes > 4 || nBytesPerPlaneLin < ( ( nWidth * nBitsPerPlanePix+7 ) >> 3 ) )
208 {
209 nStatus = sal_False;
210 return;
211 }
212
213 // Wenn das Bild nur 2 Farben hat, ist die Palette zumeist ungueltig, und es handelt sich
214 // immer (?) um ein schwarz-weiss-Bild:
215 if ( nPlanes == 1 && nBitsPerPlanePix == 1 )
216 {
217 pPalette[ 0 ] = pPalette[ 1 ] = pPalette[ 2 ] = 0x00;
218 pPalette[ 3 ] = pPalette[ 4 ] = pPalette[ 5 ] = 0xff;
219 }
220 }
221
ImplReadBody()222 void PCXReader::ImplReadBody()
223 {
224 sal_uInt8 *pPlane[ 4 ], * pDest, * pSource1, * pSource2, * pSource3, *pSource4;
225 sal_uLong i, nx, ny, np, nCount, nUsedLineSize, nLineSize, nPercent;
226 sal_uLong nLastPercent = 0;
227 sal_uInt8 nDat = 0, nCol = 0;
228
229 nUsedLineSize = (sal_uLong)( ( ( nWidth * (sal_uLong)nDestBitsPerPixel ) + 7 ) >> 3 );
230 nLineSize = ( nUsedLineSize + 3 ) & 0xfffc;
231
232 for( np = 0; np < nPlanes; np++ )
233 pPlane[ np ] = new sal_uInt8[ nBytesPerPlaneLin ];
234
235 nCount = 0;
236 for ( ny = 0; ny < nHeight; ny++ )
237 {
238 if (pPCX->GetError() || pPCX->IsEof())
239 {
240 nStatus = sal_False;
241 break;
242 }
243 nPercent = ny * 60 / nHeight + 10;
244 if ( ny == 0 || nLastPercent + 4 <= nPercent )
245 {
246 nLastPercent = nPercent;
247 if ( Callback( (sal_uInt16)nPercent ) == sal_True )
248 break;
249 }
250 for ( np = 0; np < nPlanes; np++)
251 {
252 if ( nEncoding == 0)
253 pPCX->Read( (void *)pPlane[ np ], nBytesPerPlaneLin );
254 else
255 {
256 pDest = pPlane[ np ];
257 nx = nBytesPerPlaneLin;
258 while ( nCount > 0 && nx > 0)
259 {
260 *(pDest++) = nDat;
261 nx--;
262 nCount--;
263 }
264 while ( nx > 0 )
265 {
266 *pPCX >> nDat;
267 if ( ( nDat & 0xc0 ) == 0xc0 )
268 {
269 nCount =( (sal_uLong)nDat ) & 0x003f;
270 *pPCX >> nDat;
271 if ( nCount < nx )
272 {
273 nx -= nCount;
274 while ( nCount > 0)
275 {
276 *(pDest++) = nDat;
277 nCount--;
278 }
279 }
280 else
281 {
282 nCount -= nx;
283 do
284 {
285 *(pDest++) = nDat;
286 nx--;
287 }
288 while ( nx > 0 );
289 break;
290 }
291 }
292 else
293 {
294 *(pDest++) = nDat;
295 nx--;
296 }
297 }
298 }
299 }
300 pSource1 = pPlane[ 0 ];
301 pSource2 = pPlane[ 1 ];
302 pSource3 = pPlane[ 2 ];
303 pSource4 = pPlane[ 3 ];
304 switch ( nBitsPerPlanePix + ( nPlanes << 8 ) )
305 {
306 // 2 colors
307 case 0x101 :
308 for ( i = 0; i < nWidth; i++ )
309 {
310 sal_uLong nShift = ( i & 7 ) ^ 7;
311 if ( nShift == 0 )
312 pAcc->SetPixelIndex( ny, i, *(pSource1++) & 1 );
313 else
314 pAcc->SetPixelIndex( ny, i, (*pSource1 >> nShift ) & 1 );
315 }
316 break;
317 // 4 colors
318 case 0x102 :
319 for ( i = 0; i < nWidth; i++ )
320 {
321 switch( i & 3 )
322 {
323 case 0 :
324 nCol = *pSource1 >> 6;
325 break;
326 case 1 :
327 nCol = ( *pSource1 >> 4 ) & 0x03 ;
328 break;
329 case 2 :
330 nCol = ( *pSource1 >> 2 ) & 0x03;
331 break;
332 case 3 :
333 nCol = ( *pSource1++ ) & 0x03;
334 break;
335 }
336 pAcc->SetPixelIndex( ny, i, nCol );
337 }
338 break;
339 // 256 colors
340 case 0x108 :
341 for ( i = 0; i < nWidth; i++ )
342 {
343 pAcc->SetPixelIndex( ny, i, *pSource1++ );
344 }
345 break;
346 // 8 colors
347 case 0x301 :
348 for ( i = 0; i < nWidth; i++ )
349 {
350 sal_uLong nShift = ( i & 7 ) ^ 7;
351 if ( nShift == 0 )
352 {
353 nCol = ( *pSource1++ & 1) + ( ( *pSource2++ << 1 ) & 2 ) + ( ( *pSource3++ << 2 ) & 4 );
354 pAcc->SetPixelIndex( ny, i, nCol );
355 }
356 else
357 {
358 nCol = sal::static_int_cast< sal_uInt8 >(
359 ( ( *pSource1 >> nShift ) & 1) + ( ( ( *pSource2 >> nShift ) << 1 ) & 2 ) +
360 ( ( ( *pSource3 >> nShift ) << 2 ) & 4 ));
361 pAcc->SetPixelIndex( ny, i, nCol );
362 }
363 }
364 break;
365 // 16 colors
366 case 0x401 :
367 for ( i = 0; i < nWidth; i++ )
368 {
369 sal_uLong nShift = ( i & 7 ) ^ 7;
370 if ( nShift == 0 )
371 {
372 nCol = ( *pSource1++ & 1) + ( ( *pSource2++ << 1 ) & 2 ) + ( ( *pSource3++ << 2 ) & 4 ) +
373 ( ( *pSource4++ << 3 ) & 8 );
374 pAcc->SetPixelIndex( ny, i, nCol );
375 }
376 else
377 {
378 nCol = sal::static_int_cast< sal_uInt8 >(
379 ( ( *pSource1 >> nShift ) & 1) + ( ( ( *pSource2 >> nShift ) << 1 ) & 2 ) +
380 ( ( ( *pSource3 >> nShift ) << 2 ) & 4 ) + ( ( ( *pSource4 >> nShift ) << 3 ) & 8 ));
381 pAcc->SetPixelIndex( ny, i, nCol );
382 }
383 }
384 break;
385 // 16m colors
386 case 0x308 :
387 for ( i = 0; i < nWidth; i++ )
388 {
389 pAcc->SetPixel( ny, i, Color( *pSource1++, *pSource2++, *pSource3++ ) );
390
391 }
392 break;
393 default :
394 nStatus = sal_False;
395 break;
396 }
397 }
398 for ( np = 0; np < nPlanes; np++ )
399 delete[] pPlane[ np ];
400 }
401
ImplReadPalette(sal_uLong nCol)402 void PCXReader::ImplReadPalette( sal_uLong nCol )
403 {
404 sal_uInt8 r, g, b;
405 sal_uInt8* pPtr = pPalette;
406 for ( sal_uLong i = 0; i < nCol; i++ )
407 {
408 *pPCX >> r >> g >> b;
409 *pPtr++ = r;
410 *pPtr++ = g;
411 *pPtr++ = b;
412 }
413 }
414
415 //================== GraphicImport - die exportierte Funktion ================
416
GraphicImport(SvStream & rStream,Graphic & rGraphic,FilterConfigItem *,sal_Bool)417 extern "C" sal_Bool __LOADONCALLAPI GraphicImport(SvStream & rStream, Graphic & rGraphic, FilterConfigItem*, sal_Bool )
418 {
419 PCXReader aPCXReader;
420 sal_Bool nRetValue = aPCXReader.ReadPCX( rStream, rGraphic );
421 if ( nRetValue == sal_False )
422 rStream.SetError( SVSTREAM_FILEFORMAT_ERROR );
423 return nRetValue;
424 }
425
426