symba (779893), страница 38
Текст из файла (страница 38)
The latter may inmany cases be even faster as most of the Symbian-supplied decoders(and the framework itself) are optimized for this color mode. In factmany ICL components internally use a TRgb-like pixel data representation with subsequent conversion of this data into the destinationcolor mode. Other parts of ICL are optimized for this color mode aswell (see Section 6.6).6.3 Encoding ImagesImage encoding can be seen as a reverse operation for image decodingas it is all about taking a native bitmap and translating it (encoding it)into another image format. The encoding API is mostly represented by theENCODING IMAGES175CImageEncoder class.
It is a far simpler API than CImageDecoder,although it mirrors most of the decoding functionality.There are two main use cases for the encoding API:• The image editor use case. This use case boils down to the necessityof encoding a native bitmap in a well-defined image format, so thatthe image can be passed to other devices which do not necessarilyshare the native bitmap format.• Saving a photo obtained using the onboard camera API.Another reason for using some of the common image formats insteadof native bitmaps is the limited storage size – while the native bitmapformat is the most efficient way of storing images as regards performance,it is far from being the most optimal in terms of storage size or output filesize.6.3.1 Using the CImageEncoder APIThe CImageEncoder API shares many usage patterns and data structureswith the CImageDecoder API.
Its basic usage scenario is essentially thesame:1. An encoder object is to be created by using one of the synchronousfactory methods CImageEncoder::DataNewL() or CImageEncoder::FileNewL().2. Some optional encoding parameters may be adjusted synchronously.3.
An asynchronous encoding process is initiated by calling CImageEncoder::Convert().4. The application waits for the request to be accomplished and makesuse of the output data in cases when no error has been reported.So why is this API simpler than the decoding one? Let us examine thedifferences:• The encoding client application has to explicitly specify the outputfile format (either by MIME type or image type UID) and the onlyinput format supported is the native bitmap. There is no support forstreamed or partial encoding: the input data must be presented in onecomplete native bitmap object.• The encoding parameters may be seen as a bit more complicatedas they may require the client application to have some knowledgeabout the destination file format in order to perform format-specificsetup.
However, a client application always knows the output fileformat as it has to specify it while creating an encoder object.176IMAGE CONVERSION LIBRARY• The encoding process is much simpler as CImageEncoder supportsonly encoding of single-frame images without transparency information. No scaling is supported either, so the input bitmap is encodedin 1:1 scale where the format permits.• The CImageEncoder class does not support streamed encoding soany error code apart from KErrNone is fatal and means that encodinghas failed. The application may endeavor to fix the problem.Symbian plans to significantly extend CImageEncoder to addressmost of these limitations in the near future.
Curious readers mayexplore imageconversion.h to see the new prototype APIs inSymbian OS v9.5.This is a fairly basic, but fully functional CImageEncoder example:CSimpleEncodeHandler::CSimpleEncodeHandler() : CActive(EPriorityStandard){}void CSimpleEncodeHandler::ConstructL(const TDesC& aDestinationFileName,TUid aImageFormatId){// create a connection to the file serverUser::LeaveIfError( iFs.Connect() );// create an encoder object for encoding into a fileiEncoder = CImageEncoder::FileNewL(iFs, aDestinationFileName,CImageEncoder::EOptionAlwaysThread,aImageFormatId);// Add this object to the schedulerCActiveScheduler::Add(this);}CSimpleEncodeHandler::∼CSimpleEncodeHandler(){// Cancel any request, if outstandingCancel();// Delete instance variables, if any, and close resourcesdelete iEncoder;iFs.Close();}void CSimpleEncodeHandler::BeginEncode(CFbsBitmap& aSourceBitmap){// start encoding processiEncoder->Convert(&iStatus, aSourceBitmap);// Tell scheduler a request is activeSetActive();}void CSimpleEncodeHandler::DoCancel(){// cancel encoding processiEncoder->Cancel();}ENCODING IMAGES177void CSimpleEncodeHandler::RunL(){if (iStatus.Int() == KErrNone){// bitmap has been encoded successfully}else{// something went wrong, deal with error code}}In contrast to the image decoder, the list of encoder object creationoptions is quite short (see Table 6.6).Table 6.6 The CImageEncoder::TOptions EnumerationEOptionNoneThis option means ‘no special options have been requested’; itis used by default if no other options have been specified.EOptionAlwaysThreadThis option allows an API user to instruct the framework tocreate an encoder object in a separate operating system threadand marshal all the calls when required.
This option should beused when the responsiveness of the application user interface isthe top priority as it involves some overhead in thread creation.Note: Even if this option has been used, the client must still properly manage active objects and User::WaitForRequest()cannot be used to wait for encoding process completion.EOptionGenerateAdaptivePaletteThis option instructs the underlying encoder plug-in to generatean adaptive (i.e. ‘best match’) palette. This option is silentlyignored by encoders that do not support adaptive palette generation. You should use this option only when performanceis non-critical as it may make the encoder use complex andcomputationally expensive algorithms for palette calculation.When this option is not used, the Symbian-supplied encodersuse the default system palette when required. In some extremeuse cases (e.g.
encoding a gradient-like picture into a GIF imageformat), use of the system-wide default palette would make theoutput file virtually useless, so an application should apply someintelligence as to when to use this option.6.3.2 Setting up Encoding ParametersApart from the instantiation-time parameters, there are parameters thatcan be set up before the encoding process takes place. This kind ofparameter setup split is used to keep the CImageEncoder interface asgeneric as possible while allowing format-specific settings to be suppliedby an API client if necessary.178IMAGE CONVERSION LIBRARYThe setup mechanism for CImageEncoder that is specific to eachplug-in is driven by parameter data rather than custom interface functions(see Figure 6.8 for a UML diagram):• There are two base classes, the image data abstract parameter container (TImageDataBlock) and the frame data abstract parametercontainer (TFrameDataBlock).
These containers are T classes withjust one data member of type Uid and a protected constructor.• There is a data container collection (CFrameImageData) class whichcan (despite its name) hold both of the base classes.• The plug-ins which support their own encoding parameters have tocreate a class derived from one of these abstract data containers. Theplug-in adds some data members and provides a public constructorso that it is possible to create an instance of that class.CFrameImageData++++CImageEncoderGetFrameData(TInt) : TFrameDataBlock∗GetImageData(TInt) : TImageDataBlock∗AppendImageData(const TImageDataBlock∗) : TIntAppendFrameData(const TFrameDataBlock∗) : TIntTFrameDataBlockTImageDataBlock#+«use»#+TImageDataBlock(TUid)DataType() : TUidTFrameDataBlock(TUid)DataType() : TUidTPngEncodeDataTBmpCompressionTBmpImageData+ iCompression: TCompression+iBitsPerPixel: TInt+ TBmpCompression()+TBmpImageData()TJpegQTableTMbmEncodeData++++iBitsPerPixel: TIntiColor: TBooliPaletted: TBooliLevel: TPngCompressLevel+TPngEncodeData()TJpegImageData++iTableIndex: TIntiEntries: TBuf8<KJpgQTableEntries>++iSampleScheme: TColorSamplingiQualityFactor: TInt+TJpegQTable()+TJpegImageData()Figure 6.8 Setup parameters specific to a plug-in+iDisplayMode: TDisplayMode+TMbmEncodeData()ENCODING IMAGES179Despite the fact that no multiframe encoding is currently supported,some plug-ins derive their parameters from the TFrameDataBlock;that is probably for future extensibility.An API client wanting to customize encoding parameters should dothe following:1.
Create an instance of the parameter collection holder (CFrameImageData).2. Create and initialize instances of the desired parameters for theimage type being encoded. For example, in the case of encoding to JPEG, these parameter classes could be TJpegQTable orTJpegImageData. These parameters can be created and added inany order and are optional unless their documentation says otherwise.3.
Pass an instance of the CFrameImageData as the third argument toCImageEncoder::Convert().If no encoding parameters are provided by the API client, an encoderplug-in applies defaults. These defaults can sometimes lead to undesired side effects. For example, the Symbian-provided BMP encoderalways encodes images using the 24-bit per pixel mode unless it istold to use another color mode.Now we can create a small piece of code that sets up a JPEG encoderto use an application-defined quality factor and sampling scheme, butlets it use default quantization tables:void CSimpleEncodeHandler::BeginEncode(CFbsBitmap& aSourceBitmap){// create the encoding parameter collectioniImageData = CFrameImageData::NewL();// create the Jpeg image encoding parameter on the heapTJpegImageData* jpegData = new (ELeave) TJpegImageData;CleanupDeletePushL(jpegData);jpegData->iSampleScheme = TJpegImageData::EColor444;jpegData->iQualityFactor= 90;User::LeaveIfError(iImageData->AppendImageData(jpegData));// remove the parameter pointer from the Cleanup stack// as the parameter collection owns it nowCleanupStack::Pop( jpegData );180IMAGE CONVERSION LIBRARY// start encoding processiEncoder->Convert(&iStatus, aSourceBitmap, iImageData);// Tell scheduler a request is activeSetActive();}There are some things to note about this code:• Ownership of the CFrameImageData is not passed to the imageencoder, so it is the API client’s responsibility to delete it.• Despite being T classes, all the parameters are allocated on the heap.That is because the CFrameImageData implementation tries to deallocate memory pointed to by parameters as part of its destructioncode.• This code is a bit paranoid about encoder plug-in implementationand keeps the instance of CFrameImageData alive during the entireencoding process (we assume iImageData is a class member).