Enhanced Features for Encoder and Decoder Tutorial

This document gives you more information about the enhanced features for the encoder and the decoder during the bitmap transformation.

Purpose

The purpose of the enhanced features for encoder and decoder is to set various transformation operations during encoding and decoding, which gives faster and more resource friendly output.

Required Background

The enhanced features for encoder and decoder are provided through Imaging Frameworks and Imaging plugins.

Introduction

The enhanced features of the decoder are currently supported by the Symbian JPEG codec and PNG codec. The transformation features during the decoding are as follows:

  • Clipping :

    A rectangular region of an image is chosen and it is clipped for decoding. The decoded output is either a native bitmap ( CFbsBitmap ) or a pixel buffer (e.g YUV 4:2:2 frames).

  • Rotation / Mirroring :

    The functionality in rotation are 90º increments, mirroring over the horizontal axis, mirroring over the vertical axis, and combination of these features.

  • Scaling :

    In scaling only downscaling is supported during the decode operation. At present the supported scaling coefficients for an image are ½, ¼ or ⅛ of the original image size.

In transformation of an image during decode you can choose more than one operation. For example you can choose clipping and scaling, or clipping and rotation, or all the three combinations of clipping, scaling and rotation.

Note:- When you want to clip and scale an image you need to follow this order:

  • First you need to clip the image.

  • Then you can scale the image.

This order is defined because if you scale an image and do clipping the output will not be a resource friendly output.

The enhanced feature of the encoder is currently supported by the Symbian JPEG codec and PNG codec. The transformation feature during the encoding is:

  • Imaging Frameworks provides support for rotation and mirroring while encode bitmaps or YUV pixel data, contained in a memory descriptor, to the data format.

Setup and Configuration Requirements

Setting up the right decoder

In order to allow the decoder to advertise the extended operations (cropping, rotation, horizontal flipping and vertical flipping) use CImageDecoder::TOptions() and select the option for CImageDecoder::FileNewL() and CImageDecoder::DataNewL() . The code below shows, how to set the right decoder and to set the options:

       
        
       
       TUint options =    CImageDecoder::EOptionExtRotation |
            CImageDecoder::EOptionExtMirrorHorizontalAxis |
            CImageDecoder::EOptionExtScaling;

// The installed decoder supports all the operations requested.
CImageDecoder* decoder = CImageDecoder::FileNewL(iFs, KInputFile, static_cast<CImageDecoder::TOptions>(options));

// Ask for vertical flipping support.
TImageConvOperation* operation = decoder->OperationL();
if (operation)
    {
    // This gives KErrNotSupported because you have not asked for vertical flipping support.
    
operation>AddOperationL(TImageConvOperation::EMirrorVerticalAxis);
}
      

Setting up the right encoder

In order to allow the encoder to advertise the extended operations (rotation, horizontal flipping and vertical flipping) use CImageEncoder::TOptions() and select the option for CImageEncoder::FileNewL() and CImageEncoder::DataNewL() . The code below shows, how to set the right encoder and to set the options:

       
        
       
       TUint options =    CImageEncoder::EOptionExtRotation |
            CImageEncoder::EOptionExtMirrorHorizontalAxis 
            
// The installed encoder supports all the operations requested.
CImageEncoder* encoder = CImageEncoder::FileNewL(iFs, KInputFile, static_cast<CImageEncoder::TOptions>(options));

// Ask for vertical flipping support.
TImageConvOperation* operation = encoder->OperationL();
if (operation)
    {
    // This gives KErrNotSupported because you have not asked for vertical flipping support.
    
operation>AddOperationL(TImageConvOperation::EMirrorVerticalAxis);
}
      

Using Enhanced Features for Encoder and Decoder

The Following tasks are covered in this tutorial:

Basic Procedure For Clipping / Cropping Operation During Decode

The high level steps to set clipping / cropping operation during decode are as follows:

  1. To create the decoder call CImageDecoder::FileNewL() or CImageDecoder::DataNewL() , using the TOptions parameter of EOptionExtCrop to request the added functionality.

  2. In order to clip / crop the image call CImageDecoder::SetClippingRectL() .

  3. Then you need to obtain the size of the bitmap which holds the output of the operation being performed during decode, call the CImageDecoder::GetDestinationSize() function.

  4. Finally start the decoding operation by calling CImageDecoder::Convert() and use the CFbsBitmap obtained by CImageDecoder::GetDestinationSize() .

For example code got to the session Example Code During Decode .

Basic Procedure For Scaling Operation During Decode

