/************************************************************** * * 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 #include #ifndef _SV_FLTCALL_HXX #include #endif #include #include "lzwdecom.hxx" #include "ccidecom.hxx" #define OOODEBUG(str,Num) //(InfoBox(NULL,String(str)+String(" ")+String(Num)).Execute(); namespace { template< typename T > T BYTESWAP(T nByte) { return ( nByte << 7 ) | ( ( nByte & 2 ) << 5 ) | ( ( nByte & 4 ) << 3 ) | ( ( nByte & 8 ) << 1 ) | ( ( nByte & 16 ) >> 1 ) | ( ( nByte & 32 ) >> 3 ) | ( ( nByte & 64 ) >> 5 ) | ( ( nByte & 128 ) >> 7 ); } } //============================ TIFFReader ================================== class TIFFReader { private: sal_Bool bStatus; // Ob bisher kein Fehler auftrat Animation aAnimation; sal_uLong nLastPercent; SvStream* pTIFF; // Die einzulesende TIFF-Datei Bitmap aBitmap; BitmapWriteAccess* pAcc; sal_uInt16 nDstBitsPerPixel; sal_uLong nOrigPos; // Anfaengliche Position in pTIFF sal_uInt16 nOrigNumberFormat; // Anfaengliches Nummern-Format von pTIFF sal_uInt16 nDataType; // Daten, die aus dem TIFF-Tags entnommen werden: sal_Bool bByteSwap; // sal_True wenn bits 0..7 -> 7..0 invertiert werden sollen ( FILLORDER = 2 ); sal_uInt8 nByte1; // 'I', wenn Format LittleEndian sal_uLong nNewSubFile; // sal_uLong nSubFile; // sal_uLong nImageWidth; // Bildbreite in Pixel sal_uLong nImageLength; // Bildhoehe in Pixel sal_uLong nBitsPerSample; // Bits pro Pixel pro Ebene sal_uLong nCompression; // Art der Kompriemierung sal_uLong nPhotometricInterpretation; // sal_uLong nThresholding; // sal_uLong nCellWidth; // sal_uLong nCellLength; // sal_uLong nFillOrder; // sal_uLong* pStripOffsets; // Feld von Offsets zu den Bitmap-Daten-"Strips" sal_uLong nNumStripOffsets; // Groesse obigen Feldes sal_uLong nOrientation; // sal_uLong nSamplesPerPixel; // Anzahl der Ebenen sal_uLong nRowsPerStrip; // Wenn nicht komprimiert: Zahl der Zeilen pro Strip sal_uLong* pStripByteCounts; // Wenn komprimiert (bestimmte Art): Groesse der Strips sal_uLong nNumStripByteCounts; // Anzahl der Eintraege in obiges Feld sal_uLong nMinSampleValue; // sal_uLong nMaxSampleValue; // double fXResolution; // X-Aufloesung oder 0.0 double fYResolution; // Y-Aufloesung oder 0.0 sal_uLong nPlanarConfiguration; // sal_uLong nGroup3Options; // sal_uLong nGroup4Options; // sal_uLong nResolutionUnit; // Einheit von fX/YResolution: 1=unbekannt, 2(default)=Zoll, 3=cm sal_uLong nPredictor; // sal_uLong* pColorMap; // Farb-Palette sal_uLong nNumColors; // Anzahl Farben in der Farbpalette sal_uLong nPlanes; // Anzahl der Ebenen in der Tiff-Datei sal_uLong nStripsPerPlane; // Anzahl der Strips pro Ebene sal_uLong nBytesPerRow; // Bytes pro Zeile pro Ebene in der Tiff-Datei ( unkomprimiert ) sal_uInt8* pMap[ 4 ]; // Temporaere Scanline void MayCallback( sal_uLong nPercent ); sal_uLong DataTypeSize(); sal_uLong ReadIntData(); double ReadDoubleData(); void ReadHeader(); void ReadTagData( sal_uInt16 nTagType, sal_uInt32 nDataLen ); sal_Bool ReadMap( sal_uLong nMinPercent, sal_uLong nMaxPercent ); // Liesst/dekomprimert die Bitmap-Daten, und fuellt pMap sal_uLong GetBits( const sal_uInt8 * pSrc, sal_uLong nBitsPos, sal_uLong nBitsCount ); // Holt nBitsCount Bits aus pSrc[..] an der Bit-Position nBitsPos void MakePalCol( void ); // Erzeugt die Bitmap aus der temporaeren Bitmap pMap // und loescht dabei pMap teilweise sal_Bool ConvertScanline( sal_uLong nY ); // Konvertiert eine Scanline in das Windows-BMP-Format public: TIFFReader() {} ~TIFFReader() {} sal_Bool ReadTIFF( SvStream & rTIFF, Graphic & rGraphic ); }; //=================== Methoden von TIFFReader ============================== void TIFFReader::MayCallback( sal_uLong /*nPercent*/ ) { /* if ( nPercent >= nLastPercent + 3 ) { nLastPercent=nPercent; if ( pCallback != NULL && nPercent <= 100 && bStatus == sal_True ) { if (((*pCallback)(pCallerData,(sal_uInt16)nPercent)) == sal_True ) bStatus = sal_False; } } */ } // --------------------------------------------------------------------------------- sal_uLong TIFFReader::DataTypeSize() { sal_uLong nSize; switch ( nDataType ) { case 1 : // BYTE case 2 : // ACSII case 6 : // SIGNED Byte case 7 : // UNDEFINED nSize = 1; break; case 3 : // UINT16 case 8 : // INT16 nSize = 2; break; case 4 : // UINT32 case 9 : // INT32 case 11 : // FLOAT nSize = 4; break; case 5 : // RATIONAL case 10 : // SIGNED RATINAL case 12 : // DOUBLE nSize = 8; break; default: pTIFF->SetError(SVSTREAM_FILEFORMAT_ERROR); nSize=1; } return nSize; } // --------------------------------------------------------------------------------- sal_uLong TIFFReader::ReadIntData() { double nDOUBLE; float nFLOAT; sal_uInt32 nUINT32a, nUINT32b; sal_Int32 nINT32; sal_uInt16 nUINT16; sal_Int16 nINT16; sal_uInt8 nBYTE; char nCHAR; switch( nDataType ) { case 0 : //?? case 1 : case 2 : case 7 : *pTIFF >> nBYTE; nUINT32a = (sal_uLong)nBYTE; break; case 3 : *pTIFF >> nUINT16; nUINT32a = (sal_uLong)nUINT16; break; case 9 : case 4 : *pTIFF >> nUINT32a; break; case 5 : *pTIFF >> nUINT32a >> nUINT32b; if ( nUINT32b != 0 ) nUINT32a /= nUINT32b; break; case 6 : *pTIFF >> nCHAR; nUINT32a = (sal_Int32)nCHAR; break; case 8 : *pTIFF >> nINT16; nUINT32a = (sal_Int32)nINT16; break; case 10 : *pTIFF >> nUINT32a >> nINT32; if ( nINT32 != 0 ) nUINT32a /= nINT32; break; case 11 : *pTIFF >> nFLOAT; nUINT32a = (sal_Int32)nFLOAT; break; case 12 : *pTIFF >> nDOUBLE; nUINT32a = (sal_Int32)nDOUBLE; break; default: *pTIFF >> nUINT32a; break; } return nUINT32a; } // --------------------------------------------------------------------------------- double TIFFReader::ReadDoubleData() { sal_uInt32 nulong; double nd; if ( nDataType == 5 ) { *pTIFF >> nulong; nd = (double)nulong; *pTIFF >> nulong; if ( nulong != 0 ) nd /= (double)nulong; } else nd = (double)ReadIntData(); return nd; } // --------------------------------------------------------------------------------- void TIFFReader::ReadTagData( sal_uInt16 nTagType, sal_uInt32 nDataLen) { if ( bStatus == sal_False ) return; switch ( nTagType ) { case 0x00fe: // New Sub File nNewSubFile = ReadIntData(); OOODEBUG("NewSubFile",nNewSubFile); break; case 0x00ff: // Sub File nSubFile = ReadIntData(); OOODEBUG("SubFile",nSubFile); break; case 0x0100: // Image Width nImageWidth = ReadIntData(); OOODEBUG("ImageWidth",nImageWidth); break; case 0x0101: // Image Length nImageLength = ReadIntData(); OOODEBUG("ImageLength",nImageLength); break; case 0x0102: // Bits Per Sample nBitsPerSample = ReadIntData(); OOODEBUG("BitsPerSample",nBitsPerSample); break; case 0x0103: // Compression nCompression = ReadIntData(); OOODEBUG("Compression",nCompression); break; case 0x0106: // Photometric Interpreation nPhotometricInterpretation = ReadIntData(); OOODEBUG("PhotometricInterpretation",nPhotometricInterpretation); break; case 0x0107: // Thresholding nThresholding = ReadIntData(); OOODEBUG("Thresholding",nThresholding); break; case 0x0108: // Cell Width nCellWidth = ReadIntData(); break; case 0x0109: // Cell Length nCellLength = ReadIntData(); break; case 0x010a: // Fill Order nFillOrder = ReadIntData(); OOODEBUG("FillOrder",nFillOrder); break; case 0x0111: { // Strip Offset(s) sal_uLong nOldNumSO, i, * pOldSO; pOldSO = pStripOffsets; if ( pOldSO == NULL ) nNumStripOffsets = 0; nOldNumSO = nNumStripOffsets; nDataLen += nOldNumSO; if ( ( nDataLen > nOldNumSO ) && ( nDataLen < SAL_MAX_UINT32 / sizeof( sal_uInt32 ) ) ) { nNumStripOffsets = nDataLen; try { pStripOffsets = new sal_uLong[ nNumStripOffsets ]; } catch (std::bad_alloc) { pStripOffsets = NULL; nNumStripOffsets = 0; } if ( pStripOffsets ) { for ( i = 0; i < nOldNumSO; i++ ) pStripOffsets[ i ] = pOldSO[ i ] + nOrigPos; for ( i = nOldNumSO; i < nNumStripOffsets; i++ ) pStripOffsets[ i ] = ReadIntData() + nOrigPos; } delete[] pOldSO; } OOODEBUG("StripOffsets (Anzahl:)",nDataLen); break; } case 0x0112: // Orientation nOrientation = ReadIntData(); OOODEBUG("Orientation",nOrientation); break; case 0x0115: // Samples Per Pixel nSamplesPerPixel = ReadIntData(); OOODEBUG("SamplesPerPixel",nSamplesPerPixel); break; case 0x0116: // Rows Per Strip nRowsPerStrip = ReadIntData(); OOODEBUG("RowsPerStrip",nRowsPerStrip); break; case 0x0117: { // Strip Byte Counts sal_uLong nOldNumSBC, i, * pOldSBC; pOldSBC = pStripByteCounts; if ( pOldSBC == NULL ) nNumStripByteCounts = 0; // Sicherheitshalber nOldNumSBC = nNumStripByteCounts; nDataLen += nOldNumSBC; if ( ( nDataLen > nOldNumSBC ) && ( nDataLen < SAL_MAX_UINT32 / sizeof( sal_uInt32 ) ) ) { nNumStripByteCounts = nDataLen; try { pStripByteCounts = new sal_uLong[ nNumStripByteCounts ]; } catch (std::bad_alloc) { pStripByteCounts = NULL; nNumStripByteCounts = 0; } if ( pStripByteCounts ) { for ( i = 0; i < nOldNumSBC; i++ ) pStripByteCounts[ i ] = pOldSBC[ i ]; for ( i = nOldNumSBC; i < nNumStripByteCounts; i++) pStripByteCounts[ i ] = ReadIntData(); } delete[] pOldSBC; } OOODEBUG("StripByteCounts (Anzahl:)",nDataLen); break; } case 0x0118: // Min Sample Value nMinSampleValue = ReadIntData(); OOODEBUG("MinSampleValue",nMinSampleValue); break; case 0x0119: // Max Sample Value nMaxSampleValue = ReadIntData(); OOODEBUG("MaxSampleValue",nMaxSampleValue); break; case 0x011a: // X Resolution fXResolution = ReadDoubleData(); break; case 0x011b: // Y Resolution fYResolution = ReadDoubleData(); break; case 0x011c: // Planar Configuration nPlanarConfiguration = ReadIntData(); OOODEBUG("PlanarConfiguration",nPlanarConfiguration); break; case 0x0124: // Group 3 Options nGroup3Options = ReadIntData(); OOODEBUG("Group3Options",nGroup3Options); break; case 0x0125: // Group 4 Options nGroup4Options = ReadIntData(); OOODEBUG("Group4Options",nGroup4Options); break; case 0x0128: // Resolution Unit nResolutionUnit = ReadIntData(); break; case 0x013d: // Predictor nPredictor = ReadIntData(); OOODEBUG("Predictor",nPredictor); break; case 0x0140: { // Color Map sal_uInt16 nVal; sal_uLong i; nNumColors= ( 1 << nBitsPerSample ); if ( nDataType == 3 && nNumColors <= 256) { pColorMap = new sal_uLong[ 256 ]; for ( i = 0; i < nNumColors; i++ ) pColorMap[ i ] = 0; for ( i = 0; i < nNumColors; i++ ) { *pTIFF >> nVal; pColorMap[ i ] |= ( ( (sal_uLong)nVal ) << 8 ) & 0x00ff0000; } for ( i = 0; i < nNumColors; i++ ) { *pTIFF >> nVal; pColorMap[ i ] |= ( (sal_uLong)nVal ) & 0x0000ff00; } for ( i = 0; i < nNumColors; i++ ) { *pTIFF >> nVal; pColorMap[ i ] |= ( ( (sal_uLong)nVal ) >> 8 ) & 0x000000ff; } } else bStatus = sal_False; OOODEBUG("ColorMap (Anzahl Farben:)", nNumColors); break; } } if ( pTIFF->GetError() ) bStatus = sal_False; } // --------------------------------------------------------------------------------- sal_Bool TIFFReader::ReadMap( sal_uLong nMinPercent, sal_uLong nMaxPercent ) { if ( nCompression == 1 || nCompression == 32771 ) { sal_uLong ny, np, nStrip, nStripBytesPerRow; if ( nCompression == 1 ) nStripBytesPerRow = nBytesPerRow; else nStripBytesPerRow = ( nBytesPerRow + 1 ) & 0xfffffffe; for ( ny = 0; ny < nImageLength; ny++ ) { for ( np = 0; np < nPlanes; np++ ) { nStrip = ny / nRowsPerStrip + np * nStripsPerPlane; if ( nStrip >= nNumStripOffsets ) return sal_False; pTIFF->Seek( pStripOffsets[ nStrip ] + ( ny % nRowsPerStrip ) * nStripBytesPerRow ); pTIFF->Read( pMap[ np ], nBytesPerRow ); if ( pTIFF->GetError() ) return sal_False; MayCallback( nMinPercent + ( nMaxPercent - nMinPercent ) * ( np * nImageLength + ny) / ( nImageLength * nPlanes ) ); } if ( !ConvertScanline( ny ) ) return sal_False; } } else if ( nCompression == 2 || nCompression == 3 || nCompression == 4 ) { sal_uLong ny, np, nStrip, nOptions; if ( nCompression == 2 ) { nOptions = CCI_OPTION_BYTEALIGNROW; } else if ( nCompression == 3 ) { nOptions = CCI_OPTION_EOL; if ( nGroup3Options & 0x00000001 ) nOptions |= CCI_OPTION_2D; if ( nGroup3Options & 0x00000004 ) nOptions |= CCI_OPTION_BYTEALIGNEOL; if ( nGroup3Options & 0xfffffffa ) return sal_False; } else { // nCompression==4 nOptions = CCI_OPTION_2D; if ( nGroup4Options & 0xffffffff ) return sal_False; } if ( nFillOrder == 2 ) { nOptions |= CCI_OPTION_INVERSEBITORDER; bByteSwap = sal_False; } nStrip = 0; if ( nStrip >= nNumStripOffsets ) return sal_False; pTIFF->Seek(pStripOffsets[nStrip]); CCIDecompressor aCCIDecom( nOptions, nImageWidth ); aCCIDecom.StartDecompression( *pTIFF ); for ( ny = 0; ny < nImageLength; ny++ ) { for ( np = 0; np < nPlanes; np++ ) { if ( ny / nRowsPerStrip + np * nStripsPerPlane > nStrip ) { nStrip=ny/nRowsPerStrip+np*nStripsPerPlane; if ( nStrip >= nNumStripOffsets ) return sal_False; pTIFF->Seek( pStripOffsets[ nStrip ] ); aCCIDecom.StartDecompression( *pTIFF ); } if ( aCCIDecom.DecompressScanline( pMap[ np ], nImageWidth * nBitsPerSample * nSamplesPerPixel / nPlanes ) == sal_False ) return sal_False; if ( pTIFF->GetError() ) return sal_False; MayCallback(nMinPercent+(nMaxPercent-nMinPercent)*(np*nImageLength+ny)/(nImageLength*nPlanes)); } if ( !ConvertScanline( ny ) ) return sal_False; } } else if ( nCompression == 5 ) { LZWDecompressor aLZWDecom; sal_uLong ny, np, nStrip; nStrip=0; if ( nStrip >= nNumStripOffsets ) return sal_False; pTIFF->Seek(pStripOffsets[nStrip]); aLZWDecom.StartDecompression(*pTIFF); for ( ny = 0; ny < nImageLength; ny++ ) { for ( np = 0; np < nPlanes; np++ ) { if ( ny / nRowsPerStrip + np * nStripsPerPlane > nStrip ) { nStrip = ny / nRowsPerStrip + np * nStripsPerPlane; if ( nStrip >= nNumStripOffsets ) return sal_False; pTIFF->Seek(pStripOffsets[nStrip]); aLZWDecom.StartDecompression(*pTIFF); } if ( ( aLZWDecom.Decompress( pMap[ np ], nBytesPerRow ) != nBytesPerRow ) || pTIFF->GetError() ) return sal_False; MayCallback(nMinPercent+(nMaxPercent-nMinPercent)*(np*nImageLength+ny)/(nImageLength*nPlanes)); } if ( !ConvertScanline( ny ) ) return sal_False; } } else if ( nCompression == 32773 ) { sal_uLong nStrip,nRecCount,nRowBytesLeft,ny,np,i; sal_uInt8 * pdst, nRecHeader, nRecData; nStrip = 0; if ( nStrip >= nNumStripOffsets ) return sal_False; pTIFF->Seek(pStripOffsets[nStrip]); for ( ny = 0; ny < nImageLength; ny++ ) { for ( np = 0; np < nPlanes; np++ ) { if ( ny / nRowsPerStrip + np * nStripsPerPlane > nStrip ) { nStrip=ny/nRowsPerStrip+np*nStripsPerPlane; if ( nStrip >= nNumStripOffsets ) return sal_False; pTIFF->Seek(pStripOffsets[nStrip]); } nRowBytesLeft = nBytesPerRow; pdst=pMap[ np ]; do { *pTIFF >> nRecHeader; if ((nRecHeader&0x80)==0) { nRecCount=0x00000001+((sal_uLong)nRecHeader); if ( nRecCount > nRowBytesLeft ) return sal_False; pTIFF->Read(pdst,nRecCount); pdst+=nRecCount; nRowBytesLeft-=nRecCount; } else if ( nRecHeader != 0x80 ) { nRecCount = 0x000000101 - ( (sal_uLong)nRecHeader ); if ( nRecCount > nRowBytesLeft ) { nRecCount = nRowBytesLeft; // bStatus = sal_False; // return; } *pTIFF >> nRecData; for ( i = 0; i < nRecCount; i++ ) *(pdst++) = nRecData; nRowBytesLeft -= nRecCount; } } while ( nRowBytesLeft != 0 ); if ( pTIFF->GetError() ) return sal_False; MayCallback(nMinPercent+(nMaxPercent-nMinPercent)*(np*nImageLength+ny)/(nImageLength*nPlanes)); } if ( !ConvertScanline( ny ) ) return sal_False; } } else return sal_False; return sal_True; } sal_uLong TIFFReader::GetBits( const sal_uInt8 * pSrc, sal_uLong nBitsPos, sal_uLong nBitsCount ) { sal_uLong nRes; if ( bByteSwap ) { pSrc += ( nBitsPos >> 3 ); nBitsPos &= 7; sal_uInt8 nDat = *pSrc; nRes = (sal_uLong)( BYTESWAP( nDat ) & ( 0xff >> nBitsPos ) ); if ( nBitsCount <= 8 - nBitsPos ) { nRes >>= ( 8 - nBitsPos - nBitsCount ); } else { pSrc++; nBitsCount -= 8 - nBitsPos; while ( nBitsCount >= 8 ) { nDat = *(pSrc++); nRes = ( nRes << 8 ) | ((sal_uLong)BYTESWAP( nDat ) ); nBitsCount -= 8; } if ( nBitsCount > 0 ) { nDat = *pSrc; nRes = ( nRes << nBitsCount ) | (((sal_uLong)BYTESWAP(nDat))>>(8-nBitsCount)); } } } else { pSrc += ( nBitsPos >> 3 ); nBitsPos &= 7; nRes = (sal_uLong)((*pSrc)&(0xff>>nBitsPos)); if ( nBitsCount <= 8 - nBitsPos ) { nRes >>= ( 8 - nBitsPos - nBitsCount ); } else { pSrc++; nBitsCount -= 8 - nBitsPos; while ( nBitsCount >= 8 ) { nRes = ( nRes << 8 ) | ((sal_uLong)*(pSrc++)); nBitsCount -= 8; } if ( nBitsCount > 0 ) nRes = ( nRes << nBitsCount ) | (((sal_uLong)*pSrc)>>(8-nBitsCount)); } } return nRes; } // --------------------------------------------------------------------------------- sal_Bool TIFFReader::ConvertScanline( sal_uLong nY ) { sal_uInt32 nRed, nGreen, nBlue, ns, nx, nVal, nByteCount; sal_uInt8 nByteVal; if ( nDstBitsPerPixel == 24 ) { if ( nBitsPerSample == 8 && nSamplesPerPixel >= 3 && nPlanes == 1 && nPhotometricInterpretation == 2 ) { sal_uInt8* pt = pMap[ 0 ]; // sind die Werte als Differenz abgelegt? if ( 2 == nPredictor ) { sal_uInt8 nLRed = 0; sal_uInt8 nLGreen = 0; sal_uInt8 nLBlue = 0; for ( nx = 0; nx < nImageWidth; nx++, pt += nSamplesPerPixel ) { nLRed = nLRed + pt[ 0 ]; nLGreen = nLGreen + pt[ 1 ]; nLBlue = nLBlue + pt[ 2 ]; pAcc->SetPixel( nY, nx, Color( nLRed, nLGreen, nLBlue ) ); } } else { for ( nx = 0; nx < nImageWidth; nx++, pt += nSamplesPerPixel ) { pAcc->SetPixel( nY, nx, Color( pt[0], pt[1], pt[2] ) ); } } } else if ( nPhotometricInterpretation == 2 && nSamplesPerPixel >= 3 ) { if ( nMaxSampleValue > nMinSampleValue ) { sal_uLong nMinMax = nMinSampleValue * 255 / ( nMaxSampleValue - nMinSampleValue ); for ( nx = 0; nx < nImageWidth; nx++ ) { if ( nPlanes < 3 ) { nRed = GetBits( pMap[ 0 ], ( nx * nSamplesPerPixel + 0 ) * nBitsPerSample, nBitsPerSample ); nGreen = GetBits( pMap[ 1 ], ( nx * nSamplesPerPixel + 1 ) * nBitsPerSample, nBitsPerSample ); nBlue = GetBits( pMap[ 2 ], ( nx * nSamplesPerPixel + 2 ) * nBitsPerSample, nBitsPerSample ); } else { nRed = GetBits( pMap[ 0 ], nx * nBitsPerSample, nBitsPerSample ); nGreen = GetBits( pMap[ 1 ], nx * nBitsPerSample, nBitsPerSample ); nBlue = GetBits( pMap[ 2 ], nx * nBitsPerSample, nBitsPerSample ); } pAcc->SetPixel( nY, nx, Color( (sal_uInt8)( nRed - nMinMax ), (sal_uInt8)( nGreen - nMinMax ), (sal_uInt8)(nBlue - nMinMax) ) ); } } } else if ( nPhotometricInterpretation == 5 && nSamplesPerPixel == 3 ) { if ( nMaxSampleValue > nMinSampleValue ) { sal_uLong nMinMax = nMinSampleValue * 255 / ( nMaxSampleValue - nMinSampleValue ); for ( nx = 0; nx < nImageWidth; nx++ ) { if ( nPlanes < 3 ) { nRed = GetBits( pMap[ 0 ],( nx * nSamplesPerPixel + 0 ) * nBitsPerSample, nBitsPerSample ); nGreen = GetBits( pMap[ 0 ],( nx * nSamplesPerPixel + 1 ) * nBitsPerSample, nBitsPerSample ); nBlue = GetBits( pMap[ 0 ],( nx * nSamplesPerPixel + 2 ) * nBitsPerSample, nBitsPerSample ); } else { nRed = GetBits( pMap[ 0 ], nx * nBitsPerSample, nBitsPerSample ); nGreen = GetBits( pMap[ 1 ], nx * nBitsPerSample, nBitsPerSample ); nBlue = GetBits( pMap[ 2 ], nx * nBitsPerSample, nBitsPerSample ); } nRed = 255 - (sal_uInt8)( nRed - nMinMax ); nGreen = 255 - (sal_uInt8)( nGreen - nMinMax ); nBlue = 255 - (sal_uInt8)( nBlue - nMinMax ); pAcc->SetPixel( nY, nx, Color( (sal_uInt8) nRed, (sal_uInt8) nGreen, (sal_uInt8) nBlue ) ); } } } else if( nPhotometricInterpretation == 5 && nSamplesPerPixel == 4 ) { if ( nMaxSampleValue > nMinSampleValue ) { sal_uInt8 nSamp[ 4 ]; sal_uInt8 nSampLast[ 4 ] = { 0, 0, 0, 0 }; long nBlack; for( nx = 0; nx < nImageWidth; nx++ ) { // sind die Werte als Differenz abgelegt? if( 2 == nPredictor ) { for( ns = 0; ns < 4; ns++ ) { if( nPlanes < 3 ) nSampLast[ ns ] = nSampLast[ ns ] + (sal_uInt8) GetBits( pMap[ 0 ], ( nx * nSamplesPerPixel + ns ) * nBitsPerSample, nBitsPerSample ); else nSampLast[ ns ] = nSampLast[ ns ] + (sal_uInt8) GetBits( pMap[ ns ], nx * nBitsPerSample, nBitsPerSample ); nSamp[ ns ] = nSampLast[ ns ]; } } else { for( ns = 0; ns < 4; ns++ ) { if( nPlanes < 3 ) nSamp[ ns ] = (sal_uInt8) GetBits( pMap[ 0 ], ( nx * nSamplesPerPixel + ns ) * nBitsPerSample, nBitsPerSample ); else nSamp[ ns ]= (sal_uInt8) GetBits( pMap[ ns ], nx * nBitsPerSample, nBitsPerSample ); } } nBlack = nSamp[ 3 ]; nRed = (sal_uInt8) Max( 0L, 255L - ( ( (long) nSamp[ 0 ] + nBlack - ( ( (long) nMinSampleValue ) << 1 ) ) * 255L/(long)(nMaxSampleValue-nMinSampleValue) ) ); nGreen = (sal_uInt8) Max( 0L, 255L - ( ( (long) nSamp[ 1 ] + nBlack - ( ( (long) nMinSampleValue ) << 1 ) ) * 255L/(long)(nMaxSampleValue-nMinSampleValue) ) ); nBlue = (sal_uInt8) Max( 0L, 255L - ( ( (long) nSamp[ 2 ] + nBlack - ( ( (long) nMinSampleValue ) << 1 ) ) * 255L/(long)(nMaxSampleValue-nMinSampleValue) ) ); pAcc->SetPixel( nY, nx, Color ( (sal_uInt8)nRed, (sal_uInt8)nGreen, (sal_uInt8)nBlue ) ); } } } } else if ( nSamplesPerPixel == 1 && ( nPhotometricInterpretation <= 1 || nPhotometricInterpretation == 3 ) ) { if ( nMaxSampleValue > nMinSampleValue ) { sal_uLong nMinMax = ( ( 1 << nDstBitsPerPixel ) - 1 ) / ( nMaxSampleValue - nMinSampleValue ); sal_uInt8* pt = pMap[ 0 ]; sal_uInt8 nShift; switch ( nDstBitsPerPixel ) { case 8 : { sal_uInt8 nLast; if ( bByteSwap ) { if ( nPredictor == 2 ) { nLast = BYTESWAP( (sal_uInt8)*pt++ ); for ( nx = 0; nx < nImageWidth; nx++ ) { pAcc->SetPixelIndex( nY, nx, nLast ); nLast = nLast + *pt++; } } else { for ( nx = 0; nx < nImageWidth; nx++ ) { nLast = *pt++; pAcc->SetPixelIndex( nY, nx, static_cast( (BYTESWAP((sal_uLong)nLast) - nMinSampleValue) * nMinMax ) ); } } } else { if ( nPredictor == 2 ) { nLast = *pt++; for ( nx = 0; nx < nImageWidth; nx++ ) { pAcc->SetPixelIndex( nY, nx, nLast ); nLast = nLast + *pt++; } } else { for ( nx = 0; nx < nImageWidth; nx++ ) { pAcc->SetPixelIndex( nY, nx, static_cast( ((sal_uLong)*pt++ - nMinSampleValue) * nMinMax ) ); } } } } break; case 7 : case 6 : case 5 : case 4 : case 3 : case 2 : { for ( nx = 0; nx < nImageWidth; nx++ ) { nVal = ( GetBits( pt, nx * nBitsPerSample, nBitsPerSample ) - nMinSampleValue ) * nMinMax; pAcc->SetPixelIndex( nY, nx, static_cast(nVal)); } } break; case 1 : { if ( bByteSwap ) { nx = 0; nByteCount = ( nImageWidth >> 3 ) + 1; while ( --nByteCount ) { nByteVal = *pt++; pAcc->SetPixelIndex( nY, nx++, nByteVal & 1 ); nByteVal >>= 1; pAcc->SetPixelIndex( nY, nx++, nByteVal & 1 ); nByteVal >>= 1; pAcc->SetPixelIndex( nY, nx++, nByteVal & 1 ); nByteVal >>= 1; pAcc->SetPixelIndex( nY, nx++, nByteVal & 1 ); nByteVal >>= 1; pAcc->SetPixelIndex( nY, nx++, nByteVal & 1 ); nByteVal >>= 1; pAcc->SetPixelIndex( nY, nx++, nByteVal & 1 ); nByteVal >>= 1; pAcc->SetPixelIndex( nY, nx++, nByteVal & 1 ); nByteVal >>= 1; pAcc->SetPixelIndex( nY, nx++, nByteVal ); } if ( nImageWidth & 7 ) { nByteVal = *pt++; while ( nx < nImageWidth ) { pAcc->SetPixelIndex( nY, nx++, nByteVal & 1 ); nByteVal >>= 1; } } } else { nx = 7; nByteCount = ( nImageWidth >> 3 ) + 1; while ( --nByteCount ) { nByteVal = *pt++; pAcc->SetPixelIndex( nY, nx, nByteVal & 1 ); nByteVal >>= 1; pAcc->SetPixelIndex( nY, --nx, nByteVal & 1 ); nByteVal >>= 1; pAcc->SetPixelIndex( nY, --nx, nByteVal & 1 ); nByteVal >>= 1; pAcc->SetPixelIndex( nY, --nx, nByteVal & 1 ); nByteVal >>= 1; pAcc->SetPixelIndex( nY, --nx, nByteVal & 1 ); nByteVal >>= 1; pAcc->SetPixelIndex( nY, --nx, nByteVal & 1 ); nByteVal >>= 1; pAcc->SetPixelIndex( nY, --nx, nByteVal & 1 ); nByteVal >>= 1; pAcc->SetPixelIndex( nY, --nx, nByteVal ); nx += 15; } if ( nImageWidth & 7 ) { nx -= 7; nByteVal = *pt++; nShift = 7; while ( nx < nImageWidth ) { pAcc->SetPixelIndex( nY, nx++, ( nByteVal >> nShift ) & 1); } } } } break; default : return sal_False; } } } else if ( ( nSamplesPerPixel == 2 ) && ( nBitsPerSample == 8 ) && ( nPlanarConfiguration == 1 ) && ( pColorMap == 0 ) ) // grayscale { if ( nMaxSampleValue > nMinSampleValue ) { sal_uLong nMinMax = ( ( 1 << 8 /*nDstBitsPerPixel*/ ) - 1 ) / ( nMaxSampleValue - nMinSampleValue ); sal_uInt8* pt = pMap[ 0 ]; if ( nByte1 == 'I' ) pt++; for ( nx = 0; nx < nImageWidth; nx++, pt += 2 ) { pAcc->SetPixelIndex( nY, nx, static_cast( ((sal_uLong)*pt - nMinSampleValue) * nMinMax) ); } } } else return sal_False; return sal_True; } // --------------------------------------------------------------------------------- void TIFFReader::MakePalCol( void ) { if ( nDstBitsPerPixel <= 8 ) { sal_uLong i, nVal, n0RGB; if ( pColorMap == NULL ) pColorMap = new sal_uLong[ 256 ]; if ( nPhotometricInterpretation <= 1 ) { nNumColors = 1 << nBitsPerSample; if ( nNumColors > 256 ) nNumColors = 256; pAcc->SetPaletteEntryCount( (sal_uInt16)nNumColors ); for ( i = 0; i < nNumColors; i++ ) { nVal = ( i * 255 / ( nNumColors - 1 ) ) & 0xff; n0RGB = nVal | ( nVal << 8 ) | ( nVal << 16 ); if ( nPhotometricInterpretation == 1 ) pColorMap[ i ] = n0RGB; else pColorMap[ nNumColors - i - 1 ] = n0RGB; } } for ( i = 0; i < nNumColors; i++ ) { pAcc->SetPaletteColor( (sal_uInt16)i, BitmapColor( (sal_uInt8)( pColorMap[ i ] >> 16 ), (sal_uInt8)( pColorMap[ i ] >> 8 ), (sal_uInt8)pColorMap[ i ] ) ); } } if ( fXResolution > 1.0 && fYResolution > 1.0 && ( nResolutionUnit == 2 || nResolutionUnit == 3 ) ) { sal_uLong nRX,nRY; if (nResolutionUnit==2) { nRX=(sal_uLong)(fXResolution+0.5); nRY=(sal_uLong)(fYResolution+0.5); } else { nRX=(sal_uLong)(fXResolution*2.54+0.5); nRY=(sal_uLong)(fYResolution*2.54+0.5); } MapMode aMapMode(MAP_INCH,Point(0,0),Fraction(1,nRX),Fraction(1,nRY)); aBitmap.SetPrefMapMode(aMapMode); aBitmap.SetPrefSize(Size(nImageWidth,nImageLength)); } } // --------------------------------------------------------------------------------- void TIFFReader::ReadHeader() { sal_uInt8 nbyte1, nbyte2; sal_uInt16 nushort; *pTIFF >> nbyte1; if ( nbyte1 == 'I' ) pTIFF->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); else pTIFF->SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN ); *pTIFF >> nbyte2 >> nushort; if ( nbyte1 != nbyte2 || ( nbyte1 != 'I' && nbyte1 != 'M' ) || nushort != 0x002a ) bStatus = sal_False; } // --------------------------------------------------------------------------------- sal_Bool TIFFReader::ReadTIFF(SvStream & rTIFF, Graphic & rGraphic ) { sal_uInt16 i, nNumTags, nTagType; sal_uLong nMaxPos; sal_uLong nPos; sal_uInt32 nFirstIfd, nDataLen; bStatus = sal_True; nLastPercent = 0; pTIFF = &rTIFF; nMaxPos = nOrigPos = pTIFF->Tell(); nOrigNumberFormat = pTIFF->GetNumberFormatInt(); MayCallback( 0 ); // Kopf einlesen: ReadHeader(); // Ersten IFD einlesen: *pTIFF >> nFirstIfd; if( !nFirstIfd || pTIFF->GetError() ) bStatus = sal_False; if ( bStatus ) { sal_uInt32 nOffset = nFirstIfd; // calculate length of TIFF file do { pTIFF->Seek( nOrigPos + nOffset ); if( pTIFF->GetError() ) { pTIFF->ResetError(); break; }; nMaxPos = Max( pTIFF->Tell(), nMaxPos ); *pTIFF >> nNumTags; // Schleife ueber Tags: for( i = 0; i < nNumTags; i++ ) { *pTIFF >> nTagType >> nDataType >> nDataLen >> nOffset; if( DataTypeSize() * nDataLen > 4 ) nMaxPos = Max( nOrigPos + nOffset + DataTypeSize() * nDataLen, nMaxPos ); } *pTIFF >> nOffset; if ( pTIFF->IsEof() ) nOffset = 0; nMaxPos = Max( pTIFF->Tell(), nMaxPos ); if ( !nOffset ) nMaxPos = Max( pTIFF->Tell(), nMaxPos ); } while( nOffset ); for ( sal_uInt32 nNextIfd = nFirstIfd; nNextIfd && bStatus; ) { pTIFF->Seek( nOrigPos + nNextIfd ); { bByteSwap = sal_False; nNewSubFile = 0; nSubFile = 0; nImageWidth = 0; nImageLength = 0; nBitsPerSample = 1; // Defaultwert laut Doku nCompression = 1; nPhotometricInterpretation = 0; nThresholding = 1; // Defaultwert laut Doku nCellWidth = 1; nCellLength = 1; nFillOrder = 1; // Defaultwert laut Doku nNumStripOffsets = 0; nOrientation = 1; nSamplesPerPixel = 1; // Defaultwert laut Doku nRowsPerStrip = 0xffffffff; // Defaultwert laut Doku nNumStripByteCounts = 0; nMinSampleValue = 0; // Defaultwert laut Doku nMaxSampleValue = 0; fXResolution = 0.0; fYResolution = 0.0; nPlanarConfiguration = 1; nGroup3Options = 0; // Defaultwert laut Doku nGroup4Options = 0; // Defaultwert laut Doku nResolutionUnit = 2; // Defaultwert laut Doku nPredictor = 1; nNumColors = 0; pAcc = NULL; pColorMap = NULL; pStripOffsets = NULL; pStripByteCounts = NULL; pMap[ 0 ] = pMap[ 1 ] = pMap[ 2 ] = pMap[ 3 ] = NULL; *pTIFF >> nNumTags; nPos = pTIFF->Tell(); // Schleife ueber Tags: for( i = 0; i < nNumTags; i++ ) { *pTIFF >> nTagType >> nDataType >> nDataLen; if( DataTypeSize() * nDataLen > 4 ) { *pTIFF >> nOffset; pTIFF->Seek( nOrigPos + nOffset ); } ReadTagData( nTagType, nDataLen ); nPos += 12; pTIFF->Seek( nPos ); if ( pTIFF->GetError() ) bStatus = sal_False; if ( bStatus == sal_False ) break; } *pTIFF >> nNextIfd; if ( pTIFF->IsEof() ) nNextIfd = 0; } if ( !nBitsPerSample || ( nBitsPerSample > 32 ) ) bStatus = sal_False; if ( bStatus ) { if ( nMaxSampleValue == 0 ) { if ( nBitsPerSample == 32 ) // sj: i93300, compiler bug, 1 << 32 gives 1 one 32bit windows platforms, nMaxSampleValue = 0xffffffff; // (up from 80286 only the lower 5 bits are used when shifting a 32bit register) else nMaxSampleValue = ( 1 << nBitsPerSample ) - 1; } if ( nPhotometricInterpretation == 2 || nPhotometricInterpretation == 5 || nPhotometricInterpretation == 6 ) nDstBitsPerPixel = 24; else if ( nBitsPerSample*nSamplesPerPixel <= 1 ) nDstBitsPerPixel = 1; else if ( nBitsPerSample*nSamplesPerPixel <= 4 ) nDstBitsPerPixel = 4; else nDstBitsPerPixel = 8; aBitmap = Bitmap( Size( nImageWidth, nImageLength ), nDstBitsPerPixel ); pAcc = aBitmap.AcquireWriteAccess(); if ( pAcc ) { if ( nPlanarConfiguration == 1 ) nPlanes = 1; else nPlanes = nSamplesPerPixel; if ( ( nFillOrder == 2 ) && ( nCompression != 5 ) ) // im LZW Mode werden die bits schon invertiert bByteSwap = sal_True; nStripsPerPlane = ( nImageLength - 1 ) / nRowsPerStrip + 1; nBytesPerRow = ( nImageWidth * nSamplesPerPixel / nPlanes * nBitsPerSample + 7 ) >> 3; for ( sal_uLong j = 0; j < 4; j++ ) { try { pMap[ j ] = new sal_uInt8[ nBytesPerRow ]; } catch (std::bad_alloc) { pMap[ j ] = NULL; bStatus = sal_False; break; } } if ( bStatus && ReadMap( 10, 60 ) ) { nMaxPos = Max( pTIFF->Tell(), nMaxPos ); MakePalCol(); nMaxPos = Max( pTIFF->Tell(), nMaxPos ); } else bStatus = sal_False; if( pAcc ) { aBitmap.ReleaseAccess( pAcc ); if ( bStatus ) { AnimationBitmap aAnimationBitmap( aBitmap, Point( 0, 0 ), aBitmap.GetSizePixel(), ANIMATION_TIMEOUT_ON_CLICK, DISPOSE_BACK ); aAnimation.Insert( aAnimationBitmap ); } } // Aufraeumen: for ( i = 0; i < 4; i++ ) delete[] pMap[ i ]; delete[] pColorMap; delete[] pStripOffsets; delete[] pStripByteCounts; } } } } // seek to end of TIFF if succeeded pTIFF->SetNumberFormatInt( nOrigNumberFormat ); pTIFF->Seek( bStatus ? nMaxPos : nOrigPos ); if ( aAnimation.Count() ) { if ( aAnimation.Count() == 1 ) rGraphic = aAnimation.GetBitmapEx(); else rGraphic = aAnimation; //aBitmap; return sal_True; } else return sal_False; } //================== GraphicImport - die exportierte Funktion ================ extern "C" sal_Bool __LOADONCALLAPI GraphicImport(SvStream & rStream, Graphic & rGraphic, FilterConfigItem*, sal_Bool ) { TIFFReader aTIFFReader; if ( aTIFFReader.ReadTIFF( rStream, rGraphic ) == sal_False ) return sal_False; return sal_True; }