| 
                   | 
               
                  
                   | 
            |
            The image decoding class CImageDecoder
            (CBufferedImageDecoder is described later) provides
            functions to decode images held in descriptors or files from standard formats
            for use with devices such as screens, browsers and viewer applications. This
            class provides these features via a plugin framework. The standard formats
            supported by the decoder plugins are shown in the table in
            Overview. 
            
         
For the purposes of this description, the decoding process has been broken down into the following sections:
                  Creation -
                  The creation of the CImageDecoder object and special
                  considerations when doing so. 
                  
               
Conversion - Covers the basic form of image decoding. More advanced features such as progressive and buffered decoding are described separately.
Enquiry features - Additional features that enable you to retrieve information stored in certain types of images, for example frame information, comments and so on.
Streamed and progressive decoding - Reading partial image files and displaying image data before the entire image is read.
Buffered decoding - The decoding of an image using a buffered input rather than a file or descriptor.
            CImageDecoder decodes images stored in files or in
            descriptors. The decoder object is owned by the client and must be deleted once
            decoding is finished. CImageDecoder objects cannot be reused to
            decode other images - each image requires its own instance of the decoder. 
            
         
            CImageDecoder objects are created using the
            CImageDecoder::DataNewL() and
            CImageDecoder::FileNewL() factory functions for images
            held in descriptors or files respectively: 
            
         
            In creating a CImageDecoder object, a suitable plugin has
            to be associated with the image to be decoded. How the plugin is specified
            depends on the factory function you use to create the object and what
            parameters you specify. There are four alternatives: 
            
         
MIME type - the plugin is determined by looking up a specified MIME type against a list of known MIME type/plugin implementations. Use the following "File" factory function (or its "Data" equivalent).
static CImageDecoder* FileNewL(RFs& aFs, const TDesC& aSourceFilename, const TDesC8& aMIMEType, const TOptions aOptions = EOptionNone);
Image type and sub-type - the plugin is determined by looking up the specified image type and sub-types against a list of known type/sub-type plugin implementations. Use the following "File" factory function (or its "Data" equivalent).
static CImageDecoder* FileNewL(RFs& aFs, const TDesC& aSourceFilename, const TOptions aOptions = EOptionNone, const TUid aImageType = KNullUid, const TUid aImageSubType = KNullUid, const TUid aDecoderUid = KNullUid);
                  Note: For images types that do not have sub-types use
                  KNullUid. 
                  
               
                  Implementation UID - the plugin is determined by
                  looking up its specific UID and the image type and sub-type. Use the same
                  FileNewL() factory function shown in "Image type and sub-type",
                  but in addition to the type and sub-type parameters, also specify the plugin
                  UID using aDecoderUid. 
                  
               
Note: Implementation UID is supported because it is possible to have more than one plugin for a particular image type. This method is recommended if the application or calling DLL needs to exploit features of a particular plugin.
                  Automatic detection - no MIME type, format
                  type/sub-type or UIDs are specified. The plugin to use is determined by
                  analysing the header information of the specified image. Use the same
                  FileNewL() factory function shown in "Image type and sub-type",
                  but do not specify any values for aImageType
                  aImageSubType or aDecoderUid. 
                  
               
                  If no suitable plugin can be found, the factory function leaves
                  with KErrNotFound. If a suitable plugin is found, but that plugin
                  cannot interpret the image data the factory function leaves with
                  KErrCorrupt. 
                  
               
