blob: 5c8c0c161fe01e400fd33e0f3b9ff53e4b20174b [file] [log] [blame]
/**************************************************************
*
* 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>
#ifndef _SV_FLTCALL_HXX
#include <svtools/fltcall.hxx>
#endif
#include <vcl/animate.hxx>
#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<sal_uInt8>( (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_uInt8>( ((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<sal_uInt8>(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_uInt8>( ((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;
}