imageeditorengine/JpegRotator/src/CJpRotate.cpp
changeset 1 edfc90759b9f
--- /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<nqt; i++ )
+						{
+						TUint8 t = iBuffer[ iBufPos++ ];
+						TInt n = t & 15;
+						WriteSaveBuffer( t );
+
+						// 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++ ];
+							}
+
+
+						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<iNumComponents; i++ )
+						{
+						TUint8 comp = iBuffer[ iBufPos++ ] - 1;
+						TUint8 samplingFactor = iBuffer[ iBufPos++ ];
+						TUint8 quantizationTable = iBuffer[ iBufPos++ ];
+						iComponent[ comp ].iXFactor = samplingFactor >> 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<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:
+					{
+					// 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( n<l-2 )
+						{
+						THuffman* huff = new( ELeave )THuffman;
+					
+						table = iBuffer[ iBufPos++ ];
+						n++;
+						TUint8 huffSize[ 16 ];
+						TInt numSymbols = 0;
+						TInt i;
+
+						for( i=0; i<16; i++ )
+							{
+							TInt size = iBuffer[ iBufPos++ ];
+							huffSize[ i ] = size;
+							numSymbols += size;
+							n++;
+							}
+						
+						for( i=0; i<numSymbols; i++ )
+							{
+							TUint8 v = iBuffer[ iBufPos++ ];
+							huff->iSymbol[ 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; i<huffSize[ l ]; i++ )
+								{
+								huff->iLength[ 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; j<l; j++ )
+								{
+								huff->iSearch[ 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<numComponents; i++ )
+						{
+						TInt componentId = iBuffer[ iBufPos++ ];
+						TInt componentHt = iBuffer[ iBufPos++ ];
+						}
+					WriteSaveBuffer( (TUint8)1 );	// component 1
+					WriteSaveBuffer( (TUint8)0 );
+					
+					WriteSaveBuffer( (TUint8)2 );	// component 2
+					WriteSaveBuffer( (TUint8)17 );
+					
+					WriteSaveBuffer( (TUint8)3 );	// component 3
+					WriteSaveBuffer( (TUint8)17 );
+
+					WriteSaveBuffer( (TUint8)0 );
+					WriteSaveBuffer( (TUint8)63 );	// dctsize - 1
+					WriteSaveBuffer( (TUint8)0 );
+
+					iBufPos += 3;
+					
+					//
+					// Create default huffman tables for save
+					//
+					TSHuffman* huff = new( ELeave )TSHuffman;
+					CreateSaveHuffmanL( huff, bits_dc_luminance, val_dc_luminance );
+					iSaveHuffman[ 0 ] = huff;
+
+					huff = new( ELeave )TSHuffman;
+					CreateSaveHuffmanL( huff, bits_dc_chrominance, val_dc_chrominance );
+					iSaveHuffman[ 1 ] = huff;
+
+					huff = new( ELeave )TSHuffman;
+					CreateSaveHuffmanL( huff, bits_ac_luminance, val_ac_luminance );
+					iSaveHuffman[ 2 ] = huff;
+					
+					huff = new( ELeave )TSHuffman;
+					CreateSaveHuffmanL( huff, bits_ac_chrominance, val_ac_chrominance );
+					iSaveHuffman[ 3 ] = huff;
+
+					
+
+					// decode
+					
+					TInt bw = iData.iSizeInBlocks.iWidth;
+					TInt bh = iData.iSizeInBlocks.iHeight;
+
+					TInt bx;
+					TInt by;
+
+					for( by=0; by<bh; by++ )
+						{
+						for( bx=0; bx<bw; bx++ )
+							{
+							if( iRst )
+								{
+								// reset marker zeroes DC-values
+								c1 = 0;
+								c2 = 0;
+								c3 = 0;
+								iRst = EFalse;
+								}
+							
+							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++ )
+								{
+								DecodeBlock2L();
+								}
+							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++ )
+								{
+								DecodeBlock2L();
+								}
+							c2 = iDct[ 0 ];
+
+							iCurrentSaveHuffman = iSaveHuffman[ 1 ];
+							// V-component
+							n = iComponent[ 1 ].iXFactor * iComponent[ 1 ].iYFactor;
+							iDct[ 0 ] = c3;
+							for( i=0; i<n; i++ )
+								{
+								DecodeBlock2L();
+								}
+							c3 = iDct[ 0 ];
+
+							// take care of RST0's leftover bits:
+							if( iRst )
+								{
+								TInt goodBits = ( iBufBits >> 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; i<numSymbols; i++ )
+		{
+		huffValue[ i ] = aVal[ i ];
+		}
+	
+	TInt l;
+	TInt p = 0;
+	for( i=0; i<256; i++ ) huffLength[ i ] = -1;
+	for( l=0; l<16; l++ )
+		{
+		for( i=0; i<huffSize[ l ]; i++ )
+			{
+			huffLength[ p++ ] = l+1;
+			}
+		}
+
+	TInt code = 0;
+	huffLength[ p ] = 0;
+	TInt si = huffLength[ 0 ];
+	
+	p = 0;
+
+	while( huffLength[ p ] )
+		{
+		while( huffLength[ p ] == si )
+			{
+			huffCode[ p++ ] = code++;
+			}
+		code *= 2;
+		si++;
+		}
+
+	for( i=0; i<numSymbols; i++ )
+		{
+		TInt v = huffValue[ i ];
+		aHuffman->iLength[ 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<iNumComponents; comp++ )
+		{
+		TComponent& c = iComponent[ comp ];
+
+		for( y=0; y<c.iYFactor; y++ )
+			{
+			for( x=0; x<c.iXFactor; x++ )
+				{
+				TInt xx = x;
+				TInt yy = y;
+				TInt fx = c.iXFactor;
+				TInt fy = c.iYFactor;
+				
+
+				if( iRotate )
+					{
+					TInt t = xx; xx = yy; yy = t;
+					if( iFlip ) yy = fx - 1 - yy;
+					if( iMirror ) xx = fy - 1 - xx;
+					t = fx; fx=fy; fy = t;
+					}
+				else
+					{
+					if( iFlip ) yy = fy - 1 - yy;
+					if( iMirror ) xx = fx - 1 - xx;
+					}
+
+				TInt v = xx + yy * fx; //1302
+				//while( v >= 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; y<bh; y++ )
+		{
+		for( x=0; x<bw; x++ )
+			{
+
+			iCurrentQt = iQt[ 0 ];
+			TInt i = 0;
+			TInt n;
+			for( n=0; n<yBlocks; n++ )
+				{
+				TInt bo = blockOffset[ i++ ];
+				TJpegBasicBlock& bl = iBasicBlock[ blockPos + bo ];
+				iBuf = bl.iBuf;
+				iBufPos = bl.iOffset;
+				iBufBits = bl.iBufBits;
+
+				iCurrentHuffman = 0;
+				iCurrentSaveHuffman = iSaveHuffman[ 0 ];
+				DecodeBlockL( bl.iDc - yDc );
+				yDc = bl.iDc;
+				}
+
+			iCurrentQt = iQt[ 1 ];
+
+			for( n=0; n<uBlocks; n++ )
+				{
+				TJpegBasicBlock& bl = iBasicBlock[ blockPos + blockOffset[ i++ ] ];
+				iBuf = bl.iBuf;
+				iBufPos = bl.iOffset;
+				iBufBits = bl.iBufBits;
+
+				iCurrentHuffman = 1;
+				iCurrentSaveHuffman = iSaveHuffman[ 1 ];
+				DecodeBlockL( bl.iDc - uDc );
+				uDc = bl.iDc;
+				}
+
+			for( n=0; n<vBlocks; n++ )
+				{
+				TJpegBasicBlock& bl = iBasicBlock[ blockPos + blockOffset[ i++ ] ];
+				iBuf = bl.iBuf;
+				iBufPos = bl.iOffset;
+				iBufBits = bl.iBufBits;
+
+				iCurrentHuffman = 1;
+				iCurrentSaveHuffman = iSaveHuffman[ 1 ];
+				DecodeBlockL( bl.iDc - vDc );
+				vDc = bl.iDc;
+				}
+
+
+			//
+			// Rst ( 0xFFD0..0xFFD7 ) after each macroblock
+			//
+			/*
+			if( iSaveBufBitPos ) 
+				{
+				WriteBits( 0,8-iSaveBufBitPos );
+				}
+			WriteSaveBuffer( (TUint16)( 0xffd0 + (count & 7 ) ) );
+			
+			yDc = 0;
+			uDc = 0;
+			vDc = 0;
+			
+			count++;
+			*/
+
+			blockPos += blockXAdd;
+
+			if( iCallBack )
+				{
+				iCallBack->JpRotateStatus( 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;
+	}