Note: Some image formats cannot be automatically detected because they do not contain sufficient header information, for example, WBMP and OTA images are known to fall into this category. Under such circumstances, use one of the other three alternative for opening the image.
            It is possible for more than one valid plugin decoder to be available
            for a specific image format. If a plugin determined by MIME type or
            type/sub-type fails to open an image due to KErrCorrupt, it will
            continue to try with subsequent valid plugins if available. This mechanism is
            carried out behind the scenes and is largely invisible to the application. If
            you require a specific function you know to be available within a specific
            plugin, specify that plugin using aDecoderUid. 
            
         
            As part of the CImageDecoder creation basic information
            about the image is pre-read from the image headers. This information is used to
            support certain enquiry methods such as
            CImageDecoder::FrameCount() and
            CImageDecoder::FrameInfo() and so on (more on the enquiry
            methods is supplied in Enquiry features). 
            
         
            You are free to decode any subset of individual frames, in any order,
            and to repeat the decoding if necessary. To decode an image frame use the
            asynchronous conversion method CImageDecoder::Convert(),
            as shown below. 
            
         
void Convert(TRequestStatus* aRequestStatus, CFbsBitmap& aDestination, TInt aFrameNumber = 0);
void ContinueConvert(TRequestStatus* aRequestStatus);
            Note: The use of CImageDecoder::ContinueConvert()
            is described in Streamed and progressive decoding. 
            
         
            There is a second variant of the Convert() function
            intended for use when decoding images with bitmap masks. 
            
         
void Convert(TRequestStatus* aRequestStatus, CFbsBitmap& aDestination, CFbsBitmap& aDestinationMask, TInt aFrameNumber = 0);
            Within the Symbian OS it is normal to store the bitmap mask separately
            from the main image data. Calls such as BitBltMasked()
            expect this data to be provided separately. This separation is true for both
            CFbsBitmap objects and MBM files. 
            
         
            To determine whether an image contains a bitmap mask use
            FrameInfo(), the presence or absence of a mask will be indicated
            the ETransparencyPossible flag. Two types of mask are possible. 
            
         
                  8-bit alpha blend - indicated by the
                  EAlphaChannel flag of
                  CImageDecoder::FrameInfo()
                  iFlags. The
                  destination mask bitmap must be of type EGray256. 
                  
               
                  Simple on/off mask - if no EAlphaChannel
                  flag is set. The destination bitmap mask can be either EGray2 or
                  EGray256. 
                  
               
Note: Images that contain bitmap masks do not have to have those masks decoded if they are not required.
            Before Convert() can be used the destination
            CFbsBitmap objects for image data and possibly bitmap
            masks must be created. The simplest way to do this is to use a 1 to 1 approach,
            that is, create the CFbsBitmap object with the same properties as
            the source image (if at all possible). This could be achieved by using
            something similar to: 
            
         
iFrameInfo = &imageDecoder->FrameInfo(FrameNum);
iBitmap->Create(iFrameInfo->iOverallSizeInPixels, iFrameInfo->iFrameDisplayMode );
            If the ECanDither flag of
            CImageDecoder::FrameInfo()
            iFlags is set then
            the destination display mode can be adjusted. In such cases it is generally
            recommended that the current window's display mode is used as this can make
            drawing faster. 
            
         
Note: The mask bitmap must have the same size in pixels as the main image, even though the display mode is generally different.
            As indicated above the size of the image bitmap is available via
            FrameInfo() (iOverallSizeInPixels). However, in
            addition to a direct mapping of an image's size, ReducedSize()
                function can be used to calculate the reduced size of the decoded
            bitmap based on the input parameters. 
            
         
            If the EFullyScaleable flag of FrameInfo()
            iFlags is set, you can specify any size for the
            CFbsBitmap and the image will be resized appropriately. 
            
         
            Included in the CImageDecoder::FrameInfo() result
            are flags that enable the support of GIF animation. These flags are
            iDelay, ELeaveInPlace,
            ERestoreToBackground and ERestoreToPrevious. ICL
            provides these flags to enable the application to implement the animation; ICL
            does not provide functions to display the animation directly. 
            
         