The high level steps to set scaling during decode are as follows:

  1. To create the decoder call CImageDecoder::FileNewL() or CImageDecoder::DataNewL() .

  2. In order to scale the image call CImageDecoder::ScalerL() .

  3. Then you need to obtain the size of the bitmap which holds the output of the operation being performed during decode, call the CImageDecoder::GetDestinationSize() function.

  4. Finally start the decoding operation by calling CImageDecoder::Convert() and use the CFbsBitmap obtained by CImageDecoder::GetDestinationSize() .

For example code got to the session Example Code During Decode .

Example Code For Clipping And Scaling During Decode

The example below shows how to peform clipping and scaling during decode :

       
        
       
       void CIclExample::ClipScaleDuringDecode()
    {
    TRect clipRect(TPoint(50, 65), TSize(170, 160));    // The wheel in thumbimage.jpg
    TSize finalSize;

    // The decoder supports all the operations you are going to perform.
    TUint options =    CImageDecoder::EOptionExtRotation |
                    CImageDecoder::EOptionExtMirrorHorizontalAxis |
                    CImageDecoder::EOptionExtCrop |
                    CImageDecoder::EOptionExtScaling;

    // The installed decoder supports all the operations requested in options.
    _LIT(KInputFile, "c:\\ICLExample\\thumbimage.jpg");
    CImageDecoder* decoder = CImageDecoder::FileNewL(iFs, KInputFile, static_cast<CImageDecoder::TOptions>(options));
    CleanupStack::PushL(decoder);

    const TFrameInfo& frameInfo = decoder->FrameInfo(KFirstFrame);
    CFbsBitmap* output = new(ELeave) CFbsBitmap();
    CleanupStack::PushL(output);
    User::LeaveIfError(output->Create(frameInfo.iFrameSizeInPixels, frameInfo.iFrameDisplayMode));

    CActiveListener* ao = CActiveListener::NewLC();

    TImageConvOperation* operation = decoder->OperationL();
    TImageConvScaler* scaler = decoder->ScalerL();

    TInt i = 0;
    while (KDecodeParams[i].iOutputFile != NULL)
        {
        const TDecodeParams& params = KDecodeParams[i++];

        operation->ClearOperationStack();
        if (params.iRotate90)
            {
            operation->AddOperationL(TImageConvOperation::ERotation90DegreesClockwise);
            }

        if (params.iMirrorVerticalAxis)
            {
            operation->AddOperationL(TImageConvOperation::EMirrorVerticalAxis);
            }

        // Some codecs have a limit on the amount of scaling they can do.
        scaler->SetScalingL(params.iScalingCoeff, TImageConvScaler::EMaximumQuality);

        // Setting the clipping rect to NULL decodes the whole image.
        decoder->SetClippingRectL(params.iClip ? &clipRect : NULL);
        User::LeaveIfError(decoder->GetDestinationSize(finalSize, KFirstFrame));
        User::LeaveIfError(output->Resize(finalSize));

        // See Note 1
        ao->Initialize();
        decoder->Convert(&ao->iStatus, *output, KFirstFrame);

        // See Note 2
        CActiveScheduler::Start();

        TPtrC outputFile(params.iOutputFile);
        output->Save(outputFile);    // Ignore error code.
        }

    CleanupStack::PopAndDestroy(3); // decoder, output, ao
    }
      

Basic Procedure For Rotation / Mirroring Operation During Decode

The high level steps to set rotation / mirroring operation during decode are as follows:

  1. To create the decoder call CImageDecoder::FileNewL() or CImageDecoder::DataNewL() , using the TOptions parameter to request the desired functionality from the decoder.

  2. In order to rotate the image call CImageDecoder::EOptionRotation() and for vertical mirroring call CImageDecoder::EOptionMirrorVerticalAxis() .

  3. Then you need to obtain the size of the bitmap which holds the output of the operation being performed during decode, call the CImageDecoder::GetDestinationSize() function.

  4. Finally start the decoding operation by calling CImageDecoder::Convert() and use the CFbsBitmap obtained by CImageDecoder::GetDestinationSize() .

Example

