xref: /AOO41X/main/filter/source/graphicfilter/ipcx/ipcx.cxx (revision 0af288bd36294aa09e93d369656aab1681e705d2)
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