/*
* Copyright (c) 2010 Ixonos Plc.
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - Initial contribution
*
* Contributors:
* Ixonos Plc
*
* Description:
*
*/
#include "CJpeg.h"
#include <e32svr.h>
const TUint8 KQuantIndex[ 3 ] = { 0,1,1 };
const TUint8 KHuffIndex[ 3 ] = { 0,1,1 };
const TUint8 KZigZag[] = {
0, 8, 1, 2, 9, 16, 24, 17,
10, 3, 4, 11, 18, 25, 32, 40,
33, 26, 19, 12, 5, 6, 13, 20,
27, 34, 41, 48, 56, 49, 42, 35,
28, 21, 14, 7, 15, 22, 29, 36,
43, 50, 57, 58, 51, 44, 37, 30,
23, 31, 38, 45, 52, 59, 60, 53,
46, 39, 47, 54, 61, 62, 55, 63
};
/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */
/* IMPORTANT: these are only valid for 8-bit data precision! */
const TUint8 bits_dc_luminance[17] =
{ /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
const TUint8 val_dc_luminance[] =
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
const TUint8 bits_dc_chrominance[17] =
{ /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
const TUint8 val_dc_chrominance[] =
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
const TUint8 bits_ac_luminance[17] =
{ /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
const TUint8 val_ac_luminance[] =
{ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa
};
const TUint8 bits_ac_chrominance[17] =
{ /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
const TUint8 val_ac_chrominance[] =
{ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa
};
const TUint8 KExifHeader[] = "Exif";
class THuffman
{
public:
TInt8 iLength[ 256 ];
TUint8 iSymbol[ 256 ];
TUint8 iSearch[ 65536 ];
};
CJpeg* CJpeg::NewL()
{
CJpeg* self = NewLC();
CleanupStack::Pop( self );
return self;
}
CJpeg* CJpeg::NewLC()
{
CJpeg* self = new( ELeave )CJpeg();
CleanupStack::PushL( self );
self->ConstructL();
return self;
}
CJpeg::~CJpeg()
{
delete iHuffman[ 0 ];
delete iHuffman[ 1 ];
delete iHuffman[ 2 ];
delete iHuffman[ 3 ];
delete iQt[ 0 ];
delete iQt[ 1 ];
delete iQt[ 2 ];
delete iQt[ 3 ];
iCurrentQt = NULL;
iExifData = NULL;
//iBlock.Reset();
delete iBlock;
delete iBuffer;
delete iC[ 0 ];
delete iC[ 1 ];
delete iC[ 2 ];
//iDebug.Close();
//iFs.Close();
}
CJpeg::CJpeg()
{
}
void CJpeg::ConstructL()
{
}
void CJpeg::OpenL( const TFileName& aFile )
{
if (iBuffer)
{
delete iBuffer;
iBuffer = NULL;
}
RFs fs;
User::LeaveIfError( fs.Connect() );
CleanupClosePushL( fs );
RFile file;
TInt err = file.Open( fs, aFile, EFileRead | EFileShareReadersOnly );
if (KErrNone != err)
{
User::LeaveIfError( file.Open( fs, aFile, EFileRead | EFileShareAny ) );
}
CleanupClosePushL( file );
TInt size;
file.Size( size );
iBuffer = new( ELeave )TUint8[ size + 2 ];
TPtr8 ptr( iBuffer, size );
file.Read( ptr );
CleanupStack::PopAndDestroy( 2 ); // file, fs
OpenL( ptr );
}
void CJpeg::OpenL( const TPtr8& aData )
{
//iFs.Connect();
//iDebug.Replace( iFs, _L("e:\\TestData\\jpdeb.txt"), EFileWrite );
EnableRgvConv();
iBuffer = (TUint8*)aData.Ptr();
// if used again, all variables should be cleared
iBuf = 0;
iBufBits = 0;
delete iHuffman[ 0 ];
delete iHuffman[ 1 ];
delete iHuffman[ 2 ];
delete iHuffman[ 3 ];
iHuffman[ 0 ] = 0;
iHuffman[ 1 ] = 0;
iHuffman[ 2 ] = 0;
iHuffman[ 3 ] = 0;
//iDebug.Write( _L8("d1\n") );
//
// This is only needed if no huffman tables found
//
//CreateDefaultHuffmanL();
iQt[ 0 ] = 0;
iQt[ 1 ] = 0;
iQt[ 2 ] = 0;
iQt[ 3 ] = 0;
//
//TBitmapHandle bm;
//bm.iData = 0;
TBool moreChunks = ETrue;
TBool possibleChunk = EFalse;
// TInt pos;
while( moreChunks )
{
TUint8 b = iBuffer[ iBufPos++ ];
if( possibleChunk )
{
possibleChunk = EFalse;
switch( b )
{
case 0xd8: // start of image
{
//RDebug::Print( _L("--Jpeg start of image") );
//iDebug.Write( _L8("d2\n") );
break;
}
case 0xe0: // JFIF application segment
{
//RDebug::Print( _L("--Jpeg application segment") );
//iDebug.Write( _L8("d3\n") );
break;
}
case 0xe1: // APP1 segment, possible EXIF
{
//iDebug.Write( _L8("d4\n") );
//RDebug::Print( _L("--Jpeg app1 segment") );
TInt l = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; iBufPos += 2;
l -= 2;
// this could be used to read exif data:
//TPtrC8 exifData( iBuffer + iBufPos, l );
// Check that there is "Exif" header in the data
const TUint8* pos = &iBuffer[ iBufPos ];
if (Mem::Compare(pos, 2, &KExifHeader[0], 2 ))
{
iBufPos += l;
break;
}
// suppose there is exif here
// exif header is 6 bytes ( 45 78 69 66 00 00 "Exif.." )
iBufPos += 6;
l -= 6;
iExifData = iBuffer + iBufPos;
iExifDataLength = l;
iBufPos += l;
break;
}
case 0xe2:
case 0xe3:
case 0xe4:
case 0xe5:
case 0xe6:
case 0xe7:
case 0xe8:
case 0xe9:
case 0xea:
case 0xeb:
case 0xec:
case 0xed:
case 0xee:
case 0xef:
{
//iDebug.Write( _L8("d5\n") );
//
// Unused segment, skip
//
//RDebug::Print( _L("--Jpeg unused tag %x"), b );
TInt l = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; iBufPos += 2;
iBufPos += l-2;
break;
}
case 0xdb: // Quantization table
{
//iDebug.Write( _L8("d6\n") );
//RDebug::Print( _L("--Jpeg quant table") );
TInt l = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; iBufPos += 2;
////RDebug::Print( _L("Start:%x length:%d"), iBufPos-2, l );
TInt nqt = l / 65;
TInt i;
// one or more quantization table
for( i=0; i<nqt; i++ )
{
TUint8 t = iBuffer[ iBufPos++ ];
TInt n = t & 15;
// not used:
// TInt precision = n >> 4;
if (iQt[ n ])
{
delete iQt[ n ];
iQt[ n ] = NULL;
}
iQt[ n ] = new( ELeave )TUint8[ 64 ];
TInt j;
for( j=0; j<64; j++ )
{
iQt[ n ][ j ] = iBuffer[ iBufPos++ ];
//RDebug::Print( _L("Quant %d:first=%d"), j, iQt[ n ][ j ] );
}
}
break;
}
case 0xc0: // start of frame ( SOF )
{
//iDebug.Write( _L8("d7\n") );
//RDebug::Print( _L("--Jpeg start of frame") );
//TInt length = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ];
iBufPos += 2;
////RDebug::Print( _L("Start:%x length:%d"), iBufPos-2, length );
// not used:
// TInt precision = iBuffer[ iBufPos ];
iBufPos++;
// height
TInt t = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; iBufPos += 2;
iData.iSize.iHeight = t;
// width
t = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; iBufPos += 2;
iData.iSize.iWidth = t;
// component data
iNumComponents = iBuffer[ iBufPos++ ];
TInt i;
for( i=0; i<iNumComponents; i++ )
{
TInt compID = iBuffer[ iBufPos++ ];
TInt samplingFactor = iBuffer[ iBufPos++ ];
TInt quantizationTable = iBuffer[ iBufPos++ ];
iComponent[ i ].iXFactor = samplingFactor >> 4;
iComponent[ i ].iYFactor = samplingFactor & 15;
iComponent[ i ].iQuantTable = quantizationTable;
iComponent[ i ].iID = compID;
//RDebug::Print( _L("component %d = %d"), i, compID );
//RDebug::Print( _L("component %d quanttable=%d"), i, quantizationTable );
//RDebug::Print( _L("component %d factor = %d,%d"), iComponent[ i ].iXFactor, iComponent[ i ].iYFactor );
}
TInt xBlocks = 0;
TInt yBlocks = 0;
for( i=0; i<iNumComponents; i++ )
{
TInt x = iComponent[ i ].iXFactor;
TInt y = iComponent[ i ].iYFactor;
if( x > xBlocks )
{
xBlocks = x;
}
if( y > yBlocks )
{
yBlocks = y;
}
}
iData.iBlockSize.iWidth = xBlocks * 8;
iData.iBlockSize.iHeight = yBlocks * 8;
TSize size = iData.iSize;
size.iWidth /= iData.iBlockSize.iWidth;
size.iHeight /= iData.iBlockSize.iHeight;
if( iData.iSize.iWidth & ( iData.iBlockSize.iWidth - 1 ) )
{
size.iWidth++;
}
if( iData.iSize.iHeight & ( iData.iBlockSize.iHeight - 1 ) )
{
size.iHeight++;
}
iData.iSizeInBlocks = size;
break;
}
case 0xc1:
{
//iDebug.Write( _L8("d8\n") );
//RDebug::Print( _L("--Jpeg tag 0xc1, extended sequential, unsupported") );
// Extended sequential Jpeg, not supported
User::Leave( KErrNotSupported );
break;
};
case 0xc2:
{
//iDebug.Write( _L8("d9\n") );
//RDebug::Print( _L("--Jpeg tag 0xc2, Progressive DCT, unsupported") );
// Progressive DCT jpeg, not supported
User::Leave( KErrNotSupported );
break;
};
case 0xc3:
{
//iDebug.Write( _L8("d10\n") );
//RDebug::Print( _L("--Jpeg tag 0xc1, Lossless, unsupported") );
// Lossless ( sequential ) Jpeg, not supported
User::Leave( KErrNotSupported );
break;
};
case 0xc5:
case 0xc6:
case 0xc7:
case 0xc8:
case 0xc9:
case 0xca:
case 0xcb:
case 0xcc:
case 0xcd:
case 0xce:
case 0xcf:
{
//iDebug.Write( _L8("d11\n") );
//RDebug::Print( _L("--Jpeg tag %x, unknown"), b );
User::Leave( KErrNotSupported );
break;
};
case 0xc4: // huffman table
{
//iDebug.Write( _L8("d12\n") );
//RDebug::Print( _L("--Jpeg huffman table") );
TInt l = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; iBufPos += 2;
TInt table = 0;
TInt n = 0;
// one or more huffman tables
while( n<l-2 )
{
THuffman* huff = new( ELeave )THuffman;
table = iBuffer[ iBufPos++ ];
n++;
TInt huffSize[ 16 ];
TInt numSymbols = 0;
TInt i;
for( i=0; i<16; i++ )
{
TInt size = iBuffer[ iBufPos++ ];
huffSize[ i ] = size;
numSymbols += size;
n++;
}
////RDebug::Print( _L(" # of symbols %d"), numSymbols );
for( i=0; i<numSymbols; i++ )
{
TUint8 v = iBuffer[ iBufPos++ ];
huff->iSymbol[ i ] = v;
n++;
}
// Generate huffman lookup tables ( huffSize, table )
TInt ll;
TInt p = 0;
for( ll=0; ll<16; ll++ )
{
for( i=0; i<huffSize[ ll ]; i++ )
{
huff->iLength[ p++ ] = ll+1;
}
}
TInt code = 0;
huff->iLength[ p ] = 0;
TInt si = huff->iLength[ 0 ];
TInt lastP = p;
TInt hc[ 256 ];
p = 0;
while( huff->iLength[ p ] )
{
while( huff->iLength[ p ] == si )
{
hc[ p++ ] = code++;
}
code *= 2;
si++;
}
ll = 65536;
for( i=lastP-1; i>=0; i-- )
{
TInt t = 16 - huff->iLength[ i ];
TInt k = hc[ i ] * ( 1 << t );
TInt j;
for( j=k; j<ll; j++ )
{
huff->iSearch[ j ] = i;
}
ll = k;
}
i = ( table & 16 ) / 8 + ( table & 15 );
delete iHuffman[ i ];
iHuffman[ i ] = huff;
}
break;
}
//
case 0xda: // start of scan ( SOS )
{
//iDebug.Write( _L8("d13\n") );
//RDebug::Print( _L("--Jpeg start of scan") );
//TInt l = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; iBufPos += 2;
iBufPos += 2;
TInt numComponents = iBuffer[ iBufPos++ ];
//RDebug::Print( _L("JPEG: number of components=%d"), numComponents );
if( numComponents != iNumComponents )
{
// non-interleaved( planar ) not supported
User::Leave( KErrNotSupported );
}
//RDebug::Print( _L("Number of components=%d"), numComponents );
TInt componentHt[ 3 ];
TInt i;
for( i=0; i<numComponents; i++ )
{
TInt componentId = iBuffer[ iBufPos++ ];
// find index by ID
TInt index = -1;
for( TInt j=0; j<iNumComponents; j++ )
{
if( iComponent[ j ].iID == componentId )
{
index = j;
}
}
if( index == -1 )
{
// ID not found
User::Leave( KErrNotSupported );
}
componentHt[ index ] = iBuffer[ iBufPos++ ];
//RDebug::Print( _L("id=%d, ht=%d"), componentId, componentHt[ i ] );
}
if( componentHt[ 1 ] == 0 || componentHt[ 2 ] == 0 )
{
// images with same huffman for all components
// not yet supported
//RDebug::Print( _L("jpeg not supported") );
User::Leave( KErrNotSupported );
}
if( iHuffman[ 0 ] == NULL )
{
// no huffman tables found, create default tables
CreateDefaultHuffmanL();
}
iBufPos += 3;
iImageDataStart = iBufPos;
iRandomScanned = false;
moreChunks = EFalse;
break;
}
case 0xd9: // end of image ( EOI )
{
//RDebug::Print( _L("--Jpeg end of image") );
// not really used for anything
// will exit if picture data is read.
break;
}
case 0xdd: // define restart interval
{
//RDebug::Print( _L("--Jpeg define restart interval") );
//TInt l = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; iBufPos += 2;
iBufPos += 2;
TInt interval = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; iBufPos += 2;
//iBufPos += 2;
//RDebug::Print( _L(" interval = %d"), interval );
iResetInterval = interval;
// not really used for anything
// restart markers are just handled when they come
break;
}
case 0x00: // escaped 0xff
{
// only comes if file is broken somehow
break;
}
default:
{
// unknown jpeg tag
//RDebug::Print( _L("unknown jpeg tag %x"), b );
break;
}
}
}
else if( b == 255 )
{
possibleChunk = ETrue;
}
}
PrepareLoadBlockL();
}
void CJpeg::PrepareLoadBlockL()
{
if( iLoadBlockPrepared )
{
return;
}
// prepare rgb block bitmap
iBm.iSize = iData.iBlockSize;
iBm.iDrawRect = iBm.iSize;
iBlkPixels = iData.iBlockSize.iWidth * iData.iBlockSize.iHeight;
iBm.iData = NULL;
iBm.iType = E16MColor;
// prepare yuv buffers
iC[ 0 ] = new( ELeave )TUint8[ 64 * iComponent[ 0 ].iXFactor * iComponent[ 0 ].iYFactor ];
iC[ 1 ] = new( ELeave )TUint8[ 64 * iComponent[ 1 ].iXFactor * iComponent[ 1 ].iYFactor ];
iC[ 2 ] = new( ELeave )TUint8[ 64 * iComponent[ 2 ].iXFactor * iComponent[ 2 ].iYFactor ];
// prepare yuv->rgb scale
TInt bw = iBm.iSize.iWidth;
TInt bh = iBm.iSize.iHeight;
iYxa = 256 * ( 8 * iComponent[ 0 ].iXFactor ) / bw;
iYya = 256 * ( 8 * iComponent[ 0 ].iYFactor ) / bh;
iUxa = 256 * ( 8 * iComponent[ 1 ].iXFactor ) / bw;
iUya = 256 * ( 8 * iComponent[ 1 ].iYFactor ) / bh;
iVxa = 256 * ( 8 * iComponent[ 2 ].iXFactor ) / bw;
iVya = 256 * ( 8 * iComponent[ 2 ].iYFactor ) / bh;
//
// Select YUV -> RGB function
//
iYuv2rgbFunc = Yuv2RgbFree; // default, handles all combinations
if( iComponent[ 0 ].iXFactor == 2 && iComponent[ 0 ].iYFactor == 1 &&
iComponent[ 1 ].iXFactor == 1 && iComponent[ 1 ].iYFactor == 1 &&
iComponent[ 2 ].iXFactor == 1 && iComponent[ 2 ].iYFactor == 1 )
{
iYuv2rgbFunc = Yuv2Rgb21_11_11;
}
else if( iComponent[ 0 ].iXFactor == 2 && iComponent[ 0 ].iYFactor == 2 &&
iComponent[ 1 ].iXFactor == 1 && iComponent[ 1 ].iYFactor == 1 &&
iComponent[ 2 ].iXFactor == 1 && iComponent[ 2 ].iYFactor == 1 )
{
iYuv2rgbFunc = Yuv2Rgb22_11_11;
}
iLoadBlockPrepared = true;
}
void CJpeg::ScanRandomL()
{
if( iRandomScanned )
{
return;
}
//
// Set file read position
//
iBufPos = iImageDataStart;
iBufBits = 0;
iBuf = 0;
//
// Reserve memory for random access tables
//
TInt numBlocks = iData.iSizeInBlocks.iWidth * iData.iSizeInBlocks.iHeight;
iBlock = new( ELeave )TJpegBlock[ numBlocks ];
TInt bw = iData.iSizeInBlocks.iWidth;
TInt bh = iData.iSizeInBlocks.iHeight;
TInt bx;
TInt by;
TInt c1 = 0;
TInt c2 = 0;
TInt c3 = 0;
//TInt blockNum = 0;
for( by=0; by<bh; by++ )
{
////RDebug::Print( _L("Jpeg scan %d/%d"), by+1,bh );
for( bx=0; bx<bw; bx++ )
{
if( iRst )
{
iRst = false;
iBuf = 0;
iBufBits = 0;
c1 = 0;
c2 = 0;
c3 = 0;
}
// store information for every block
TJpegBlock& block = iBlock[ iNumBlocks++ ];
block.iY = c1;
block.iU = c2;
block.iV = c3;
block.iOffset = iBufPos;
block.iBuf = iBuf;
block.iBufBits = iBufBits;
//iBlock.Append( block );
TInt i;
// go fast trough all huffman data
iCurrentHuffman = 0;
iCurrentQt = iQt[ 0 ];
// Y-component
TInt n = iComponent[ 0 ].iXFactor * iComponent[ 0 ].iYFactor;
iDct[ 0 ] = c1;
for( i=0; i<n; i++ )
{
DecodeBlock();
}
c1 = iDct[ 0 ];
iCurrentHuffman = 1;
iCurrentQt = iQt[ 1 ];
// U-component
n = iComponent[ 1 ].iXFactor * iComponent[ 1 ].iYFactor;
iDct[ 0 ] = c2;
for( i=0; i<n; i++ )
{
DecodeBlock();
}
c2 = iDct[ 0 ];
// V-component
n = iComponent[ 1 ].iXFactor * iComponent[ 1 ].iYFactor;
iDct[ 0 ] = c3;
for( i=0; i<n; i++ )
{
DecodeBlock();
}
c3 = iDct[ 0 ];
}
}
iRandomScanned = true;
}
TBitmapHandle CJpeg::LoadBlockL( const TPoint& aBlock )
{
TBitmapHandle bm = iBm;
bm.iData = new( ELeave )TUint32[ iBlkPixels ];
CleanupStack::PushL(bm.iData);
TUint32* rgb = (TUint32*) bm.iData;
TInt blkNum = aBlock.iX + aBlock.iY * iData.iSizeInBlocks.iWidth;
if( aBlock.iX < 0 || aBlock.iX >= iData.iSizeInBlocks.iWidth )
{
blkNum = -1;
}
//if( blkNum < 0 || blkNum >= iBlock.Count() )
if( blkNum < 0 || blkNum >= iNumBlocks )
{
Mem::FillZ( bm.iData, iBlkPixels * sizeof( TUint32 ) );
return bm;
}
TJpegBlock& blk = iBlock[ blkNum ];
iBuf = blk.iBuf;
iBufBits = blk.iBufBits;
iBufPos = blk.iOffset;
//
// Decode block
//
TInt c1 = blk.iY;
TInt c2 = blk.iU;
TInt c3 = blk.iV;
///////////
TInt x;
TInt y;
TInt xx;
TInt yy;
TInt w;
TInt* p;
// Y-component
iCurrentHuffman = 0;
iCurrentQt = iQt[ 0 ];
xx = iComponent[ 0 ].iXFactor;
yy = iComponent[ 0 ].iYFactor;
w = xx * 8;
p = iBlk;
iDct[ 0 ] = c1;
for( y=0; y<yy; y++ )
{
for( x=0; x<xx; x++ )
{
DecodeBlock2();
TUint8* tp = iC[ 0 ] + x*8 + y * 8 * w;
p = iBlk;
for( TInt ty=0; ty<8; ty++ )
{
for( TInt tx=0; tx<8; tx++ )
{
tp[ tx + ty * w ] = *p++;
}
}
}
}
// U-component
iCurrentHuffman = 1;
iCurrentQt = iQt[ 1 ];
xx = iComponent[ 1 ].iXFactor;
yy = iComponent[ 1 ].iYFactor;
w = xx * 8;
p = iBlk;
iDct[ 0 ] = c2;
for( y=0; y<yy; y++ )
{
for( x=0; x<xx; x++ )
{
DecodeBlock2();
TUint8* tp = iC[ 1 ] + x*8 + y * 8 * w;
p = iBlk;
for( TInt ty=0; ty<8; ty++ )
{
for( TInt tx=0; tx<8; tx++ )
{
tp[ tx + ty * w ] = *p++;
}
}
}
}
// V-component
iCurrentHuffman = 1;
iCurrentQt = iQt[ 1 ];
xx = iComponent[ 2 ].iXFactor;
yy = iComponent[ 2 ].iYFactor;
w = xx * 8;
iDct[ 0 ] = c3;
for( y=0; y<yy; y++ )
{
for( x=0; x<xx; x++ )
{
DecodeBlock2();
TUint8* tp = iC[ 2 ] + x*8 + y * 8 * w;
p = iBlk;
for( TInt ty=0; ty<8; ty++ )
{
for( TInt tx=0; tx<8; tx++ )
{
tp[ tx + ty * w ] = *p++;
}
}
}
}
///////////
//
// Scaled blit YUV->RGB
//
TInt bw = bm.iSize.iWidth;
TInt bh = bm.iSize.iHeight;
TInt y1y = 0;
TInt y1u = 0;
TInt y1v = 0;
TInt yw = iComponent[ 0 ].iXFactor * 8;
TInt uw = iComponent[ 1 ].iXFactor * 8;
TInt vw = iComponent[ 2 ].iXFactor * 8;
TUint32* prgb = rgb;
for( y=0; y<bh; y++ )
{
TInt txy = 0;
TInt txu = 0;
TInt txv = 0;
TUint8* ccy = iC[ 0 ] + ( y1y/256 ) * yw;
TUint8* ccu = iC[ 1 ] + ( y1u/256 ) * uw;
TUint8* ccv = iC[ 2 ] + ( y1v/256 ) * vw;
for( x=0; x<bw; x++ )
{
TInt cy = ccy[ txy / 256 ];
TInt cu = ccu[ txu / 256 ] - 128;
TInt cv = ccv[ txv / 256 ] - 128;
txy += iYxa;
txu += iUxa;
txv += iVxa;
TInt cr = cy + ( 91881 * cv ) / 65536;
TInt cg = cy - ( 22554 * cu + 46802 * cv ) / 65536;
TInt cb = cy + ( 116130 * cu ) / 65536;
if( cr < 0 ) cr = 0;
if( cg < 0 ) cg = 0;
if( cb < 0 ) cb = 0;
if( cr > 255 ) cr = 255;
if( cg > 255 ) cg = 255;
if( cb > 255 ) cb = 255;
//rgb[ x + y * bw ] = cr * 65536 + cg * 256 + cb;
*prgb++ = cr * 65536 + cg * 256 + cb;
}
y1y += iYya;
y1u += iUya;
y1v += iVya;
}
CleanupStack::Pop();
return bm;
}
void CJpeg::DecodeBlock()
{
// //RDebug::Print( _L("DecodeBlock()") );
//
// Dummy version of block decode
// only traverses through huffman data
// and collects DC-values
//
THuffman* h = iHuffman[ iCurrentHuffman ];
TInt k;
for( k=0; k<64; k++ )
{
TInt v = Buf16();
TInt index = h->iSearch[ v ];
TInt symbol = h->iSymbol[ index ];
BufFwd( h->iLength[ index ] );
TInt nullCount = 0;
if( k>0 )
{
nullCount = symbol >> 4;
symbol &= 15;
}
v = BufBits( symbol );
if( v < ( 1 << ( symbol-1 ) ) )
{
v += 1 - ( 1 << symbol );
}
if( k )
{
if( nullCount==0 && v==0 )
{
k = 64;
break;
}
else if( nullCount==15 && v==0 )
{
k += 15;
}
else
{
k += nullCount;
}
}
else
{
iDct[ 0 ] += v * iCurrentQt[ 0 ];
h = iHuffman[ iCurrentHuffman+2 ];
}
}
}
void CJpeg::DecodeBlock2()
{
//
// Real block decoder
// fills iDct table and calls Idct() function
//
THuffman* h = iHuffman[ iCurrentHuffman ];
TInt k;
for( k=1; k<64; k++ )
{
iDct[ k ] = 0;
}
for( k=0; k<64; k++ )
{
TInt v = Buf16();
TInt index = h->iSearch[ v ];
TInt symbol = h->iSymbol[ index ];
BufFwd( h->iLength[ index ] );
TInt nullCount = 0;
if( k>0 )
{
nullCount = symbol >> 4;
symbol &= 15;
}
v = BufBits( symbol );
if( v < ( 1 << ( symbol-1 ) ) )
{
v += 1 - ( 1 << symbol );
}
if( k )
{
if( nullCount==0 && v==0 )
{
k = 64;
break;
}
else if( nullCount==15 && v==0 )
{
k += 15;
}
else
{
k += nullCount;
iDct[ KZigZag[ k ] ] = v * iCurrentQt[ k ];
}
}
else
{
iDct[ 0 ] += v * iCurrentQt[ 0 ];
h = iHuffman[ iCurrentHuffman+2 ];
}
}
Idct();
}
void CJpeg::DecodeBlock3()
{
//
// Real block decoder
// fills iDct table and calls Idct() function
//
THuffman* h = iHuffman[ iCurrentHuffman ];
TInt k;
for( k=1; k<64; k++ )
{
iDct[ k ] = 0;
}
for( k=0; k<64; k++ )
{
TInt v = Buf16();
TInt index = h->iSearch[ v ];
TInt symbol = h->iSymbol[ index ];
BufFwd( h->iLength[ index ] );
TInt nullCount = 0;
if( k>0 )
{
nullCount = symbol >> 4;
symbol &= 15;
}
v = BufBits( symbol );
if( v < ( 1 << ( symbol-1 ) ) )
{
v += 1 - ( 1 << symbol );
}
if( k )
{
if( nullCount==0 && v==0 )
{
k = 64;
break;
}
else if( nullCount==15 && v==0 )
{
k += 15;
}
else
{
k += nullCount;
iDct[ KZigZag[ k ] ] = v * iCurrentQt[ k ];
}
}
else
{
iDct[ 0 ] += v * iCurrentQt[ 0 ];
h = iHuffman[ iCurrentHuffman+2 ];
}
}
}
void CJpeg::Idct()
{
TInt even[ 4 ];
TInt odd[ 4 ];
TInt res[ 64 ];
TInt* p = iDct;
for( TInt x=0; x<8; x++ )
{
TInt x0 = *p++;
TInt x1 = *p++;
TInt x2 = *p++;
TInt x3 = *p++;
TInt x4 = *p++;
TInt x5 = *p++;
TInt x6 = *p++;
TInt x7 = *p++;
TInt tx0 = x0;
x0 = (x0 + x4) * 181;
x4 = (tx0 - x4) * 181;
TInt tx2 = x2;
TInt tx6 = x6;
x2 = tx2 * 236 + tx6 * 98;
x6 = tx2 * 98 - tx6 * 236;
even[0] = x0 + x2;
even[1] = x4 + x6;
even[2] = x4 - x6;
even[3] = x0 - x2;
odd[0] = x1 * 251 + x5 * 142 + x3 * 212 + x7 * 49;
odd[1] = x1 * 213 - x5 * 251 - x3 * 50 - x7 * 142;
odd[2] = x1 * 142 + x5 * 50 - x3 * 251 + x7 * 213;
odd[3] = x1 * 50 + x5 * 213 - x3 * 142 - x7 * 251;
res[x + 0] = even[0] + odd[0];
res[x + 8] = even[1] + odd[1];
res[x + 16] = even[2] + odd[2];
res[x + 24] = even[3] + odd[3];
res[x + 32] = even[3] - odd[3];
res[x + 40] = even[2] - odd[2];
res[x + 48] = even[1] - odd[1];
res[x + 56] = even[0] - odd[0];
}
p = res;
TInt* tp = iBlk;
for( TInt y=0; y<8; y++ )
{
TInt x0 = *p++;
TInt x1 = *p++;
TInt x2 = *p++;
TInt x3 = *p++;
TInt x4 = *p++;
TInt x5 = *p++;
TInt x6 = *p++;
TInt x7 = *p++;
TInt tx0 = x0;
x0 = (x0 + x4) * 181;
x4 = (tx0 - x4) * 181;
TInt tx2 = x2;
TInt tx6 = x6;
x2 = tx2 * 236 + tx6 * 98;
x6 = tx2 * 98 - tx6 * 236;
even[0] = x0 + x2;
even[1] = x4 + x6;
even[2] = x4 - x6;
even[3] = x0 - x2;
odd[0] = x1 * 251 + x5 * 142 + x3 * 212 + x7 * 49;
odd[1] = x1 * 213 - x5 * 251 - x3 * 50 - x7 * 142;
odd[2] = x1 * 142 + x5 * 50 - x3 * 251 + x7 * 213;
odd[3] = x1 * 50 + x5 * 213 - x3 * 142 - x7 * 251;
*tp++ = (even[0] + odd[0]) / 262144 + 128;
*tp++ = (even[1] + odd[1]) / 262144 + 128;
*tp++ = (even[2] + odd[2]) / 262144 + 128;
*tp++ = (even[3] + odd[3]) / 262144 + 128;
*tp++ = (even[3] - odd[3]) / 262144 + 128;
*tp++ = (even[2] - odd[2]) / 262144 + 128;
*tp++ = (even[1] - odd[1]) / 262144 + 128;
*tp++ = (even[0] - odd[0]) / 262144 + 128;
}
//
// Clamp
//
tp = iBlk;
TInt* tpe = tp + 64;
while( tp < tpe )
{
if( *tp < 0 ) *tp = 0;
if( *tp > 255 ) *tp = 255;
tp++;
}
}
void CJpeg::IdctHalf()
{
TInt even[ 4 ];
TInt odd[ 4 ];
TInt res[ 64 ];
TInt* p = iDct;
for( TInt x=0; x<4; x++ )
{
TInt x0 = *p++;
TInt x1 = *p++;
TInt x2 = *p++;
TInt x3 = *p++;
p += 4;
x0 = x0 * 181;
TInt x6 = x2 * 98;
x2 = x2 * 236;
even[0] = x0 + x2;
even[1] = x0 + x6;
even[2] = x0 - x6;
even[3] = x0 - x2;
odd[0] = x1 * 251 + x3 * 212;
odd[1] = x1 * 213 - x3 * 50;
odd[2] = x1 * 142 - x3 * 251;
odd[3] = x1 * 50 - x3 * 142;
res[x + 0] = even[0] + odd[0];
res[x + 4] = even[2] + odd[2];
res[x + 8] = even[3] - odd[3];
res[x + 12] = even[1] - odd[1];
}
p = res;
TInt* tp = iBlk;
for( TInt y=0; y<4; y++ )
{
TInt x0 = *p++;
TInt x1 = *p++;
TInt x2 = *p++;
TInt x3 = *p++;
x0 = x0 * 181;
TInt x6 = x2 * 98;
x2 = x2 * 236;
even[0] = x0 + x2;
even[1] = x0 + x6;
even[2] = x0 - x6;
even[3] = x0 - x2;
odd[0] = x1 * 251 + x3 * 212;
odd[1] = x1 * 213 - x3 * 50;
odd[2] = x1 * 142 - x3 * 251;
odd[3] = x1 * 50 - x3 * 142;
*tp++ = (even[0] + odd[0]) / 262144 + 128;
*tp++ = (even[2] + odd[2]) / 262144 + 128;
*tp++ = (even[3] - odd[3]) / 262144 + 128;
*tp++ = (even[1] - odd[1]) / 262144 + 128;
}
//
// Clamp
//
tp = iBlk;
TInt* tpe = tp + 16;
while( tp < tpe )
{
if( *tp < 0 ) *tp = 0;
if( *tp > 255 ) *tp = 255;
tp++;
}
}
const TJpegData& CJpeg::Info()
{
return iData;
}
TPtrC8 CJpeg::ExifData()
{
return TPtrC8( iExifData, iExifDataLength );
}
void CJpeg::CreateHuffmanL( THuffman* aHuffman, const TUint8* aBits, const TUint8* aVal )
{
//
// default huffman lookup table generator
//
TInt huffSize[ 16 ];
TInt numSymbols = 0;
TInt i;
for( i=0; i<16; i++ )
{
TInt size = aBits[ i+1 ];
huffSize[ i ] = size;
numSymbols += size;
}
for( i=0; i<numSymbols; i++ )
{
aHuffman->iSymbol[ i ] = aVal[ i ];
}
TInt l;
TInt p = 0;
for( l=0; l<16; l++ )
{
for( i=0; i<huffSize[ l ]; i++ )
{
aHuffman->iLength[ p++ ] = l+1;
}
}
TInt code = 0;
aHuffman->iLength[ p ] = 0;
TInt si = aHuffman->iLength[ 0 ];
TInt lastP = p;
TInt hc[ 256 ];
p = 0;
while( aHuffman->iLength[ p ] )
{
while( aHuffman->iLength[ p ] == si )
{
hc[ p++ ] = code++;
}
code *= 2;
si++;
}
l = 65536;
for( i=lastP-1; i>=0; i-- )
{
TInt t = 16 - aHuffman->iLength[ i ];
TInt k = hc[ i ] * ( 1 << t );
TInt j;
for( j=k; j<l; j++ )
{
aHuffman->iSearch[ j ] = i;
}
l = k;
}
}
void CJpeg::CreateDefaultHuffmanL()
{
//
// Creates default huffman tables
// needed if jpeg file doesn't have huffman tables
// for example motion jpeg file doesn't have.
//
THuffman* huff = new( ELeave )THuffman;
CleanupStack::PushL( huff );
CreateHuffmanL( huff, bits_dc_luminance, val_dc_luminance );
iHuffman[ 0 ] = huff;
CleanupStack::Pop( huff );
huff = new( ELeave )THuffman;
CleanupStack::PushL( huff );
CreateHuffmanL( huff, bits_dc_chrominance, val_dc_chrominance );
iHuffman[ 1 ] = huff;
CleanupStack::Pop( huff );
huff = new( ELeave )THuffman;
CleanupStack::PushL( huff );
CreateHuffmanL( huff, bits_ac_luminance, val_ac_luminance );
iHuffman[ 2 ] = huff;
CleanupStack::Pop( huff );
huff = new( ELeave )THuffman;
CleanupStack::PushL( huff );
CreateHuffmanL( huff, bits_ac_chrominance, val_ac_chrominance );
iHuffman[ 3 ] = huff;
CleanupStack::Pop( huff );
}
void CJpeg::DecRgb1_1L( const TBitmapHandle& aBitmap, const TRect& aBlockRect )
{
PrepareLoadBlockL();
//
// Set file read position
//
iBufPos = iImageDataStart;
iBufBits = 0;
iBuf = 0;
TInt c[ 3 ];
c[ 0 ] = 0;
c[ 1 ] = 0;
c[ 2 ] = 0;
TInt w = aBitmap.iSize.iWidth;
TUint32* rgb = (TUint32*)aBitmap.iData;
//
// Store data for yuv->rgb conversion
//
iYuvConv.iBlkSize = iData.iBlockSize;
iYuvConv.iRgbWidth = w;
iYuvConv.iBlkPixels = 8;
TInt blw = aBlockRect.Size().iWidth;
TInt blh = aBlockRect.Size().iHeight;
for( TInt by=0; by<blh; by++ )
{
if( iRandomScanned )
{
TPoint pos( aBlockRect.iTl.iX, aBlockRect.iTl.iY + by );
TInt blkNum = pos.iX + pos.iY * iData.iSizeInBlocks.iWidth;
TJpegBlock& blk = iBlock[ blkNum ];
iBuf = blk.iBuf;
iBufBits = blk.iBufBits;
iBufPos = blk.iOffset;
c[ 0 ] = blk.iY;
c[ 1 ] = blk.iU;
c[ 2 ] = blk.iV;
iRst = false;
}
//TInt blockNum = aBlockRect.iTl.iX + ( aBlockRect.iTl.iY + by ) * iData.iSizeInBlocks.iWidth;
for( TInt bx=0; bx<blw; bx++ )
{
iYuvConv.iRgb = rgb + bx * iData.iBlockSize.iWidth;
iYuvConv.iRgb += by * iData.iBlockSize.iHeight * w;
if( iRst )
{
iRst = false;
iBuf = 0;
iBufBits = 0;
c[ 0 ] = 0;
c[ 1 ] = 0;
c[ 2 ] = 0;
}
//blockNum++;
TInt xx;
TInt yy;
TInt* p;
for( TInt i=0; i<iNumComponents; i++ )
{
iCurrentQt = iQt[ KQuantIndex[ i ] ];
xx = iComponent[ i ].iXFactor;
yy = iComponent[ i ].iYFactor;
TInt dw = xx * 8;
p = iBlk;
iDct[ 0 ] = c[ i ];
for( TInt y=0; y<yy; y++ )
{
for( TInt x=0; x<xx; x++ )
{
iCurrentHuffman = KHuffIndex[ i ];
DecodeBlock3();
Idct();
TUint8* tp = iC[ i ] + x*8 + y*8 * dw;
p = iBlk;
for( TInt ty=0; ty<8; ty++ )
{
for( TInt tx=0; tx<8; tx++ )
{
tp[ tx + ty * dw ] = *p++;
}
}
}
}
c[ i ] = iDct[ 0 ];
}
//
// Scaled blit YUV->RGB
//
if( iRgbConv )
{
iYuv2rgbFunc( this );
}
}
}
}
void CJpeg::DecRgb1_2L( const TBitmapHandle& aBitmap, const TRect& aBlockRect )
{
PrepareLoadBlockL();
//
// Set file read position
//
iBufPos = iImageDataStart;
iBufBits = 0;
iBuf = 0;
TInt c[ 3 ];
c[ 0 ] = 0;
c[ 1 ] = 0;
c[ 2 ] = 0;
TInt w = aBitmap.iSize.iWidth;
TUint32* rgb = (TUint32*)aBitmap.iData;
TInt bw = iData.iBlockSize.iWidth / 2;
TInt bh = iData.iBlockSize.iHeight / 2;
//
// Store data for yuv->rgb conversion
//
iYuvConv.iBlkSize = TSize( bw, bh );
iYuvConv.iRgbWidth = w;
iYuvConv.iBlkPixels = 4;
TInt blw = aBlockRect.Size().iWidth;
TInt blh = aBlockRect.Size().iHeight;
for( TInt by=0; by<blh; by++ )
{
if( iRandomScanned )
{
TPoint pos( aBlockRect.iTl.iX, aBlockRect.iTl.iY + by );
TInt blkNum = pos.iX + pos.iY * iData.iSizeInBlocks.iWidth;
TJpegBlock& blk = iBlock[ blkNum ];
iBuf = blk.iBuf;
iBufBits = blk.iBufBits;
iBufPos = blk.iOffset;
c[ 0 ] = blk.iY;
c[ 1 ] = blk.iU;
c[ 2 ] = blk.iV;
iRst = false;
}
//TInt blockNum = aBlockRect.iTl.iX + ( aBlockRect.iTl.iY + by ) * iData.iSizeInBlocks.iWidth;
for( TInt bx=0; bx<blw; bx++ )
{
iYuvConv.iRgb = rgb + bx * bw;
iYuvConv.iRgb += by * bh * w;
if( iRst )
{
iRst = false;
iBuf = 0;
iBufBits = 0;
c[ 0 ] = 0;
c[ 1 ] = 0;
c[ 2 ] = 0;
}
//blockNum++;
///////////
TInt x;
TInt y;
TInt xx;
TInt yy;
TInt* p;
for( TInt i=0; i<iNumComponents; i++ )
{
iCurrentQt = iQt[ KQuantIndex[ i ] ];
xx = iComponent[ i ].iXFactor;
yy = iComponent[ i ].iYFactor;
TInt dw = xx * 4;
p = iBlk;
iDct[ 0 ] = c[ i ];
for( y=0; y<yy; y++ )
{
for( x=0; x<xx; x++ )
{
iCurrentHuffman = KHuffIndex[ i ];
DecodeBlock3();
TUint8* tp = iC[ i ] + x*4 + y*4 * dw;
//
// 4x4 Idct
//
IdctHalf();
for( TInt ty=0; ty<4; ty++ )
{
for( TInt tx=0; tx<4; tx++ )
{
tp[ tx + ty * dw ] = p[ tx + ty*4 ];
}
}
}
}
c[ i ] = iDct[ 0 ];
}
//
// Scaled blit YUV->RGB
//
if( iRgbConv )
{
iYuv2rgbFunc( this );
}
}
}
}
void CJpeg::DecRgb1_4L( const TBitmapHandle& aBitmap, const TRect& aBlockRect )
{
PrepareLoadBlockL();
//
// Set file read position
//
iBufPos = iImageDataStart;
iBufBits = 0;
iBuf = 0;
TInt c[ 3 ];
c[ 0 ] = 0;
c[ 1 ] = 0;
c[ 2 ] = 0;
TInt w = aBitmap.iSize.iWidth;
TUint32* rgb = (TUint32*)aBitmap.iData;
TInt bw = iData.iBlockSize.iWidth / 4;
TInt bh = iData.iBlockSize.iHeight / 4;
//
// Store data for yuv->rgb conversion
//
iYuvConv.iBlkSize = TSize( bw, bh );
iYuvConv.iRgbWidth = w;
iYuvConv.iBlkPixels = 2;
TInt blw = aBlockRect.Size().iWidth;
TInt blh = aBlockRect.Size().iHeight;
for( TInt by=0; by<blh; by++ )
{
if( iRandomScanned )
{
TPoint pos( aBlockRect.iTl.iX, aBlockRect.iTl.iY + by );
TInt blkNum = pos.iX + pos.iY * iData.iSizeInBlocks.iWidth;
TJpegBlock& blk = iBlock[ blkNum ];
iBuf = blk.iBuf;
iBufBits = blk.iBufBits;
iBufPos = blk.iOffset;
c[ 0 ] = blk.iY;
c[ 1 ] = blk.iU;
c[ 2 ] = blk.iV;
iRst = false;
}
//TInt blockNum = aBlockRect.iTl.iX + ( aBlockRect.iTl.iY + by ) * iData.iSizeInBlocks.iWidth;
for( TInt bx=0; bx<blw; bx++ )
{
iYuvConv.iRgb = rgb + bx * bw;
iYuvConv.iRgb += by * bh * w;
if( iRst )
{
iRst = false;
iBuf = 0;
iBufBits = 0;
c[ 0 ] = 0;
c[ 1 ] = 0;
c[ 2 ] = 0;
}
//blockNum++;
TInt x;
TInt y;
TInt xx;
TInt yy;
for( TInt i=0; i<iNumComponents; i++ )
{
iCurrentQt = iQt[ KQuantIndex[ i ] ];
xx = iComponent[ i ].iXFactor;
yy = iComponent[ i ].iYFactor;
TInt dw = xx * 2;
iDct[ 0 ] = c[ i ];
for( y=0; y<yy; y++ )
{
for( x=0; x<xx; x++ )
{
iCurrentHuffman = KHuffIndex[ i ];
DecodeBlock3();
TUint8* tp = iC[ i ] + x*2 + y*2 * dw;
//
// 2x2 Idct
//
TInt v0 = 181*iDct[1];
TInt v1 = 32761 * iDct[ 0 ];
TInt v2 = 45431 * iDct[ 8 ];
TInt v3 = -9050 * iDct[ 8 ];
TInt v4 = v0 + 251*iDct[9];
TInt v5 = v0 - 50*iDct[9];
TInt v = (v1 + v2 + 251*v4 ) / 262144 + 128;
if( v<0 ) v=0; if( v>255 ) v=255; tp[ 0 ] = v;
v = (v1 + v2 - 50*v4 ) / 262144 + 128;
if( v<0 ) v=0; if( v>255 ) v=255; tp[ dw ] = v;
v = (v1 + v3 + 251*v5 ) / 262144 + 128;
if( v<0 ) v=0; if( v>255 ) v=255; tp[ 1 ] = v;
v = (v1 + v3 - 50*v5 ) / 262144 + 128;
if( v<0 ) v=0; if( v>255 ) v=255; tp[ dw+1 ] = v;
}
}
c[ i ] = iDct[ 0 ];
}
//
// Scaled blit YUV->RGB
//
if( iRgbConv )
{
iYuv2rgbFunc( this );
}
}
}
}
void CJpeg::DecRgb1_8L( const TBitmapHandle& aBitmap, const TRect& aBlockRect )
{
PrepareLoadBlockL();
//
// Set file read position
//
iBufPos = iImageDataStart;
iBufBits = 0;
iBuf = 0;
TInt c[ 3 ];
c[ 0 ] = 0;
c[ 1 ] = 0;
c[ 2 ] = 0;
TInt w = aBitmap.iSize.iWidth;
TUint32* rgb = (TUint32*)aBitmap.iData;
TInt bw = iData.iBlockSize.iWidth / 8;
TInt bh = iData.iBlockSize.iHeight / 8;
//
// Store data for yuv->rgb conversion
//
iYuvConv.iBlkSize = TSize( bw, bh );
iYuvConv.iRgbWidth = w;
iYuvConv.iBlkPixels = 1;
TInt blw = aBlockRect.Size().iWidth;
TInt blh = aBlockRect.Size().iHeight;
for( TInt by=0; by<blh; by++ )
{
if( iRandomScanned )
{
TPoint pos( aBlockRect.iTl.iX, aBlockRect.iTl.iY + by );
TInt blkNum = pos.iX + pos.iY * iData.iSizeInBlocks.iWidth;
TJpegBlock& blk = iBlock[ blkNum ];
iBuf = blk.iBuf;
iBufBits = blk.iBufBits;
iBufPos = blk.iOffset;
c[ 0 ] = blk.iY;
c[ 1 ] = blk.iU;
c[ 2 ] = blk.iV;
iRst = false;
}
//TInt blockNum = aBlockRect.iTl.iX + ( aBlockRect.iTl.iY + by ) * iData.iSizeInBlocks.iWidth;
for( TInt bx=0; bx<blw; bx++ )
{
iYuvConv.iRgb = rgb + bx * bw;
iYuvConv.iRgb += by * bh * w;
if( iRst )
{
iRst = false;
iBuf = 0;
iBufBits = 0;
c[ 0 ] = 0;
c[ 1 ] = 0;
c[ 2 ] = 0;
}
//blockNum++;
TInt x;
TInt y;
TInt xx;
TInt yy;
for( TInt i=0; i<iNumComponents; i++ )
{
iCurrentQt = iQt[ KQuantIndex[ i ] ];
xx = iComponent[ i ].iXFactor;
yy = iComponent[ i ].iYFactor;
TInt dw = xx * 1;
iDct[ 0 ] = c[ i ];
for( y=0; y<yy; y++ )
{
for( x=0; x<xx; x++ )
{
iCurrentHuffman = KHuffIndex[ i ];
DecodeBlock3();
TUint8* tp = iC[ i ] + x*1 + y*1 * dw;
*tp = iDct[ 0 ] / 8 + 128;
}
}
c[ i ] = iDct[ 0 ];
}
//
// Scaled blit YUV->RGB
//
if( iRgbConv )
{
iYuv2rgbFunc( this );
}
}
}
}
void CJpeg::SetScale( TJpegScale aScale )
{
iScale = aScale;
}
void CJpeg::Yuv2Rgb22_11_11( TAny* aPtr )
{
CJpeg& p = *(CJpeg*)aPtr;
//
// YUV420
//
// YY
// YY U V
//
TUint8* cY = p.iC[ 0 ];
TUint8* cU = p.iC[ 1 ];
TUint8* cV = p.iC[ 2 ];
TUint32* rgb = p.iYuvConv.iRgb;
TInt modulo = p.iYuvConv.iRgbWidth - p.iYuvConv.iBlkSize.iWidth;
TInt w = p.iYuvConv.iBlkSize.iWidth;
TInt h = p.iYuvConv.iBlkSize.iHeight;
for( TInt y=0; y<h; y++ )
{
TInt x = 0;
TInt cu = 0;
TInt cv = 0;
for( x=0; x<w; x++ )
{
TInt cy = *cY++;
if( ( x & 1 ) == 0 )
{
// when X even, fetch new color components
cu = *cU++ - 128;
cv = *cV++ - 128;
}
// urgb color
TUint32 c;
// rgb color component
TInt cc;
// add red
cc = cy + ( 359 * cv ) / 256;
if( cc < 0 ) cc = 0;
if( cc > 255 ) cc = 255;
c = cc << 16;
// add green
cc = cy - ( 88 * cu + 183 * cv ) / 256;
if( cc < 0 ) cc = 0;
if( cc > 255 ) cc = 255;
c |= cc << 8;
// add blue
cc = cy + ( 454 * cu ) / 256;
if( cc < 0 ) cc = 0;
if( cc > 255 ) cc = 255;
// write to bitmap
*rgb++ = c + cc;
}
rgb += modulo;
if( ( y & 1 ) == 0 )
{
// only advance color components on odd Y
// so on even, do rewind
cU -= x/2;
cV -= x/2;
}
}
}
void CJpeg::Yuv2Rgb21_11_11( TAny* aPtr )
{
CJpeg& p = *(CJpeg*)aPtr;
//
// YUV422
//
// YY U V
//
TUint8* cY = p.iC[ 0 ];
TUint8* cU = p.iC[ 1 ];
TUint8* cV = p.iC[ 2 ];
TUint32* rgb = p.iYuvConv.iRgb;
TInt modulo = p.iYuvConv.iRgbWidth - p.iYuvConv.iBlkSize.iWidth;
TInt w = p.iYuvConv.iBlkSize.iWidth;
TInt h = p.iYuvConv.iBlkSize.iHeight;
for( TInt y=0; y<h; y++ )
{
TInt cu = 0;
TInt cv = 0;
for( TInt x=0; x<w; x++ )
{
TInt cy = *cY++;
if( ( x & 1 ) == 0 )
{
// for every even X, fetch new color components
cu = *cU++ - 128;
cv = *cV++ - 128;
}
// urgb color
TUint32 c;
// rgb color component
TInt cc;
// add red
cc = cy + ( 359 * cv ) / 256;
if( cc < 0 ) cc = 0;
if( cc > 255 ) cc = 255;
c = cc << 16;
// add green
cc = cy - ( 88 * cu + 183 * cv ) / 256;
if( cc < 0 ) cc = 0;
if( cc > 255 ) cc = 255;
c |= cc << 8;
// add blue
cc = cy + ( 454 * cu ) / 256;
if( cc < 0 ) cc = 0;
if( cc > 255 ) cc = 255;
// write to bitmap
*rgb++ = c + cc;
}
rgb += modulo;
}
}
void CJpeg::Yuv2RgbFree( TAny* aPtr )
{
CJpeg& p = *(CJpeg*)aPtr;
TInt bw = p.iYuvConv.iBlkSize.iWidth;
TInt bh = p.iYuvConv.iBlkSize.iHeight;
TInt y1y = 0;
TInt y1u = 0;
TInt y1v = 0;
TInt yw = p.iComponent[ 0 ].iXFactor * p.iYuvConv.iBlkPixels;
TInt uw = p.iComponent[ 1 ].iXFactor * p.iYuvConv.iBlkPixels;
TInt vw = p.iComponent[ 2 ].iXFactor * p.iYuvConv.iBlkPixels;
TUint32* rgb = p.iYuvConv.iRgb;
TInt modulo = p.iYuvConv.iRgbWidth - bw;
for( TInt y=0; y<bh; y++ )
{
TInt txy = 0;
TInt txu = 0;
TInt txv = 0;
TUint8* ccy = p.iC[ 0 ] + ( y1y/256 ) * yw;
TUint8* ccu = p.iC[ 1 ] + ( y1u/256 ) * uw;
TUint8* ccv = p.iC[ 2 ] + ( y1v/256 ) * vw;
for( TInt x=0; x<bw; x++ )
{
TInt cy = ccy[ txy / 256 ];
TInt cu = ccu[ txu / 256 ] - 128;
TInt cv = ccv[ txv / 256 ] - 128;
txy += p.iYxa;
txu += p.iUxa;
txv += p.iVxa;
// urgb color
TUint32 c;
// rgb color component
TInt cc;
// add red
cc = cy + ( 359 * cv ) / 256;
if( cc < 0 ) cc = 0;
if( cc > 255 ) cc = 255;
c = cc << 16;
// add green
cc = cy - ( 88 * cu + 183 * cv ) / 256;
if( cc < 0 ) cc = 0;
if( cc > 255 ) cc = 255;
c |= cc << 8;
// add blue
cc = cy + ( 454 * cu ) / 256;
if( cc < 0 ) cc = 0;
if( cc > 255 ) cc = 255;
// write to bitmap
*rgb++ = c + cc;
}
y1y += p.iYya;
y1u += p.iUya;
y1v += p.iVya;
rgb += modulo;
}
}
void CJpeg::EnableRgvConv()
{
iRgbConv = true;
}
void CJpeg::DisableRgbConv()
{
iRgbConv = false;
}
TBitmapHandle CJpeg::LoadImageL( TRect& aRect )
{
//
// Crop possible illegal rect
//
//aRect.BoundingRect( TRect( iData.iSize ) );
if( aRect.iTl.iX < 0 ) aRect.iTl.iX = 0;
if( aRect.iTl.iY < 0 ) aRect.iTl.iY = 0;
if( aRect.iBr.iX < 0 ) aRect.iBr.iX = 0;
if( aRect.iBr.iY < 0 ) aRect.iBr.iY = 0;
if( aRect.iTl.iX > iData.iSize.iWidth ) aRect.iTl.iX = iData.iSize.iWidth;
if( aRect.iTl.iY > iData.iSize.iHeight ) aRect.iTl.iY = iData.iSize.iHeight;
if( aRect.iBr.iX > iData.iSize.iWidth ) aRect.iBr.iX = iData.iSize.iWidth;
if( aRect.iBr.iY > iData.iSize.iHeight ) aRect.iBr.iY = iData.iSize.iHeight;
//
// Create rectangle of blocks that has all the pixels of aRect
//
TRect blockRect = aRect;
blockRect.iTl.iX /= iData.iBlockSize.iWidth;
blockRect.iBr.iX /= iData.iBlockSize.iWidth;
blockRect.iTl.iY /= iData.iBlockSize.iHeight;
blockRect.iBr.iY /= iData.iBlockSize.iHeight;
if( aRect.iBr.iX & ( iData.iBlockSize.iWidth - 1 ) )
{
blockRect.iBr.iX++;
}
if( aRect.iBr.iY & ( iData.iBlockSize.iHeight - 1 ) )
{
blockRect.iBr.iY++;
}
//
// Return the real 1:1 scale pixel rectangle back in aRect
//
aRect.iTl.iX = blockRect.iTl.iX * iData.iBlockSize.iWidth;
aRect.iTl.iY = blockRect.iTl.iY * iData.iBlockSize.iHeight;
aRect.iBr.iX = blockRect.iBr.iX * iData.iBlockSize.iWidth;
aRect.iBr.iY = blockRect.iBr.iY * iData.iBlockSize.iHeight;
// decode area size in blocks
TSize blockSize = blockRect.Size();
// create bitmap
TBitmapHandle bm;
bm.iSize.iWidth = iData.iBlockSize.iWidth * blockSize.iWidth;
bm.iSize.iHeight = iData.iBlockSize.iHeight * blockSize.iHeight;
//
// If not whole image decode, random access must be initialized
//
if( iData.iSizeInBlocks != blockSize )
{
ScanRandomL();
}
//
// ...and decode
//
switch( iScale )
{
case EScale1:
{
bm.iData = new( ELeave )TUint32[ bm.iSize.iWidth * bm.iSize.iHeight ];
CleanupStack::PushL( bm.iData );
DecRgb1_1L( bm, blockRect );
CleanupStack::Pop( bm.iData );
break;
}
case EScale2:
{
bm.iSize.iWidth /= 2;
bm.iSize.iHeight /= 2;
bm.iData = new( ELeave )TUint32[ bm.iSize.iWidth * bm.iSize.iHeight ];
CleanupStack::PushL( bm.iData );
DecRgb1_2L( bm, blockRect );
CleanupStack::Pop( bm.iData );
break;
}
case EScale4:
{
bm.iSize.iWidth /= 4;
bm.iSize.iHeight /= 4;
bm.iData = new( ELeave )TUint32[ bm.iSize.iWidth * bm.iSize.iHeight ];
CleanupStack::PushL( bm.iData );
DecRgb1_4L( bm, blockRect );
CleanupStack::Pop( bm.iData );
break;
}
case EScale8:
{
bm.iSize.iWidth /= 8;
bm.iSize.iHeight /= 8;
bm.iData = new( ELeave )TUint32[ bm.iSize.iWidth * bm.iSize.iHeight ];
CleanupStack::PushL( bm.iData );
DecRgb1_8L( bm, blockRect );
CleanupStack::Pop( bm.iData );
break;
}
}
return bm;
}