| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_filter.hxx" |
| |
| #include <vcl/graph.hxx> |
| #include <vcl/bmpacc.hxx> |
| #include <svtools/fltcall.hxx> |
| |
| //============================ PCXReader ================================== |
| |
| class PCXReader { |
| |
| private: |
| |
| SvStream* pPCX; // Die einzulesende PCX-Datei |
| |
| Bitmap aBmp; |
| BitmapWriteAccess* pAcc; |
| sal_uInt8 nVersion; // PCX-Version |
| sal_uInt8 nEncoding; // Art der Komprimierung |
| sal_uLong nBitsPerPlanePix; // Bits Pro Ebene pro Pixel |
| sal_uLong nPlanes; // Anzahl Ebenen |
| sal_uLong nBytesPerPlaneLin; // Bytes in einer Ebenen pro Zeile |
| sal_uInt16 nPaletteInfo; |
| |
| sal_uLong nWidth, nHeight; // Bildausmass in Pixeln |
| sal_uInt16 nResX, nResY; // Aufloesung in Pixel pro Inch oder 0,0 |
| sal_uInt16 nDestBitsPerPixel; // Bits pro Pixel der Zielbitmap 1,4,8 oder 24 |
| sal_uInt8* pPalette; // |
| sal_Bool nStatus; // status nun nicht mehr am stream abfragen ( SJ ) |
| |
| |
| sal_Bool Callback( sal_uInt16 nPercent ); |
| void ImplReadBody(); |
| void ImplReadPalette( sal_uLong nCol ); |
| void ImplReadHeader(); |
| |
| public: |
| PCXReader(); |
| ~PCXReader(); |
| sal_Bool ReadPCX( SvStream & rPCX, Graphic & rGraphic ); |
| // Liesst aus dem Stream eine PCX-Datei und fuellt das GDIMetaFile |
| }; |
| |
| //=================== Methoden von PCXReader ============================== |
| |
| PCXReader::PCXReader() : |
| pAcc ( NULL ) |
| { |
| pPalette = new sal_uInt8[ 768 ]; |
| } |
| |
| PCXReader::~PCXReader() |
| { |
| delete[] pPalette; |
| } |
| |
| sal_Bool PCXReader::Callback( sal_uInt16 /*nPercent*/ ) |
| { |
| /* |
| if (pCallback!=NULL) { |
| if (((*pCallback)(pCallerData,nPercent))==sal_True) { |
| nStatus = sal_False; |
| return sal_True; |
| } |
| } |
| */ |
| return sal_False; |
| } |
| |
| sal_Bool PCXReader::ReadPCX( SvStream & rPCX, Graphic & rGraphic ) |
| { |
| if ( rPCX.GetError() ) |
| return sal_False; |
| |
| sal_uLong* pDummy = new sal_uLong; delete pDummy; // damit unter OS/2 |
| // das richtige (Tools-)new |
| // verwendet wird, da es sonst |
| // in dieser DLL nur Vector-news |
| // gibt; |
| |
| pPCX = &rPCX; |
| pPCX->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN); |
| |
| // Kopf einlesen: |
| |
| nStatus = sal_True; |
| |
| ImplReadHeader(); |
| |
| // BMP-Header und ggf. (eventuell zunaechst ungueltige) Farbpalette schreiben: |
| if ( nStatus ) |
| { |
| aBmp = Bitmap( Size( nWidth, nHeight ), nDestBitsPerPixel ); |
| pAcc = aBmp.AcquireWriteAccess(); |
| if ( !pAcc ) |
| return sal_False; |
| |
| if ( nDestBitsPerPixel <= 8 ) |
| { |
| sal_uInt16 nColors = 1 << nDestBitsPerPixel; |
| sal_uInt8* pPal = pPalette; |
| pAcc->SetPaletteEntryCount( nColors ); |
| for ( sal_uInt16 i = 0; i < nColors; i++, pPal += 3 ) |
| { |
| pAcc->SetPaletteColor( i, BitmapColor ( pPal[ 0 ], pPal[ 1 ], pPal[ 2 ] ) ); |
| } |
| } |
| // Bitmap-Daten einlesen |
| ImplReadBody(); |
| |
| // Wenn erweiterte Farbpalette am Ende von PCX, dann diese einlesen, und nochmals |
| // in Palette schreiben: |
| if ( nDestBitsPerPixel == 8 && nStatus ) |
| { |
| sal_uInt8* pPal = pPalette; |
| pPCX->SeekRel(1); |
| ImplReadPalette(256); |
| pAcc->SetPaletteEntryCount( 256 ); |
| for ( sal_uInt16 i = 0; i < 256; i++, pPal += 3 ) |
| { |
| pAcc->SetPaletteColor( i, BitmapColor ( pPal[ 0 ], pPal[ 1 ], pPal[ 2 ] ) ); |
| } |
| } |
| /* |
| // Aufloesung einstellen: |
| if (nResX!=0 && nResY!=0) { |
| MapMode aMapMode(MAP_INCH,Point(0,0),Fraction(1,nResX),Fraction(1,nResY)); |
| rBitmap.SetPrefMapMode(aMapMode); |
| rBitmap.SetPrefSize(Size(nWidth,nHeight)); |
| } |
| */ if ( nStatus && pAcc ) |
| { |
| aBmp.ReleaseAccess( pAcc ), pAcc = NULL; |
| rGraphic = aBmp; |
| return sal_True; |
| } |
| } |
| return sal_False; |
| } |
| |
| void PCXReader::ImplReadHeader() |
| { |
| sal_uInt8 nbyte; |
| sal_uInt16 nushort; |
| sal_uInt16 nMinX,nMinY,nMaxX,nMaxY; |
| |
| *pPCX >> nbyte >> nVersion >> nEncoding; |
| if ( nbyte!=0x0a || (nVersion != 0 && nVersion != 2 && nVersion != 3 && nVersion != 5) || nEncoding > 1 ) |
| { |
| nStatus = sal_False; |
| return; |
| } |
| |
| *pPCX >> nbyte; nBitsPerPlanePix = (sal_uLong)nbyte; |
| *pPCX >> nMinX >> nMinY >> nMaxX >> nMaxY; |
| |
| if ((nMinX > nMaxX) || (nMinY > nMaxY)) |
| { |
| nStatus = sal_False; |
| return; |
| } |
| |
| nWidth = nMaxX-nMinX+1; |
| nHeight = nMaxY-nMinY+1; |
| |
| *pPCX >> nResX; |
| *pPCX >> nResY; |
| if ( nResX >= nWidth || nResY >= nHeight || ( nResX != nResY ) ) |
| nResX = nResY = 0; |
| |
| ImplReadPalette( 16 ); |
| |
| pPCX->SeekRel( 1 ); |
| *pPCX >> nbyte; nPlanes = (sal_uLong)nbyte; |
| *pPCX >> nushort; nBytesPerPlaneLin = (sal_uLong)nushort; |
| *pPCX >> nPaletteInfo; |
| |
| pPCX->SeekRel( 58 ); |
| |
| nDestBitsPerPixel = (sal_uInt16)( nBitsPerPlanePix * nPlanes ); |
| if (nDestBitsPerPixel == 2 || nDestBitsPerPixel == 3) nDestBitsPerPixel = 4; |
| |
| if ( ( nDestBitsPerPixel != 1 && nDestBitsPerPixel != 4 && nDestBitsPerPixel != 8 && nDestBitsPerPixel != 24 ) |
| || nPlanes > 4 || nBytesPerPlaneLin < ( ( nWidth * nBitsPerPlanePix+7 ) >> 3 ) ) |
| { |
| nStatus = sal_False; |
| return; |
| } |
| |
| // Wenn das Bild nur 2 Farben hat, ist die Palette zumeist ungueltig, und es handelt sich |
| // immer (?) um ein schwarz-weiss-Bild: |
| if ( nPlanes == 1 && nBitsPerPlanePix == 1 ) |
| { |
| pPalette[ 0 ] = pPalette[ 1 ] = pPalette[ 2 ] = 0x00; |
| pPalette[ 3 ] = pPalette[ 4 ] = pPalette[ 5 ] = 0xff; |
| } |
| } |
| |
| void PCXReader::ImplReadBody() |
| { |
| sal_uInt8 *pPlane[ 4 ], * pDest, * pSource1, * pSource2, * pSource3, *pSource4; |
| sal_uLong i, nx, ny, np, nCount, nUsedLineSize, nLineSize, nPercent; |
| sal_uLong nLastPercent = 0; |
| sal_uInt8 nDat = 0, nCol = 0; |
| |
| nUsedLineSize = (sal_uLong)( ( ( nWidth * (sal_uLong)nDestBitsPerPixel ) + 7 ) >> 3 ); |
| nLineSize = ( nUsedLineSize + 3 ) & 0xfffc; |
| |
| for( np = 0; np < nPlanes; np++ ) |
| pPlane[ np ] = new sal_uInt8[ nBytesPerPlaneLin ]; |
| |
| nCount = 0; |
| for ( ny = 0; ny < nHeight; ny++ ) |
| { |
| if (pPCX->GetError() || pPCX->IsEof()) |
| { |
| nStatus = sal_False; |
| break; |
| } |
| nPercent = ny * 60 / nHeight + 10; |
| if ( ny == 0 || nLastPercent + 4 <= nPercent ) |
| { |
| nLastPercent = nPercent; |
| if ( Callback( (sal_uInt16)nPercent ) == sal_True ) |
| break; |
| } |
| for ( np = 0; np < nPlanes; np++) |
| { |
| if ( nEncoding == 0) |
| pPCX->Read( (void *)pPlane[ np ], nBytesPerPlaneLin ); |
| else |
| { |
| pDest = pPlane[ np ]; |
| nx = nBytesPerPlaneLin; |
| while ( nCount > 0 && nx > 0) |
| { |
| *(pDest++) = nDat; |
| nx--; |
| nCount--; |
| } |
| while ( nx > 0 ) |
| { |
| *pPCX >> nDat; |
| if ( ( nDat & 0xc0 ) == 0xc0 ) |
| { |
| nCount =( (sal_uLong)nDat ) & 0x003f; |
| *pPCX >> nDat; |
| if ( nCount < nx ) |
| { |
| nx -= nCount; |
| while ( nCount > 0) |
| { |
| *(pDest++) = nDat; |
| nCount--; |
| } |
| } |
| else |
| { |
| nCount -= nx; |
| do |
| { |
| *(pDest++) = nDat; |
| nx--; |
| } |
| while ( nx > 0 ); |
| break; |
| } |
| } |
| else |
| { |
| *(pDest++) = nDat; |
| nx--; |
| } |
| } |
| } |
| } |
| pSource1 = pPlane[ 0 ]; |
| pSource2 = pPlane[ 1 ]; |
| pSource3 = pPlane[ 2 ]; |
| pSource4 = pPlane[ 3 ]; |
| switch ( nBitsPerPlanePix + ( nPlanes << 8 ) ) |
| { |
| // 2 colors |
| case 0x101 : |
| for ( i = 0; i < nWidth; i++ ) |
| { |
| sal_uLong nShift = ( i & 7 ) ^ 7; |
| if ( nShift == 0 ) |
| pAcc->SetPixelIndex( ny, i, *(pSource1++) & 1 ); |
| else |
| pAcc->SetPixelIndex( ny, i, (*pSource1 >> nShift ) & 1 ); |
| } |
| break; |
| // 4 colors |
| case 0x102 : |
| for ( i = 0; i < nWidth; i++ ) |
| { |
| switch( i & 3 ) |
| { |
| case 0 : |
| nCol = *pSource1 >> 6; |
| break; |
| case 1 : |
| nCol = ( *pSource1 >> 4 ) & 0x03 ; |
| break; |
| case 2 : |
| nCol = ( *pSource1 >> 2 ) & 0x03; |
| break; |
| case 3 : |
| nCol = ( *pSource1++ ) & 0x03; |
| break; |
| } |
| pAcc->SetPixelIndex( ny, i, nCol ); |
| } |
| break; |
| // 256 colors |
| case 0x108 : |
| for ( i = 0; i < nWidth; i++ ) |
| { |
| pAcc->SetPixelIndex( ny, i, *pSource1++ ); |
| } |
| break; |
| // 8 colors |
| case 0x301 : |
| for ( i = 0; i < nWidth; i++ ) |
| { |
| sal_uLong nShift = ( i & 7 ) ^ 7; |
| if ( nShift == 0 ) |
| { |
| nCol = ( *pSource1++ & 1) + ( ( *pSource2++ << 1 ) & 2 ) + ( ( *pSource3++ << 2 ) & 4 ); |
| pAcc->SetPixelIndex( ny, i, nCol ); |
| } |
| else |
| { |
| nCol = sal::static_int_cast< sal_uInt8 >( |
| ( ( *pSource1 >> nShift ) & 1) + ( ( ( *pSource2 >> nShift ) << 1 ) & 2 ) + |
| ( ( ( *pSource3 >> nShift ) << 2 ) & 4 )); |
| pAcc->SetPixelIndex( ny, i, nCol ); |
| } |
| } |
| break; |
| // 16 colors |
| case 0x401 : |
| for ( i = 0; i < nWidth; i++ ) |
| { |
| sal_uLong nShift = ( i & 7 ) ^ 7; |
| if ( nShift == 0 ) |
| { |
| nCol = ( *pSource1++ & 1) + ( ( *pSource2++ << 1 ) & 2 ) + ( ( *pSource3++ << 2 ) & 4 ) + |
| ( ( *pSource4++ << 3 ) & 8 ); |
| pAcc->SetPixelIndex( ny, i, nCol ); |
| } |
| else |
| { |
| nCol = sal::static_int_cast< sal_uInt8 >( |
| ( ( *pSource1 >> nShift ) & 1) + ( ( ( *pSource2 >> nShift ) << 1 ) & 2 ) + |
| ( ( ( *pSource3 >> nShift ) << 2 ) & 4 ) + ( ( ( *pSource4 >> nShift ) << 3 ) & 8 )); |
| pAcc->SetPixelIndex( ny, i, nCol ); |
| } |
| } |
| break; |
| // 16m colors |
| case 0x308 : |
| for ( i = 0; i < nWidth; i++ ) |
| { |
| pAcc->SetPixel( ny, i, Color( *pSource1++, *pSource2++, *pSource3++ ) ); |
| |
| } |
| break; |
| default : |
| nStatus = sal_False; |
| break; |
| } |
| } |
| for ( np = 0; np < nPlanes; np++ ) |
| delete[] pPlane[ np ]; |
| } |
| |
| void PCXReader::ImplReadPalette( sal_uLong nCol ) |
| { |
| sal_uInt8 r, g, b; |
| sal_uInt8* pPtr = pPalette; |
| for ( sal_uLong i = 0; i < nCol; i++ ) |
| { |
| *pPCX >> r >> g >> b; |
| *pPtr++ = r; |
| *pPtr++ = g; |
| *pPtr++ = b; |
| } |
| } |
| |
| //================== GraphicImport - die exportierte Funktion ================ |
| |
| extern "C" sal_Bool __LOADONCALLAPI GraphicImport(SvStream & rStream, Graphic & rGraphic, FilterConfigItem*, sal_Bool ) |
| { |
| PCXReader aPCXReader; |
| sal_Bool nRetValue = aPCXReader.ReadPCX( rStream, rGraphic ); |
| if ( nRetValue == sal_False ) |
| rStream.SetError( SVSTREAM_FILEFORMAT_ERROR ); |
| return nRetValue; |
| } |
| |