Processing the information from these flags will inevitably require a state machine, and additional timers, within the application. Requirements will vary depending on the architecture of the client application itself.
            Some image formats contain background colour information. This is
            information is presented by ICL via
            CImageDecoder::FrameInfo()
            iBackgroundColor.
            If a non-masked image with background colour is decoded, the colour is included
            in the image data. If the decoded image also contains a bitmap mask, then the
            background colour will be a component of the mask
            CFbsBitmap object. Depending on your application, you may
            want to choose your own background colour rather than use the one provided by
            the source image. 
            
         
            Previous sections shown above have made use of
            CImageDecode::FrameInfo(). There are however, other
            enquiry functions that also provide useful information. They are: 
            
         
                  CImageDecode::FrameData()
                  
               
                  Provides access to additional chunks of data within the images, for
                  example, palette and similar lookup tables, copyright information and other
                  strings. This information should be used with care, the returned data is merely
                  a reference to the original data within the CImageDecoder
                  object, and is only valid for the lifetime of the object. 
                  
               
                  CImageDecode::NumberOfImageComments() and
                  CImageDecode::ImageCommentL()
                  
               
Images can have comments embedded in them. These comments are usually either embedded as a single repository which can be retrieved on an image level, or multiple repositories attached to individual frames within the image. The two functions above return the number of comments attached to the entire image and provide a mechanism for retrieving any of those comments.
                  CImageDecode::NumberOfFrameComments() and
                  CImageDecode::FrameCommentL()
                  
               
Similar functionality to above, but these functions return the number of comments attached to individually specified frames and provide a mechanism for retrieving any of those comments.
                  CImageDecode::FrameInfoStringsLC and
                  CImageDecode::FrameInfoStringsL()
                  
               