The example below shows how to peform clipping and rotation operation during decode:

       
        
       
       void CIclExample::ClipAndRotateDuringDecode()
    {
    TRect clipRect(TPoint(50, 65), TSize(170, 160));    // The wheel in thumbimage.jpg
    TSize finalSize;

    // The decoder must support *all* the operations we're going to perform.
    TUint options =    CImageDecoder::EOptionExtRotation |
                    CImageDecoder::EOptionExtMirrorHorizontalAxis |
                    CImageDecoder::EOptionExtCrop |
                    CImageDecoder::EOptionExtScaling;

    // The installed decoders must support *all* the operations requested in aOptions.
    _LIT(KInputFile, "c:\\ICLExample\\thumbimage.jpg");
    CImageDecoder* decoder = CImageDecoder::FileNewL(iFs, KInputFile, static_cast<CImageDecoder::TOptions>(options));
    CleanupStack::PushL(decoder);

    const TFrameInfo& frameInfo = decoder->FrameInfo(KFirstFrame);
    CFbsBitmap* output = new(ELeave) CFbsBitmap();
    CleanupStack::PushL(output);
    User::LeaveIfError(output->Create(frameInfo.iFrameSizeInPixels, frameInfo.iFrameDisplayMode));

    CActiveListener* ao = CActiveListener::NewLC();

    TImageConvOperation* operation = decoder->OperationL();
    TImageConvScaler* scaler = decoder->ScalerL();

    TInt i = 0;
    while (KDecodeParams[i].iOutputFile != NULL)
        {
        const TDecodeParams& params = KDecodeParams[i++];

        operation->ClearOperationStack();
        if (params.iRotate90)
            {
            operation->AddOperationL(TImageConvOperation::ERotation90DegreesClockwise);
            }

        if (params.iMirrorVerticalAxis)
            {
            operation->AddOperationL(TImageConvOperation::EMirrorVerticalAxis);
            }

        // Some codecs may have a limit on the amount of scaling they can do.
        scaler->SetScalingL(params.iScalingCoeff, TImageConvScaler::EMaximumQuality);

        // Setting the clipping rect to NULL will decode the whole image.
        decoder->SetClippingRectL(params.iClip ? &clipRect : NULL);
        User::LeaveIfError(decoder->GetDestinationSize(finalSize, KFirstFrame));
        User::LeaveIfError(output->Resize(finalSize));

        // See Note 1
        ao->Initialize();
        decoder->Convert(&ao->iStatus, *output, KFirstFrame);

        // See Note 2
        CActiveScheduler::Start();

        TPtrC outputFile(params.iOutputFile);
        output->Save(outputFile);    // Ignore error code.
        }

    CleanupStack::PopAndDestroy(3); // decoder, output, ao
    }
      

Basic Procedure For Rotation / Mirroring Operation During Encode

The high level steps to set rotation / mirroring during encode are as follows:

  1. To create the encoder call CImageEncoder::FileNewL() or CImageEncoder::DataNewL() and a bitmap holding the image which is to be encoded.

  2. To request an operation extension call, CImageEncoder::OperationL() . If the extension is supported then a T class pointer is returned which gives access to the codec extension. TImageConvOperation has the extension function for rotation, and mirroring operation.

  3. To add multiple transformation operations call TImageConvOperation::AddOperationL() . And to remove the transformation operation call TImageConvOperation::ClearOperationStack() .

    The rotations defined are:

    • Clockwise rotation 90 degrees.

    • Clockwise rotation 180 degrees.

    • Clockwise rotation 270 degrees.

    • Horizontal axis mirroring.

    • Vertical axis mirroring.

  4. Finally call CImageDecoder::Convert() to decode the image. At the end of the Convert() call, the waiting application output in the main application is signalled and the bitmap or YUV image is encoded into a transformed JPEG based on the operations applied, assuming that no error is returned.

    NOTE: The transformation operations are only supported by the images which are multiples of Minimum Coded Unit (MCU).

Example

The example below shows how to peform rotation / mirrioring operation during encode:

       
        
       
       void CIclExample::EncodeBitmapToFileUsingOperationExtensionL(const TDesC& aSrcFileName, const TDesC& aDestFileName)
    {
    // Create the encoder, passing the filename. 
    // If the image is not recognised or valid then the call will leave with an error    
    CImageEncoder* jpegImageEncoder = CImageEncoder::FileNewL(iFs, aDestFileName, CImageEncoder::EOptionNone, KImageTypeJPGUid);
    CleanupStack::PushL(jpegImageEncoder);
    
    // Create a CFbsBitmap to store the source bitmap to encode
    CFbsBitmap* sourceBitmap = new(ELeave) CFbsBitmap;
    CleanupStack::PushL(sourceBitmap);

    User::LeaveIfError(sourceBitmap->Create(TSize(20,30), EColor16M));
    User::LeaveIfError(sourceBitmap->Load(aSrcFileName));
    
    // Create operation extension
    TImageConvOperation* operation = jpegImageEncoder->OperationL();
    
    // Add Rotate 90degrees operation
    operation->AddOperationL(TImageConvOperation::ERotation90DegreesClockwise); 
    //NOTE: Multiple operations can be added
    
    // See Note 1
    CActiveListener* activeListener = CreateAndInitializeActiveListenerLC();

    // Convert the image
    jpegImageEncoder->Convert(&activeListener->iStatus, *sourceBitmap, NULL);

    // See Note 2
    CActiveScheduler::Start();
    User::LeaveIfError(activeListener->iStatus.Int());// encode complete either display the image or report an error.
    
    CleanupStack::PopAndDestroy(3); // jpegImageEncoder, sourceBitmap and activeListener
    }