mmplugins/imagingplugins/codecs/JPEGCodec/Exif/ExifThumbnailGenerator.cpp
changeset 0 40261b775718
equal deleted inserted replaced
-1:000000000000 0:40261b775718
       
     1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "ExifThumbnailGenerator.h"
       
    17 #include <imageconversion.h>
       
    18 #include <bitmaptransforms.h>
       
    19 #include "JpegTypes.h"
       
    20 #include "jpegwritecodec.h"
       
    21 
       
    22 #include "ExifGeneralConsts.h"
       
    23 
       
    24 #include "exiftransformdataaccessor.h"
       
    25 
       
    26 CScaledJpegGenerator* CScaledJpegGenerator ::NewL(TRequestStatus* aNotifier, const MExifSource* aSource, 
       
    27 	TBool aMaintainAspectRatio, CImageDecoder::TOptions aDecoderOptions)
       
    28 	{
       
    29 	CScaledJpegGenerator* self= new (ELeave) CScaledJpegGenerator(aNotifier, aMaintainAspectRatio, aDecoderOptions);
       
    30 	CleanupStack::PushL(self);
       
    31 	self->ConstructL(aSource);
       
    32 	CleanupStack::Pop(self);
       
    33 	
       
    34 	return self;	
       
    35 	}
       
    36 	
       
    37 HBufC8* CScaledJpegGenerator::GetJpegDataL()
       
    38 	{
       
    39 	if(iState!=EFinished)
       
    40 		{
       
    41 		User::Leave(KErrInUse);
       
    42 		}
       
    43 	if(iJPegImage.Count()==0)
       
    44 		{
       
    45 		User::Leave(KErrNotFound);
       
    46 		}
       
    47 
       
    48 	TInt size=0;
       
    49 	TInt i;
       
    50 	for(i=0; i<iJPegImage.Count(); i++)
       
    51 		{
       
    52 		size += iJPegImage[i]->Length();
       
    53 		}
       
    54 	HBufC8* thumbnailData=HBufC8::NewL(size);
       
    55 	TPtr8 bufPtr(thumbnailData->Des());
       
    56 	
       
    57 	for(i=0; i<iJPegImage.Count(); i++)
       
    58 		{
       
    59 		bufPtr.Append(*(iJPegImage[i]));
       
    60 		}
       
    61 	
       
    62 	return thumbnailData;
       
    63 	}
       
    64 
       
    65 HBufC8* CScaledJpegGenerator::JpegDataBufferL(const TUint aIndex)
       
    66 	{
       
    67 	if (iState != EFinished)
       
    68 		{
       
    69 		User::Leave(KErrInUse);
       
    70 		}
       
    71 	if (iJPegImage.Count() == 0)
       
    72 		{
       
    73 		User::Leave(KErrNotFound);
       
    74 		}
       
    75 
       
    76 	if (aIndex < iJPegImage.Count())
       
    77 		{
       
    78 		return iJPegImage[aIndex]->AllocL();
       
    79 		}
       
    80 	else
       
    81 		{
       
    82 		return NULL;
       
    83 		}
       
    84 	}
       
    85 	
       
    86 CScaledJpegGenerator::CScaledJpegGenerator(TRequestStatus* aNotifier, TBool aMaintainAspectRatio, 
       
    87 	CImageDecoder::TOptions aDecoderOptions)
       
    88 	: CActive(EPriorityStandard), iNotifier(aNotifier), iState(EFinished), 
       
    89 	iMaintainAspectRatio(aMaintainAspectRatio)
       
    90 	{	
       
    91 	iDecoderOptions = aDecoderOptions;
       
    92 	}
       
    93 
       
    94 CScaledJpegGenerator::~CScaledJpegGenerator()
       
    95 	{
       
    96 	Cancel();
       
    97 	CleanData();
       
    98 	iJPegImage.Close();
       
    99 	}
       
   100 	
       
   101 void CScaledJpegGenerator::ConstructL(const MExifSource* aSource)
       
   102 	{
       
   103 	ASSERT(aSource != NULL);
       
   104 	iSource = aSource;
       
   105 	CActiveScheduler::Add(this);
       
   106 	}
       
   107 	
       
   108 
       
   109 
       
   110 void CScaledJpegGenerator::StartL(TSize aSize, TImageToGenerate aImageType)
       
   111 	{
       
   112 	if(iState!=EFinished)
       
   113 		{
       
   114 		User::Leave(KErrInUse);
       
   115 		}
       
   116 	
       
   117 	
       
   118 	CleanResultData();
       
   119 	CleanTempData();
       
   120 	iSize=aSize;
       
   121 	iImageType=aImageType;
       
   122 	
       
   123 	if(!iImageDecoder)
       
   124 		{
       
   125 		iImageDecoder = iSource->CreateImageDecoderL(iDecoderOptions);
       
   126 		TFrameInfo frameInfo= iImageDecoder->FrameInfo();
       
   127 
       
   128 		if(iBitmap)
       
   129 			{
       
   130 			delete iBitmap;
       
   131 			iBitmap = NULL;
       
   132 			}
       
   133 		iBitmap= new (ELeave) CFbsBitmap();
       
   134 		
       
   135 		User::LeaveIfError(iBitmap->Create(frameInfo.iFrameCoordsInPixels.Size(), frameInfo.iFrameDisplayMode));
       
   136 		iState=EDecode;
       
   137 		iImageDecoder->Convert(&iStatus, *iBitmap);
       
   138 		SetActive();
       
   139 		}
       
   140 	else
       
   141 		{	// the initialisation has already been done, there is no need to do it again
       
   142 		DoScaleBitmapL();
       
   143 		SetActive();
       
   144 		}
       
   145 	*iNotifier=KRequestPending;
       
   146 	}
       
   147 
       
   148 void CScaledJpegGenerator::RunL()
       
   149 	{
       
   150 	if(iStatus.Int()==KErrNone)
       
   151 		{
       
   152 		switch(iState)
       
   153 			{
       
   154 			case EDecode:
       
   155 				// the decode is finished, we now scale the image
       
   156 				DoScaleBitmapL();
       
   157 				SetActive();
       
   158 				break;
       
   159 				
       
   160 			case EScale:
       
   161 				 // the scaling is over. We now Convert the image
       
   162 				DoConvertL();
       
   163 				SetActive();
       
   164 				break;
       
   165 			case EConvert:
       
   166 				{
       
   167 				switch(iFrameState)
       
   168 					{
       
   169 					case EFrameIncomplete:
       
   170 						DoConvertL();
       
   171 						SetActive();
       
   172 						break;
       
   173 					case EFrameComplete:
       
   174 						GenerationCompleteL();
       
   175 						break;
       
   176 					default:
       
   177 						iStatus=KErrCorrupt;
       
   178 						RunError(KErrCorrupt);
       
   179 					}
       
   180 				}
       
   181 				break;
       
   182 			case EFinished:
       
   183 				break;
       
   184 			default:
       
   185 				break;
       
   186 			}
       
   187 		// we have the bitmap, now scale it
       
   188 		}
       
   189 	else
       
   190 		{
       
   191 		RunError(iStatus.Int());
       
   192 		}
       
   193 	}
       
   194 	
       
   195 void CScaledJpegGenerator::DoCancel()
       
   196 	{
       
   197 	if (iImageDecoder)
       
   198 		{
       
   199 		iImageDecoder->Cancel();
       
   200 		}
       
   201 	if (iBitmapScaler)
       
   202 		{
       
   203 		iBitmapScaler->Cancel();
       
   204 		}
       
   205 	CleanData();
       
   206 	User::RequestComplete(iNotifier, KErrCancel);
       
   207 	iState=EFinished;
       
   208 	}
       
   209 	
       
   210 void CScaledJpegGenerator::DoScaleBitmapL()
       
   211 	{
       
   212 	if(iBitmapScaler)
       
   213 		{
       
   214 		delete iBitmapScaler;
       
   215 		iBitmapScaler = NULL;
       
   216 		}
       
   217 	iBitmapScaler=CBitmapScaler::NewL();
       
   218 
       
   219 	iBitmapScaler->UseLowMemoryAlgorithm(ETrue);
       
   220 	iBitmapScaler->Scale(&iStatus, *iBitmap, iSize, iMaintainAspectRatio);
       
   221 	iState=EScale;
       
   222 	}
       
   223 
       
   224 
       
   225  // returns ETrue if it is the last chunk of data to be received
       
   226 void CScaledJpegGenerator::DoConvertL()
       
   227 	{
       
   228 	if(iState!=EConvert)
       
   229 		{
       
   230 		delete iBitmapScaler;
       
   231 		iBitmapScaler=NULL;
       
   232 		CreateJpegCodecL();
       
   233 		if(iJpegChunck)
       
   234 			{
       
   235 			delete iJpegChunck;
       
   236 			iJpegChunck = NULL;
       
   237 			}
       
   238 		iJpegChunck=HBufC8::NewMaxL(4096);
       
   239 		iJpegChunckPtr.Set(*iJpegChunck);
       
   240 
       
   241 		if(iImageType==EThumbnail)
       
   242 			{
       
   243 			// write SOI
       
   244 			iJpegChunckPtr[0] = (TUint8)((KJpgSOISignature & 0xff00) >> 8);
       
   245 			iJpegChunckPtr[1] = (TUint8)(KJpgSOISignature & 0xff);
       
   246 			iJpegChunckPtr.Shift(2);
       
   247 			}
       
   248 		
       
   249 		iJpegCodec->InitFrameL(iJpegChunckPtr, *iBitmap);
       
   250 		
       
   251 		if(iImageType==EThumbnail)
       
   252 			{
       
   253 			// Adjust iJpegChunckPtr to account for SOI added above 
       
   254 			TInt len=iJpegChunckPtr.Length() + 2;
       
   255 			iJpegChunckPtr.Set(*iJpegChunck);
       
   256 			iJpegChunckPtr.SetLength(len);		
       
   257 			}
       
   258 			
       
   259 		HBufC8* buf = iJpegChunckPtr.AllocLC();
       
   260 		iJPegImage.AppendL(buf);
       
   261 		CleanupStack::Pop(buf);
       
   262 		iJpegChunckPtr.Set(*iJpegChunck);
       
   263 		iFrameState=EFrameIncomplete;
       
   264 		}
       
   265 	else
       
   266 		{
       
   267 		iFrameState= iJpegCodec->ProcessFrameL(iJpegChunckPtr);
       
   268 		HBufC8* buf = iJpegChunckPtr.AllocLC();
       
   269 		iJPegImage.AppendL(buf);
       
   270 		CleanupStack::Pop(buf);
       
   271 		}	
       
   272 	
       
   273 
       
   274 	iStatus=KRequestPending;
       
   275 	TRequestStatus* status=&iStatus;
       
   276 	User::RequestComplete(status, KErrNone);
       
   277 	iState=EConvert;
       
   278 	}
       
   279 
       
   280 
       
   281 void CScaledJpegGenerator::CreateJpegCodecL()
       
   282 	{
       
   283 	const CFrameImageData* frameImageData= &iImageDecoder->FrameData();
       
   284 
       
   285 	//PDEF115929
       
   286 	//This should not be the case - corrupt file
       
   287 	if (frameImageData == NULL)
       
   288 		{
       
   289 		User::Leave(KErrCorrupt);
       
   290 		}
       
   291 
       
   292 	TJpgFrameInfo frameInfo;
       
   293 	TInt qualityFactor;
       
   294 
       
   295 	qualityFactor = 0;
       
   296 
       
   297  	TInt count = frameImageData->ImageDataCount();
       
   298 
       
   299 	//PDEF115929
       
   300 	//This should not be the case - corrupt file
       
   301 	if (count == 0)
       
   302 		{
       
   303 		User::Leave(KErrCorrupt);
       
   304 		}
       
   305 
       
   306 	TBool jpgImageDataProcessed = EFalse;
       
   307 	for (TInt index = 0 ; index<count ; index++)
       
   308 		{	
       
   309 		const TImageDataBlock& encoderData = *frameImageData->GetImageData(index);
       
   310 		if (encoderData.DataType() == KJPGImageDataUid)
       
   311 			{
       
   312 			// Leave if we have already processed one of these.
       
   313 			if (jpgImageDataProcessed)
       
   314 				User::Leave(KErrCorrupt);
       
   315 
       
   316 			const TJpegImageData& jpegImageData = STATIC_CAST(const TJpegImageData&, encoderData);
       
   317 			qualityFactor = jpegImageData.iQualityFactor;
       
   318 
       
   319 			TJpegImageData::TColorSampling sampleScheme = jpegImageData.iSampleScheme;
       
   320 			frameInfo.iComponent[0].iQTable = 0;
       
   321 			if (sampleScheme == TJpegImageData::EMonochrome)
       
   322 				{
       
   323 				frameInfo.iNumberOfComponents = 1;
       
   324 				frameInfo.iComponent[0].iHorzSampleFactor = 1;
       
   325 				frameInfo.iComponent[0].iVertSampleFactor = 1;
       
   326 				}
       
   327 			else
       
   328 				{
       
   329 				frameInfo.iNumberOfComponents = 3;
       
   330 				switch (sampleScheme)
       
   331 					{
       
   332 				case TJpegImageData::EColor420:
       
   333 					frameInfo.iComponent[0].iHorzSampleFactor = 2;
       
   334 					frameInfo.iComponent[0].iVertSampleFactor = 2;
       
   335 					frameInfo.iComponent[1].iVertSampleFactor = 1;
       
   336 					frameInfo.iComponent[2].iVertSampleFactor = 1;
       
   337 					break;
       
   338 				case TJpegImageData::EColor422:
       
   339 					frameInfo.iComponent[0].iHorzSampleFactor = 2;
       
   340 					frameInfo.iComponent[0].iVertSampleFactor = 1;
       
   341 					frameInfo.iComponent[1].iVertSampleFactor = 1;
       
   342 					frameInfo.iComponent[2].iVertSampleFactor = 1;
       
   343 					break;
       
   344 				case TJpegImageData::EColor444:
       
   345 					frameInfo.iComponent[0].iHorzSampleFactor = 1;
       
   346 					frameInfo.iComponent[0].iVertSampleFactor = 1;
       
   347 					frameInfo.iComponent[1].iVertSampleFactor = 1;
       
   348 					frameInfo.iComponent[2].iVertSampleFactor = 1;
       
   349 					break;
       
   350 				default:
       
   351 					User::Leave(KErrNotSupported);
       
   352 					}
       
   353 
       
   354 				frameInfo.iComponent[1].iHorzSampleFactor = 1;
       
   355 				frameInfo.iComponent[1].iQTable = 1;
       
   356 				frameInfo.iComponent[2].iHorzSampleFactor = 1;
       
   357 				frameInfo.iComponent[2].iQTable = 1;
       
   358 				}
       
   359 			
       
   360 			frameInfo.iMaxHorzSampleFactor = frameInfo.iComponent[0].iHorzSampleFactor;
       
   361 			frameInfo.iMaxVertSampleFactor = frameInfo.iComponent[0].iVertSampleFactor;
       
   362 
       
   363 			jpgImageDataProcessed = ETrue;
       
   364 			}
       
   365 		else if (encoderData.DataType() == KJPGQTableUid)
       
   366 			{
       
   367 			const TJpegQTable& jpegQTable = STATIC_CAST(const TJpegQTable&, encoderData);
       
   368 			TInt tableIndex = jpegQTable.iTableIndex;
       
   369 			if ((tableIndex != TJpegQTable::ELumaTable) && (tableIndex != TJpegQTable::EChromaTable))
       
   370 				{
       
   371 				// This can happen if client has given us a second chroma QTable
       
   372 				// replacement.  We do not support this at present, so we ignore
       
   373 				// the extra Q table and encode using the same QTable for both
       
   374 				// chroma components.
       
   375 				continue;
       
   376 				}
       
   377 
       
   378 			TUint8 values[KJpgQTableEntries];
       
   379 			TUint8* valuePtr = values;
       
   380 			const TUint8* zigZagPtr = KZigZagSequence.iZigZag;
       
   381 			const TUint8* valuePtrLimit = valuePtr + KJpgQTableEntries;
       
   382 
       
   383 			while (valuePtr < valuePtrLimit)
       
   384 				*valuePtr++ = jpegQTable.iEntries[*zigZagPtr++];
       
   385 
       
   386 			if (tableIndex == TJpegQTable::ELumaTable)
       
   387 				{
       
   388 				delete iLumaTable;
       
   389 				iLumaTable=NULL;
       
   390 				iLumaTable = new(ELeave) TQTable;
       
   391 
       
   392 				iLumaTable->Set(values, EFalse);
       
   393 				}
       
   394 			else // tableIndex must be TJpegQTable::EChromaTable
       
   395 				{
       
   396 				delete iChromaTable;
       
   397 				iChromaTable=NULL;
       
   398 				iChromaTable = new(ELeave) TQTable;
       
   399 
       
   400 				iChromaTable->Set(values, EFalse);
       
   401 				}
       
   402 			}
       
   403 		else if ((encoderData.DataType() == KJPGCommentUid))
       
   404 			{
       
   405 			if (iImageType == EMainImage) 
       
   406 				{
       
   407 				const TJpegComment& jpegComment = STATIC_CAST(const TJpegComment&, encoderData);
       
   408 				if (!jpegComment.iComment)
       
   409 					User::Leave(KErrNotFound);
       
   410 
       
   411 				if ((jpegComment.iComment->Length() == 0) || (jpegComment.iComment->Length() > 65534))
       
   412 					User::Leave(KErrNotSupported);
       
   413 	            
       
   414 	        	HBufC8* thisComment = jpegComment.iComment->AllocL();
       
   415 		    	TInt ret = iComment.Append(thisComment);
       
   416 			    if (ret != KErrNone)
       
   417 			    	{
       
   418 			    	delete thisComment;
       
   419 			    	User::Leave(ret);
       
   420 				    }
       
   421 				
       
   422 				}
       
   423 			}
       
   424 		else
       
   425 			User::Leave(KErrCorrupt);
       
   426 		}
       
   427 
       
   428 	iJpegCodec= CJpgWriteCodec::NewL(frameInfo,qualityFactor,iLumaTable,iChromaTable,iComment,NULL);
       
   429 	}
       
   430 
       
   431 
       
   432 TInt CScaledJpegGenerator::RunError(TInt aError)
       
   433 	{
       
   434 	CleanData();
       
   435 	User::RequestComplete(iNotifier, aError);
       
   436 	iState=EFinished;
       
   437 	
       
   438 	return KErrNone;
       
   439 	}
       
   440 	
       
   441 void CScaledJpegGenerator::GenerationCompleteL()
       
   442 	{
       
   443 	// write EOI
       
   444 	TBuf8<2> buffer2Bytes;
       
   445 	buffer2Bytes.SetLength(2);
       
   446 	TUint8* headerPtr2 = &buffer2Bytes[0];
       
   447 	headerPtr2[0] = (TUint8)((KJpgEOISignature & 0xff00) >> 8);
       
   448 	headerPtr2[1] = (TUint8)(KJpgEOISignature & 0xff);
       
   449 	HBufC8* buf = buffer2Bytes.AllocLC();
       
   450 	iJPegImage.AppendL(buf);
       
   451 	CleanupStack::Pop(buf);
       
   452 	iState=EFinished;
       
   453 	CleanTempData();
       
   454 	User::RequestComplete(iNotifier, KErrNone);
       
   455 	}
       
   456 
       
   457 void CScaledJpegGenerator::CleanTempData()
       
   458 	{
       
   459 	delete iJpegCodec;
       
   460 	iJpegCodec=NULL;
       
   461 	delete iBitmapScaler;
       
   462 	iBitmapScaler=NULL;
       
   463 
       
   464 	delete iJpegChunck;
       
   465 	iJpegChunck=NULL;
       
   466 
       
   467 	iComment.ResetAndDestroy();
       
   468 	delete iLumaTable;
       
   469 	iLumaTable=NULL;
       
   470 	delete iChromaTable;
       
   471 	iChromaTable=NULL;
       
   472 	}
       
   473 
       
   474 void CScaledJpegGenerator::CleanResultData()
       
   475 	{
       
   476 	iJPegImage.ResetAndDestroy();
       
   477 	}
       
   478 	
       
   479 void CScaledJpegGenerator::CleanData()
       
   480 	{
       
   481 	CleanTempData();
       
   482 	CleanResultData();
       
   483 	
       
   484 	delete iImageDecoder;
       
   485 	iImageDecoder=NULL;
       
   486 	delete iBitmap;
       
   487 	iBitmap=NULL;
       
   488 	}
       
   489 
       
   490 void CScaledJpegGenerator::GetScaledImageSize(TSize &aSize)
       
   491 	{
       
   492 	if (iBitmap)
       
   493 		{
       
   494 		aSize = iBitmap->SizeInPixels();
       
   495 		}
       
   496 	else
       
   497 		{
       
   498 		aSize = iSize;
       
   499 		}
       
   500 	}