mmplugins/imagingplugins/codecs/JPEGCodec/JPEGConvert.cpp
changeset 0 40261b775718
equal deleted inserted replaced
-1:000000000000 0:40261b775718
       
     1 // Copyright (c) 1999-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 <barsc.h>
       
    17 #include <barsread.h>
       
    18 #include <bautils.h>
       
    19 #include <imageconversion.h>
       
    20 #include "icl/ImageCodec.h"
       
    21 #include "ImageClientMain.h"
       
    22 #include <101F45D6_extra.rsg>
       
    23 
       
    24 #include "JpegTypes.h"
       
    25 #include "jpegwritecodec.h"
       
    26 #include "JpegYuvDecoder.h"
       
    27 #include "icl/ICL_UIDS.hrh"
       
    28 #include <bitmaptransforms.h>
       
    29 #include "exifdecoder.h"
       
    30 #include "ExifEncoder.h"
       
    31 #include "exiftransform.h"
       
    32 #include "ImageUtils.h"
       
    33 
       
    34 #include "JPEGCodec.h"
       
    35 #include "JPEGConvert.h"
       
    36 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    37 #include <icl/icl_uids_const.hrh>
       
    38 #include <icl/icl_uids_def.hrh>
       
    39 #include <icl/imagecodecdef.h>
       
    40 #endif
       
    41 
       
    42 _LIT(KJPEGPanicCategory, "JPEGConvertPlugin");
       
    43 
       
    44 const TInt KBlockSignatureSearchSize = 256;
       
    45 const TInt KSizeOfBlockSignaturePlusBlockLength = sizeof(KJpgMarker) + sizeof(TUint16);
       
    46 
       
    47 //
       
    48 // this file doesn't contain much of performance-critical code so use thumb
       
    49 // instruction set to save on some ROM footprint
       
    50 //
       
    51 #if defined(__ARMCC__)
       
    52 #pragma thumb
       
    53 #endif
       
    54 
       
    55 // Global panic function
       
    56 GLDEF_C void Panic(TIclPanic aError)
       
    57 	{
       
    58 	User::Panic(KJPEGPanicCategory, aError);
       
    59 	}
       
    60 
       
    61 // Jpeg decoder.
       
    62 CJpegDecoder* CJpegDecoder::NewL()
       
    63 	{
       
    64 	return new(ELeave)CJpegDecoder();
       
    65 	}
       
    66 
       
    67 CJpegDecoder::CJpegDecoder()
       
    68  :	iImageType(CImageDecoder::EImageTypeMain)
       
    69 	{
       
    70 	}
       
    71 
       
    72 CJpegDecoder::~CJpegDecoder()
       
    73 	{
       
    74 	delete iExtensionManager;
       
    75 	delete iStreamedDecodeExt;
       
    76 		
       
    77 	delete iExifDecoder;
       
    78 	iComment.ResetAndDestroy();
       
    79 	Cleanup();
       
    80 	}
       
    81 
       
    82 void CJpegDecoder::ImageType(TInt aFrameNumber, TUid& aImageType, TUid& aImageSubType) const
       
    83 	{
       
    84 	__ASSERT_ALWAYS(aFrameNumber == 0, Panic(EFrameNumberOutOfRange));
       
    85 	aImageType = KImageTypeJPGUid;
       
    86 	aImageSubType = KNullUid;
       
    87 	}
       
    88 
       
    89 TInt CJpegDecoder::NumberOfFrameComments(TInt aFrameNumber) const
       
    90 	{
       
    91 	__ASSERT_ALWAYS(IsImageHeaderProcessingComplete(), Panic(EHeaderProcessingNotComplete));
       
    92 	__ASSERT_ALWAYS((aFrameNumber >= 0) && (aFrameNumber < NumberOfFrames()), Panic(EFrameNumberOutOfRange));
       
    93 
       
    94 	const CFrameImageData& frameImageData = FrameData(aFrameNumber);
       
    95 	TInt frameCommentCount = 0;
       
    96 	// Because this is a single frame format, the comments are stored
       
    97 	// in the global rather than local comment block
       
    98 	TInt imageDataCount = frameImageData.ImageDataCount();
       
    99 	for (TInt count = 0; count < imageDataCount; count++)
       
   100 		{
       
   101 		const TImageDataBlock* imageData = frameImageData.GetImageData(count);
       
   102 		if (imageData->DataType() == KJPGCommentUid)
       
   103 			frameCommentCount++;
       
   104 		}
       
   105 
       
   106 	return frameCommentCount;
       
   107 	}
       
   108 
       
   109 HBufC* CJpegDecoder::FrameCommentL(TInt aFrameNumber, TInt aCommentNumber) const
       
   110 	{
       
   111 	__ASSERT_ALWAYS(IsImageHeaderProcessingComplete(), Panic(EHeaderProcessingNotComplete));
       
   112 	__ASSERT_ALWAYS((aFrameNumber >= 0) && (aFrameNumber < NumberOfFrames()), Panic(EFrameNumberOutOfRange));
       
   113 	__ASSERT_ALWAYS((aCommentNumber >= 0) && (aCommentNumber < NumberOfFrameComments(aFrameNumber)), Panic(ECommentNumberOutOfRange));
       
   114 
       
   115 	const CFrameImageData& frameImageData = FrameData(aFrameNumber);
       
   116 	TInt commentCount = 0;
       
   117 	// Because this is a single frame format, the comments are stored
       
   118 	// in the global rather than local comment block
       
   119 	TInt imageDataCount = frameImageData.ImageDataCount();
       
   120 	const TImageDataBlock* imageData = NULL;
       
   121 	for (TInt count = 0; count < imageDataCount; count++)
       
   122 		{
       
   123 		imageData = frameImageData.GetImageData(count);
       
   124 		if (imageData->DataType() == KJPGCommentUid)
       
   125 			{
       
   126 			if (commentCount == aCommentNumber)
       
   127 				{
       
   128 				break;
       
   129 				}
       
   130 			commentCount++;
       
   131 			}
       
   132 		}
       
   133 
       
   134 	const TJpegComment* jpegComment = static_cast<const TJpegComment*>(imageData);
       
   135 	HBufC* comment = NULL;
       
   136 	if (jpegComment)
       
   137 		{
       
   138 		comment = HBufC::NewL(jpegComment->iComment->Length());
       
   139 		comment->Des().Copy(*(jpegComment->iComment)); // Create a 16 bit copy of the 8 bit original	
       
   140 		}
       
   141 	return comment;
       
   142 	}
       
   143 
       
   144 TInt CJpegDecoder::FrameHeaderBlockSize(TInt /*aFrameNumber*/) const
       
   145 	{
       
   146 	return KJfifHeaderBlockSizeInBytes;
       
   147 	}
       
   148 
       
   149 TInt CJpegDecoder::FrameBlockSize(TInt /*aFrameNumber*/) const
       
   150 	{
       
   151 	return KJfifDataBlockSizeInBytes;
       
   152 	}
       
   153 
       
   154 //
       
   155 //
       
   156 //
       
   157 TInt CJpegDecoder::GetDestinationSize(TSize& aSize, TInt aFrameNumber)
       
   158 	{
       
   159 	ASSERT(iExtensionManager);
       
   160 	const TFrameInfo frameInfo = FrameInfo(aFrameNumber);
       
   161 	TSize originalSize = frameInfo.iOverallSizeInPixels;
       
   162 	TInt err = iExtensionManager->GetDestinationSize(originalSize);
       
   163 	if(err == KErrNone)
       
   164 		{
       
   165 		aSize = originalSize;
       
   166 		}
       
   167 	return err;
       
   168 	}
       
   169 
       
   170 void CJpegDecoder::InitConvertL()
       
   171 	{
       
   172 	iState = EStateStart; //  when starting convert, always start from the top
       
   173 	CImageDecoderPlugin::InitConvertL();
       
   174 	}
       
   175 
       
   176 void CJpegDecoder::DoConvert()
       
   177 	{
       
   178 	switch(iState)
       
   179 		{
       
   180 		case EStateStart:
       
   181 			{
       
   182 			TRAPD(errCode, PrepareForProcessFrameL());
       
   183 			if (errCode!=KErrNone)
       
   184 				{
       
   185 				RequestComplete(errCode);
       
   186 				return;
       
   187 				}
       
   188 
       
   189 			iCodecState = EFrameIncomplete;
       
   190 
       
   191 			TBufPtr8& sourceData = SourceData();
       
   192 			TInt sourceLength = sourceData.Length();
       
   193 			if (sourceLength!=0)
       
   194 				{
       
   195 				TRAP(errCode, iCodecState = ImageReadCodec()->ProcessFrameL(sourceData));
       
   196 				}
       
   197 
       
   198 			if (errCode == KErrNone && (sourceData.Length() == sourceLength || iCodecState == EFrameComplete || iCodecState == EBlockComplete))
       
   199 				{
       
   200 				CJpgReadCodec* readCodec = static_cast<CJpgReadCodec*>(ImageReadCodec());
       
   201 				JPEG_ASSERT(readCodec);
       
   202 				readCodec->InitDrawFrame();
       
   203 				iState=EStateDrawFrame;
       
   204 				SelfComplete(KErrNone);
       
   205 				}
       
   206 			else
       
   207 				{
       
   208 				ASSERT(iState==EStateStart);
       
   209 				HandleProcessFrameResult(errCode,iCodecState);
       
   210 				}
       
   211 			}
       
   212 			break;
       
   213 		case EStateDrawFrame:
       
   214 			{
       
   215 			CJpgReadCodec* readCodec = static_cast<CJpgReadCodec*>(ImageReadCodec());
       
   216 			JPEG_ASSERT(readCodec);
       
   217 			TBool result = EFalse;
       
   218 			TRAPD(errCode, result = readCodec->DrawFrameL());
       
   219 			if (errCode != KErrNone)
       
   220 				{
       
   221 				HandleProcessFrameResult(errCode, iCodecState);
       
   222 				}
       
   223 			else if (result)
       
   224 				{
       
   225 				HandleProcessFrameResult(KErrNone, iCodecState);
       
   226 				iState = EStateStart;
       
   227 				}
       
   228 			else
       
   229 				{
       
   230 				ASSERT(iState==EStateDrawFrame);
       
   231 				SelfComplete(KErrNone);
       
   232 				}
       
   233 			}
       
   234 			break;
       
   235 		default:
       
   236 			ASSERT(EFalse);
       
   237 		}
       
   238 	}
       
   239 
       
   240 MExifMetadata* CJpegDecoder::ExifMetadata()
       
   241 	{
       
   242 	return iExifDecoder;
       
   243 	}
       
   244 
       
   245 // Scan header.
       
   246 // Validate that format is correct.
       
   247 // Create codec.
       
   248 // Fill in image info. (All frames)
       
   249 void CJpegDecoder::ScanDataL()
       
   250 	{
       
   251 	ReadFormatL();
       
   252 
       
   253 	ASSERT(ImageReadCodec() == NULL);
       
   254 
       
   255 	CJpgReadCodec* imageReadCodec = NULL;
       
   256 
       
   257 	if (iJpgFrameInfo.iProgressive)
       
   258 		{
       
   259 		imageReadCodec = CProgressiveJpgReadCodec::NewL(
       
   260 				iJpgFrameInfo,
       
   261 				iScanInfo,
       
   262 				iDCHuffmanTable,
       
   263 				iACHuffmanTable,
       
   264 				iQTable);
       
   265 		}
       
   266 	else if (iJpgFrameInfo.iNumberOfComponents == iScanInfo.iNumberOfComponents)
       
   267 		{
       
   268 		imageReadCodec = CSequentialJpgReadCodec::NewL(
       
   269 				iJpgFrameInfo,
       
   270 				iScanInfo,
       
   271 				iDCHuffmanTable,
       
   272 				iACHuffmanTable,
       
   273 				iQTable);
       
   274 		}
       
   275 	else
       
   276 		{
       
   277 		iJpgFrameInfo.iMultiScan = ETrue;
       
   278 		imageReadCodec = CMultiScanSequentialJpgReadCodec::NewL(
       
   279 				iJpgFrameInfo,
       
   280 				iScanInfo,
       
   281 				iDCHuffmanTable,
       
   282 				iACHuffmanTable,
       
   283 				iQTable);
       
   284 		}
       
   285 
       
   286 	CleanupStack::PushL(imageReadCodec);
       
   287 	
       
   288 	if (!iExtensionManager)
       
   289 		{
       
   290 		// Manager settings persist over all frames.
       
   291 		iExtensionManager = CPluginExtensionManager::NewL(imageReadCodec);
       
   292 		}
       
   293 	else
       
   294 		{
       
   295 		// Maintain manager settings, but reset the codec that it points to.
       
   296 		iExtensionManager->ResetCodecExtension(imageReadCodec);
       
   297 		}
       
   298 	
       
   299 
       
   300 	CleanupStack::Pop(); // imageReadCodec
       
   301 	
       
   302 	imageReadCodec->SetExtensionManager(iExtensionManager);
       
   303 	imageReadCodec->SetHighSpeedMode( (DecoderOptions() & CImageDecoder::EPreferFastDecode) == CImageDecoder::EPreferFastDecode );
       
   304 
       
   305 	// If this is the main image - pull the thumbnail out and give it to the
       
   306 	// framework
       
   307 	if (iImageType == CImageDecoder::EImageTypeMain)
       
   308 		{
       
   309 		if (iExifDecoder != NULL)
       
   310 			{
       
   311 			TInt err = 0;
       
   312 			TInt thumbDataOffset = 0;
       
   313 
       
   314 			HBufC8* thumbnailData = NULL;
       
   315 			// Hold the thumbnail data (extracted from the Exif object).
       
   316 
       
   317 			// Get both the offset of the thumbnail data and its length.
       
   318 			err = iExifDecoder->GetIntegerParam(KJPEGInterchangeFormat, 1, thumbDataOffset);
       
   319 			if(err == KErrNone)
       
   320 				{
       
   321 				TInt thumbDataLength = 0;
       
   322 				err = iExifDecoder->GetIntegerParam(KJPEGInterchangeFormatLength, 1, thumbDataLength);
       
   323 				if(err == KErrNone)
       
   324 					{
       
   325 					//get the thumbnail data.
       
   326 					thumbnailData = iExifDecoder->GetJpegThumbnailData();
       
   327 					// Pass the thumbnailData back to the framework (ownership remains here).
       
   328 					SetThumbnailData(thumbnailData);
       
   329 					}
       
   330 				}
       
   331 			}
       
   332 		}
       
   333 
       
   334 	imageReadCodec->SetAutoRotateFlag(iAutoRotateFlag);
       
   335 	
       
   336 	SetImageReadCodec(imageReadCodec);
       
   337 
       
   338 	ReadFrameHeadersL();
       
   339 	}
       
   340 
       
   341 void CJpegDecoder::NotifyImageTypeChangeL(TInt aImageType)
       
   342 	{
       
   343 	TInt prevImageType = iImageType;
       
   344 	iImageType = aImageType;
       
   345 	TRAPD(err, ScanDataL());
       
   346 	if (err != KErrNone)
       
   347 		{
       
   348 		iImageType = prevImageType;
       
   349 		JPEG_LEAVE(err, "ScanDataL");
       
   350 		}
       
   351 	}
       
   352 
       
   353 void CJpegDecoder::ReadFormatL()
       
   354 	{
       
   355 	iJpgFrameInfo.iProgressive = EFalse; // Reset
       
   356 
       
   357 	TPtrC8 bufferDes;
       
   358 	ReadDataL(0, bufferDes, KJfifInitialHeaderSize);
       
   359 
       
   360 	// Validate the header.
       
   361 	if (bufferDes.Length() < KJfifInitialHeaderSize)
       
   362 		{
       
   363 		JPEG_LEAVE(KErrUnderflow, "Not enough data for JFIF header");
       
   364 		}
       
   365 
       
   366 	iPtr = &bufferDes[0];
       
   367 	const TUint8* ptr = iPtr;
       
   368 	TInt startPosition = 6; // Move past SOISignature + first block sig/length.
       
   369 	TUint16 soiSig = ReadBigEndianUint16(ptr);
       
   370 	if (soiSig != CJpgReadCodec::EMarkerSOI)
       
   371 		{
       
   372 		JPEG_LEAVE(KErrCorrupt, "Expected SOI marker");
       
   373 		}
       
   374 
       
   375 	iJpgFrameInfo.iRestartInterval = KErrNotFound;
       
   376 	SetStartPosition(startPosition);
       
   377 
       
   378 	//delete all comments
       
   379 	iComment.ResetAndDestroy();
       
   380 
       
   381 	for (;;)
       
   382 		{
       
   383 		// Read the signature and length of the next block.
       
   384 		iBlockSignature = ReadBigEndianUint16(ptr);
       
   385 
       
   386 		// Skip until next block signature is valid
       
   387 		if ((iBlockSignature & KJpgMarkerMask) != KJpgMarker)
       
   388 			{
       
   389 			TInt blockIndex = KErrNotFound;
       
   390 			TChar jpgMarker = TChar(KJpgMarker >> 8);
       
   391 			for (;;)
       
   392 				{
       
   393 				// search in blocks of size KBlockSignatureSearchSize
       
   394 				// for occurrence of a jpeg marker (0xff)
       
   395 
       
   396 				ReadDataL(startPosition, bufferDes, KBlockSignatureSearchSize);
       
   397 				if (!bufferDes.Length())
       
   398 					{
       
   399 					// no marker found, no data left
       
   400 					JPEG_LEAVE(KErrCorrupt, "No marker, no data");
       
   401 					}
       
   402 				blockIndex = bufferDes.Locate(jpgMarker);
       
   403 				if (blockIndex != KErrNotFound)
       
   404 					{
       
   405 					startPosition += blockIndex;
       
   406 					break;
       
   407 					}
       
   408 				startPosition += bufferDes.Length();
       
   409 				}
       
   410 
       
   411 			if ((bufferDes.Length() - blockIndex) < KSizeOfBlockSignaturePlusBlockLength)
       
   412 				{
       
   413 				// ensure there are at least KSizeOfBlockSignaturePlusBlockLength bytes in bufferDes after the blockIndex
       
   414 				ReadDataL(startPosition, bufferDes, KSizeOfBlockSignaturePlusBlockLength);
       
   415 				if (bufferDes.Length() < KSizeOfBlockSignaturePlusBlockLength)
       
   416 					{
       
   417 					JPEG_LEAVE(KErrUnderflow, "Not enough data");	// Not enough data present
       
   418 					}
       
   419 				blockIndex = 0;
       
   420 				}
       
   421 			iPtr = &bufferDes[blockIndex];
       
   422 			ptr = iPtr;
       
   423 			iBlockSignature = ReadBigEndianUint16(ptr);
       
   424 			startPosition += KSizeOfBlockSignaturePlusBlockLength;
       
   425 			SetStartPosition(startPosition);
       
   426 			}
       
   427 
       
   428 		// Read the current block's length.
       
   429 		iBlockLength = ReadBigEndianUint16(ptr);
       
   430 
       
   431 		// Read the next block plus the signature and size of block to follow
       
   432 		ReadDataL(StartPosition(),bufferDes,iBlockLength+2);
       
   433 
       
   434 		if (bufferDes.Length() < iBlockLength+2)
       
   435 			{
       
   436 			JPEG_LEAVE(KErrUnderflow, "Not enough data");	// Not enough data present
       
   437 			}
       
   438 
       
   439 		iPtr = &bufferDes[0];
       
   440 		switch (iBlockSignature)
       
   441 			{
       
   442 			case CJpgReadCodec::EMarkerAPP0:
       
   443 				ProcessApp0L();
       
   444 				break;
       
   445 			
       
   446 			case CJpgReadCodec::EMarkerAPP1:
       
   447 				// Process the EXIF information
       
   448 				// Check if the flag to ignore is set. If yes, set the data to NULL.
       
   449 				if (DecoderOptions() & CImageDecoder::EOptionIgnoreExifMetaData)
       
   450 					{
       
   451 					delete iExifDecoder;
       
   452 					iExifDecoder = NULL;
       
   453 					}
       
   454 				else
       
   455 					{
       
   456 					TRAPD(err, ProcessApp1L());
       
   457 					if ((err != KErrCorrupt) && (err != KErrNotSupported))
       
   458 						{
       
   459 						JPEG_LEAVE_IF_ERROR(err, "ProcessApp1L");
       
   460 						}
       
   461 					}
       
   462 				break;
       
   463 				
       
   464 			case CJpgReadCodec::EMarkerAPP14:
       
   465 				ProcessAppEL();
       
   466 				break;
       
   467 				
       
   468 			case CJpgReadCodec::EMarkerDHT:
       
   469 				ProcessHuffmanTableL();
       
   470 				break;
       
   471 			
       
   472 			case CJpgReadCodec::EMarkerDQT:
       
   473 				ProcessQTableL();
       
   474 				break;
       
   475 			
       
   476 			case CJpgReadCodec::EMarkerSOF2:
       
   477 				iJpgFrameInfo.iProgressive = ETrue; // Fall through to ProcessStartOfFrameL()
       
   478 			case CJpgReadCodec::EMarkerSOF0:
       
   479 			case CJpgReadCodec::EMarkerSOF1:
       
   480 				ProcessStartOfFrameL();
       
   481 				break;
       
   482 			
       
   483 			case CJpgReadCodec::EMarkerSOF3:
       
   484 				User::Leave(KErrNotSupported);
       
   485 				break;
       
   486 			
       
   487 			case CJpgReadCodec::EMarkerSOS:
       
   488 				ProcessStartOfScanL();
       
   489 				FinishedProcessing();
       
   490 				// Fill in image data structures and give control to the codec.
       
   491 				InitialiseImageDataL();
       
   492 				return;
       
   493 			
       
   494 			case CJpgReadCodec::EMarkerDRI:
       
   495 				ProcessRestartInterval();
       
   496 				break;
       
   497 			
       
   498 			case CJpgReadCodec::EMarkerCOM:
       
   499 				CheckCommentBlockL();
       
   500 				ProcessCommentL();
       
   501 				break;
       
   502 			
       
   503 		default:
       
   504 			// ProcessOtherBlockL();
       
   505 			break;
       
   506 			}
       
   507 
       
   508 		ptr = iPtr + (iBlockLength - 2); // Advance past this block.
       
   509 		startPosition += iBlockLength + 2; // Advance past this block and the signature and length of the next block
       
   510 		SetStartPosition(startPosition);
       
   511 		}
       
   512 	}
       
   513 
       
   514 //
       
   515 // APP markers are reserved for application use. Different applications are
       
   516 // free to use the same APP marker for different purposes.
       
   517 // In our case, we look for the EXIF header and ignore it otherwise.
       
   518 //
       
   519 void CJpegDecoder::ProcessApp1L()
       
   520 	{
       
   521 	if (iBlockLength < KExifHeaderLength)
       
   522 		{
       
   523 		return;
       
   524 		}
       
   525 	TPtrC8 exifHeaderPtr(iPtr, KExifHeaderLength);
       
   526 	if ((KExifHeader().Compare(exifHeaderPtr) == KErrNone) && (iExifDecoder == NULL))
       
   527 		{
       
   528 		// This is the EXIF header block, so instantiate the EXIF decoder object
       
   529 		iExifDecoder = CExifDecoder::NewL(iBlockLength, iPtr);
       
   530 		}
       
   531 	}
       
   532 
       
   533 //
       
   534 // Check that length of comment block is correct, if not
       
   535 // calculate real size of comment block and adjust data read.
       
   536 //
       
   537 void CJpegDecoder::CheckCommentBlockL()
       
   538 	{
       
   539 	// INC076787 -
       
   540 	// Allow successful decoding of a JPEG file with incorrect comment block length.
       
   541 	TUint16 nextBlockSignature = PtrReadUtil::ReadBigEndianUint16(iPtr + iBlockLength - 2);
       
   542 	if ((nextBlockSignature & KJpgMarkerMask) != KJpgMarker)
       
   543 		{
       
   544 		// Block length is incorrect. Calculate real length of comment block
       
   545 		TPtrC8 commentBuffer;
       
   546 		TInt realLength = 0;
       
   547 
       
   548 		// First check whether the block is smaller than expected.
       
   549 		nextBlockSignature = PtrReadUtil::ReadBigEndianUint16(iPtr);
       
   550 		while (((nextBlockSignature & KJpgMarkerMask) != KJpgMarker) && (realLength <= (iBlockLength - 2)))
       
   551 			{
       
   552 			realLength++;
       
   553 			nextBlockSignature = PtrReadUtil::ReadBigEndianUint16(iPtr + realLength);
       
   554 			}
       
   555 		if (realLength <= (iBlockLength - 2))
       
   556 			{
       
   557 			// Correct block length
       
   558 			iBlockLength = realLength + 2; // Add the two bytes which contain length
       
   559 			}
       
   560 		else		// Otherwise check for more data
       
   561 			{
       
   562 			TInt offset = 1;
       
   563 			TInt startPos = StartPosition() + iBlockLength - 2;
       
   564 
       
   565 			ReadDataL(startPos + offset, commentBuffer, 2);
       
   566 			if (!commentBuffer.Length())
       
   567 				{
       
   568 				// Not enough data in the 'commentBuffer'
       
   569 				JPEG_LEAVE(KErrUnderflow, "Not enough data");	
       
   570 				}
       
   571 			nextBlockSignature = PtrReadUtil::ReadBigEndianUint16(&commentBuffer[0]);
       
   572 
       
   573 			while ((nextBlockSignature & KJpgMarkerMask) != KJpgMarker)
       
   574 				{
       
   575 				offset++;
       
   576 				ReadDataL(startPos + offset, commentBuffer, 2);
       
   577 				if (!commentBuffer.Length())
       
   578 					{
       
   579 					// Not enough data in the 'commentBuffer'
       
   580 					JPEG_LEAVE(KErrUnderflow, "Not enough data");
       
   581 					}
       
   582 				nextBlockSignature = PtrReadUtil::ReadBigEndianUint16(&commentBuffer[0]);
       
   583 				}
       
   584 			// Correct block length
       
   585 			iBlockLength += offset;
       
   586 			}
       
   587 
       
   588 		// Re-read the comment block again plus the signature and size of block which follows
       
   589 		ReadDataL(StartPosition(), commentBuffer, iBlockLength + 2);
       
   590 		iPtr = &commentBuffer[0];
       
   591 		}
       
   592 	}
       
   593 
       
   594 
       
   595 CFrameInfoStrings* CJpegDecoder::FrameInfoStringsL(RFs& aFs, TInt aFrameNumber)
       
   596 	{
       
   597 	const TUid KJpgCodecDllUid = {KJPGCodecDllUidValue};
       
   598 
       
   599 	RResourceFile resourceFile;
       
   600 	OpenExtraResourceFileLC(aFs, KJpgCodecDllUid, resourceFile);
       
   601 
       
   602 	HBufC8* resourceInfo = resourceFile.AllocReadLC(THEDECODERINFO);
       
   603 	TResourceReader resourceReader;
       
   604 	resourceReader.SetBuffer(resourceInfo);
       
   605 
       
   606 	TBuf<KCodecResourceStringMax> info;
       
   607 	TBuf<KCodecResourceStringMax> templte;
       
   608 
       
   609 	const TFrameInfo& frameInfo = FrameInfo(aFrameNumber);
       
   610 	CFrameInfoStrings* frameInfoStrings = CFrameInfoStrings::NewLC();
       
   611 
       
   612 	info = resourceReader.ReadTPtrC();
       
   613 	frameInfoStrings->SetDecoderL(info);
       
   614 
       
   615 	info = resourceReader.ReadTPtrC();
       
   616 	frameInfoStrings->SetFormatL(info);
       
   617 
       
   618 	TInt width = frameInfo.iOverallSizeInPixels.iWidth;
       
   619 	TInt height = frameInfo.iOverallSizeInPixels.iHeight;
       
   620 	TInt depth = frameInfo.iBitsPerPixel;
       
   621 
       
   622 	templte = resourceReader.ReadTPtrC();
       
   623 	info.Format(templte, width, height);
       
   624 	frameInfoStrings->SetDimensionsL(info);
       
   625 
       
   626 	CDesCArrayFlat* resourceArray = resourceReader.ReadDesCArrayL();
       
   627 	CleanupStack::PushL(resourceArray);
       
   628 	TUint formatIndex = (frameInfo.iFlags & TFrameInfo::EColor) ? 1 : 0;
       
   629 	templte = (*resourceArray)[formatIndex];
       
   630 	CleanupStack::PopAndDestroy(resourceArray);
       
   631 	info.Format(templte, depth);
       
   632 	frameInfoStrings->SetDepthL(info);
       
   633 
       
   634 	resourceArray = resourceReader.ReadDesCArrayL();
       
   635 	CleanupStack::PushL(resourceArray);
       
   636 	formatIndex = (iJpgFrameInfo.iProgressive) ? 1 : 0;
       
   637 	info = (*resourceArray)[formatIndex];
       
   638 	CleanupStack::PopAndDestroy(resourceArray);
       
   639 	frameInfoStrings->SetDetailsL(info);
       
   640 
       
   641 	CleanupStack::Pop(frameInfoStrings);
       
   642 	CleanupStack::PopAndDestroy(2); // resourceInfo + resourceFile
       
   643 	return frameInfoStrings;
       
   644 	}
       
   645 
       
   646 void CJpegDecoder::InitialiseImageDataL()
       
   647 	{
       
   648 	// Fill in image data info.
       
   649 	TInt quality = 0;
       
   650 	TInt tables = 0;
       
   651 	TInt qTableIndex;
       
   652 	for (qTableIndex = 0; qTableIndex < KJpgMaxNumberOfTables; qTableIndex++)
       
   653 		{
       
   654 		if (iQTable[qTableIndex].QualityFactor() > 0)
       
   655 			{
       
   656 			quality += iQTable[qTableIndex].QualityFactor();
       
   657 			tables++;
       
   658 			}
       
   659 		}
       
   660 	if (tables > 0)
       
   661 		quality /= tables;
       
   662 
       
   663 	TJpegImageData* jpegImageData = new(ELeave) TJpegImageData;
       
   664 	CleanupStack::PushL(jpegImageData);
       
   665 
       
   666 	jpegImageData->iQualityFactor = quality;
       
   667 	if (iJpgFrameInfo.iNumberOfComponents == 1)
       
   668 		jpegImageData->iSampleScheme = TJpegImageData::EMonochrome;
       
   669 	else
       
   670 		{
       
   671 		if (iJpgFrameInfo.iMaxHorzSampleFactor == 1 && iJpgFrameInfo.iMaxVertSampleFactor == 1)
       
   672 			jpegImageData->iSampleScheme = TJpegImageData::EColor444;
       
   673 		else if (iJpgFrameInfo.iMaxHorzSampleFactor == 2 && iJpgFrameInfo.iMaxVertSampleFactor == 1)
       
   674 			jpegImageData->iSampleScheme = TJpegImageData::EColor422;
       
   675 		else
       
   676 			jpegImageData->iSampleScheme = TJpegImageData::EColor420;
       
   677 		}
       
   678 	
       
   679 	JPEG_LEAVE_IF_ERROR(AppendImageData(jpegImageData), "AppendImageData: jpegImageData");
       
   680 	CleanupStack::Pop(jpegImageData);
       
   681 
       
   682 	// Fill in QTable image data.
       
   683 	for (qTableIndex = 0 ; qTableIndex < KJpgMaxNumberOfTables ; qTableIndex++)
       
   684 		{
       
   685 		if (iQTable[qTableIndex].QualityFactor() > 0)
       
   686 			{
       
   687 			TJpegQTable* jpegQTable = new(ELeave) TJpegQTable;
       
   688 			CleanupStack::PushL(jpegQTable);
       
   689 
       
   690 			TQTable& qTable = iQTable[qTableIndex];
       
   691 			TUint8 values[2 * KJpgQTableEntries];
       
   692 
       
   693 			const TInt precisionBytes = qTable.Get(values) / KJpgQTableEntries;
       
   694 			const TUint8* zigZagPtr = KZigZagSequence.iZigZag;
       
   695 			TUint8* valuePtr = values;
       
   696 			const TUint8* valuePtrLimit = valuePtr + (KJpgQTableEntries * precisionBytes);
       
   697 
       
   698 			while (valuePtr < valuePtrLimit)
       
   699 				{
       
   700 				jpegQTable->iEntries[*zigZagPtr++] = valuePtr[0]; // Lose the low byte of 16 bit precision values
       
   701 				valuePtr += precisionBytes;
       
   702 				}
       
   703 
       
   704 			jpegQTable->iTableIndex = qTableIndex;
       
   705 			JPEG_LEAVE_IF_ERROR(AppendImageData(jpegQTable), "AppendImageData: jpegQTable");
       
   706 			CleanupStack::Pop();
       
   707 			}
       
   708 		}
       
   709 
       
   710 	// Add the comments
       
   711 	const TInt noOfComments = iComment.Count();
       
   712 	for(TInt commentNo=0; commentNo < noOfComments; commentNo++)
       
   713 		{
       
   714 		TJpegComment* jpegComment = new(ELeave) TJpegComment;
       
   715 		CleanupStack::PushL(jpegComment);
       
   716 
       
   717 		HBufC8* comment = iComment[0];
       
   718 		jpegComment->iComment = comment;
       
   719 
       
   720 		JPEG_LEAVE_IF_ERROR(AppendImageDataBuffer(comment), "AppendImageDataBuffer");
       
   721 		iComment.Remove(0);
       
   722 
       
   723 		JPEG_LEAVE_IF_ERROR(AppendImageData(jpegComment), "AppendImageData(jpegComment)");
       
   724 		CleanupStack::Pop(); // jpegComment
       
   725 		}
       
   726 	}
       
   727 
       
   728 void CJpegDecoder::ProcessApp0L()
       
   729 	{
       
   730 	// iBlockLength must specify at least the 2 byte
       
   731 	// length field itself for Application Data!
       
   732 	if (iBlockLength<2)
       
   733 		{
       
   734 		JPEG_LEAVE(KErrCorrupt, "Not enough data for App0");
       
   735 		}
       
   736 
       
   737 	const TUint8* ptr = iPtr;
       
   738 
       
   739 	TPtrC8 id(ptr, Min(KJpgApp0IdSize, iBlockLength-2));
       
   740 
       
   741 	if (id == KJfifId)
       
   742 		{
       
   743 		// We know jfif will always have a minimum of 14 bytes of
       
   744 		// data in addition to the 2 byte length field.
       
   745 		if (iBlockLength<16)
       
   746 			{
       
   747 			JPEG_LEAVE(KErrCorrupt, "Not enough data in App0");
       
   748 			}
       
   749 
       
   750 		ptr += KJpgApp0IdSize + 1;
       
   751 		TUint16 version = ReadBigEndianUint16(ptr);
       
   752 		if (version != KJfifVersion0100 &&
       
   753 			version != KJfifVersion0101 &&
       
   754 			version != KJfifVersion0102)
       
   755 			{
       
   756 			JPEG_LEAVE(KErrNotSupported, "Unsupported jfif version");
       
   757 			}
       
   758 
       
   759 		iJpgFrameInfo.iUnits = TJpgFrameInfo::TJpgImageUnits(*ptr++);
       
   760 		iJpgFrameInfo.iSizeInTwips.iWidth = ReadBigEndianUint16(ptr);
       
   761 		iJpgFrameInfo.iSizeInTwips.iHeight = ReadBigEndianUint16(ptr);
       
   762 		iJpgFrameInfo.iThumbnailSize.iWidth = *ptr++;
       
   763 		iJpgFrameInfo.iThumbnailSize.iHeight = *ptr;
       
   764 		
       
   765 		JPEG_DEBUG2("Frame units: %d", iJpgFrameInfo.iUnits);
       
   766 		JPEG_DEBUG2("Frame twips width: %d", iJpgFrameInfo.iSizeInTwips.iWidth);
       
   767 		JPEG_DEBUG2("Frame twips height: %d", iJpgFrameInfo.iSizeInTwips.iHeight);
       
   768 		JPEG_DEBUG2("Frame thumbnail width: %d", iJpgFrameInfo.iThumbnailSize.iWidth);
       
   769 		JPEG_DEBUG2("Frame twips width: %d", iJpgFrameInfo.iThumbnailSize.iHeight);
       
   770 
       
   771 		// skip over JFIF thumbnail data without storing it
       
   772 		// there are currently no client APIs for accessing it
       
   773 		ptr += iJpgFrameInfo.iThumbnailSize.iWidth * iJpgFrameInfo.iThumbnailSize.iHeight * 3;
       
   774 
       
   775 		iJFIFMarkerPresent = ETrue;
       
   776 		}
       
   777 	}
       
   778 
       
   779 void CJpegDecoder::ProcessAppEL()
       
   780 	{
       
   781 	const TUint8* ptr = iPtr;
       
   782 
       
   783 	TPtrC8 id(ptr,KJpgAppEIdSize);
       
   784 
       
   785 	if (id == KAdobeId)
       
   786 		{
       
   787 		iAdobeMarkerPresent = ETrue;
       
   788 		iAdobeTransform = ptr[11];
       
   789 		}
       
   790 	}
       
   791 
       
   792 void CJpegDecoder::ProcessHuffmanTableL()
       
   793 	{
       
   794 	const TUint8* dataPtr = iPtr;
       
   795 	const TUint8* dataPtrLimit = dataPtr + iBlockLength - 2;
       
   796 	THuffmanTableProcessor::ProcessHuffmanTableL(dataPtr, dataPtrLimit, iDCHuffmanTable, iACHuffmanTable);
       
   797 	}
       
   798 
       
   799 void CJpegDecoder::ProcessQTableL()
       
   800 	{
       
   801 	const TUint8* dataPtr = iPtr;
       
   802 	const TUint8* dataPtrLimit = dataPtr + iBlockLength - 2;
       
   803 
       
   804 	while (dataPtr < dataPtrLimit)
       
   805 		{
       
   806 		TInt index = *dataPtr++;
       
   807 		TBool sixteenBitPrecision = index & 0x10;
       
   808 		index &= 0x0f;
       
   809 		if (index >= KJpgMaxNumberOfTables)
       
   810 			{
       
   811 			JPEG_LEAVE(KErrCorrupt, "table index out of range");
       
   812 			}
       
   813 
       
   814 		dataPtr += iQTable[index].Set(dataPtr,sixteenBitPrecision);
       
   815 		}
       
   816 	}
       
   817 
       
   818 void CJpegDecoder::ProcessStartOfFrameL()
       
   819 	{
       
   820 	const TUint8* ptr = iPtr;
       
   821 
       
   822 	iJpgFrameInfo.iSamplePrecision = *ptr++;
       
   823 	if (iJpgFrameInfo.iSamplePrecision != 8)
       
   824 		{
       
   825 		JPEG_LEAVE(KErrNotSupported, "Unsupported sample precision");
       
   826 		}
       
   827 
       
   828 	iJpgFrameInfo.iSizeInPixels.iHeight = ReadBigEndianUint16(ptr);
       
   829 	iJpgFrameInfo.iSizeInPixels.iWidth = ReadBigEndianUint16(ptr);
       
   830 	
       
   831 	JPEG_DEBUG2("Frame pixel width: %d", iJpgFrameInfo.iSizeInPixels.iWidth);
       
   832 	JPEG_DEBUG2("Frame pixel height: %d", iJpgFrameInfo.iSizeInPixels.iHeight);
       
   833 	
       
   834 	if ((iJpgFrameInfo.iSizeInPixels.iHeight <= 0) || (iJpgFrameInfo.iSizeInPixels.iWidth <= 0))
       
   835 		{
       
   836 		JPEG_LEAVE(KErrCorrupt, "Invalid pixel height or width");		
       
   837 		}
       
   838 	
       
   839 	if (iJpgFrameInfo.iSizeInTwips.iWidth > 0 && iJpgFrameInfo.iSizeInTwips.iHeight > 0)
       
   840 		{
       
   841 		if (iJpgFrameInfo.iUnits == TJpgFrameInfo::EDotsPerInch)
       
   842 			{
       
   843 			iJpgFrameInfo.iSizeInTwips.iWidth = iJpgFrameInfo.iSizeInPixels.iWidth * KTwipsPerInch / iJpgFrameInfo.iSizeInTwips.iWidth;
       
   844 			iJpgFrameInfo.iSizeInTwips.iHeight = iJpgFrameInfo.iSizeInPixels.iHeight * KTwipsPerInch / iJpgFrameInfo.iSizeInTwips.iHeight;
       
   845 			}
       
   846 		else if (iJpgFrameInfo.iUnits == TJpgFrameInfo::EDotsPerCm)
       
   847 			{
       
   848 			iJpgFrameInfo.iSizeInTwips.iWidth = iJpgFrameInfo.iSizeInPixels.iWidth * KTwipsPerCm / iJpgFrameInfo.iSizeInTwips.iWidth;
       
   849 			iJpgFrameInfo.iSizeInTwips.iHeight = iJpgFrameInfo.iSizeInPixels.iHeight * KTwipsPerCm / iJpgFrameInfo.iSizeInTwips.iHeight;
       
   850 			}
       
   851 		else
       
   852 			iJpgFrameInfo.iSizeInTwips.SetSize(0,0);
       
   853 		}
       
   854 
       
   855 	iJpgFrameInfo.iMaxHorzSampleFactor = 0;
       
   856 	iJpgFrameInfo.iMaxVertSampleFactor = 0;
       
   857 	iJpgFrameInfo.iNumberOfComponents = *ptr++;
       
   858 	JPEG_DEBUG2("Frame number of components: %d", iJpgFrameInfo.iNumberOfComponents);
       
   859 	
       
   860 	//At least one component and not more than we can cope with
       
   861 	if(iJpgFrameInfo.iNumberOfComponents < KJpgMinNumberOfComponents)
       
   862 		{
       
   863 		JPEG_LEAVE(KErrCorrupt, "Not enough components");
       
   864 		}
       
   865 
       
   866 	if ((iJpgFrameInfo.iNumberOfComponents != KJpgMinNumberOfComponents) && (iJpgFrameInfo.iNumberOfComponents != KJpgNumberOfComponents))
       
   867 		{
       
   868 		JPEG_LEAVE(KErrNotSupported, "Bad number of components");
       
   869 		}
       
   870 
       
   871 	for (TInt count = 0; count < iJpgFrameInfo.iNumberOfComponents; count++)
       
   872 		{
       
   873 		TJpgFrameInfo::TComponentInfo& compInfo = iJpgFrameInfo.iComponent[count];
       
   874 		compInfo.iId = *ptr++;
       
   875 		TUint8 sampleFactor = *ptr++;
       
   876 
       
   877 		compInfo.iHorzSampleFactor = sampleFactor >> 4;
       
   878 		if(compInfo.iHorzSampleFactor < KJpgMinSampleFactor || compInfo.iHorzSampleFactor > KJpgMaxSampleFactor)
       
   879 			{
       
   880 			JPEG_LEAVE(KErrCorrupt, "Bad horizontal sample factor");
       
   881 			}
       
   882 
       
   883 		compInfo.iVertSampleFactor = sampleFactor & 0x0f;
       
   884 		if(compInfo.iVertSampleFactor < KJpgMinSampleFactor || compInfo.iVertSampleFactor > KJpgMaxSampleFactor)
       
   885 			{
       
   886 			JPEG_LEAVE(KErrCorrupt, "Bad vertical sample factor");
       
   887 			}
       
   888 
       
   889 		compInfo.iQTable = *ptr++;
       
   890 		
       
   891 		// Number of tables should be in range (0..3)
       
   892 		if ((compInfo.iQTable < 0) || (compInfo.iQTable > (KJpgMaxNumberOfTables - 1)))
       
   893 			{
       
   894 			JPEG_LEAVE(KErrCorrupt, "Bad QTable index");				
       
   895 			}
       
   896 			
       
   897 		iJpgFrameInfo.iMaxHorzSampleFactor = Max(iJpgFrameInfo.iMaxHorzSampleFactor,compInfo.iHorzSampleFactor);
       
   898 		iJpgFrameInfo.iMaxVertSampleFactor = Max(iJpgFrameInfo.iMaxVertSampleFactor,compInfo.iVertSampleFactor);
       
   899 		}
       
   900 
       
   901 	if (iJpgFrameInfo.iNumberOfComponents == 1)
       
   902 		{
       
   903 		iJpgFrameInfo.iComponent[0].iHorzSampleFactor = 1;
       
   904 		iJpgFrameInfo.iComponent[0].iVertSampleFactor = 1;
       
   905 		iJpgFrameInfo.iMaxHorzSampleFactor = 1;
       
   906 		iJpgFrameInfo.iMaxVertSampleFactor = 1;
       
   907 		}
       
   908 	else if (!iJFIFMarkerPresent)
       
   909 		{
       
   910 		if (iAdobeMarkerPresent && (iAdobeTransform != KAdobeColorTransformYCbCr))
       
   911 			{
       
   912 			JPEG_LEAVE(KErrNotSupported, "Unsupported Adobe transform");
       
   913 			}
       
   914 		else if (!iAdobeMarkerPresent)
       
   915 			{
       
   916 			// No markers present, so check for RGB and YCC, which are not supported.
       
   917 			if ((iJpgFrameInfo.iComponent[0].iId == 82) && (iJpgFrameInfo.iComponent[1].iId == 71) && (iJpgFrameInfo.iComponent[2].iId == 66))
       
   918 				{
       
   919 				JPEG_LEAVE(KErrNotSupported, "RGB and YCC not supported");
       
   920 				}
       
   921 
       
   922 			if ((iJpgFrameInfo.iComponent[0].iId == 89) && (iJpgFrameInfo.iComponent[1].iId == 67) && (iJpgFrameInfo.iComponent[2].iId == 99))
       
   923 				{
       
   924 				JPEG_LEAVE(KErrNotSupported, "RGB and YCC not supported");
       
   925 				}
       
   926 			}
       
   927 		}
       
   928 	
       
   929 	JPEG_DEBUG2("Frame max horiz sample factor: %d", iJpgFrameInfo.iMaxHorzSampleFactor);
       
   930 	JPEG_DEBUG2("Frame max vert sample factor: %d", iJpgFrameInfo.iMaxHorzSampleFactor);
       
   931 	}
       
   932 
       
   933 void CJpegDecoder::ProcessStartOfScanL()
       
   934 	{
       
   935 	const TUint8* ptr = iPtr;
       
   936 	iImageOffset = StartPosition() + iBlockLength - 2;
       
   937 	iScanInfo.iImageOffset = iImageOffset;
       
   938 	TJpgScanInfoProcessor::ProcessStartOfScanL(ptr, iJpgFrameInfo, iScanInfo, iDCHuffmanTable, iACHuffmanTable);
       
   939 	}
       
   940 
       
   941 void CJpegDecoder::ProcessRestartInterval()
       
   942 	{
       
   943 	const TUint8* ptr = iPtr;
       
   944 	iJpgFrameInfo.iRestartInterval = ReadBigEndianUint16(ptr);
       
   945 	JPEG_DEBUG2("Frame restart interval: %d", iJpgFrameInfo.iRestartInterval);
       
   946 	}
       
   947 
       
   948 void CJpegDecoder::ProcessCommentL()
       
   949 	{
       
   950 	if(iBlockLength < 2) // need at least 2 bytes for length field
       
   951 		{
       
   952 		JPEG_LEAVE(KErrCorrupt, "Not enough data for comment");
       
   953 		}
       
   954 
       
   955 	TPtrC8 commentDes(iPtr, iBlockLength - 2);
       
   956 	HBufC8* comment = commentDes.AllocLC();
       
   957 	JPEG_LEAVE_IF_ERROR(iComment.Append(comment), "Appending comment");
       
   958 	CleanupStack::Pop(comment);
       
   959 	}
       
   960 
       
   961 void CJpegDecoder::FinishedProcessing()
       
   962 	{
       
   963 	SetStartPosition(iImageOffset);
       
   964 	SetDataLength(KMaxTInt);
       
   965 
       
   966 	TFrameInfo imageInfo;
       
   967 	imageInfo = ImageInfo();
       
   968 	imageInfo.iFrameCoordsInPixels.SetRect(TPoint(0,0),iJpgFrameInfo.iSizeInPixels);
       
   969 	imageInfo.iOverallSizeInPixels = iJpgFrameInfo.iSizeInPixels;
       
   970 			
       
   971 	imageInfo.iFrameSizeInTwips = iJpgFrameInfo.iSizeInTwips;
       
   972 	imageInfo.iBitsPerPixel = 8 * iJpgFrameInfo.iNumberOfComponents;
       
   973 	imageInfo.iDelay = 0;
       
   974 	imageInfo.iFlags = TFrameInfo::ECanDither;
       
   975 	if (iJpgFrameInfo.iNumberOfComponents > 1)
       
   976 		imageInfo.iFlags |= TFrameInfo::EColor;
       
   977 
       
   978 	// Set display mode.
       
   979 	switch (imageInfo.iBitsPerPixel)
       
   980 		{
       
   981 	case 1:
       
   982 		imageInfo.iFrameDisplayMode = EGray2;
       
   983 		break;
       
   984 
       
   985 	case 2:
       
   986 		imageInfo.iFrameDisplayMode = EGray4;
       
   987 		break;
       
   988 
       
   989 	case 4:
       
   990 		imageInfo.iFrameDisplayMode = (imageInfo.iFlags & TFrameInfo::EColor) ? EColor16 : EGray16;
       
   991 		break;
       
   992 
       
   993 	case 8:
       
   994 		imageInfo.iFrameDisplayMode = (imageInfo.iFlags & TFrameInfo::EColor) ? EColor256 : EGray256;
       
   995 		break;
       
   996 
       
   997 	case 12:
       
   998 		imageInfo.iFrameDisplayMode = EColor4K;
       
   999 		break;
       
  1000 
       
  1001 	case 16:
       
  1002 		imageInfo.iFrameDisplayMode = EColor64K;
       
  1003 		break;
       
  1004 
       
  1005 	case 24:
       
  1006 		imageInfo.iFrameDisplayMode = EColor16M;
       
  1007 		break;
       
  1008 		}
       
  1009 
       
  1010 	if ((DecoderOptions() & CImageDecoder::EOptionAutoRotate) && iExifDecoder) 
       
  1011 		{
       
  1012 		TUint16 orientation = 0;
       
  1013 		
       
  1014 		// if orientation tag is not found in the Ifd it is 0 
       
  1015 		if (iImageType == CImageDecoder::EImageTypeMain)
       
  1016 			{
       
  1017 			iExifDecoder->GetShortParam(0x0112, KExifIfdZero, orientation);
       
  1018 			}
       
  1019 		else if (iImageType == CImageDecoder::EImageTypeThumbnail)
       
  1020 			{
       
  1021 			iExifDecoder->GetShortParam(0x0112, KExifIfdOne, orientation);
       
  1022 			}
       
  1023 
       
  1024 		// check for corrupted orientation tag value
       
  1025 		if (orientation > 8)
       
  1026 			{
       
  1027 			orientation = 0;
       
  1028 			}
       
  1029 		
       
  1030 		if (orientation >= 4 && orientation <= 8) 
       
  1031 			{
       
  1032 			imageInfo.iOverallSizeInPixels.iWidth = iJpgFrameInfo.iSizeInPixels.iHeight;
       
  1033 			imageInfo.iOverallSizeInPixels.iHeight = iJpgFrameInfo.iSizeInPixels.iWidth;
       
  1034 			// not sure we need the lines below but just in case
       
  1035 			imageInfo.iFrameSizeInTwips.iWidth = iJpgFrameInfo.iSizeInTwips.iHeight;
       
  1036 			imageInfo.iFrameSizeInTwips.iHeight = iJpgFrameInfo.iSizeInTwips.iWidth;
       
  1037 			imageInfo.iFrameSizeInPixels.iWidth = iJpgFrameInfo.iSizeInPixels.iHeight;
       
  1038 			imageInfo.iFrameSizeInPixels.iHeight = iJpgFrameInfo.iSizeInPixels.iWidth;
       
  1039 			imageInfo.iFrameCoordsInPixels.SetRect(TPoint(0, 0), TPoint(iJpgFrameInfo.iSizeInPixels.iHeight, iJpgFrameInfo.iSizeInPixels.iWidth));
       
  1040 			}
       
  1041 
       
  1042 		iAutoRotateFlag = orientation;
       
  1043 		}
       
  1044 
       
  1045 	SetImageInfo(imageInfo);
       
  1046 	}
       
  1047 
       
  1048 void CJpegDecoder::InitCustomAsyncL(TInt aParam)
       
  1049 	{
       
  1050 	if (aParam == KOptionConvertFrameUidValue)
       
  1051 		{
       
  1052 		HandleConvertFrameL();
       
  1053 		}
       
  1054 	else if (aParam == KOptionContinueConvertFrameUidValue)
       
  1055 		{
       
  1056 		HandleContinueConvertFrameL();
       
  1057 		}
       
  1058 	}
       
  1059 
       
  1060 void CJpegDecoder::HandleConvertFrameL()
       
  1061 	{
       
  1062 	CImageDecoderPlugin::RequestInitL(FrameNumber());
       
  1063 
       
  1064 	CJpgReadCodec* jpgReadCodec = reinterpret_cast<CJpgReadCodec*>(ImageReadCodec());
       
  1065 	JPEG_ASSERT(jpgReadCodec);
       
  1066 	jpgReadCodec->InitFrameL(DstImageFrame());
       
  1067 	}
       
  1068 
       
  1069 void CJpegDecoder::HandleContinueConvertFrameL()
       
  1070 	{
       
  1071 	CJpgReadCodec* jpgReadCodec = reinterpret_cast<CJpgReadCodec*>(ImageReadCodec());
       
  1072 	JPEG_ASSERT(jpgReadCodec);
       
  1073 	CJpgImageFrameReadCodec* imageframeCodec = jpgReadCodec->ImageFrameCodec();
       
  1074 	if(imageframeCodec == NULL)
       
  1075 		{
       
  1076 		// ConvertFrame() should have been called to initiate the image frame processor
       
  1077 		// before calling ContinueConvertFrame()
       
  1078 		JPEG_LEAVE(KErrNotReady, "Continue called before Convert");
       
  1079 		}
       
  1080 	else
       
  1081 		{
       
  1082 		if (imageframeCodec->Destination() == NULL)
       
  1083 			{
       
  1084 			// ConvertFrame() should have been called to initiate the destination
       
  1085 			// before calling ContinueConvertFrame()
       
  1086 			JPEG_LEAVE(KErrNotReady, "Continue called before Convert");
       
  1087 			}
       
  1088 		}
       
  1089 	}
       
  1090 
       
  1091 void CJpegDecoder::HandleCustomSyncL(TInt aParam)
       
  1092 	{
       
  1093 	CJpgReadCodec* codec = reinterpret_cast<CJpgReadCodec*>(ImageReadCodec());
       
  1094 	JPEG_ASSERT(codec);
       
  1095 	
       
  1096 	if(aParam == CJpegYuvDecoder::EOptionYuvDecode)
       
  1097 		{
       
  1098 		codec->SetYuvDecode(ETrue);
       
  1099 		}
       
  1100 	else if(aParam == KOptionRecommendBufferSizeUidValue)
       
  1101 		{
       
  1102 		TUid formatCode = FormatCode();
       
  1103 		TInt bufferSize = codec->RecommendBufferSizeL(formatCode);
       
  1104 		SetRecommendedBufferSize(bufferSize);
       
  1105 		}
       
  1106 	else
       
  1107 		{
       
  1108 		JPEG_LEAVE(KErrNotSupported, "Unsupported custom sync");
       
  1109 		}
       
  1110 	}
       
  1111 
       
  1112 void CJpegDecoder::NotifyComplete()
       
  1113 	{
       
  1114 	iState = EStateStart; // ensure that however we exit one run, start at top of next DoConvert()
       
  1115 	CJpgReadCodec* jpgReadCodec = REINTERPRET_CAST(CJpgReadCodec*, ImageReadCodec());
       
  1116 	JPEG_ASSERT(jpgReadCodec);
       
  1117 	
       
  1118 	if (iCodecState == EFrameComplete)
       
  1119 		{
       
  1120 		// should be safe to clear buffers here
       
  1121 		jpgReadCodec->CleanupBuffers();
       
  1122 		}
       
  1123 
       
  1124 	jpgReadCodec->SetYuvDecode(EFalse);
       
  1125 	}
       
  1126 
       
  1127 // System Wide Define
       
  1128 #ifdef SYMBIAN_ENABLE_1630_JPEG_EXTENSIONS
       
  1129 void CJpegDecoder::SetClippingRectL(const TRect* aRect)
       
  1130 	{
       
  1131 	RPointerArray<TFrameInfo> frameInfo;
       
  1132 	CleanupClosePushL(frameInfo);
       
  1133 		
       
  1134 	// JPEG only has a single frame
       
  1135 	frameInfo.AppendL(&FrameInfo(0));
       
  1136 	
       
  1137 	// The clipping operation is reset by passing a NULL rect pointer.
       
  1138 	ASSERT(iExtensionManager);
       
  1139 	iExtensionManager->SetClippingRectL(aRect, frameInfo);
       
  1140 	CleanupStack::PopAndDestroy();	// frameInfo
       
  1141 	}
       
  1142 #else
       
  1143 void CJpegDecoder::SetClippingRectL(const TRect* /*aRect*/)
       
  1144 	{
       
  1145 	User::Leave(KErrNotSupported);
       
  1146 	}
       
  1147 #endif
       
  1148 
       
  1149 TInt CJpegDecoder::SamplingScheme(TJpegImageData::TColorSampling& aSamplingScheme) const
       
  1150 	{
       
  1151 	ASSERT(iJpgFrameInfo.iMaxHorzSampleFactor != 0);
       
  1152 	ASSERT(iJpgFrameInfo.iMaxVertSampleFactor != 0);
       
  1153 	
       
  1154 	TInt retValue = KErrNotSupported;
       
  1155 	if (iJpgFrameInfo.iNumberOfComponents == 1)
       
  1156 		{
       
  1157 		aSamplingScheme = TJpegImageData::EMonochrome;
       
  1158 		retValue = KErrNone;
       
  1159 		}
       
  1160 	else
       
  1161 		{
       
  1162 		if (iJpgFrameInfo.iMaxHorzSampleFactor == 1 && iJpgFrameInfo.iMaxVertSampleFactor == 1)
       
  1163 			{
       
  1164 			aSamplingScheme = TJpegImageData::EColor444;
       
  1165 			retValue = KErrNone;
       
  1166 			}
       
  1167 		else if (iJpgFrameInfo.iMaxHorzSampleFactor == 2 && iJpgFrameInfo.iMaxVertSampleFactor == 1)
       
  1168 			{
       
  1169 			aSamplingScheme = TJpegImageData::EColor422;
       
  1170 			retValue = KErrNone;
       
  1171 			}
       
  1172 		else if (iJpgFrameInfo.iMaxHorzSampleFactor == 2 && iJpgFrameInfo.iMaxVertSampleFactor == 2)
       
  1173 			{
       
  1174 			aSamplingScheme = TJpegImageData::EColor420;
       
  1175 			retValue = KErrNone;
       
  1176 			}
       
  1177 		}
       
  1178 	return retValue;
       
  1179 	}
       
  1180 
       
  1181 void CJpegEncoder::WriteThumbnailL()
       
  1182 	{
       
  1183 	iThumbnailSize=0;
       
  1184 	if(iGenerateThumbnail)
       
  1185 		{
       
  1186 		if (iExifEncoder)
       
  1187 			{
       
  1188 			// EXIF thumbnail is surrounded by SOI and EOI
       
  1189 			iThumbnailSize += WriteSOIL(Position());
       
  1190 
       
  1191 			// encode and write the thumbnail
       
  1192 			iThumbnailSize += WriteThumbnailDataL();
       
  1193 
       
  1194 			iThumbnailSize += WriteEOIL(Position());
       
  1195 			}
       
  1196 		else
       
  1197 			{
       
  1198 			iThumbnailSize += WriteThumbnailDataL();
       
  1199 			}
       
  1200 		}
       
  1201 
       
  1202 	StartPosition() = Position();
       
  1203 	Position()=0;
       
  1204 	}
       
  1205 
       
  1206 
       
  1207 void CJpegEncoder::CreateScaledBitmapL(TRequestStatus*& aScaleCompletionStatus)
       
  1208 	{
       
  1209 	// Create the Scaled Thumbnail
       
  1210 	iSourceThumbnailImage=NULL;
       
  1211 	if(iThumbnailImage)
       
  1212 		{
       
  1213 		delete iThumbnailImage;
       
  1214 		iThumbnailImage=NULL;
       
  1215 		}
       
  1216 	if(iBitmapScaler)
       
  1217 		{
       
  1218 		delete iBitmapScaler;
       
  1219 		iBitmapScaler=NULL;
       
  1220 		}
       
  1221 	iThumbnailImage=new (ELeave) CFbsBitmap;
       
  1222 
       
  1223 	CImageWriteCodec* imageWriteCodec=ImageWriteCodec();
       
  1224 	JPEG_ASSERT(imageWriteCodec);
       
  1225 
       
  1226 
       
  1227 	// the scaler does not modify the source bmp, so we apply it directly on this
       
  1228 	iSourceThumbnailImage=const_cast<CFbsBitmap*>(imageWriteCodec->Source());
       
  1229 
       
  1230 	if (iFrameInfo.iNumberOfComponents == 1) 
       
  1231 		{
       
  1232 		//DEF113733: Monochrome image conversion so thumbnail should be grayscale
       
  1233 		TInt err = iThumbnailImage->Create(TSize(KThumbnailWidth, KThumbnailHeight), EGray256);
       
  1234 		JPEG_LEAVE_IF_ERROR(err, "Failed to create thumbnail bitmap");
       
  1235 		}
       
  1236 	else 
       
  1237 		{
       
  1238 		TInt err = iThumbnailImage->Create(TSize(KThumbnailWidth, KThumbnailHeight), KThumbnailDisplayMode);
       
  1239 		JPEG_LEAVE_IF_ERROR(err, "Failed to create thumbnail bitmap");
       
  1240 		}
       
  1241 
       
  1242 	iBitmapScaler=CBitmapScaler::NewL();
       
  1243 	*aScaleCompletionStatus=KRequestPending;
       
  1244 	iBitmapScaler->Scale(aScaleCompletionStatus, *iSourceThumbnailImage, *iThumbnailImage);
       
  1245 	}
       
  1246 
       
  1247 void CJpegEncoder::Cleanup()
       
  1248 	{
       
  1249 	if (iBitmapScaler)
       
  1250 		{
       
  1251 		iBitmapScaler->Cancel();
       
  1252 		}
       
  1253 	CImageEncoderPlugin::Cleanup();
       
  1254 	}
       
  1255 
       
  1256 void CJpegEncoder::TransformBitmapL(CFbsBitmap& aSource, CFbsBitmap& aDest)
       
  1257 	{
       
  1258 	TPositionProcessor posProcess;
       
  1259 	TPoint pos;
       
  1260 
       
  1261 	TUint8 *sourceBitmap = reinterpret_cast<TUint8*>( aSource.DataAddress() );
       
  1262 
       
  1263 	CJpgWriteCodec::InitTransformCoordinates(posProcess, TRect(TPoint(0,0),TPoint(aSource.SizeInPixels().iWidth, aSource.SizeInPixels().iHeight)), TSize(KJpgPixelRatio, KJpgPixelRatio), iOperationExtPtr->iImgConvOperations);
       
  1264 
       
  1265 	if(posProcess.SwapDimensions())
       
  1266 		{
       
  1267 		User::LeaveIfError(aDest.Create(TSize(iThumbnailImage->SizeInPixels().iHeight, iThumbnailImage->SizeInPixels().iWidth), KThumbnailDisplayMode));
       
  1268 		}
       
  1269 	else
       
  1270 		{
       
  1271 		User::LeaveIfError(aDest.Create(iThumbnailImage->SizeInPixels(), KThumbnailDisplayMode));
       
  1272 	    TInt tempDimension = iFrameInfo.iSizeInPixels.iHeight;
       
  1273 		iFrameInfo.iSizeInPixels.iHeight = iFrameInfo.iSizeInPixels.iWidth; // Y
       
  1274 		iFrameInfo.iSizeInPixels.iWidth = tempDimension; // X
       
  1275 		}
       
  1276 
       
  1277 	TUint8 *destBitmap = reinterpret_cast<TUint8*>( aDest.DataAddress() );
       
  1278 	
       
  1279 	TInt srcScanlineWidth = aSource.ScanLineLength(aSource.SizeInPixels().iWidth, KThumbnailDisplayMode);
       
  1280 	TInt destScanlineWidth = aDest.ScanLineLength(aDest.SizeInPixels().iWidth, KThumbnailDisplayMode);
       
  1281 	
       
  1282 	TInt destWidthCount = 0;
       
  1283 	TInt destWidth = aDest.SizeInPixels().iWidth;
       
  1284 
       
  1285 	do
       
  1286 		{
       
  1287 		posProcess.GetCurrentPosition(pos);
       
  1288 		TUint8* srcPtr = (sourceBitmap + (pos.iX + (pos.iY * (srcScanlineWidth))));
       
  1289 		if(++destWidthCount >= destWidth)
       
  1290 			{
       
  1291 			destBitmap = destBitmap + (destScanlineWidth - destWidth); //move the destination bitmap pointer past the padded width to make sure we don't write actual pixel data on target padded portion. Works only when thumbnail bitmap diaplay mode is EColor256.
       
  1292 			destWidthCount = 0;
       
  1293 			}	
       
  1294 		*destBitmap++ = *srcPtr;
       
  1295 		posProcess.MoveNext();
       
  1296 		} while (!posProcess.IsEndOfImage());
       
  1297    	}
       
  1298 
       
  1299 TInt CJpegEncoder::WriteThumbnailDataL()
       
  1300 	{
       
  1301 	//TUint8 cast only works because src and dest bitmap are EColor256
       
  1302 	ASSERT( KThumbnailDisplayMode == EColor256);
       
  1303 
       
  1304 	// iSourceThumbnailImage is a pointer on the image of the codec
       
  1305 	// we just need to nullify if
       
  1306 	iSourceThumbnailImage=NULL;
       
  1307 	
       
  1308 	if(iBitmapScaler)
       
  1309 		{
       
  1310 		delete iBitmapScaler;
       
  1311 		iBitmapScaler=NULL;
       
  1312 		}
       
  1313 	if(iThumbnailImage==NULL)
       
  1314 		{
       
  1315 		User::Leave(KErrNotFound);
       
  1316 		}
       
  1317 
       
  1318 	TInt writtenSize=0;
       
  1319 
       
  1320 	CFbsBitmap* tranformedThumbnailImage = NULL;
       
  1321 	CFbsBitmap* thumbImage = NULL;
       
  1322 
       
  1323 	thumbImage = iThumbnailImage;
       
  1324 
       
  1325 	if(iOperationExtPtr)
       
  1326 		{
       
  1327 		tranformedThumbnailImage = new (ELeave) CFbsBitmap;
       
  1328 		CleanupStack::PushL(tranformedThumbnailImage);
       
  1329 		TransformBitmapL(*iThumbnailImage, *tranformedThumbnailImage);
       
  1330 		thumbImage = tranformedThumbnailImage;
       
  1331 		}
       
  1332 
       
  1333 
       
  1334 	if (iExifEncoder)
       
  1335 		{
       
  1336 		// write thumbnail as EXIF
       
  1337 		writtenSize = WriteThumbnailAsExifL(*thumbImage);
       
  1338 		}
       
  1339 	else
       
  1340 		{
       
  1341 		// write thumbnail as JFIF
       
  1342 		writtenSize = WriteThumbnailAsJfifL(*thumbImage);
       
  1343 		}
       
  1344 
       
  1345 	delete iThumbnailImage;
       
  1346 	iThumbnailImage = NULL;
       
  1347 	if(iOperationExtPtr)
       
  1348 		{
       
  1349 		CleanupStack::PopAndDestroy(tranformedThumbnailImage);
       
  1350 		}
       
  1351 
       
  1352 	return writtenSize;
       
  1353 	}
       
  1354 
       
  1355 TInt CJpegEncoder::WriteThumbnailAsExifL(CFbsBitmap& aBitmap)
       
  1356 	{
       
  1357 	TInt writtenSize=0;
       
  1358 	CImageWriteCodec* thumbnailImageWriteCodec;
       
  1359 
       
  1360 	thumbnailImageWriteCodec = CJpgWriteCodec::NewL(iFrameInfo,iQualityFactor,iLumaTable,iChromaTable,iComment,NULL);
       
  1361 
       
  1362 	CleanupStack::PushL(thumbnailImageWriteCodec);
       
  1363 	// create the buffer for the thumbnail data
       
  1364 	HBufC8* encodeBuffer=HBufC8::NewL(KIOBlockSize);
       
  1365 	CleanupStack::PushL(encodeBuffer);
       
  1366 
       
  1367 	TBufPtr8 encodeBufPtr;
       
  1368 	encodeBuffer->Des().FillZ();
       
  1369 	encodeBufPtr.Set(encodeBuffer->Des());
       
  1370 
       
  1371 	thumbnailImageWriteCodec->InitFrameL(encodeBufPtr, aBitmap);
       
  1372 
       
  1373 	WriteDataPositionIncL(Position(), encodeBufPtr);
       
  1374 	writtenSize+=encodeBufPtr.Length()*sizeof(TUint8);
       
  1375 
       
  1376 	TFrameState frameErr;
       
  1377 	while((frameErr=thumbnailImageWriteCodec->ProcessFrameL(encodeBufPtr)) == EFrameIncomplete)
       
  1378 		{
       
  1379 		WriteDataPositionIncL(Position(), encodeBufPtr);
       
  1380 		writtenSize+=encodeBufPtr.Length()*sizeof(TUint8);
       
  1381 		}
       
  1382 
       
  1383 	switch(frameErr)
       
  1384 		{
       
  1385 		case EFrameComplete:
       
  1386 			// happy ending
       
  1387 			WriteDataPositionIncL(Position(), encodeBufPtr);
       
  1388 			writtenSize+=encodeBufPtr.Length()*sizeof(TUint8);
       
  1389 			break;
       
  1390 		case EUnexpectedEndOfData:
       
  1391 		case EFrameIncompleteRepositionRequest:
       
  1392 			User::Leave(KErrEof);
       
  1393 			break;
       
  1394 		default:
       
  1395 			User::Leave(KErrUnknown);
       
  1396 			break;
       
  1397 		}
       
  1398 
       
  1399 	CleanupStack::PopAndDestroy(encodeBuffer);
       
  1400 	CleanupStack::PopAndDestroy(thumbnailImageWriteCodec);
       
  1401 
       
  1402 	return writtenSize;
       
  1403 	}
       
  1404 
       
  1405 
       
  1406 TInt CJpegEncoder::WriteThumbnailAsJfifL(CFbsBitmap& aBitmap)
       
  1407 	{
       
  1408 	TInt writtenSize=0;
       
  1409 	// CBitmapScaler might not produce exact KThumbnailWidth * KThumbnailHeight
       
  1410 	// so get the actual size
       
  1411 	iGeneratedThumbnailSize = aBitmap.SizeInPixels();
       
  1412 
       
  1413 	HBufC8* buffer = HBufC8::NewL(iGeneratedThumbnailSize.iWidth * iGeneratedThumbnailSize.iHeight * 3);
       
  1414 	CleanupStack::PushL(buffer);
       
  1415 	TBufPtr8 bufferPtr;
       
  1416 	bufferPtr.Set(buffer->Des());
       
  1417 
       
  1418 	TPoint currentPos(0, 0);
       
  1419 	TBitmapUtil bitmapUtil(&aBitmap);
       
  1420 	bitmapUtil.Begin(currentPos);
       
  1421 	for (; currentPos.iY < iGeneratedThumbnailSize.iHeight; currentPos.iY++)
       
  1422 		{
       
  1423 		currentPos.iX = 0;
       
  1424 		bitmapUtil.SetPos(currentPos);
       
  1425 		TRgb currentPixel;
       
  1426 		for (; currentPos.iX < iGeneratedThumbnailSize.iWidth; currentPos.iX++)
       
  1427 			{
       
  1428 			if (iFrameInfo.iNumberOfComponents == 1)
       
  1429 				{
       
  1430 				//DEF113733: if number of components is 1, we want to use grey scale pixels
       
  1431 				currentPixel = TRgb::Gray256(bitmapUtil.GetPixel());
       
  1432 				}
       
  1433 			else 
       
  1434 				{
       
  1435 				currentPixel = TRgb::Color256(bitmapUtil.GetPixel());
       
  1436 				}
       
  1437 				
       
  1438 			bufferPtr.Append(currentPixel.Red());
       
  1439 			bufferPtr.Append(currentPixel.Green());
       
  1440 			bufferPtr.Append(currentPixel.Blue());
       
  1441 
       
  1442 			bitmapUtil.IncXPos();
       
  1443 			}
       
  1444 		}
       
  1445 	bitmapUtil.End();
       
  1446 
       
  1447 	WriteDataPositionIncL(Position(), bufferPtr);
       
  1448 	writtenSize += bufferPtr.Length() * sizeof(TUint8);
       
  1449 
       
  1450 	CleanupStack::PopAndDestroy(buffer);
       
  1451 
       
  1452 	return writtenSize;
       
  1453 	}
       
  1454 
       
  1455 void CJpegEncoder::WriteExifDataL(TRequestStatus*& aScaleCompletionStatus)
       
  1456 	{
       
  1457 	User::LeaveIfError( iThumbnailStatus );
       
  1458 
       
  1459 	if (iExifEncoder)
       
  1460 		{
       
  1461 		// we get the exifData
       
  1462 		// exif data is own by the exif encoder. We don't push it on the cleanupstack
       
  1463 		iExifDataPosition=Position();
       
  1464 		TPtrC8 exifDataStr=iExifEncoder->CreateExifHeaderL();
       
  1465 		// and write it
       
  1466 		iExifSize=exifDataStr.Length()*sizeof(TUint8);
       
  1467 		WriteDataPositionIncL(iExifDataPosition, exifDataStr);
       
  1468 		}
       
  1469 
       
  1470 	if(iGenerateThumbnail)
       
  1471 		{
       
  1472 		CreateScaledBitmapL(aScaleCompletionStatus);
       
  1473 		}
       
  1474 	else
       
  1475 		{
       
  1476 		// the framework waits for	aScaleCompletionStatus to  complete
       
  1477 		SelfComplete(KErrNone);
       
  1478 		}
       
  1479 	}
       
  1480 
       
  1481 // Jpeg encoder.
       
  1482 CJpegEncoder* CJpegEncoder::NewL()
       
  1483 	{
       
  1484 	CJpegEncoder* self=new(ELeave) CJpegEncoder;
       
  1485 	CleanupStack::PushL(self);
       
  1486 	self->ConstructL();
       
  1487 	CleanupStack::Pop(self);
       
  1488 
       
  1489 	return self;
       
  1490 	}
       
  1491 
       
  1492 void CJpegEncoder::ConstructL()
       
  1493 	{
       
  1494 	}
       
  1495 
       
  1496 CJpegEncoder::CJpegEncoder()
       
  1497 	: iGenerateThumbnail(EFalse)
       
  1498 	{
       
  1499 	// Set relevant defaults for the write codec.
       
  1500 	// Output precision is 8, not progressive, no restarts and no thumbnail
       
  1501 	iFrameInfo.iNumberOfComponents = 3;
       
  1502 	iFrameInfo.iComponent[0].iHorzSampleFactor = 2;
       
  1503 	iFrameInfo.iComponent[0].iVertSampleFactor = 2;
       
  1504 	iFrameInfo.iComponent[0].iQTable = 0;
       
  1505 	iFrameInfo.iComponent[1].iHorzSampleFactor = 1;
       
  1506 	iFrameInfo.iComponent[1].iVertSampleFactor = 1;
       
  1507 	iFrameInfo.iComponent[1].iQTable = 1;
       
  1508 	iFrameInfo.iComponent[2].iHorzSampleFactor = 1;
       
  1509 	iFrameInfo.iComponent[2].iVertSampleFactor = 1;
       
  1510 	iFrameInfo.iComponent[2].iQTable = 1;
       
  1511 	iFrameInfo.iMaxHorzSampleFactor = 2;
       
  1512 	iFrameInfo.iMaxVertSampleFactor = 2;
       
  1513 
       
  1514 	iExtOperationActive = ENone;
       
  1515 	}
       
  1516 
       
  1517 CJpegEncoder::~CJpegEncoder()
       
  1518 	{
       
  1519 	Cleanup();
       
  1520 	delete iLumaTable;
       
  1521 	delete iChromaTable;
       
  1522 	delete iExifEncoder;
       
  1523 	
       
  1524 	iSourceThumbnailImage = NULL;
       
  1525 	delete iBitmapScaler;
       
  1526 	delete iThumbnailImage;
       
  1527 	
       
  1528 	delete iOperationExtPtr;
       
  1529 	delete iStreamedEncodeExt;
       
  1530 	
       
  1531 	iComment.ResetAndDestroy();
       
  1532 	}
       
  1533 
       
  1534 MExifMetadata* CJpegEncoder::ExifMetadata()
       
  1535 	{
       
  1536 	if (!iExifEncoder)
       
  1537 		{
       
  1538 		// set thumbnail on for EXIF (ensure continuity of behaviour)
       
  1539 		iGenerateThumbnail = ETrue;
       
  1540 
       
  1541 		// creating the CExifEncoder has the required side-effect
       
  1542 		// of switching from JFIF to EXIF header output
       
  1543 		TInt err;
       
  1544 		TRAP(err, iExifEncoder = CExifEncoder::NewL(iGenerateThumbnail));
       
  1545 		}
       
  1546 	return iExifEncoder;
       
  1547 	};
       
  1548 
       
  1549 
       
  1550 void CJpegEncoder::PrepareEncoderL(const CFrameImageData* aFrameImageData)
       
  1551 	{
       
  1552 	iQualityFactor = 0;
       
  1553 
       
  1554 	TInt count = (aFrameImageData) ? aFrameImageData->ImageDataCount() : 0;
       
  1555 
       
  1556 	if (count == 0)
       
  1557 		{
       
  1558 		// Use the default value.
       
  1559 		// Note: This default value is also used by the TJpegImageData default
       
  1560 		// constructor.  So if it changed to a different value here, then it should
       
  1561 		// be changed there as well.
       
  1562 		iQualityFactor = 75;
       
  1563 		}
       
  1564 
       
  1565 	TBool jpgImageDataProcessed = EFalse;
       
  1566 	for (TInt index = 0 ; index<count ; index++)
       
  1567 		{
       
  1568 		const TImageDataBlock& encoderData = *aFrameImageData->GetImageData(index);
       
  1569 		if (encoderData.DataType() == KJPGImageDataUid)
       
  1570 			{
       
  1571 			// Leave if we have already processed one of these.
       
  1572 			if (jpgImageDataProcessed)
       
  1573 				User::Leave(KErrCorrupt);
       
  1574 
       
  1575 			const TJpegImageData& jpegImageData = STATIC_CAST(const TJpegImageData&, encoderData);
       
  1576 			iQualityFactor = jpegImageData.iQualityFactor;
       
  1577 
       
  1578 			TJpegImageData::TColorSampling sampleScheme = jpegImageData.iSampleScheme;
       
  1579 			iFrameInfo.iComponent[0].iQTable = 0;
       
  1580 			if (sampleScheme == TJpegImageData::EMonochrome)
       
  1581 				{
       
  1582 				iFrameInfo.iNumberOfComponents = 1;
       
  1583 				iFrameInfo.iComponent[0].iHorzSampleFactor = 1;
       
  1584 				iFrameInfo.iComponent[0].iVertSampleFactor = 1;
       
  1585 				}
       
  1586 			else
       
  1587 				{
       
  1588 				iFrameInfo.iNumberOfComponents = 3;
       
  1589 				switch (sampleScheme)
       
  1590 					{
       
  1591 				case TJpegImageData::EColor420:
       
  1592 					iFrameInfo.iComponent[0].iHorzSampleFactor = 2;
       
  1593 					iFrameInfo.iComponent[0].iVertSampleFactor = 2;
       
  1594 					iFrameInfo.iComponent[1].iVertSampleFactor = 1;
       
  1595 					iFrameInfo.iComponent[2].iVertSampleFactor = 1;
       
  1596 					break;
       
  1597 				case TJpegImageData::EColor422:
       
  1598 					iFrameInfo.iComponent[0].iHorzSampleFactor = 2;
       
  1599 					iFrameInfo.iComponent[0].iVertSampleFactor = 1;
       
  1600 					iFrameInfo.iComponent[1].iVertSampleFactor = 1;
       
  1601 					iFrameInfo.iComponent[2].iVertSampleFactor = 1;
       
  1602 					break;
       
  1603 				case TJpegImageData::EColor444:
       
  1604 					iFrameInfo.iComponent[0].iHorzSampleFactor = 1;
       
  1605 					iFrameInfo.iComponent[0].iVertSampleFactor = 1;
       
  1606 					iFrameInfo.iComponent[1].iVertSampleFactor = 1;
       
  1607 					iFrameInfo.iComponent[2].iVertSampleFactor = 1;
       
  1608 					break;
       
  1609 				default:
       
  1610 					User::Leave(KErrNotSupported);
       
  1611 					}
       
  1612 
       
  1613 				iFrameInfo.iComponent[1].iHorzSampleFactor = 1;
       
  1614 				iFrameInfo.iComponent[1].iQTable = 1;
       
  1615 				iFrameInfo.iComponent[2].iHorzSampleFactor = 1;
       
  1616 				iFrameInfo.iComponent[2].iQTable = 1;
       
  1617 				}
       
  1618 
       
  1619 			iFrameInfo.iMaxHorzSampleFactor = iFrameInfo.iComponent[0].iHorzSampleFactor;
       
  1620 			iFrameInfo.iMaxVertSampleFactor = iFrameInfo.iComponent[0].iVertSampleFactor;
       
  1621 
       
  1622 			jpgImageDataProcessed = ETrue;
       
  1623 			}
       
  1624 		else if (encoderData.DataType() == KJPGQTableUid)
       
  1625 			{
       
  1626 			const TJpegQTable& jpegQTable = STATIC_CAST(const TJpegQTable&, encoderData);
       
  1627 			TInt tableIndex = jpegQTable.iTableIndex;
       
  1628 			if ((tableIndex != TJpegQTable::ELumaTable) && (tableIndex != TJpegQTable::EChromaTable))
       
  1629 				User::Leave(KErrNotSupported);
       
  1630 
       
  1631 			TUint8 values[KJpgQTableEntries];
       
  1632 			TUint8* valuePtr = values;
       
  1633 			const TUint8* zigZagPtr = KZigZagSequence.iZigZag;
       
  1634 			const TUint8* valuePtrLimit = valuePtr + KJpgQTableEntries;
       
  1635 
       
  1636 			while (valuePtr < valuePtrLimit)
       
  1637 				*valuePtr++ = jpegQTable.iEntries[*zigZagPtr++];
       
  1638 
       
  1639 			if (tableIndex == TJpegQTable::ELumaTable)
       
  1640 				{
       
  1641 				if (!iLumaTable)
       
  1642 					iLumaTable = new(ELeave) TQTable;
       
  1643 
       
  1644 				iLumaTable->Set(values, EFalse);
       
  1645 				}
       
  1646 			else if (tableIndex == TJpegQTable::EChromaTable)
       
  1647 				{
       
  1648 				if (!iChromaTable)
       
  1649 					iChromaTable = new(ELeave) TQTable;
       
  1650 
       
  1651 				iChromaTable->Set(values, EFalse);
       
  1652 				}
       
  1653 			else
       
  1654 				User::Leave(KErrNotSupported);
       
  1655 			}
       
  1656 		else if (encoderData.DataType() == KJPGCommentUid)
       
  1657 			{
       
  1658 			const TJpegComment& jpegComment = STATIC_CAST(const TJpegComment&, encoderData);
       
  1659 			if (!jpegComment.iComment)
       
  1660 				User::Leave(KErrNotFound);
       
  1661 
       
  1662 			if ((jpegComment.iComment->Length() == 0) || (jpegComment.iComment->Length() > 65534))
       
  1663 				User::Leave(KErrNotSupported);
       
  1664 
       
  1665 			HBufC8* comment = jpegComment.iComment->AllocL();
       
  1666 			TInt ret = iComment.Append(comment);
       
  1667 			if (ret != KErrNone)
       
  1668 				{
       
  1669 				delete comment;
       
  1670 				User::Leave(ret);
       
  1671 				}
       
  1672 			}
       
  1673 		else
       
  1674 			User::Leave(KErrCorrupt);
       
  1675 		}
       
  1676 
       
  1677 
       
  1678 	// Create codec.
       
  1679 	ASSERT(ImageWriteCodec() == NULL);
       
  1680 
       
  1681 	CJpgWriteCodec* imageWriteCodec;
       
  1682 
       
  1683 	if(!iOperationExtPtr)
       
  1684 		{
       
  1685 		imageWriteCodec = CJpgWriteCodec::NewL(iFrameInfo,iQualityFactor,iLumaTable,iChromaTable,iComment, NULL);
       
  1686 		}
       
  1687 	else
       
  1688 		{
       
  1689 		imageWriteCodec = CJpgWriteCodec::NewL(iFrameInfo,iQualityFactor,iLumaTable,iChromaTable,iComment, &iOperationExtPtr->iImgConvOperations);
       
  1690 		}
       
  1691 	
       
  1692 	imageWriteCodec->SetHighSpeedMode( (EncoderOptions() & CImageEncoder::EPreferFastEncode) == CImageEncoder::EPreferFastEncode);
       
  1693 	
       
  1694 	SetImageWriteCodec(imageWriteCodec);
       
  1695 
       
  1696 	}
       
  1697 
       
  1698 void CJpegEncoder::SetThumbnail(TBool aDoGenerateThumbnail)
       
  1699 	{
       
  1700 	if (iExifEncoder)
       
  1701 		{
       
  1702 		TRAP(iThumbnailStatus, iExifEncoder->SetEnableThumbnailL(aDoGenerateThumbnail) );
       
  1703 		if (iThumbnailStatus != KErrNone)
       
  1704 			{
       
  1705 			iGenerateThumbnail = EFalse;
       
  1706 			return;
       
  1707 			}
       
  1708 		}
       
  1709 	iGenerateThumbnail = aDoGenerateThumbnail;
       
  1710 	}
       
  1711 
       
  1712 void CJpegEncoder::UpdateHeaderL()
       
  1713 	{
       
  1714 	User::LeaveIfError( iThumbnailStatus );
       
  1715 	// Codec writes everything, except for EOI
       
  1716 	WriteEOIL(StartPosition()+Position());
       
  1717 
       
  1718 	if (iExifEncoder)
       
  1719 		{
       
  1720 		TBuf8<2> buffer2Bytes;
       
  1721 		buffer2Bytes.SetLength(2);
       
  1722 
       
  1723 		TUint8* headerPtr2 = &buffer2Bytes[0];
       
  1724 
       
  1725 		WriteBigEndianUint16(headerPtr2, iExifSize + iThumbnailSize - KApp1MarkerByteCount); // APP1 marker is not included in the length
       
  1726 
       
  1727 		// Since we are at the end of an encode and we have an explicit offset to the buffer
       
  1728 		// (i.e. to write the size of the APP1 header near the start of the buffer, and so
       
  1729 		// Position() is irrelevant) we can use WriteDataL.
       
  1730 		WriteDataL(iExifDataPosition+iExifEncoder->ExifLengthOffset(),buffer2Bytes);
       
  1731 
       
  1732 		if (iGenerateThumbnail)
       
  1733 			{
       
  1734 			TBuf8<4> buffer4Bytes;
       
  1735 			buffer4Bytes.SetLength(4);
       
  1736 			TUint8* headerPtr4 = &buffer4Bytes[0];
       
  1737 
       
  1738 			Mem::Copy(headerPtr4, &iThumbnailSize, sizeof(TUint));
       
  1739 			// Write the offset of the thumbnail (from the start of the buffer) in the
       
  1740 			// APP1 header.  Again, Position() is irrelevant and so use WriteDataL.
       
  1741 			WriteDataL(iExifDataPosition+iExifEncoder->ThumbnailLengthOffset(),buffer4Bytes);
       
  1742 			}
       
  1743 		}
       
  1744 	else if (iGenerateThumbnail)
       
  1745 		{
       
  1746 		TInt headerSize = iThumbnailSize + KJfifApp0DataSize;
       
  1747 		TBuf8<2> buffer2Bytes;
       
  1748 		buffer2Bytes.Append(TUint8((headerSize & 0xff00) >> 8));
       
  1749 		buffer2Bytes.Append(TUint8(headerSize & 0xff));
       
  1750 		WriteDataL(KJfifLengthOffset, buffer2Bytes);
       
  1751 
       
  1752 		buffer2Bytes.Zero();
       
  1753 		buffer2Bytes.Append(iGeneratedThumbnailSize.iWidth);
       
  1754 		buffer2Bytes.Append(iGeneratedThumbnailSize.iHeight);
       
  1755 
       
  1756 		WriteDataL(KJfifThumbnailXYOffset, buffer2Bytes);
       
  1757 		}
       
  1758 	}
       
  1759 
       
  1760 void CJpegEncoder::InitConvertL()
       
  1761 	{
       
  1762 	CImageEncoderPlugin::InitConvertL();
       
  1763 	// this way, the bitmap is initialized
       
  1764 
       
  1765 	WriteSOIL(StartPosition()+Position());
       
  1766 	if (!iExifEncoder)
       
  1767 		{
       
  1768 		// no EXIF data so default to JFIF header
       
  1769 		WriteImageHeaderL();
       
  1770 		}
       
  1771 	}
       
  1772 
       
  1773 void CJpegEncoder::InitCustomAsyncL(TInt aParam)
       
  1774 	{
       
  1775 	if (aParam == KOptionConvertFrameUidValue)
       
  1776 		{
       
  1777 		HandleConvertFrameL();
       
  1778 		}
       
  1779 	}
       
  1780 
       
  1781 void CJpegEncoder::HandleConvertFrameL()
       
  1782 	{
       
  1783 	// Prepare Frame Info and instantiates write codec
       
  1784 	PrepareEncoderL(&FrameImageData());
       
  1785 
       
  1786 	// ConvertFrame option does not support thumbnail
       
  1787 	SetThumbnail(EFalse);
       
  1788 
       
  1789 	// ConvertFrame bypasses the framework. Force required initialization here.
       
  1790 	CImageEncoderPlugin::RequestInitL();
       
  1791 
       
  1792 	// Initialize write codec with relevant data
       
  1793 	// This will also check consistency between FrameImageData and the souce ImageFrame format.
       
  1794 	CJpgWriteCodec* jpgWriteCodec = reinterpret_cast<CJpgWriteCodec*>(ImageWriteCodec());
       
  1795 	TBufPtr8& destData = DestinationData();
       
  1796 	jpgWriteCodec->InitFrameL(destData, &SrcImageFrame(), &FrameImageData());
       
  1797 
       
  1798 	// If everything went fine start writting data to the destination file.
       
  1799 	WriteSOIL(StartPosition()+Position());
       
  1800 	WriteImageHeaderL();
       
  1801 
       
  1802 	// If this image has exif metadata, then generate the exif data and write it
       
  1803 	if (iExifEncoder)
       
  1804 		{
       
  1805 		// we get the exifData
       
  1806 		// exif data is own by the exif encoder. We don't push it on the cleanupstack
       
  1807 		iExifDataPosition=Position();
       
  1808 		TPtrC8 exifDataStr=iExifEncoder->CreateExifHeaderL();
       
  1809 		// and write it
       
  1810 		iExifSize=exifDataStr.Length()*sizeof(TUint8);
       
  1811 		WriteDataPositionIncL(iExifDataPosition, exifDataStr);
       
  1812 		}
       
  1813 	}
       
  1814 
       
  1815 void CJpegEncoder::HandleStreamInitFrameL(TUid aFormat, TInt aFrameNumber, const TSize& aFrameSizeInPixels, const TSize& aBlockSizeInPixels, const CFrameImageData* aFrameImageData)
       
  1816 	{
       
  1817 	// Prepare Frame Info and instantiates write codec
       
  1818 	PrepareEncoderL(aFrameImageData);
       
  1819 
       
  1820 	// Stream option does not support thumbnail
       
  1821 	SetThumbnail(EFalse);
       
  1822 
       
  1823 	// ConvertFrame bypasses the framework. Force required initialization here.
       
  1824 	CImageEncoderPlugin::RequestInitL();
       
  1825 
       
  1826 	// Initialize write codec with relevant data
       
  1827 	// This will also check consistency between FrameImageData and the souce ImageFrame format.
       
  1828 	CJpgWriteCodec* jpgWriteCodec = reinterpret_cast<CJpgWriteCodec*>(ImageWriteCodec());
       
  1829 	TBufPtr8& destData = DestinationData();
       
  1830 	jpgWriteCodec->InitFrameL(destData, aFormat, aFrameNumber, aFrameSizeInPixels, aBlockSizeInPixels, aFrameImageData);
       
  1831 
       
  1832 	// If everything went fine start writting data to the destination file.
       
  1833 	WriteSOIL(StartPosition()+Position());
       
  1834 	WriteImageHeaderL();
       
  1835 
       
  1836 	// If this image has exif metadata, then generate the exif data and write it
       
  1837 	if (iExifEncoder)
       
  1838 		{
       
  1839 		// we get the exifData
       
  1840 		// exif data is own by the exif encoder. We don't push it on the cleanupstack
       
  1841 		iExifDataPosition=Position();
       
  1842 		TPtrC8 exifDataStr=iExifEncoder->CreateExifHeaderL();
       
  1843 		// and write it
       
  1844 		iExifSize=exifDataStr.Length()*sizeof(TUint8);
       
  1845 		WriteDataPositionIncL(iExifDataPosition, exifDataStr);
       
  1846 		}
       
  1847 	}
       
  1848 
       
  1849 void CJpegEncoder::HandleStreamAppendBlock(const CImageFrame& aBlocks, TInt aNumBlocksToAdd)
       
  1850 	{
       
  1851 	// Initialize write codec with relevant data
       
  1852 	// This will also check consistency between FrameImageData and the souce ImageFrame format.
       
  1853 	CJpgWriteCodec* jpgWriteCodec = reinterpret_cast<CJpgWriteCodec*>(ImageWriteCodec());
       
  1854 	JPEG_ASSERT(jpgWriteCodec);
       
  1855 	
       
  1856 	TRAPD(errCode, jpgWriteCodec->AppendFrameBlockL(aBlocks, aNumBlocksToAdd));
       
  1857 	if (errCode!=KErrNone)
       
  1858 		{
       
  1859 		RequestComplete(errCode);
       
  1860 		return;
       
  1861 		}
       
  1862 	}
       
  1863 
       
  1864 void CJpegEncoder::HandleStreamAddBlock(const CImageFrame& /*aBlocks*/, const TInt& /*aSeqPosition*/)
       
  1865 	{
       
  1866 	//Add blocks is not supported
       
  1867 	RequestComplete(KErrNotSupported);
       
  1868 	return;
       
  1869 	}
       
  1870 
       
  1871 void CJpegEncoder::HandleStreamCompleteFrame()
       
  1872 	{
       
  1873 	CJpgWriteCodec* jpgWriteCodec = reinterpret_cast<CJpgWriteCodec*>(ImageWriteCodec());
       
  1874 	JPEG_ASSERT(jpgWriteCodec);
       
  1875 	
       
  1876 	jpgWriteCodec->SetCompleteFrame();
       
  1877 	}
       
  1878 
       
  1879 TInt CJpegEncoder::WriteSOIL(const TInt aPosition)
       
  1880 	{
       
  1881 	// Codec writes everything, except for EOI
       
  1882 	TBuf8<2> buffer2Bytes;
       
  1883 	buffer2Bytes.SetLength(2);
       
  1884 
       
  1885 	TUint8* headerPtr = &buffer2Bytes[0];
       
  1886 	WriteBigEndianUint16(headerPtr,KJpgSOISignature); // Start of information
       
  1887 
       
  1888 	WriteDataPositionIncL(aPosition,buffer2Bytes);
       
  1889 
       
  1890 	return buffer2Bytes.Length()*sizeof(TUint8);
       
  1891 	}
       
  1892 
       
  1893 
       
  1894 
       
  1895 TInt CJpegEncoder::WriteImageHeaderL()
       
  1896 	{
       
  1897 	TBuf8<KJfifApp0DataSize+sizeof(KJpgApp0Signature)> buffer;
       
  1898 
       
  1899 	TJpegUtilities::CreateJfifHeader(buffer);
       
  1900 	WriteDataPositionIncL(StartPosition()+Position(),buffer);
       
  1901 
       
  1902 	return buffer.Length()*sizeof(TUint8);
       
  1903 	}
       
  1904 //Helper function to crate a default JFIF header
       
  1905 void TJpegUtilities::CreateJfifHeader(TDes8& aBuffer)
       
  1906 	{
       
  1907 	ASSERT(aBuffer.MaxLength() >= (KJfifApp0DataSize+sizeof(KJpgApp0Signature)));
       
  1908 
       
  1909 	TUint8* destPtr = const_cast<TUint8*>(aBuffer.Ptr());
       
  1910 	ASSERT(destPtr != NULL);
       
  1911 	TUint8* startDestPtr=destPtr;
       
  1912 
       
  1913 	WriteBigEndianUint16(destPtr,KJpgApp0Signature); // APP0
       
  1914 	WriteBigEndianUint16(destPtr,KJfifApp0DataSize); // Lp
       
  1915 	Mem::Copy(destPtr,KJfifId().Ptr(),KJpgApp0IdSize);
       
  1916 	destPtr += KJpgApp0IdSize;
       
  1917 	*destPtr++ = 0;
       
  1918 	WriteBigEndianUint16(destPtr,KJfifVersion0101); // Version
       
  1919 	*destPtr++ = TJpgFrameInfo::ENone; // Units
       
  1920 	WriteBigEndianUint16(destPtr,KJpgPixelRatio); // X density
       
  1921 	WriteBigEndianUint16(destPtr,KJpgPixelRatio); // Y density
       
  1922 	*destPtr++ = 0; // Thumbnail width
       
  1923 	*destPtr++ = 0; // Thumbnail height
       
  1924 
       
  1925 	aBuffer.SetLength((destPtr-startDestPtr)/sizeof(destPtr[0]));
       
  1926 	}
       
  1927 
       
  1928 
       
  1929 TInt CJpegEncoder::WriteEOIL(const TInt aPosition)
       
  1930 	{
       
  1931 	// Codec writes everything, except for EOI
       
  1932 	TBuf8<2> buffer2Bytes;
       
  1933 	buffer2Bytes.SetLength(2);
       
  1934 
       
  1935 	TUint8* headerPtr = &buffer2Bytes[0];
       
  1936 	WriteBigEndianUint16(headerPtr, KJpgEOISignature); // End of information
       
  1937 	WriteDataPositionIncL(aPosition,buffer2Bytes);
       
  1938 
       
  1939 	return buffer2Bytes.Length()*sizeof(TUint8);
       
  1940 	}
       
  1941 
       
  1942 CJpegEncoder::TExtensionOperation CJpegEncoder::GetActiveExtensionOperation() const
       
  1943 	{
       
  1944 	return iExtOperationActive;
       
  1945 	}
       
  1946 
       
  1947 void CJpegEncoder::SetActiveExtensionOperation(CJpegEncoder::TExtensionOperation aExtOperation)
       
  1948 	{
       
  1949 	iExtOperationActive = aExtOperation;
       
  1950 	}
       
  1951 
       
  1952 // System Wide Define
       
  1953 #ifdef SYMBIAN_ENABLE_1630_JPEG_EXTENSIONS
       
  1954 void CJpegEncoder::GetExtensionL(TUid aExtUid, MImageConvExtension*& aExtPtr)
       
  1955 	{
       
  1956 	switch (aExtUid.iUid)
       
  1957 		{
       
  1958 		case KUidImageConvExtOperationValue:
       
  1959 			{
       
  1960 			if (!iOperationExtPtr)
       
  1961 				{
       
  1962 				iOperationExtPtr = CEncodeOperationExtension::NewL(this);
       
  1963 				aExtPtr = iOperationExtPtr;
       
  1964 				}
       
  1965 			else
       
  1966 				{
       
  1967 				aExtPtr = iOperationExtPtr;
       
  1968 				}
       
  1969 
       
  1970 			break;
       
  1971 			}
       
  1972 
       
  1973 		case KUidImageConvExtStreamedEncodeValue:
       
  1974 			{
       
  1975 			if (!iStreamedEncodeExt)
       
  1976 				{
       
  1977 				iStreamedEncodeExt = CStreamedEncodeExtension::NewL(this);
       
  1978 				aExtPtr = iStreamedEncodeExt;
       
  1979 				}
       
  1980 			else
       
  1981 				{
       
  1982 				aExtPtr = iStreamedEncodeExt;
       
  1983 				}
       
  1984 
       
  1985 			break;
       
  1986 			}
       
  1987 
       
  1988 		default:
       
  1989 			{
       
  1990 			User::Leave(KErrNotSupported);
       
  1991 			}
       
  1992 		}
       
  1993 	}
       
  1994 #else
       
  1995 void CJpegEncoder::GetExtensionL(TUid /*aExtUid*/, MImageConvExtension*& /*aExtPtr*/)
       
  1996 	{
       
  1997 	User::Leave(KErrNotSupported);
       
  1998 	}
       
  1999 #endif
       
  2000 
       
  2001 CEncodeOperationExtension* CEncodeOperationExtension::NewL(CJpegEncoder* aJpegEncoder)
       
  2002 	{
       
  2003 	return new (ELeave) CEncodeOperationExtension(aJpegEncoder);
       
  2004 	}
       
  2005 
       
  2006 CEncodeOperationExtension::CEncodeOperationExtension(CJpegEncoder* aJpegEncoder)
       
  2007 :iJpegEncoder(aJpegEncoder), iOperationCaps(KJpgEncoderCapabilities)
       
  2008 	{
       
  2009 	IncrementRef();
       
  2010 	}
       
  2011 
       
  2012 CEncodeOperationExtension::~CEncodeOperationExtension()
       
  2013 	{
       
  2014 	ASSERT(iReferenceCount == 0);
       
  2015 	iImgConvOperations.Close();
       
  2016 	}
       
  2017 
       
  2018 TUid CEncodeOperationExtension::Uid() const
       
  2019 	{
       
  2020 	TUid KUidImgCovOperation = {KUidImageConvExtOperationValue};
       
  2021 	return KUidImgCovOperation;
       
  2022 	}
       
  2023 
       
  2024 void CEncodeOperationExtension::IncrementRef()
       
  2025 	{
       
  2026 	iReferenceCount++;
       
  2027 	}
       
  2028 
       
  2029 void CEncodeOperationExtension::Release()
       
  2030 	{
       
  2031 	iReferenceCount--;
       
  2032 	ASSERT( iReferenceCount >= 0 );
       
  2033 	}
       
  2034 
       
  2035 TUint CEncodeOperationExtension::Capabilities() const
       
  2036 	{
       
  2037 	return iOperationCaps;
       
  2038 	}
       
  2039 
       
  2040 void CEncodeOperationExtension::AddOperationL(TImageConvOperation::TOperation aOperation)
       
  2041 	{
       
  2042 	User::LeaveIfError(iImgConvOperations.Append(aOperation));
       
  2043 	//check to exclude interoperability of stream and operation interfaces.
       
  2044 	if(iJpegEncoder->GetActiveExtensionOperation() == CJpegEncoder::ENone)
       
  2045 		{
       
  2046 		iJpegEncoder->SetActiveExtensionOperation(CJpegEncoder::EOperationEncode);
       
  2047 		}
       
  2048 	else if(iJpegEncoder->GetActiveExtensionOperation() == CJpegEncoder::EStreamEncode)
       
  2049 		{
       
  2050 		User::Leave(KErrNotSupported);
       
  2051 		}
       
  2052 	}
       
  2053 
       
  2054 void CEncodeOperationExtension::ClearOperationStack()
       
  2055 	{
       
  2056 	if(iJpegEncoder->GetActiveExtensionOperation() == CJpegEncoder::EOperationEncode)
       
  2057 		{
       
  2058 		iImgConvOperations.Reset();
       
  2059 		iJpegEncoder->SetActiveExtensionOperation(CJpegEncoder::ENone);
       
  2060 		}
       
  2061 	}
       
  2062 
       
  2063 // Concrete Streamed Encode Extension class
       
  2064 CStreamedEncodeExtension* CStreamedEncodeExtension::NewL(CJpegEncoder* aJpegEncoder)
       
  2065 	{
       
  2066 	return new (ELeave) CStreamedEncodeExtension(aJpegEncoder);
       
  2067 	}
       
  2068 
       
  2069 CStreamedEncodeExtension::CStreamedEncodeExtension(CJpegEncoder* aJpegEncoder)
       
  2070 :iJpegEncoder(aJpegEncoder), iReferenceCount(0)
       
  2071 	{
       
  2072 	IncrementRef();
       
  2073 	}
       
  2074 
       
  2075 CStreamedEncodeExtension::~CStreamedEncodeExtension()
       
  2076 	{
       
  2077 	ASSERT(iReferenceCount == 0);
       
  2078 	}
       
  2079 
       
  2080 TUid CStreamedEncodeExtension::Uid() const
       
  2081 	{
       
  2082 	TUid KUidImgCovOperation = {KUidImageConvExtStreamedEncodeValue};
       
  2083 	return KUidImgCovOperation;
       
  2084 	}
       
  2085 
       
  2086 void CStreamedEncodeExtension::IncrementRef()
       
  2087 	{
       
  2088 	iReferenceCount++;
       
  2089 	}
       
  2090 
       
  2091 void CStreamedEncodeExtension::Release()
       
  2092 	{
       
  2093 	iReferenceCount--;
       
  2094 	ASSERT( iReferenceCount >= 0 );
       
  2095 	}
       
  2096 
       
  2097 void CStreamedEncodeExtension::GetSupportedFormatsL(RArray<TUid>& aFormats, TUid& aOptimalFormat) const
       
  2098 	{
       
  2099 	aFormats.AppendL(KUidFormatYUVMonochrome);
       
  2100 	aFormats.AppendL(KUidFormatYUV422Interleaved);
       
  2101 	aFormats.AppendL(KUidFormatYUV420Planar);
       
  2102 	aFormats.AppendL(KUidFormatYUV420PlanarReversed);
       
  2103 
       
  2104 	aOptimalFormat = KUidFormatYUV420Planar;
       
  2105 	}
       
  2106 
       
  2107 void CStreamedEncodeExtension::GetCapabilities(TUid aFormat, TEncodeStreamCaps& aCaps) const
       
  2108 	{
       
  2109 	TSize minBlockSizeInPixels;
       
  2110 	TInt optimalBlocksPerRequest = KOptimalBlockSize;
       
  2111 	TEncodeStreamCaps::TNavigation navigation = TEncodeStreamCaps::ENavigationSequentialForward;
       
  2112 	TInt maxBlocksPerRequest= KMaxTInt;
       
  2113 
       
  2114 	switch (aFormat.iUid)
       
  2115 		{
       
  2116 		case KFormatYUVMonochromeUidValue:
       
  2117 			minBlockSizeInPixels  = TSize(KSamplingMonoMCUWidthInPixels, KSamplingMonoMCUHeightInPixels);
       
  2118 			break;
       
  2119 		case KFormatYUV422InterleavedUidValue:
       
  2120 			minBlockSizeInPixels  = TSize(KSampling422MCUWidthInPixels, KSampling422MCUHeightInPixels);
       
  2121 			break;
       
  2122 		case KFormatYUV420PlanarReversedUidValue:
       
  2123 		case KFormatYUV420PlanarUidValue:
       
  2124 			minBlockSizeInPixels  = TSize(KSampling420MCUWidthInPixels, KSampling420MCUHeightInPixels);
       
  2125 			break;
       
  2126 		}
       
  2127 
       
  2128 	TEncodeStreamCaps streamCaps(maxBlocksPerRequest, minBlockSizeInPixels,
       
  2129 								optimalBlocksPerRequest, navigation);
       
  2130 	aCaps = streamCaps;
       
  2131 	}
       
  2132 
       
  2133 void CStreamedEncodeExtension::InitFrameL(TUid aFormat, TInt aFrameNumber, const TSize& aFrameSizeInPixels, const TSize& aBlockSizeInPixels, TEncodeStreamCaps::TNavigation aNavigation, const CFrameImageData* aFrameImageData)
       
  2134 	{
       
  2135 	ValidateInitParamsL(aFormat, aFrameNumber, aFrameSizeInPixels, aBlockSizeInPixels, aNavigation, aFrameImageData);
       
  2136 
       
  2137 	iJpegEncoder->HandleStreamInitFrameL(aFormat, aFrameNumber, aFrameSizeInPixels, aBlockSizeInPixels, aFrameImageData);
       
  2138 
       
  2139 	//check to exclude interoperability of stream and operation interfaces.
       
  2140 	if(iJpegEncoder->GetActiveExtensionOperation() == CJpegEncoder::ENone)
       
  2141 		{
       
  2142 		iJpegEncoder->SetActiveExtensionOperation(CJpegEncoder::EStreamEncode);
       
  2143 		}
       
  2144 	else if(iJpegEncoder->GetActiveExtensionOperation()== CJpegEncoder::EOperationEncode)
       
  2145 		{
       
  2146 		User::Leave(KErrNotSupported);
       
  2147 		}
       
  2148 	}
       
  2149 
       
  2150 void CStreamedEncodeExtension::AppendBlocks(TRequestStatus* /*aReq*/, const CImageFrame& aBlocks, TInt aNumBlocksToAdd)
       
  2151 	{
       
  2152 	iJpegEncoder->HandleStreamAppendBlock(aBlocks, aNumBlocksToAdd);
       
  2153 	}
       
  2154 
       
  2155 void CStreamedEncodeExtension::AddBlocks(TRequestStatus* /*aReq*/, const CImageFrame& aBlocks, const TInt& aSeqPosition)
       
  2156 	{
       
  2157 	iJpegEncoder->HandleStreamAddBlock(aBlocks, aSeqPosition);
       
  2158 	}
       
  2159 
       
  2160 void CStreamedEncodeExtension::Complete(TRequestStatus* /*aReq*/)
       
  2161 	{
       
  2162 	if(iJpegEncoder->GetActiveExtensionOperation() == CJpegEncoder::EStreamEncode)
       
  2163 		{
       
  2164 		iJpegEncoder->HandleStreamCompleteFrame();
       
  2165 		iJpegEncoder->SetActiveExtensionOperation(CJpegEncoder::ENone);
       
  2166 		}
       
  2167 	}
       
  2168 
       
  2169 void CStreamedEncodeExtension::ValidateInitParamsL(TUid& aFormat, TInt aFrameNumber, const TSize& aFrameSizeInPixels, const TSize& aBlockSizeInPixels, TEncodeStreamCaps::TNavigation aNavigation, const CFrameImageData* aFrameImageData)
       
  2170 	{
       
  2171 	// Prepare Frame Info and instantiates write codec
       
  2172 	// Note : Can either specify format through aFormat or aImageFrameData. Conflicts should leave with KErrArgument.
       
  2173 	if (aFormat.iUid == KFormatYUVMonochromeUidValue || aFormat.iUid == KFormatYUV422InterleavedUidValue || aFormat.iUid == KFormatYUV420PlanarUidValue || aFormat.iUid == KFormatYUV420PlanarReversedUidValue)
       
  2174 		{
       
  2175 		if(aFrameNumber)
       
  2176 			{
       
  2177 			User::Leave(KErrArgument);
       
  2178 			}
       
  2179 		}
       
  2180 	else
       
  2181 		{
       
  2182 		User::Leave(KErrArgument);
       
  2183 		}
       
  2184 
       
  2185 	TInt count = (aFrameImageData) ? aFrameImageData->ImageDataCount() : 0;
       
  2186 	// look for Frame Image Data
       
  2187 	for (TInt index = 0 ; index<count ; index++)
       
  2188 		{
       
  2189 		const TImageDataBlock& encoderData = *aFrameImageData->GetImageData(index);
       
  2190 		if (encoderData.DataType() == KJPGImageDataUid)
       
  2191 			{
       
  2192 			const TJpegImageData& jpegImageData = static_cast<const TJpegImageData&>(encoderData);
       
  2193 			TJpegImageData::TColorSampling sampleScheme = jpegImageData.iSampleScheme;
       
  2194 
       
  2195 			switch (sampleScheme)
       
  2196 				{
       
  2197 				case TJpegImageData::EMonochrome:
       
  2198 					{
       
  2199 					if (aFormat.iUid != KFormatYUVMonochromeUidValue)
       
  2200 						{
       
  2201 						User::Leave(KErrNotSupported);
       
  2202 						}
       
  2203 					break;
       
  2204 					}
       
  2205 
       
  2206 				case TJpegImageData::EColor420:
       
  2207 					{
       
  2208 					if (!(aFormat.iUid == KFormatYUV420PlanarUidValue || aFormat.iUid == KFormatYUV420PlanarReversedUidValue))
       
  2209 						{
       
  2210 						User::Leave(KErrNotSupported);
       
  2211 						}
       
  2212 					break;
       
  2213 					}
       
  2214 
       
  2215 				case TJpegImageData::EColor422:
       
  2216 					{
       
  2217 					if (aFormat.iUid != KFormatYUV422InterleavedUidValue)
       
  2218 						{
       
  2219 						User::Leave(KErrNotSupported);
       
  2220 						}
       
  2221 					break;
       
  2222 					}
       
  2223 
       
  2224 				case TJpegImageData::EColor444:
       
  2225 					{
       
  2226 					// YUV 4:4:4 sampling scheme is not supported by this codec
       
  2227 					User::Leave(KErrNotSupported);
       
  2228 					break;
       
  2229 					}
       
  2230 
       
  2231 				default:
       
  2232 					{
       
  2233 					User::Leave(KErrNotSupported);
       
  2234 					break;
       
  2235 					}
       
  2236 				}
       
  2237 			//format found - break out of for loop
       
  2238 			break;
       
  2239 			}
       
  2240 		}
       
  2241 
       
  2242 	GetCapabilities(aFormat, iEncodeCaps);
       
  2243 
       
  2244 	//validate that the frame size used is multiple of min block size
       
  2245 	CJpgWriteCodec::ValidateBlockSizeL(aFrameSizeInPixels, iEncodeCaps.MinBlockSizeInPixels());
       
  2246 
       
  2247 	//validate that the block size used is multiple of min block size
       
  2248 	CJpgWriteCodec::ValidateBlockSizeL(aBlockSizeInPixels, iEncodeCaps.MinBlockSizeInPixels());
       
  2249 
       
  2250 	if (aBlockSizeInPixels.iHeight != iEncodeCaps.MinBlockSizeInPixels().iHeight)
       
  2251 		{
       
  2252 		User::Leave(KErrNotSupported);
       
  2253 		}
       
  2254 
       
  2255 	if(aNavigation != iEncodeCaps.Navigation())
       
  2256 		{
       
  2257 		User::Leave(KErrNotSupported);
       
  2258 		}
       
  2259 	}
       
  2260 // Concrete Streamed Decode Extension class
       
  2261 CStreamedDecodeExtension* CStreamedDecodeExtension::NewL(CJpegDecoder* aJpegDecoder)
       
  2262 	{
       
  2263 	return new (ELeave) CStreamedDecodeExtension(aJpegDecoder);
       
  2264 	}
       
  2265 
       
  2266 CStreamedDecodeExtension::CStreamedDecodeExtension(CJpegDecoder* aJpegDecoder)
       
  2267 :iJpegDecoder(aJpegDecoder)
       
  2268 	{
       
  2269 	IncrementRef();
       
  2270 	}
       
  2271 
       
  2272 CStreamedDecodeExtension::~CStreamedDecodeExtension()
       
  2273 	{
       
  2274 	ASSERT(iReferenceCount == 0);
       
  2275 	}
       
  2276 
       
  2277 TUid CStreamedDecodeExtension::Uid() const
       
  2278 	{
       
  2279 	TUid uidImgConvOperation = {KUidImageConvExtStreamedDecodeValue};
       
  2280 	return uidImgConvOperation;
       
  2281 	}
       
  2282 
       
  2283 void CStreamedDecodeExtension::IncrementRef()
       
  2284 	{
       
  2285 	iReferenceCount++;
       
  2286 	}
       
  2287 
       
  2288 void CStreamedDecodeExtension::Release()
       
  2289 	{
       
  2290 	iReferenceCount--;
       
  2291 	ASSERT( iReferenceCount >= 0 );
       
  2292 	}
       
  2293 
       
  2294 void CStreamedDecodeExtension::GetSupportedFormatsL(RArray<TUid>& aFormats, TUid& aOptimalFormat) const
       
  2295 	{
       
  2296 	TJpegImageData::TColorSampling samplingScheme = TJpegImageData::EMonochrome; // intialise to mono
       
  2297 	User::LeaveIfError(iJpegDecoder->SamplingScheme(samplingScheme));
       
  2298 	
       
  2299 	switch(samplingScheme)
       
  2300 		{
       
  2301 		case TJpegImageData::EMonochrome:
       
  2302 			aFormats.AppendL(KUidFormatYUVMonochrome);
       
  2303 			aOptimalFormat = KUidFormatYUVMonochrome;
       
  2304 			break;
       
  2305 		case TJpegImageData::EColor420:
       
  2306 			aFormats.AppendL(KUidFormatYUV420Planar);
       
  2307 			aFormats.AppendL(KUidFormatYUV420PlanarReversed);
       
  2308 			aOptimalFormat = KUidFormatYUV420Planar;
       
  2309 			break;
       
  2310 		case TJpegImageData::EColor422:
       
  2311 			aFormats.AppendL(KUidFormatYUV422Interleaved);
       
  2312 			aOptimalFormat = KUidFormatYUV422Interleaved;
       
  2313 			break;
       
  2314 		default:
       
  2315 			User::Leave(KErrNotSupported);
       
  2316 		}
       
  2317 	}
       
  2318 
       
  2319 void CStreamedDecodeExtension::GetCapabilities(TUid aFormat, TInt /*aFrameNumber*/, TDecodeStreamCaps& aCaps) const
       
  2320 	{
       
  2321 	TSize minBlockSizeInPixels;
       
  2322 	TInt optimalBlocksPerRequest = KOptimalBlockSize;
       
  2323 	TDecodeStreamCaps::TNavigation navigation = static_cast<TDecodeStreamCaps::TNavigation> (TDecodeStreamCaps::ENavigationSequentialForward | TDecodeStreamCaps::ENavigationRandomForward | TDecodeStreamCaps::ENavigationRandomBackwards);
       
  2324 
       
  2325 	TInt maxBlocksPerRequest= KMaxTInt;
       
  2326 	TInt minStreamSizeInBlocks = 1;
       
  2327 
       
  2328 	switch (aFormat.iUid)
       
  2329 		{
       
  2330 		case KFormatYUVMonochromeUidValue:
       
  2331 			minBlockSizeInPixels = TSize(KSamplingMonoMCUWidthInPixels, KSamplingMonoMCUHeightInPixels);
       
  2332 			break;
       
  2333 		case KFormatYUV422InterleavedUidValue:
       
  2334 			minBlockSizeInPixels = TSize(KSampling422MCUWidthInPixels, KSampling422MCUHeightInPixels);
       
  2335 			break;
       
  2336 		case KFormatYUV420PlanarReversedUidValue:
       
  2337 		case KFormatYUV420PlanarUidValue:
       
  2338 			minBlockSizeInPixels = TSize(KSampling420MCUWidthInPixels, KSampling420MCUHeightInPixels);
       
  2339 			break;
       
  2340 		default:
       
  2341 			//does nothing
       
  2342 			maxBlocksPerRequest = 0;
       
  2343 		}
       
  2344 
       
  2345 	TDecodeStreamCaps streamCaps(maxBlocksPerRequest, minBlockSizeInPixels,
       
  2346 								optimalBlocksPerRequest, minStreamSizeInBlocks, navigation);
       
  2347 	aCaps = streamCaps;
       
  2348 	}
       
  2349 
       
  2350 TInt CStreamedDecodeExtension::GetBufferSize(TUid aFormat, TSize& aBlockSizeInPixels, TInt aNumBlocks) const
       
  2351 	{
       
  2352 	return iJpegDecoder->HandleStreamGetBufferSize(aFormat, aBlockSizeInPixels, aNumBlocks);
       
  2353 	}
       
  2354 
       
  2355 void CStreamedDecodeExtension::InitFrameL(TUid aFormat, TInt aFrameNumber, TDecodeStreamCaps::TNavigation aNavigation)
       
  2356 	{
       
  2357 	if(aNavigation == TDecodeStreamCaps::ENavigationSequentialForward || aNavigation == TDecodeStreamCaps::ENavigationRandomForward || aNavigation == TDecodeStreamCaps::ENavigationRandomBackwards)
       
  2358 		{
       
  2359 		if(aFrameNumber)
       
  2360 			{
       
  2361 			User::Leave(KErrArgument);
       
  2362 			}
       
  2363 		}
       
  2364 	else
       
  2365 		{
       
  2366 		User::Leave(KErrNotSupported);
       
  2367 		}
       
  2368 
       
  2369 	iJpegDecoder->HandleStreamInitFrameL(aFormat, aFrameNumber, aNavigation);
       
  2370 	}
       
  2371 
       
  2372 void CStreamedDecodeExtension::GetBlocks(TRequestStatus* /*aStatus*/, CImageFrame* aFrame, TInt aSeqPosition, TInt aNumBlocksToGet, TInt* aNumBlocksRead)
       
  2373 	{
       
  2374 	iJpegDecoder->HandleStreamGetBlocks(aFrame, aSeqPosition, aNumBlocksToGet, aNumBlocksRead);
       
  2375 	}
       
  2376 
       
  2377 void CStreamedDecodeExtension::GetNextBlocks(TRequestStatus* /*aStatus*/, CImageFrame* aFrame, TInt aNumBlocksToGet, TInt* aNumBlocksRead, TBool* aHaveMoreBlocks)
       
  2378 	{
       
  2379 	iJpegDecoder->HandleStreamGetNextBlocks(aFrame, aNumBlocksToGet, aNumBlocksRead, aHaveMoreBlocks);
       
  2380 	}
       
  2381 
       
  2382 //return The memory buffer size in bytes to hold the requested blocks. Returns error if unable to retrieve buffer size.
       
  2383 TInt CJpegDecoder::HandleStreamGetBufferSize(TUid aFormat, TSize& aBlockSizeInPixels, TInt aNumBlocks) const
       
  2384 	{
       
  2385 	CJpgReadCodec* jpgReadCodec = reinterpret_cast<CJpgReadCodec*>(ImageReadCodec());
       
  2386 	TInt bufferSize = KErrNone;
       
  2387 	TRAPD(errCode, bufferSize = jpgReadCodec->GetStreamBufferSizeL(aFormat, aBlockSizeInPixels, aNumBlocks));
       
  2388 	if (errCode!=KErrNone)
       
  2389 		{
       
  2390 		bufferSize = errCode;
       
  2391 		}
       
  2392 
       
  2393 	return bufferSize;
       
  2394 	}
       
  2395 
       
  2396 void CJpegDecoder::HandleStreamInitFrameL(TUid aFormat, TInt aFrameNumber, TDecodeStreamCaps::TNavigation aNavigation)
       
  2397 	{
       
  2398 	//Validate source image dimensions. Make sure that image is multiple of MCUs
       
  2399 	CJpgWriteCodec::ValidateBlockSizeL(iJpgFrameInfo.iSizeInPixels, TSize(iJpgFrameInfo.MCUWidthInPixels(), iJpgFrameInfo.MCUHeightInPixels()));
       
  2400 	
       
  2401 	if(iExtensionManager)
       
  2402 		{
       
  2403 		if(iExtensionManager->ClippingRectExtensionRequested() || iExtensionManager->ScalerExtensionRequested() || iExtensionManager->OperationExtensionRequested())
       
  2404 			{
       
  2405 			User::Leave(KErrNotSupported);
       
  2406 			}
       
  2407 		}
       
  2408 
       
  2409 	CImageDecoderPlugin::RequestInitL(aFrameNumber);
       
  2410 
       
  2411 	CJpgReadCodec* jpgReadCodec = reinterpret_cast<CJpgReadCodec*>(ImageReadCodec());
       
  2412 	jpgReadCodec->InitFrameL(aFormat, aNavigation);
       
  2413 	}
       
  2414 
       
  2415 void CJpegDecoder::HandleStreamGetBlocks(CImageFrame* aFrame, TInt aSeqPosition, TInt aNumBlocksToGet, TInt* aNumBlocksRead)
       
  2416 	{
       
  2417 	CJpgReadCodec* jpgReadCodec = reinterpret_cast<CJpgReadCodec*>(ImageReadCodec());
       
  2418 
       
  2419 	TRAPD(errCode, jpgReadCodec->GetBlocksL(aFrame, aSeqPosition, aNumBlocksToGet, aNumBlocksRead));
       
  2420 	if (errCode!=KErrNone)
       
  2421 		{
       
  2422 		RequestComplete(errCode);
       
  2423 		return;
       
  2424 		}
       
  2425 	}
       
  2426 
       
  2427 void CJpegDecoder::HandleStreamGetNextBlocks(CImageFrame* aFrame, TInt aNumBlocksToGet, TInt* aNumBlocksRead, TBool* aHaveMoreBlocks)
       
  2428 	{
       
  2429 	CJpgReadCodec* jpgReadCodec = reinterpret_cast<CJpgReadCodec*>(ImageReadCodec());
       
  2430 	
       
  2431 	TRAPD(errCode, jpgReadCodec->GetNextBlocksL(aFrame, aNumBlocksToGet, aNumBlocksRead, aHaveMoreBlocks));
       
  2432 	if (errCode!=KErrNone)
       
  2433 		{
       
  2434 		RequestComplete(errCode);
       
  2435 		return;
       
  2436 		}
       
  2437 	}
       
  2438 
       
  2439 // System Wide Define
       
  2440 #ifdef SYMBIAN_ENABLE_1630_JPEG_EXTENSIONS
       
  2441 void CJpegDecoder::GetExtensionL(TUid aExtUid, MImageConvExtension*& aExtPtr)
       
  2442 	{
       
  2443 	
       
  2444 	switch (aExtUid.iUid)
       
  2445 		{
       
  2446 		case KUidImageConvExtStreamedDecodeValue:
       
  2447 			{
       
  2448 			if (iJpgFrameInfo.iProgressive)
       
  2449 				{
       
  2450 				User::Leave(KErrNotSupported); //codec dosen't support progressive decoding
       
  2451 				}
       
  2452 			
       
  2453 			if (iJpgFrameInfo.iMultiScan)
       
  2454 				{
       
  2455 				JPEG_LEAVE(KErrNotSupported, "Multiscan in GetExtensionL");
       
  2456 				}
       
  2457 			
       
  2458 			if (!iStreamedDecodeExt)
       
  2459 				{
       
  2460 				iStreamedDecodeExt = CStreamedDecodeExtension::NewL(this);
       
  2461 				}
       
  2462 			
       
  2463 			aExtPtr = iStreamedDecodeExt;
       
  2464 			break;
       
  2465 			}
       
  2466 			
       
  2467 		default:
       
  2468 			{
       
  2469 			ASSERT(iExtensionManager);
       
  2470 			iExtensionManager->GetExtensionL(aExtUid, aExtPtr);
       
  2471 			}
       
  2472 		}
       
  2473 	}
       
  2474 #else
       
  2475 void CJpegDecoder::GetExtensionL(TUid /*aExtUid*/, MImageConvExtension*& /*aExtPtr*/)
       
  2476 	{
       
  2477 	User::Leave(KErrNotSupported);
       
  2478 	}
       
  2479 #endif
       
  2480