imageeditorengine/JpegScaler/src/CJpegScale.cpp
changeset 1 edfc90759b9f
equal deleted inserted replaced
0:57d4cdd99204 1:edfc90759b9f
       
     1 /*
       
     2 * Copyright (c) 2010 Ixonos Plc.
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - Initial contribution
       
    11 *
       
    12 * Contributors:
       
    13 * Ixonos Plc
       
    14 *
       
    15 * Description:  
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 #include "CJpegScale.h"
       
    21 #include "CJpeg.h"
       
    22 #include "CJpegSave.h"
       
    23 #include "CExifParser.h"
       
    24 
       
    25 
       
    26 CJpegScale::CJpegScale( MJpegScaleCallBack* aCallBack )
       
    27 	: iTargetScale( 0 )
       
    28 	, iQuality( 95 )
       
    29 	, iCallBack( aCallBack )
       
    30 	{
       
    31 	}
       
    32 	
       
    33 
       
    34 	
       
    35 CJpegScale::~CJpegScale()
       
    36 	{
       
    37 	}
       
    38 	
       
    39 
       
    40 	
       
    41 	
       
    42 void CJpegScale::ScaleL()
       
    43 	{
       
    44 	const TInt KxShift = 14;
       
    45 	const TInt KxMul = ( 1 << KxShift );
       
    46 	const TInt KxAnd = KxMul - 1;	
       
    47 	
       
    48 	CJpeg* source;
       
    49 	CJpegSave* target;
       
    50 	
       
    51 	// file server session
       
    52 	RFs fs;
       
    53 	User::LeaveIfError( fs.Connect() );
       
    54 	CleanupClosePushL( fs );
       
    55 	
       
    56 	// encoded file
       
    57 	RFile targetFile;
       
    58 	User::LeaveIfError( targetFile.Replace( fs, iTargetName, EFileWrite ) );
       
    59 	CleanupClosePushL( targetFile );
       
    60 	
       
    61 	// jpeg source
       
    62 	source = CJpeg::NewL();
       
    63 	CleanupStack::PushL( source );
       
    64 	
       
    65 	// jpeg target
       
    66 	target = CJpegSave::NewL( &fs, &targetFile );
       
    67 	CleanupStack::PushL( target );
       
    68 
       
    69 	source->OpenL( iSourceName );
       
    70 	
       
    71 	TJpegData info = source->Info();
       
    72 
       
    73 	TInt tw = iTargetSize.iWidth;
       
    74 	TInt th = iTargetSize.iHeight;
       
    75 	
       
    76 	TInt sw = info.iSize.iWidth;
       
    77 	TInt sh = info.iSize.iHeight;
       
    78 
       
    79 	TInt xscale;
       
    80 	TInt yscale;
       
    81 
       
    82 	//
       
    83 	// Decide scale or target size
       
    84 	//
       
    85 	if( iTargetScale != 0 )
       
    86 		{
       
    87 		xscale = (TInt)(iTargetScale * KxMul);
       
    88 		yscale = xscale;
       
    89 		tw = xscale * sw / KxMul;
       
    90 		th = yscale * sh / KxMul;
       
    91 		}
       
    92 	else
       
    93 		{
       
    94 		yscale = KxMul * th / sh;
       
    95 		xscale = KxMul * tw / sw;
       
    96 		}
       
    97 
       
    98 	if( tw>sw || th>sh )
       
    99 		{
       
   100 		// no upscaling yet.
       
   101 		User::Leave( KErrNotSupported );
       
   102 		}
       
   103 
       
   104 	//
       
   105 	// Hardscale is scaling which is done in jpeg decoder
       
   106 	// possible hardscales are 1:1, 1:2, 1:4 and 1:8
       
   107 	// hard scaling speeds up things a lot.
       
   108 	//
       
   109 	TInt hardScale = 1;
       
   110 	source->SetScale( EScale1 );
       
   111 
       
   112 	if( xscale <= KxMul/8 && yscale <= KxMul/8 )
       
   113 		{
       
   114 		hardScale = 8;
       
   115 		source->SetScale( EScale8 );
       
   116 		}
       
   117 
       
   118 	else if( xscale <= KxMul/4 && yscale <= KxMul/4 )
       
   119 		{
       
   120 		hardScale = 4;
       
   121 		source->SetScale( EScale4 );
       
   122 		}
       
   123 
       
   124 	else if( xscale <= KxMul/2 && yscale <= KxMul/2 )
       
   125 		{
       
   126 		hardScale = 2;
       
   127 		source->SetScale( EScale2 );
       
   128 		}
       
   129 	// else hardscale = 1
       
   130 
       
   131 
       
   132 	sw /= hardScale;
       
   133 	sh /= hardScale;
       
   134 	xscale *= hardScale;
       
   135 	yscale *= hardScale;
       
   136 	
       
   137 
       
   138 	//
       
   139 	// Jpeg store bitmap block
       
   140 	// Jpeg encoder always uses block size of 16x8 pixels
       
   141 	//
       
   142 	TBitmapHandle blk;
       
   143 	blk.iSize = TSize( 16,8 );
       
   144 	blk.iData = new( ELeave )TUint32[ 16*8 ];
       
   145 	CleanupStack::PushL( blk.iData );
       
   146 
       
   147 	iTargetSize = TSize( tw,th );
       
   148 		
       
   149 	CExifParser* parser = CExifParser::NewLC();
       
   150 	parser->ParseL(source->ExifData());
       
   151 	
       
   152     // ImageWidth - Not used for JPEG images 
       
   153     if (parser->TagExist(CExifParser::EIfd0, 0x0100))
       
   154     {
       
   155         parser->DeleteTag ( CExifParser::EIfd0, 0x0100);
       
   156         //iExifParser->AddTagL ( CExifParser::EIfd0, 0x0100, (TUint16)iTargetSize.iWidth);        
       
   157     }
       
   158 
       
   159     // ImageHeight - Not used for JPEG images 
       
   160     if (parser->TagExist(CExifParser::EIfd0, 0x0101))
       
   161     {
       
   162         parser->DeleteTag ( CExifParser::EIfd0, 0x0101);
       
   163         //iExifParser->AddTagL ( CExifParser::EIfd0, 0x0101, (TUint16)iTargetSize.iHeight);
       
   164     }
       
   165 	    
       
   166 	// PixelXResolution 
       
   167     if (parser->TagExist(CExifParser::ESubIfd, 0xA002))
       
   168     {
       
   169         parser->DeleteTag ( CExifParser::ESubIfd, 0xA002);
       
   170         parser->AddTagL ( CExifParser::ESubIfd, 0xA002,(TUint32)iTargetSize.iWidth);
       
   171     }
       
   172     // PixelYResolution 
       
   173     if (parser->TagExist(CExifParser::ESubIfd, 0xA003))
       
   174     {
       
   175         parser->DeleteTag ( CExifParser::ESubIfd, 0xA003);
       
   176         parser->AddTagL ( CExifParser::ESubIfd, 0xA003, (TUint32)iTargetSize.iHeight);
       
   177     }
       
   178 
       
   179     TPtr8 exif = parser->SaveL(parser->ThumbData());
       
   180 	
       
   181 	//
       
   182 	// Initialize jpeg encoder
       
   183 	// no exif
       
   184 	// save buffer ~16KB
       
   185 	// use iQuality as quality ( values from 0 to 100 )
       
   186 	//
       
   187 	target->StartSaveL( iTargetSize, exif, 16000, iQuality );
       
   188 	
       
   189 	CleanupStack::PopAndDestroy(); // parser
       
   190     	
       
   191 	TInt yStep = 8;		// jpeg encoder block height
       
   192 	TInt yPos = 0;		// number of encoded lines
       
   193 	
       
   194 	//
       
   195 	// Reserve scaled buffer
       
   196 	//
       
   197 	TInt pixels = tw * ( yStep*2 ); // room for 2 block lines
       
   198 
       
   199 	TUint32* cr = new( ELeave )TUint32[ pixels ];
       
   200 	CleanupStack::PushL( cr );
       
   201 	TUint32* cg = new( ELeave )TUint32[ pixels ];
       
   202 	CleanupStack::PushL( cg );
       
   203 	TUint32* cb = new( ELeave )TUint32[ pixels ];
       
   204 	CleanupStack::PushL( cb );
       
   205 	TUint32* cm = new( ELeave )TUint32[ pixels ];
       
   206 	CleanupStack::PushL( cm );
       
   207 
       
   208 	//
       
   209 	// Clear scaled buffer
       
   210 	//
       
   211 	Mem::FillZ( cr, pixels * sizeof( TUint32 ) );
       
   212 	Mem::FillZ( cg, pixels * sizeof( TUint32 ) );
       
   213 	Mem::FillZ( cb, pixels * sizeof( TUint32 ) );
       
   214 	Mem::FillZ( cm, pixels * sizeof( TUint32 ) );
       
   215 	
       
   216 
       
   217 	TInt srcBlockHeight = info.iBlockSize.iHeight;
       
   218 	
       
   219 	TInt srcY1 = 0;
       
   220 	TInt srcY2 = 0;
       
   221 	TBitmapHandle bm;
       
   222 	bm.iData = 0;
       
   223 
       
   224 	for( TInt y=0; y<sh; y++ )
       
   225 		{
       
   226 		if( iCallBack )
       
   227 			{
       
   228 			iCallBack->JpegStatusCallBack( 100 * y / sh );
       
   229 			}
       
   230 		//
       
   231 		// Fill source buffer when needed
       
   232 		//
       
   233 		if( srcY2 <= y )
       
   234 			{
       
   235 			delete bm.iData;
       
   236 			TRect rect( 0,y*hardScale, info.iSize.iWidth, ( y + srcBlockHeight ) * hardScale );
       
   237 			bm = source->LoadImageL( rect );
       
   238 			srcY1 = y;
       
   239 			srcY2 = srcY1 + bm.iSize.iHeight;
       
   240 			}
       
   241 
       
   242 		TUint32* srcRgb = (TUint32*)bm.iData;
       
   243 		srcRgb += (y-srcY1) * bm.iSize.iWidth;
       
   244 
       
   245 		TInt ty = y * yscale;
       
   246 		TInt y2 = ty & KxAnd;
       
   247 		TInt y1 = KxMul - y2;
       
   248 		ty >>= KxShift;
       
   249 		
       
   250 		TInt oy = ( ty - yPos ) * tw;
       
   251 		TUint32* pr = cr + oy;
       
   252 		TUint32* pg = cg + oy;
       
   253 		TUint32* pb = cb + oy;
       
   254 		TUint32* pm = cm + oy;
       
   255 
       
   256 		//
       
   257 		// Add pixels to scaled buffer
       
   258 		//
       
   259 		for( TInt x=0; x<sw; x++ )
       
   260 			{
       
   261 			TInt tx = x * xscale;
       
   262 			TInt x2 = tx & KxAnd;
       
   263 			TInt x1 = KxMul - x2;
       
   264 			tx >>= KxShift;
       
   265 			
       
   266 			TUint32 pixel = *srcRgb++;
       
   267 
       
   268 			TUint32 m1 = x1*y1 / KxMul;
       
   269 			TUint32 m2 = x2*y1 / KxMul;
       
   270 			TUint32 m3 = x1*y2 / KxMul;
       
   271 			TUint32 m4 = x2*y2 / KxMul;
       
   272 			
       
   273 			TInt red = pixel >> 16;
       
   274 			pr[ tx ] += m1 * red;
       
   275 			pr[ tx+1 ] += m2 * red;
       
   276 			pr[ tx+tw ] += m3 * red;
       
   277 			pr[ tx+tw+1 ] += m4 * red;
       
   278 
       
   279 			TInt green = ( pixel >> 8 ) & 255;
       
   280 			pg[ tx ] += m1 * green;
       
   281 			pg[ tx+1 ] += m2 * green;
       
   282 			pg[ tx+tw ] += m3 * green;
       
   283 			pg[ tx+tw+1 ] += m4 * green;
       
   284 
       
   285 			TInt blue = pixel & 255;
       
   286 			pb[ tx ] += m1 * blue;
       
   287 			pb[ tx+1 ] += m2 * blue;
       
   288 			pb[ tx+tw ] += m3 * blue;
       
   289 			pb[ tx+tw+1 ] += m4 * blue;
       
   290 
       
   291 			pm[ tx ] += m1;
       
   292 			pm[ tx+1 ] += m2;
       
   293 			pm[ tx+tw ] += m3;
       
   294 			pm[ tx+tw+1 ] += m4;
       
   295 			}
       
   296 
       
   297 
       
   298 		//
       
   299 		// Transfer scaled buffer block-by-block to jpeg encoder
       
   300 		//
       
   301 		if( ty >= yPos + yStep || y == sh-1 )
       
   302 			{
       
   303 			yPos += yStep;
       
   304 
       
   305 			TUint32* trgb = (TUint32*)blk.iData;
       
   306 			
       
   307 			for( TInt b=0; b<tw; b += 16 )
       
   308 				{
       
   309 				TUint32* p = trgb;
       
   310 				for( TInt by=0; by<8; by++ )
       
   311 				for( TInt bx=0; bx<16; bx++ )
       
   312 					{
       
   313 					TUint32 pos = b + bx + by*tw;
       
   314 					TUint32 bcr = cr[ pos ];
       
   315 					TUint32 bcg = cg[ pos ];
       
   316 					TUint32 bcb = cb[ pos ];
       
   317 					TUint32 m = cm[ pos ];
       
   318 					if( m )
       
   319 						{
       
   320 						bcr /= m;
       
   321 						bcg /= m;
       
   322 						bcb /= m;
       
   323 						}
       
   324 					//trgb[ bx + by * 16 ] = bcr*65536 + bcg*256 + bcb;
       
   325 
       
   326 					TUint32 c = bcr << 16;
       
   327 					c += ( bcg << 8 );
       
   328 					c += bcb;
       
   329 					*p++ = c;
       
   330 					}
       
   331 				target->SaveBlock( blk );
       
   332 				}
       
   333 
       
   334 			//
       
   335 			// move overflow line to first line in scaled buffer
       
   336 			//
       
   337 			TInt offset = tw * yStep;
       
   338 			for( TInt rx=0; rx<tw; rx++ )
       
   339 				{
       
   340 				cr[ rx ] = cr[ rx + offset ];
       
   341 				cg[ rx ] = cg[ rx + offset ];
       
   342 				cb[ rx ] = cb[ rx + offset ];
       
   343 				cm[ rx ] = cm[ rx + offset ];
       
   344 
       
   345 				}
       
   346 
       
   347 			//
       
   348 			// clear all but first line from scaled buffer
       
   349 			//
       
   350 			TInt clrbytes = tw * yStep * sizeof( TUint32 );
       
   351 			offset = tw;
       
   352 			Mem::FillZ( cr+offset, clrbytes );
       
   353 			Mem::FillZ( cg+offset, clrbytes );
       
   354 			Mem::FillZ( cb+offset, clrbytes );
       
   355 			Mem::FillZ( cm+offset, clrbytes );
       
   356 			}
       
   357 		}
       
   358 
       
   359 	target->FinalizeSave();
       
   360 	
       
   361 	delete bm.iData;
       
   362 
       
   363 	CleanupStack::PopAndDestroy( 4 ); // cm,cb,cg,cr
       
   364 	CleanupStack::PopAndDestroy( blk.iData );
       
   365 	CleanupStack::PopAndDestroy( target );
       
   366 	CleanupStack::PopAndDestroy( source );
       
   367 	CleanupStack::PopAndDestroy( 2 ); // file, fs
       
   368 
       
   369 	if( iCallBack )
       
   370 		{
       
   371 		iCallBack->JpegStatusCallBack( 100 );
       
   372 		}
       
   373 
       
   374 	}