diff -r 57d4cdd99204 -r edfc90759b9f imageeditorengine/JpegRotator/src/CJpRotate.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imageeditorengine/JpegRotator/src/CJpRotate.cpp Fri Jan 29 13:53:17 2010 +0200 @@ -0,0 +1,1679 @@ +/* +* 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 "CJpRotate.h" +#include "MJpRotateCallBack.h" +#include "CExifParser.h" + +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 + }; + +const TUint8 KReZig[] = { + 0,2,1,5,4,3,9,8, + 7,6,14,13,12,11,10,20, + 19,18,17,16,15,27,26,25, + 24,23,22,21,35,34,33,32, + 31,30,29,28,42,41,40,39, + 38,37,36,48,47,46,45,44, + 43,53,52,51,50,49,57,56, + 55,54,60,59,58,62,61,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 ]; + }; + + +CJpRotate* CJpRotate::NewL( RFs& aFs, RFile* aSaveFile, TInt aSaveBufSize ) + { + CJpRotate* self = NewLC( aFs, aSaveFile, aSaveBufSize ); + CleanupStack::Pop( self ); + return self; + } + + +CJpRotate* CJpRotate::NewLC( RFs& aFs, RFile* aSaveFile, TInt aSaveBufSize ) + { + CJpRotate* self = new( ELeave )CJpRotate( aFs, aSaveFile, aSaveBufSize ); + CleanupStack::PushL( self ); + self->ConstructL(); + return self; + } + + +CJpRotate::~CJpRotate() + { + delete iHuffman[ 0 ]; + delete iHuffman[ 1 ]; + delete iHuffman[ 2 ]; + delete iHuffman[ 3 ]; + + delete iSaveHuffman[ 0 ]; + delete iSaveHuffman[ 1 ]; + delete iSaveHuffman[ 2 ]; + delete iSaveHuffman[ 3 ]; + + delete iQt[ 0 ]; + delete iQt[ 1 ]; + delete iQt[ 2 ]; + delete iQt[ 3 ]; + + if( iOwnBuffer ) + { + delete iBuffer; + } + delete iSaveBuf; + iBasicBlock.Reset(); + + if( &iSaveFile != NULL ) + { + iSaveFile.Flush(); + iSaveFile.Close(); + } + } + +CJpRotate::CJpRotate( RFs& aFs, RFile* aSaveFile, TInt aSaveBufSize ) + : iCancelled(EFalse) + , iFs( aFs ) + , iSaveFile( *aSaveFile ) + , iSaveBufSize( aSaveBufSize ) + { + + } + +void CJpRotate::ConstructL() + { + } + + + +void CJpRotate::SetCallBack( MJpRotateCallBack* aCallBack ) + { + iCallBack = aCallBack; + } + +void CJpRotate::Cancel() + { + iCancelled = ETrue; + } + + + +void CJpRotate::RotateL( const TFileName& aFile, TBool aRotate, TBool aFlip, TBool aMirror ) + { + + iCancelled = EFalse; + + if (iBuffer) + { + delete iBuffer; + iBuffer = NULL; + } + + RFile file; + TInt err = file.Open( iFs, aFile, EFileRead | EFileShareReadersOnly ); + if (KErrNone != err) + { + User::LeaveIfError( file.Open( iFs, aFile, EFileRead | EFileShareAny ) ); + } + CleanupClosePushL( file ); + + TInt size; + file.Size( size ); + iOwnBuffer = true; + iBuffer = new( ELeave )TUint8[ size + 2 ]; + TPtr8 ptr( iBuffer, size ); + file.Read( ptr ); + + CleanupStack::PopAndDestroy( 1 ); // file + RotateL( ptr, aRotate, aFlip, aMirror ); + } + + + +void CJpRotate::RotateL( const TPtrC8& aData, TPtrC8& aTarget, TBool aRotate, TBool aFlip, TBool aMirror ) + { + iOwnBuffer = false; + RotateL( aData, aRotate, aFlip, aMirror ); + + aTarget.Set( iSaveBuf, iSaveBufPos ); + } + + + +void CJpRotate::RotateL( const TPtrC8& aData, TBool aRotate, TBool aFlip, TBool aMirror ) + { + + iFlip = aFlip; + iMirror = aMirror; + iRotate = aRotate; + if( iRotate ) + { + if( iFlip ) + { + iFlip = false; + } + else + { + iFlip = true; + } + } + + + iBuffer = (TUint8*)aData.Ptr(); + + iSaveBuf = new( ELeave )TUint8[ iSaveBufSize ]; + //Mem::FillZ( iSaveBuf, iS ); + iSaveByte = 0; + iSaveBufPos = 0; + iSaveBufBitPos = 0; + + // 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; + //CreateDefaultHuffmanL(); + + + iQt[ 0 ] = 0; + iQt[ 1 ] = 0; + iQt[ 2 ] = 0; + iQt[ 3 ] = 0; + + + TBool moreChunks = ETrue; + TBool possibleChunk = EFalse; + + while( moreChunks ) + { + if (iCancelled) + { + return; + } + + TUint8 b = iBuffer[ iBufPos++ ]; + if( possibleChunk ) + { + possibleChunk = EFalse; + switch( b ) + { + case 0xd8: // start of image + { + WriteSaveBuffer( (TUint16)0xffd8 ); + break; + } + case 0xe0: // JFIF application segment + { + WriteSaveBuffer( (TUint16)0xffe0 ); + TInt l = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; iBufPos += 2; + WriteSaveBuffer( (TUint16)l ); + WriteSaveBuffer( iBuffer + iBufPos, l-2 ); + iBufPos += l-2; + break; + } + case 0xe1: // APP1 segment, possible EXIF + { + + TInt l = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; + iBufPos += 2; + l -= 2; + + // 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; + } + + iBufPos += 6; + l -= 6; + + iExifData = iBuffer + iBufPos; + iExifDataLength = l; + + CExifParser* p = CExifParser::NewLC(); + + TRAP_IGNORE(p->ParseL( TPtrC8( iExifData, iExifDataLength ) );); + + TPtrC8 thumb( p->ThumbData() ); + TPtrC8 saveThumb( 0,0 ); + TUint8* thumbPtr = 0; + + + if( iRotate ) + { + // + // swap width and height ( if exists ) + // + if( p->TagExist( CExifParser::ESubIfd, 0xa002 ) && + p->TagExist( CExifParser::ESubIfd, 0xa003 ) ) + { + TUint16 width = p->TagValue( CExifParser::ESubIfd, 0xa002 ); + TUint16 height = p->TagValue( CExifParser::ESubIfd, 0xa003 ); + + p->DeleteTag( CExifParser::ESubIfd, 0xa002 ); + p->DeleteTag( CExifParser::ESubIfd, 0xa003 ); + + p->AddTagL( CExifParser::ESubIfd, 0xa002, height ); + p->AddTagL( CExifParser::ESubIfd, 0xa003, width ); + } + } + + // + // Rotate thumbnail ( if exists ) + // + if( thumb.Ptr() ) + { + CJpRotate* r = CJpRotate::NewLC( iFs, NULL, 0x10000 ); + + TPtrC8 target; + r->RotateL( thumb, target, aRotate, aFlip, aMirror ); + + thumbPtr = new( ELeave )TUint8[ target.Length() ]; + Mem::Copy( thumbPtr, target.Ptr(), target.Length() ); + saveThumb.Set( thumbPtr, target.Length() ); + + CleanupStack::PopAndDestroy( r ); + CleanupStack::PushL( thumbPtr ); + } + + + TPtrC8 exif = p->SaveL( saveThumb ); + + WriteSaveBuffer( (TUint16)0xffe1 ); // APP1 segment + + TUint16 l2 = exif.Length() + 6 + 2; // +header+tagsize + WriteSaveBuffer( l2 ); + + // exif header is 6 bytes ( 45 78 69 66 00 00 "Exif.." ) + WriteSaveBuffer( (TUint8)0x45 ); + WriteSaveBuffer( (TUint8)0x78 ); + WriteSaveBuffer( (TUint8)0x69 ); + WriteSaveBuffer( (TUint8)0x66 ); + WriteSaveBuffer( (TUint8)0x00 ); + WriteSaveBuffer( (TUint8)0x00 ); + + WriteSaveBuffer( exif.Ptr(), exif.Length() ); + + if( thumbPtr ) + { + CleanupStack::PopAndDestroy( thumbPtr ); + } + CleanupStack::PopAndDestroy( p ); + + + 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: + { + WriteSaveBuffer( (TUint8)0xff ); + WriteSaveBuffer( (TUint8)b ); + + TInt l = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; iBufPos += 2; + WriteSaveBuffer( (TUint16)l ); + WriteSaveBuffer( iBuffer + iBufPos, l-2 ); + + iBufPos += l-2; + break; + } + case 0xdb: // Quantization table + { + TInt l = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; iBufPos += 2; + + WriteSaveBuffer( (TUint16)0xffdb ); + WriteSaveBuffer( (TUint16)l ); + + TInt nqt = l / 65; + TInt i; + + // one or more quantization table + for( i=0; i> 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++ ]; + } + + + TUint8 qt[ 64 ]; + ConvertQuants( iQt[ n ], qt ); + WriteSaveBuffer( qt, 64 ); + } + + + break; + } + case 0xc0: // start of frame ( SOF ) + { + TInt length = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; iBufPos += 2; + + WriteSaveBuffer( (TUint16)0xffc0 ); + WriteSaveBuffer( (TUint16)length ); + + // not used: + TUint8 precision = iBuffer[ iBufPos ]; + WriteSaveBuffer( precision ); + iBufPos++; + + // height + TUint16 h = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; iBufPos += 2; + iData.iSize.iHeight = h; + + // width + TUint16 w = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; iBufPos += 2; + iData.iSize.iWidth = w; + + if( iRotate ) + { + WriteSaveBuffer( w ); + WriteSaveBuffer( h ); + } + else + { + WriteSaveBuffer( h ); + WriteSaveBuffer( w ); + } + + // component data + iNumComponents = iBuffer[ iBufPos++ ]; + WriteSaveBuffer( (TUint8)iNumComponents ); + + TInt i; + for( i=0; i> 4; + iComponent[ comp ].iYFactor = samplingFactor & 15; + iComponent[ comp ].iQuantTable = quantizationTable; + + + comp++; + + + if( iRotate ) + { + samplingFactor = samplingFactor/16 + ( samplingFactor & 15 )*16; + } + + WriteSaveBuffer( comp ); + WriteSaveBuffer( samplingFactor ); + WriteSaveBuffer( quantizationTable ); + } + + TInt xBlocks = 0; + TInt yBlocks = 0; + + for( i=0; i 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: + { + // Extended sequential Jpeg, not supported + User::Leave( KErrNotSupported ); + break; + }; + case 0xc2: + { + // Progressive DCT jpeg, not supported + User::Leave( KErrNotSupported ); + break; + }; + case 0xc3: + { + // 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: + { + User::Leave( KErrNotSupported ); + break; + }; + case 0xc4: // huffman table + { + TInt l = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; iBufPos += 2; + + + // + // Write default huffman tables + // + WriteSaveBuffer( (TUint16)0xffc4 ); + TUint16 saveLen = 2+1+16+12+1+16+12+1+16+162+1+16+162; + WriteSaveBuffer( saveLen ); + + WriteSaveBuffer( (TUint8)0 ); + WriteSaveBuffer( bits_dc_luminance+1, 16 ); + WriteSaveBuffer( val_dc_luminance, 12 ); + + WriteSaveBuffer( (TUint8)1 ); + WriteSaveBuffer( bits_dc_chrominance+1, 16 ); + WriteSaveBuffer( val_dc_chrominance, 12 ); + + WriteSaveBuffer( (TUint8)16 ); + WriteSaveBuffer( bits_ac_luminance+1, 16 ); + WriteSaveBuffer( val_ac_luminance, 20*8+2 ); + + WriteSaveBuffer( (TUint8)17 ); + WriteSaveBuffer( bits_ac_chrominance+1, 16 ); + WriteSaveBuffer( val_ac_chrominance, 20*8+2 ); + + TInt table = 0; + + TInt n = 0; + + // one or more huffman tables + while( niSymbol[ i ] = v; + n++; + } + + i = ( table & 16 ) / 8 + ( table & 15 ); + + + // Generate huffman lookup tables ( huffSize, table ) + + + TInt l; + TInt p = 0; + for( l=0; l<16; l++ ) + { + for( i=0; iiLength[ p++ ] = l+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++; + } + + l = 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; jiSearch[ j ] = i; + } + l = k; + } + + i = ( table & 16 ) / 8 + ( table & 15 ); + delete iHuffman[ i ]; + iHuffman[ i ] = huff; + } + + break; + } +// + case 0xda: // start of scan ( SOS ) + { + // write restart interval before SOS + /* + WriteSaveBuffer( (TUint16)0xffdd ); + WriteSaveBuffer( (TUint16)0x0004 ); + WriteSaveBuffer( (TUint16)1 ); // reset every (1) macroblock + */ + // SOS now: + WriteSaveBuffer( (TUint16)0xffda ); + TInt l = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; iBufPos += 2; + + WriteSaveBuffer( (TUint16)l ); + + TInt c1 = 0; + TInt c2 = 0; + TInt c3 = 0; + + TInt numComponents = iBuffer[ iBufPos++ ]; + WriteSaveBuffer( (TUint8)3 ); + TInt i; + for( i=0; i> 3 ) << 3; + TInt badBits = iBufBits - goodBits; + iBuf <<= badBits; + iBufBits = goodBits; + } + } + } + + moreChunks = EFalse; + + SaveBlocks(); + + // flush last bits to save buffer + if( iSaveBufBitPos ) + { + WriteBits( 0, 8-iSaveBufBitPos ); + } + + // EOI + + + + //iSaveBuf[ iSaveBufPos++ ] = 0xff; + //iSaveBuf[ iSaveBufPos++ ] = 0xd9; + WriteSaveBuffer( (TUint16)0xffd9 ); + + FlushSaveBuf(); + + + + break; + } + case 0xd9: // end of image ( EOI ) + { + // not really used for anything + // will exit if picture data is read. + break; + } + case 0xdd: // define restart interval + { + //TInt l = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; + iBufPos += 2; + //TInt interval = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; + iBufPos += 2; + + break; + } + case 0x00: // escaped 0xff + { + // only comes if file is broken somehow + break; + } + case 0xfe: // jpeg comment + { + TInt l = 256 * iBuffer[ iBufPos ] + iBuffer[ iBufPos + 1 ]; iBufPos += 2; + WriteSaveBuffer( (TUint16)0xfffe ); + WriteSaveBuffer( (TUint16)l ); + WriteSaveBuffer( iBuffer + iBufPos, l-2 ); + iBufPos += l-2; + break; + }; + default: + { + // unknown block + break; + } + } + } + else if( b == 255 ) + { + possibleChunk = ETrue; + } + + } + + } + + + + +void CJpRotate::BufFwd( TInt aBits ) + { + iBuf <<= aBits; + iBufBits -= aBits; + } + + + +TInt CJpRotate::BufBits( TInt aBits ) + { + if( aBits == 0 ) return 0; + while( iBufBits < aBits ) + { + BufLoad8(); + } + TInt val = iBuf >> ( 32-aBits ); + BufFwd( aBits ); + return val; + } + + + +TInt CJpRotate::Buf16() + { + while( iBufBits < 16 ) + { + BufLoad8(); + } + TInt val = iBuf >> ( 32-16 ); + return val; + } + + + +void CJpRotate::BufLoad8() + { + TInt v; + v = iBuffer[ iBufPos++ ]; + if( v == 255 ) + { + v = iBuffer[ iBufPos++ ]; // escaped 0xff ? + if( v == 0 ) + { + v = 255; + } + else if( v == 0xd9 ) // EOI + { + iEOF = true; + v = 0; + } + else + { + // here we have probably discarded a RST0 or similar + v = iBuffer[ iBufPos++ ]; + iRst = ETrue; + } + } + + v <<= ( 24 - iBufBits ); + iBuf |= v; + iBufBits += 8; + } + + + +void CJpRotate::DecodeBlockL( TInt aDc ) + { + + // + // Dummy version of block decode + // only traverses through huffman data + // and collects DC-values + // + TInt16 vals[ 64 ]; + TUint16 bits[ 64 ]; + TUint8 lens[ 64 ]; + + Mem::FillZ( vals, 64*2 ); + Mem::FillZ( bits, 64*2 ); + Mem::FillZ( lens, 64 ); + + //for( TInt i=0; i<64; i++ ) lens[ i ] = 255; + + + 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 ); + + TUint16 currentBits = v; + + 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; + if( k > 63 ) break; + TInt pos = k; + if( iRotate ) pos = KReZig[ pos ]; + lens[ pos ] = symbol; + vals[ pos ] = v; + bits[ pos ] = currentBits; + } + } + else + { + h = iHuffman[ iCurrentHuffman+2 ]; // DC -> AC huffman + + lens[ 0 ] = symbol; + vals[ 0 ] = aDc / iCurrentQt[ 0 ]; + //vals[ 0 ] = aDc; + bits[ 0 ] = currentBits; + } + } + + + + TInt count; + for( count=63; count>=0; count-- ) + { + if( lens[ count ] != 0 ) break; + } + if( count < 0 ) count = 0; + + TInt nullCount = 0; + + // + // Write DC + // + + TInt value = vals[ 0 ]; + bool minus = false; + if( value < 0 ) + { + minus = true; + value = -value; + } + TInt v = value; + TInt vl = 0; + + while( v ) + { + v >>= 1; + vl++; + } + + if( minus ) + { + TInt a = ( 1 << vl ) - 1; + value ^= a; + } + + WriteHuffmanL( vl ); + WriteBits( value, vl ); + + // DC -> AC huffman + if( iCurrentSaveHuffman == iSaveHuffman[ 0 ] ) + { + iCurrentSaveHuffman = iSaveHuffman[ 2 ]; + } + else if( iCurrentSaveHuffman == iSaveHuffman[ 1 ] ) + { + iCurrentSaveHuffman = iSaveHuffman[ 3 ]; + } + // + // Write AC + // + for( k=1; k<=count; k++ ) + { + + if( vals[ k ] == 0 ) + { + nullCount++; + if( nullCount == 16 ) + { + // write nullCount 15 with value 0 + WriteHuffmanL( 15 * 16 ); + nullCount = 0; + } + } + else + { + // write bits & nullCount huffman coded + + TUint8 neg = 0; + TInt p = KZigZag[ k ]; + if( p & 8 && iMirror ) neg = 1; + if( p & 1 && iFlip ) neg ^= 1; + + TUint16 b = bits[ k ]; + TInt l = lens[ k ]; + TInt v = vals[ k ]; + if( neg ) + { + if( v>0 ) + { + b = v ^ ( ( 1 << l ) - 1 ); + } + else + { + b = -v; + } + + } + + WriteHuffmanL( l + nullCount * 16 ); + WriteBits( b,l ); + + nullCount = 0; + } + } + if( count != 63 ) + { + WriteHuffmanL( 0 ); + } + + } + + + +void CJpRotate::DecodeBlock2L() + { + + THuffman* h = iHuffman[ iCurrentHuffman ]; + + TInt k; + + TJpegBasicBlock bl; + bl.iOffset = iBufPos; + bl.iBuf = iBuf; + bl.iBufBits = iBufBits; + + + 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 ]; + } + + } + + bl.iDc = iDct[ 0 ]; + + User::LeaveIfError(iBasicBlock.Append( bl )); + + //Idct(); + } + + + + +const TJpegData& CJpRotate::Info() + { + return iData; + } + + +TPtrC8 CJpRotate::ExifData() + { + return TPtrC8( iExifData, iExifDataLength ); + } + + + + +void CJpRotate::WriteHuffmanL( TInt aValue ) + { + TInt code = iCurrentSaveHuffman->iCode[ aValue ]; + TInt len = iCurrentSaveHuffman->iLength[ aValue ]; + if( aValue != 0 && len == 0 ) + { + // + // The value which we tried to write doesn't exist in + // the huffman table. Therefore the output would be + // corrupted. Thus the leave. + // actually this should not happen ever. + // + User::Leave( KErrCorrupt ); + } + WriteBits( code, len ); + } + + + +void CJpRotate::WriteBits( TUint32 aValue, TInt aNumBits ) + { + + aValue &= ( ( 1 << aNumBits ) - 1 ); + while( aNumBits > 0 ) + { + TInt bitroom = 8 - iSaveBufBitPos; + //iSaveBuf[ iSaveBufPos ] |= ( ( aValue << ( 24+bitroom-aNumBits ) ) >> 24 ); + iSaveByte |= ( ( aValue << ( 24+bitroom-aNumBits ) ) >> 24 ); + + if( aNumBits < bitroom ) + { + iSaveBufBitPos += aNumBits; + } + else + { + iSaveBufBitPos += bitroom; + } + + if( iSaveBufBitPos == 8 ) + { + + iSaveBufBitPos = 0; + iSaveBuf[ iSaveBufPos ] = iSaveByte; + + if( iSaveByte == 255 ) + { + iSaveBufPos++; + if( iSaveBufPos == iSaveBufSize ) + { + FlushSaveBuf(); + } + iSaveBuf[ iSaveBufPos ] = 0; // 255,0 = 255 ( escaped 255 ) + } + iSaveByte = 0; + iSaveBufPos++; + + if( iSaveBufPos == iSaveBufSize ) + { + FlushSaveBuf(); + } + + } + aNumBits -= bitroom; + } + } + + +void CJpRotate::CreateSaveHuffmanL( TSHuffman* aHuffman, const TUint8* aBits, const TUint8* aVal ) + { + + + TInt huffSize[ 16 ]; + + TUint32 huffCode[ 256 ]; + TInt huffValue[ 256 ]; + TInt huffLength[ 256 ]; + + TInt numSymbols = 0; + TInt i; + + for( i=0; i<16; i++ ) + { + TInt size = aBits[ i+1 ]; + huffSize[ i ] = size; + numSymbols += size; + } + + for( i=0; iiLength[ v ] = huffLength[ i ]; + aHuffman->iCode[ v ] = huffCode[ i ]; + } + + + } + + +void CJpRotate::ConvertQuants( TUint8* aSrc, TUint8* aTgt ) + { + if( ! iRotate ) + { + Mem::Copy( aTgt, aSrc, 64 ); + return; + } + + for( TInt i=0; i<64; i++ ) + { + aTgt[ KReZig[ i ] ] = aSrc[ i ]; + } + } + + + +void CJpRotate::WriteSaveBuffer( const TUint8* aSrc, TInt aBytes ) + { + TInt pos = 0; + while( aBytes ) + { + TInt bytes = aBytes; + if( iSaveBufPos + bytes > iSaveBufSize ) + { + bytes = iSaveBufSize - iSaveBufPos; + } + Mem::Copy( iSaveBuf + iSaveBufPos, aSrc + pos, bytes ); + iSaveBufPos += bytes; + if( iSaveBufPos == iSaveBufSize ) + { + FlushSaveBuf(); + } + aBytes -= bytes; + pos += bytes; + } + } + + +void CJpRotate::WriteSaveBuffer( TUint8 aValue ) + { + iSaveBuf[ iSaveBufPos++ ] = aValue; + if( iSaveBufPos == iSaveBufSize ) + { + FlushSaveBuf(); + } + } + + +void CJpRotate::WriteSaveBuffer( TUint16 aValue ) + { + WriteSaveBuffer( (TUint8) ( aValue / 256 ) ); + WriteSaveBuffer( (TUint8) ( aValue & 255 ) ); + } + + +void CJpRotate::SaveBlocks() + { + TInt yBlocks = iComponent[ 0 ].iXFactor * iComponent[ 0 ].iYFactor; + TInt uBlocks = iComponent[ 1 ].iXFactor * iComponent[ 1 ].iYFactor; + TInt vBlocks = iComponent[ 2 ].iXFactor * iComponent[ 2 ].iYFactor; + + TInt blocks = yBlocks + uBlocks + vBlocks; + TInt blockOffset[ 16 ]; + + TInt x; + TInt y; + + TInt i = 0; + TInt b = 0; + for( TInt comp = 0; comp= n ) v -= n; + //blockOffset[ i++ ] = b + v; + blockOffset[ b+v ] = i++; + } + } + b += c.iXFactor*c.iYFactor; + } + TInt bw = iData.iSizeInBlocks.iWidth; + TInt bh = iData.iSizeInBlocks.iHeight; + + TInt yDc = 0; + TInt uDc = 0; + TInt vDc = 0; + + TInt count = 0; + + TInt blockXAdd; + TInt blockYAdd; + TInt blockPos; + + if( iRotate ) + { + if( iMirror ) + { + if( iFlip ) + { + blockPos = blocks * ( bw * bh - 1 ); + blockXAdd = -blocks * bw; + blockYAdd = blocks * bw * bh - blocks; + } + else + { + blockPos = blocks * bw * ( bh - 1 ); + blockXAdd = -blocks * bw; + blockYAdd = blocks * bw * bh + blocks; + } + } + else + { + if( iFlip ) + { + blockPos = blocks * ( bw - 1 ); + blockXAdd = blocks * bw; + blockYAdd = -blocks * bw * bh - blocks; + } + else + { + blockPos = 0; + blockXAdd = blocks * bw; + blockYAdd = -blocks * ( bw * bh - 1 ); + } + } + TInt t = bw; bw = bh; bh = t; + } + else + { + if( iMirror ) + { + if( iFlip ) + { + blockPos = blocks * ( bw * bh - 1 ); + blockXAdd = -blocks; + blockYAdd = 0; + } + else + { + blockPos = blocks * ( bw-1 ); + blockXAdd = -blocks; + blockYAdd = bw * blocks * 2; + } + } + else + { + if( iFlip ) + { + blockPos = blocks * bw * ( bh-1 ); + blockXAdd = blocks; + blockYAdd = -blocks*bw*2; + } + else + { + blockPos = 0; + blockXAdd = blocks; + blockYAdd = 0; + } + } + } + + TInt numMacroBlocks = bw*bh; + + for( y=0; yJpRotateStatus( count, numMacroBlocks ); + } + + } + blockPos += blockYAdd; + } + + //RDebug::Print( _L("last access block :%d"), mx ); + } + + + +void CJpRotate::FlushSaveBuf() + { + if( &iSaveFile == NULL ) return; // no flushing without file + TPtr8 ptr( iSaveBuf, iSaveBufPos ); + ptr.SetLength( iSaveBufPos ); + iSaveFile.Write( ptr ); + iSaveBufPos = 0; + }