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