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