Provide a list of data for a specified frame, including data items such as format, plugin description, size and so on, in a readable format.
Although the property strings can be accessed by name, it is recommended that they be generally treated as a list of strings.
            CImageDecoder includes facilities to support the
            simultaneous decoding and display of images as they are being loaded. The
            decoder does not wait for the entire image to be loaded before processing it,
            rather it begins as soon as possible, stops when it runs out of data and then
            carries on when more data is available. The decoding rules that
            CImageDecoder follows are shown below: 
            
         
                  If there is insufficient data to work out the image format (plugin
                  decoder to use) CImageDecoder::FileNewL() (or its "Data"
                  equivalent) leaves with KErrUnderflow. This is only applicable to
                  instances where automatic detection of the plugin decoder is used. For more
                  information see, "Automatic detection" in
                  Creation. 
                  
               
                  As soon as the correct plugin decoder has been determined it is
                  opened and whatever addition image data is available is scanned. The plugin
                  decoder continues to decode image data as it arrives, updating
                  FrameCount() whenever it becomes aware of a new frame within the
                  data. The internal flag
                  CImageDecoder::IsHeaderProcessingComplete() is maintained
                  at EFalse until the entire image has been loaded. 
                  
               
                  Frames can be decoded before the entire image is loaded, but the
                  frame to be decoded must be at least partially loaded. If
                  IsHeaderProcessingComplete() is set to EFalse and
                  FrameCount() is equal to or less than the frame to decode, the
                  application must wait for the relevant frame to load. In such circumstances a
                  call to CImageDecoder::ContinueProcessingHeadersL() should
                  be made that scans for any further headers. FrameCount() and
                  IsHeaderProcessingComplete() should then be recalled to determine
                  if the frame has arrived. 
                  
               
                  Once FrameCount() is greater than the frame the
                  application wants to decode, it is possible to start to decoding the frame
                  using CImageDecoder::Convert(). Frame headers and their
                  associated data do not always follow each other in some image formats. This has
                  the implication that although FrameCount() has indicated that the
                  frame is available, it may not yet be fully loaded. Under such circumstances as
                  much decoding as possible is undertaken, and Convert() then
                  completes with the error code KErrUnderflow. If the
                  EPartialDecodeInvalid flag (from FrameInfo()) is not
                  set, the partially decoded image can be displayed - for some image formats, a
                  partially decoded image is not generally usable, but this facility is supported
                  by most known formats. Obviously, if all of the image is present,
                  Convert() completes with KErrNone as normal. 
                  
               
                  Where only a partial conversion has been completed,
                  CImageDecoder::ContinueConvert() should be used to
                  continue converting when new data arrives. ContinueConvert()
                  continues to convert the frame data where the previous call left off. This
                  function should continue to be called until it returns the error code
                  KErrNone rather than KErrUnderflow. 
                  
               
                  Note: The CFbsBitmap must never be resized
                  during a conversion session using ContinueConvert(), if resizing
                  does occur, a panic will be raised by the function. If resizing or any other
                  parameter changes need to be made to the CFbsBitmap, frame
                  decoding should be restarted by using Convert() rather than trying
                  to continue an existing conversion session. 
                  
               
            There is no explicit decoder call to say "all of the data is now
            present". This could be done via inference, continuously checking
            IsHeaderProcessingComplete() until it returns ETrue.
            However, this is not advisable as it is possible that
            IsHeaderProcessingComplete() could continue to return
            EFalse even after the application has finished sending image data.
            Your state machine should be written so that it takes this possibility into
            account. 
            
         
            CBufferedImageDecoder is a wrapper that
            encapsulates not only a CImageDecoder but also the
            descriptor used to store the image, and in some circumstances can replace the
            use of CImageDecoder itself.
            CBufferedImageDecoder can always be created, even if there
            is no data available at the time of creation. Another key feature of
            CBufferedImageDecoder is that it can be reused to decode multiple
            images. The use of this class is outlined below. 
            
         
                  The decoder is created using the
                  CBufferedImageDecoder::NewL() factory function, and the
                  decoding process is started with one of the two
                  CBufferedImageDecoder::OpenL() calls, specifying either
                  MIME-type or image type/sub-type and UID, which are similar to
                  CImageDecoder::DataNewL(). If not enough data is available
                  to create an internal decoder a call to
                  CBufferedImageDecoder::ValidDecoder() returns
                  EFalse. The decoder keeps an internal copy of the data provided so
                  the client can discard its own copy. 
                  
               
                  Warning: The decoding and enquiry functions must not
                  be used until an internal decoder has been created, otherwise calls will panic
                  with EDecoderNotCreated. 
                  
               
                  Additional data can be supplied to the decoder, when it becomes
                  available, by using CBufferedImageDecoder::AppendDataL()
                  and CBufferedImageDecoder::ContinueOpenL(), which will
                  copy the data and try to find an appropriate plugin. This step should be
                  repeated until enough data is available to create the internal decoder,
                  indicated by ValidDecoder() returning ETrue.
                  OpenL() and ContinueOpenL() will leave with
                  KErrCorrupt if a suitable decoder is found, but that decoder was
                  unable to interpret the supplied image data. 
                  
               
                  Note: As with OpenL(), data provided by
                  AppendDataL() is kept in an internal buffer by the decoder so the
                  client can discard its own copy. 
                  
               
                  The process for decoding the image header and frames are the same
                  as for CImageDecoder with
                  IsHeaderProcessingComplete(), FrameCount(),
                  Convert() and ContinueConvert() calls except that the
                  data is not appended to a descriptor, but supplied to the decoder with
                  AppendDataL(). 
                  
               
                  The decoder can be reused by calling a
                  CBufferedImageDecoder::Reset(), which destroys the
                  internal data buffer and decoder. A new decoder plugin can then be started
                  using OpenL(). 
                  
               
ICL client side architecture - brief overview of the architecture of the image converted library client side classes.
Overview - general overview of ICL, synchronous and asynchronous methods, active objects and concurrency issues.
Image decoding - frame information and data, still image decoding, animated image decoding, progressive decoding and buffered decoding.
Image encoding - encoding/decoding feature comparison, image encoding.
Additional information - dithering, enabling progressive decoding, MIME type and plugin reporting, threading, memory usage, error handling and performance considerations.