--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/imagingmodules/jp2kcodec/Src/JP2KImageWriter.cpp Thu Dec 17 09:22:31 2009 +0200
@@ -0,0 +1,2187 @@
+/*
+* Copyright (c) 2003, 2004 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: CJ2kImageWriter class used to perform inverse transformation and
+* writing decoded image data to bitmap.
+*
+*/
+
+
+// INCLUDE FILES
+#include <e32math.h>
+#include <fbs.h>
+#include "JP2KImageUtils.h"
+#include "JP2KFormat.h"
+#include "JP2KTileInfo.h"
+#include "JP2KImageInfo.h"
+#include "JP2KSubband.h"
+#include "JP2KComponentInfo.h"
+#include "JP2KImageWriter.h"
+
+// EXTERNAL DATA STRUCTURES
+
+// EXTERNAL FUNCTION PROTOTYPES
+
+// CONSTANTS
+
+// MACROS
+#define INT2BYTE( n ) ( ( n ) < 0 ? (TUint8)0 : ( ( n ) > 255 ? (TUint8)255 : (TUint8)( n ) ) )
+#define CLIPINT( n,bitdepth ) ( ( n >= ( 1 << bitdepth ) ) ? ( ( 1<<bitdepth ) - 1 ) : ( n < 0 ) ? 0 : n )
+#define CLIP2BITDEPTH( n, maxValue ) ( ( n > maxValue ) ? ( maxValue ) : ( n < 0 ) ? 0 : n )
+#define CLIP2RANGE( n, minValue, maxValue ) ( ( n > maxValue ) ? ( maxValue ) : ( n < minValue ) ? minValue : n )
+
+// LOCAL CONSTANTS AND MACROS
+
+// MODULE DATA STRUCTURES
+
+// LOCAL FUNCTION PROTOTYPES
+
+// FORWARD DECLARATIONS
+
+// LOCAL CONSTANTS AND MACROS
+
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// Destructor
+CJ2kWriterComponentInfo::~CJ2kWriterComponentInfo()
+ {
+ iTileStartList.Close();
+ FreeData();
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kWriterComponentInfo::AllocDataL
+// Allocate 2-D data array with a size
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kWriterComponentInfo::AllocDataL( const TSize& aSize )
+ {
+ FreeData();
+ iData = TJ2kUtils::Alloc2DArrayL( aSize.iHeight, aSize.iWidth );
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kWriterComponentInfo::FreeData
+// Free the 2-D data array
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kWriterComponentInfo::FreeData()
+ {
+ if ( iData )
+ {
+ TJ2kUtils::Free2DArray( iData );
+ iData = 0;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kWriterComponentInfo::Data
+// Get the 2-D data array
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TPrecInt** CJ2kWriterComponentInfo::Data()
+ {
+ return iData;
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kWriterComponentInfo::TileStartAt
+// Get the starting point of a tile
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TPoint& CJ2kWriterComponentInfo::TileStartAt( TUint16 aTileIndex )
+ {
+ return iTileStartList[aTileIndex];
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kWriterComponentInfo::UpdateNextTileStartAt
+// Update the starting point of next tile
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kWriterComponentInfo::UpdateNextTileStartAt( TUint16 aTileIndex,
+ const TSize& aSize,
+ CJ2kImageInfo& aImageInfo )
+ {
+ TUint16 numOfHorizTiles = aImageInfo.NumOfHorizTiles();
+ TUint16 numOfVertTiles = aImageInfo.NumOfVertTiles();
+
+ // Calculate the p and q of a tile
+ TDiv tDiv = TJ2kUtils::Div( aTileIndex, numOfHorizTiles );
+ if ( tDiv.rem != ( numOfHorizTiles - 1 ) )
+ {
+ iTileStartList[aTileIndex + 1].iX = iTileStartList[aTileIndex].iX + aSize.iWidth;
+ }
+
+ if ( tDiv.quot != ( numOfVertTiles - 1 ) )
+ {
+ iTileStartList[aTileIndex + numOfHorizTiles].iY = iTileStartList[aTileIndex].iY + aSize.iHeight;
+ }
+ }
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CJ2kImageWriter* CJ2kImageWriter::NewL( CImageProcessor* aImageProcessor,
+ CJ2kImageInfo& aImageInfo,
+ TJ2kInfo& aJ2kInfo )
+ {
+ CJ2kImageWriter *self = new ( ELeave ) CJ2kImageWriter( aImageProcessor, aImageInfo, aJ2kInfo );
+
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop();
+
+ return self;
+ }
+
+// Destructor
+CJ2kImageWriter::~CJ2kImageWriter()
+ {
+ iComponents.ResetAndDestroy();
+
+ delete iLinearsRGBLut;
+ iLinearsRGBLut = 0;
+
+ User::Free( iGrayTRCLut );
+ User::Free( iRedTRCLut );
+ User::Free( iGreenTRCLut );
+ User::Free( iBlueTRCLut );
+ User::Free( iMonoPixelBlock );
+ User::Free( iColorPixelBlock );
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::WriterComponentAt
+// Get the component of the image writer
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+const CJ2kWriterComponentInfo& CJ2kImageWriter::WriterComponentAt( TUint16 aIndex ) const
+ {
+ return *iComponents[aIndex];
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::OutputImageL
+// Output the image related to the component of the tile
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::OutputImageL( CJ2kTileInfo& aTile, TUint16 aComponentIndex )
+ {
+ TUint8 bitdepth = 0;
+ TUint16 c = 0;
+ CJ2kComponentInfo& componentInfo = CONST_CAST( CJ2kComponentInfo&, aTile.ComponentAt( aComponentIndex ) );
+
+ TInt16 reducedLevels = (TInt16)( componentInfo.Levels() - iImageInfo.LevelDrop() );
+ if ( reducedLevels < 0 )
+ {
+ reducedLevels = 0;
+ }
+
+ CJ2kSubband* subband = CONST_CAST( CJ2kSubband*, componentInfo.SubbandAt( (TUint8)reducedLevels ) );
+
+ if ( subband->SubbandResLevel() != 0 )
+ {
+ subband = subband->Parent();
+ }
+
+ TSize subbandSize = subband->SubbandCanvasSize();
+
+ // Note that in case of component truncation color transform is not performed
+ if ( iImageInfo.ComponentDrop() )
+ {
+ iNumComponents = 1;
+ }
+ else // Only perform color transform if we don't drop components
+ {
+ // Perform the color transfrom
+ if ( aComponentIndex == 2 && aTile.ColorTransformation() )
+ {
+ // Perform the inverse color transform
+ if ( aTile.ComponentAt( 0 ).IsReversible() ) // If RCT is used
+ {
+ PerformInverseRCT( subbandSize );
+ }
+ else
+ {
+ PerformInverseICT( subbandSize );
+ }
+ }
+ }
+
+ // Check if palettes are used. If so, get the number of output channels
+ if ( iJ2kInfo.iCMPList.Count() )
+ {
+ TUint16 numCSComp = iImageInfo.NumOfComponents();
+
+ // Allocate more memory for data if needed
+ if ( iNumComponents > numCSComp )
+ {
+ for ( c = numCSComp; c < iNumComponents; c++ )
+ {
+ // Allocate memory for component data
+ iComponents[c]->AllocDataL( subbandSize );
+ }
+ }
+ // Check if we have all the necessary channels for component mapping
+ if ( aComponentIndex == ( numCSComp - 1 ) )
+ {
+ MapComponentsL( numCSComp, reducedLevels, subbandSize, aTile );
+ }
+ }
+
+ // We start the output of files:
+ if ( iSingleFileOutput )
+ {
+ if ( iNumComponents == 3 ) // 3 comp to combine
+ {
+ // Compute the subbandSize from the first component since others might be downsampled.
+ TInt16 tempNumLevels = (TUint16)( aTile.ComponentAt( 0 ).Levels() - iImageInfo.LevelDrop() );
+
+ if ( tempNumLevels < 0 )
+ {
+ tempNumLevels = 0;
+ }
+
+ CJ2kSubband* tempSubband = CONST_CAST( CJ2kSubband*, aTile.ComponentAt( 0 ).SubbandAt( (TUint8)tempNumLevels ) );
+
+ if ( tempSubband->SubbandResLevel() != 0 )
+ {
+ tempSubband = tempSubband->Parent();
+ }
+
+ subbandSize = tempSubband->SubbandCanvasSize();
+
+ if( !iColorPixelBlock )
+ {
+ // Allocate memory for block of color pixels
+ iColorPixelBlock = STATIC_CAST( TRgb*, User::AllocL( 2 * KPixelsBlock * sizeof( TRgb ) ) );
+ }
+
+ CombineOutputFile( aTile, subbandSize );
+ for ( c = 0; c < iNumComponents; c++ )
+ {
+ iComponents[c]->FreeData();
+ }
+ }
+ else // 1 comp to output
+ {
+ if ( iImageInfo.ComponentDrop() )
+ {
+ c = ( TUint16 )( iImageInfo.ComponentDrop() - 1 );
+ }
+ else
+ {
+ c = aComponentIndex;
+ }
+
+ bitdepth = iImageInfo.DepthOfComponent( c );
+
+ if( !iMonoPixelBlock )
+ {
+ // Allocate memory for block of grayscale pixels
+ iMonoPixelBlock = STATIC_CAST( TUint32*, User::AllocL( KPixelsBlock * sizeof( TUint32 ) ) );
+ }
+
+ // Output a single component
+ WriteOutputFile( aTile, c, subbandSize, bitdepth );
+ iComponents[c]->FreeData();
+ }
+ }
+ else
+ {
+ // Write out three independent output files
+ if( !iMonoPixelBlock )
+ {
+ // Allocate memory for block of grayscale pixels
+ iMonoPixelBlock = STATIC_CAST( TUint32*, User::AllocL( KPixelsBlock * sizeof( TUint32 ) ) );
+ }
+
+ if ( aComponentIndex == 2 && aTile.ColorTransformation() )
+ {
+ for ( c = 0; c < 3; c++ )
+ {
+ bitdepth = iImageInfo.DepthOfComponent( c );
+
+ // Output single files
+ WriteOutputFile( aTile, c, subbandSize, bitdepth );
+ iComponents[c]->FreeData();
+ }
+ }
+ else if ( iJ2kInfo.iCMPList.Count() )
+ {
+ for ( c = 0; c < iNumComponents; c++ )
+ {
+ // Bitdepth is the lowest seven bits plus one for palettes
+ bitdepth = ( TUint8 )( ( iJ2kInfo.iPalette.iBList[0] & 0x7f )+1 );
+
+ // Output single files
+ WriteOutputFile( aTile, c, subbandSize, bitdepth );
+ iComponents[c]->FreeData();
+ }
+ }
+ else
+ {
+ bitdepth = iImageInfo.DepthOfComponent( aComponentIndex );
+
+ // Output only the first component to screen
+ if( aComponentIndex == 0 )
+ {
+ WriteOutputFile( aTile, aComponentIndex, subbandSize, bitdepth );
+ }
+ iComponents[aComponentIndex]->FreeData();
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::OutputImageL
+// Output the image related to the component of the tile
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::OutputImageL( CJ2kTileInfo& aTile, TUint16 aComponentIndex,
+ const TSize& aSize )
+ {
+ TUint8 bitdepth = 0;
+ TUint16 c = 0;
+ CJ2kComponentInfo& componentInfo = CONST_CAST( CJ2kComponentInfo&, aTile.ComponentAt( aComponentIndex ) );
+
+ TInt16 reducedLevels = (TInt16)( componentInfo.Levels() - iImageInfo.LevelDrop() );
+ if ( reducedLevels < 0 )
+ {
+ reducedLevels = 0;
+ }
+
+ CJ2kSubband* subband = CONST_CAST( CJ2kSubband*, componentInfo.SubbandAt( (TUint8)reducedLevels ) );
+ if ( subband->SubbandResLevel() != 0 )
+ {
+ subband = subband->Parent();
+ }
+
+ TSize subbandSize = aSize;
+
+ // Note that in case of component truncation color transform is not performed
+ if ( iImageInfo.ComponentDrop() )
+ {
+ iNumComponents = 1;
+ }
+ else // Only perform color transform if we don't drop components
+ {
+ // Perform the color transfrom
+ if ( aComponentIndex == 2 && aTile.ColorTransformation() )
+ {
+ // Perform the inverse color transform
+ if ( aTile.ComponentAt( 0 ).IsReversible() ) // If RCT is used
+ {
+ PerformInverseRCT( subbandSize );
+ }
+ else
+ {
+ PerformInverseICT( subbandSize );
+ }
+ }
+ }
+
+ // Check if palettes are used. If so, get the number of output channels
+ if ( iJ2kInfo.iCMPList.Count() )
+ {
+ TUint16 numCSComp = iImageInfo.NumOfComponents();
+
+ // Allocate more memory for data if needed
+ if ( iNumComponents > numCSComp )
+ {
+ for ( c = numCSComp; c < iNumComponents; c++ )
+ {
+ // Allocate memory for component data
+ iComponents[c]->AllocDataL( subbandSize );
+ }
+ }
+ // Check if we have all the necessary channels for component mapping
+ if ( aComponentIndex == ( numCSComp - 1 ) )
+ {
+ MapComponentsL( numCSComp, reducedLevels, subbandSize, aTile );
+ }
+ }
+
+ // We start the output of files:
+ if ( iSingleFileOutput )
+ {
+ if ( iNumComponents == 3 ) // 3 comp to combine
+ {
+ if( !iColorPixelBlock )
+ {
+ // Allocate memory for block of color pixels
+ iColorPixelBlock = STATIC_CAST( TRgb*, User::AllocL( 2 * KPixelsBlock * sizeof( TRgb ) ) );
+ }
+
+ CombineOutputFile( aTile, subbandSize );
+ for ( c = 0; c < iNumComponents; c++ )
+ {
+ iComponents[c]->FreeData();
+ }
+ }
+ else // 1 comp to output
+ {
+ if ( iImageInfo.ComponentDrop() )
+ {
+ c = (TUint16)( iImageInfo.ComponentDrop() - 1 );
+ }
+ else
+ {
+ c = aComponentIndex;
+ }
+
+ bitdepth = iImageInfo.DepthOfComponent( c );
+
+ if( !iMonoPixelBlock )
+ {
+ // Allocate memory for block of grayscale pixels
+ iMonoPixelBlock = STATIC_CAST( TUint32*, User::AllocL( KPixelsBlock * sizeof( TUint32 ) ) );
+ }
+
+ // Output a single component
+ WriteOutputFile( aTile, c, subbandSize, bitdepth );
+ iComponents[c]->FreeData();
+ }
+ }
+ else
+ {
+ // Write out three independent output files
+ if( !iMonoPixelBlock )
+ {
+ // Allocate memory for block of grayscale pixels
+ iMonoPixelBlock = STATIC_CAST( TUint32*, User::AllocL( KPixelsBlock * sizeof( TUint32 ) ) );
+ }
+
+ if ( aComponentIndex == 2 && aTile.ColorTransformation() )
+ {
+ for ( c = 0; c < 3; c++ )
+ {
+ bitdepth = iImageInfo.DepthOfComponent( c );
+
+ // Output single files
+ WriteOutputFile( aTile, c, subbandSize, bitdepth );
+ iComponents[c]->FreeData();
+ }
+ }
+ else if ( iJ2kInfo.iCMPList.Count() )
+ {
+ for ( c = 0; c < iNumComponents; c++ )
+ {
+ // Bitdepth is the lowest seven bits plus one for palettes
+ bitdepth = (TUint8)( ( iJ2kInfo.iPalette.iBList[0] & 0x7f )+1 );
+
+ // Output single files
+ WriteOutputFile( aTile, c, subbandSize, bitdepth );
+ iComponents[c]->FreeData();
+ }
+ }
+ else
+ {
+ bitdepth = iImageInfo.DepthOfComponent( aComponentIndex );
+
+ // Output only the first component to screen
+ if( aComponentIndex == 0 )
+ {
+ WriteOutputFile( aTile, aComponentIndex, subbandSize, bitdepth );
+ }
+
+ iComponents[aComponentIndex]->FreeData();
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::OutputBlockL
+// Output the image related to the component of the tile
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::OutputBlockL( CJ2kTileInfo& aTile, TUint16 aComponentIndex,
+ TInt32 aBlockXCoord, TInt32 aBlockYCoord,
+ TSize aFirstCompSize, TSize aThisCompSize )
+ {
+ TUint32 tileIndex = 0;
+ CJ2kWriterComponentInfo* currentComponent = iComponents[aComponentIndex];
+ TPoint tmpTileStart( 0, 0 );
+ TPoint tmpTileStart1( 0, 0 );
+ TPoint tmpTileStart2( 0, 0 );
+
+ CJ2kComponentInfo& componentInfo = CONST_CAST( CJ2kComponentInfo&, aTile.ComponentAt( aComponentIndex ) );
+ TSize outputSize( 0, 0 );
+
+ tileIndex = aTile.SotMarker().iIsot;
+
+ // Update the subband size ( which will be used to compute output size )
+ TInt16 reducedLevels = (TInt16)( componentInfo.Levels() - iImageInfo.LevelDrop() );
+ if ( reducedLevels < 0 )
+ {
+
+ TInt32 i;
+ TInt32 stepSize = 1;
+
+ // Compute the output step size, the stepSize indicates how much more
+ // resolution has to be dropped if the image didn't have enough wavelet
+ // levels to begin with. One indicates no extra resolution drop (write
+ // each sample) and for each extra drop skip half of the samples, i.e.
+ // stepSize is 2^extraLevels in case extra drop is needed.
+
+ // Compute the stepSize
+ for ( i = 0; i < (-reducedLevels); i++ )
+ {
+ // Double the step size for every extra level dropped.
+ stepSize *= 2;
+ }
+
+ // Adjust the block coordinates, so that next block is drawn to the right coordinates
+ aBlockXCoord /= stepSize;
+ aBlockYCoord /= stepSize;
+
+ reducedLevels = 0;
+ }
+
+ CJ2kSubband* subband = CONST_CAST( CJ2kSubband*, componentInfo.SubbandAt( (TUint8)reducedLevels ) );
+ if ( subband->SubbandResLevel() != 0 )
+ {
+ subband = subband->Parent();
+ }
+
+ // If we are going to combine the output into a single file we must use the first components size and
+ // tile-start values ( other components might be sub sampled ).
+ if( iSingleFileOutput && iNumComponents == 3 )
+ {
+ // Update the tileStartCoordinates
+ tmpTileStart = iComponents[0]->TileStartAt( aTile.SotMarker().iIsot );
+ iComponents[0]->iTileStartList[tileIndex].iX += aBlockXCoord;
+ iComponents[0]->iTileStartList[tileIndex].iY += aBlockYCoord;
+
+ // Also store and update the tileStartCoordinates of the other two components, as they may be output to file
+ tmpTileStart1 = iComponents[1]->TileStartAt( aTile.SotMarker().iIsot );
+ iComponents[1]->iTileStartList[tileIndex].iX += aBlockXCoord;
+ iComponents[1]->iTileStartList[tileIndex].iY += aBlockYCoord;
+ tmpTileStart2 = iComponents[2]->TileStartAt( aTile.SotMarker().iIsot );
+ iComponents[2]->iTileStartList[tileIndex].iX += aBlockXCoord;
+ iComponents[2]->iTileStartList[tileIndex].iY += aBlockYCoord;
+
+ outputSize = aFirstCompSize;
+ }
+ else
+ {
+ // Update the tileStartCoordinates
+ tmpTileStart = currentComponent->TileStartAt( aTile.SotMarker().iIsot );
+ currentComponent->iTileStartList[tileIndex].iX += aBlockXCoord;
+ currentComponent->iTileStartList[tileIndex].iY += aBlockYCoord;
+
+ outputSize = aThisCompSize;
+ }
+
+ // Call OutputImageL with the changed parameters
+ OutputImageL( aTile, aComponentIndex, outputSize );
+
+ // Restore the original values
+ if( iSingleFileOutput && iNumComponents == 3 )
+ {
+ iComponents[0]->iTileStartList[tileIndex] = tmpTileStart;
+ iComponents[1]->iTileStartList[tileIndex] = tmpTileStart1;
+ iComponents[2]->iTileStartList[tileIndex] = tmpTileStart2;
+ }
+ else
+ {
+ currentComponent->iTileStartList[tileIndex] = tmpTileStart;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::SetNewImageProcessor
+// Set the image processor of the image write
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::SetNewImageProcessor( CImageProcessor* aImageProcessor )
+ {
+ iImageProcessor = aImageProcessor;
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::SingleFileOutput
+// Get the single output file
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TUint8 CJ2kImageWriter::SingleFileOutput() const
+ {
+ return iSingleFileOutput;
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::CSCode
+// Get the EnumCS
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TUint8 CJ2kImageWriter::CSCode() const
+ {
+ return (TUint8)iJ2kInfo.iEnumCS;
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::CJ2kImageWriter
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CJ2kImageWriter::CJ2kImageWriter( CImageProcessor* aImageProcessor,
+ CJ2kImageInfo& aImageInfo,
+ TJ2kInfo& aJ2kInfo ) :
+ iImageProcessor( aImageProcessor ),
+ iImageInfo( aImageInfo ),
+ iJ2kInfo( aJ2kInfo )
+ {
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::ConstructL()
+ {
+ TInt32 i = 0;
+
+ TSizMarker& sizMarker = CONST_CAST( TSizMarker&, iImageInfo.SizMarker() );
+
+ iNumComponents = iImageInfo.NumOfComponents();
+
+ if ( iJ2kInfo.iCMPList.Count() )
+ {
+ iNumComponents = (TUint16)( iJ2kInfo.iCMPList.Count() );
+
+ if(iNumComponents < iImageInfo.NumOfComponents())
+ {
+ // Every component in the codestream must have a mapping defined
+ User::Leave( KErrCorrupt );
+ }
+ }
+
+ for ( i = 0; i < iNumComponents; i++ )
+ {
+ CJ2kWriterComponentInfo *info = new ( ELeave ) CJ2kWriterComponentInfo;
+ CleanupStack::PushL( info );
+ User::LeaveIfError( iComponents.Append( info ) );
+ CleanupStack::Pop(1);
+ }
+
+ if ( iNumComponents == 3 )
+ {
+ iSingleFileOutput = 1;
+ if ( sizMarker.iXRsiz[1] == 2 * sizMarker.iXRsiz[0] &&
+ sizMarker.iXRsiz[2] == 2 * sizMarker.iXRsiz[0] )
+ {
+ if ( sizMarker.iYRsiz[1] == 2 * sizMarker.iYRsiz[0] &&
+ sizMarker.iYRsiz[2] == 2 * sizMarker.iYRsiz[0] )
+ {
+ iFileType = KYUV420;
+ }
+ else
+ {
+ iFileType = KYUV422;
+ }
+ }
+ }
+ else if ( iNumComponents == 1 )
+ {
+ iFileType = KRGB;
+ }
+
+ if ( iImageInfo.ComponentDrop() ) //lint !e961 no else is needed here at the end of if...else if
+ {
+ iFileType = KRGB;
+ }
+
+ if ( iJ2kInfo.iICCProfile )
+ {
+ iICCProfile = ETrue;
+ InitializeICCProfileL();
+ }
+
+ // Initialize the output parameters
+ if ( iImageInfo.Crop() )
+ {
+ // Currently do nothing.
+ }
+ else
+ {
+ InitializeOutputParametersL();
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::PerformInverseRCT
+// Perform the inverse reversible color transformation
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::PerformInverseRCT( const TSize& aSize )
+ {
+ TInt32 col = 0;
+ TPrecInt red = 0;
+ TPrecInt green = 0;
+ TPrecInt blue = 0;
+ TPrecInt** block1 = iComponents[0]->iData;
+ TPrecInt** block2 = iComponents[1]->iData;
+ TPrecInt** block3 = iComponents[2]->iData;
+
+ for ( TInt32 row = 0; row < aSize.iHeight; row++ )
+ {
+ for ( col = 0; col < aSize.iWidth; col++ )
+ {
+ red = block1[row][col];
+ green = block2[row][col];
+ blue = block3[row][col];
+
+ block2[row][col] = red - ( ( blue + green ) >> 2 ); //lint !e704 shifting is OK.
+ block1[row][col] = blue + block2[row][col];
+ block3[row][col] = green + block2[row][col];
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::PerformInverseICT
+// Perform the inverse irreversible color transformation
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::PerformInverseICT( const TSize& aSize )
+ {
+ TInt32 col = 0;
+ TPrecInt red = 0;
+ TPrecInt green = 0;
+ TPrecInt blue = 0;
+ TPrecInt** block1 = iComponents[0]->iData;
+ TPrecInt** block2 = iComponents[1]->iData;
+ TPrecInt** block3 = iComponents[2]->iData;
+
+ for ( TInt32 row = 0; row < aSize.iHeight; row++ )
+ {
+ for ( col = 0; col < aSize.iWidth; col++ )
+ {
+ red = block1[row][col];
+ green = block2[row][col];
+ blue = block3[row][col];
+ InverseICTTransform( red, green, blue, block1[row][col], block2[row][col], block3[row][col] );
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::InverseICTTransform
+// Inverse irreversible color transformation
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::InverseICTTransform( TPrecInt aY, TPrecInt aU, TPrecInt aV,
+ TPrecInt& aR, TPrecInt& aG, TPrecInt& aB )
+ {
+ aR = ( TPrecInt )( ( ( ( aY << KFractionBits ) +
+ ( KIctCoefficient11 * aV ) ) + KOffset ) >> KFractionBits ); //lint !e704 shifting is OK.
+ aG = ( TPrecInt )( ( ( ( aY << KFractionBits ) +
+ ( KIctCoefficient21 * aU ) + ( KIctCoefficient22 * aV ) ) + KOffset ) >> KFractionBits ); //lint !e704 shifting is OK.
+ aB = ( TPrecInt )( ( ( ( aY << KFractionBits ) +
+ ( KIctCoefficient31 * aU ) ) + KOffset ) >> KFractionBits ); //lint !e704 shifting is OK.
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::InverseICTTransform
+// Inverse irreversible color transformation.
+// Performs fast transform and outputs even and odd samples at the same time
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::InverseICTTransform( TPrecInt aY1, TPrecInt aY2, TPrecInt aU, TPrecInt aV,
+ TPrecInt& aR1, TPrecInt& aG1, TPrecInt& aB1,
+ TPrecInt& aR2, TPrecInt& aG2, TPrecInt& aB2)
+ {
+ TInt32 y1Shifted;
+ TInt32 y2Shifted;
+ TInt32 rTempValue;
+ TInt32 gTempValue;
+ TInt32 bTempValue;
+
+ y1Shifted = ( aY1 << KFractionBits );
+ y2Shifted = ( aY2 << KFractionBits );
+ rTempValue = ( KIctCoefficient11 * aV ) + KOffset;
+ gTempValue = ( KIctCoefficient21 * aU ) + ( KIctCoefficient22 * aV ) + KOffset;
+ bTempValue = ( KIctCoefficient31 * aU ) + KOffset;
+
+ aR1 = ( TPrecInt )( ( y1Shifted + rTempValue ) >> KFractionBits ); //lint !e704 shifting is OK.
+ aG1 = ( TPrecInt )( ( y1Shifted + gTempValue ) >> KFractionBits ); //lint !e704 shifting is OK.
+ aB1 = ( TPrecInt )( ( y1Shifted + bTempValue ) >> KFractionBits ); //lint !e704 shifting is OK.
+ aR2 = ( TPrecInt )( ( y2Shifted + rTempValue ) >> KFractionBits ); //lint !e704 shifting is OK.
+ aG2 = ( TPrecInt )( ( y2Shifted + gTempValue ) >> KFractionBits ); //lint !e704 shifting is OK.
+ aB2 = ( TPrecInt )( ( y2Shifted + bTempValue ) >> KFractionBits ); //lint !e704 shifting is OK.
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::InverseICTFastYUV420Transform
+// Inverse irreversible color transformation
+// Performs fast transform and outputs even and odd samples on even and odd
+// rows (four samples) at the same time.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::InverseICTTransform( TPrecInt aY1, TPrecInt aY2, TPrecInt aY3, TPrecInt aY4,
+ TPrecInt aU, TPrecInt aV,
+ TPrecInt& aR1, TPrecInt& aG1, TPrecInt& aB1,
+ TPrecInt& aR2, TPrecInt& aG2, TPrecInt& aB2,
+ TPrecInt& aR3, TPrecInt& aG3, TPrecInt& aB3,
+ TPrecInt& aR4, TPrecInt& aG4, TPrecInt& aB4)
+ {
+ TInt32 y1Shifted;
+ TInt32 y2Shifted;
+ TInt32 y3Shifted;
+ TInt32 y4Shifted;
+ TInt32 rTempValue;
+ TInt32 gTempValue;
+ TInt32 bTempValue;
+
+ y1Shifted = ( aY1 << KFractionBits );
+ y2Shifted = ( aY2 << KFractionBits );
+ y3Shifted = ( aY3 << KFractionBits );
+ y4Shifted = ( aY4 << KFractionBits );
+ rTempValue = ( KIctCoefficient11 * aV ) + KOffset;
+ gTempValue = ( KIctCoefficient21 * aU ) + ( KIctCoefficient22 * aV ) + KOffset;
+ bTempValue = ( KIctCoefficient31 * aU ) + KOffset;
+
+ aR1 = ( TPrecInt )( ( y1Shifted + rTempValue ) >> KFractionBits ); //lint !e704 shifting is OK.
+ aG1 = ( TPrecInt )( ( y1Shifted + gTempValue ) >> KFractionBits ); //lint !e704 shifting is OK.
+ aB1 = ( TPrecInt )( ( y1Shifted + bTempValue ) >> KFractionBits ); //lint !e704 shifting is OK.
+ aR2 = ( TPrecInt )( ( y2Shifted + rTempValue ) >> KFractionBits ); //lint !e704 shifting is OK.
+ aG2 = ( TPrecInt )( ( y2Shifted + gTempValue ) >> KFractionBits ); //lint !e704 shifting is OK.
+ aB2 = ( TPrecInt )( ( y2Shifted + bTempValue ) >> KFractionBits ); //lint !e704 shifting is OK.
+ aR3 = ( TPrecInt )( ( y3Shifted + rTempValue ) >> KFractionBits ); //lint !e704 shifting is OK.
+ aG3 = ( TPrecInt )( ( y3Shifted + gTempValue ) >> KFractionBits ); //lint !e704 shifting is OK.
+ aB3 = ( TPrecInt )( ( y3Shifted + bTempValue ) >> KFractionBits ); //lint !e704 shifting is OK.
+ aR4 = ( TPrecInt )( ( y4Shifted + rTempValue ) >> KFractionBits ); //lint !e704 shifting is OK.
+ aG4 = ( TPrecInt )( ( y4Shifted + gTempValue ) >> KFractionBits ); //lint !e704 shifting is OK.
+ aB4 = ( TPrecInt )( ( y4Shifted + bTempValue ) >> KFractionBits ); //lint !e704 shifting is OK.
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::InitializeICCProfileL
+// Initialize the ICC profile from JP2 file format ( iJ2kInfo )
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::InitializeICCProfileL()
+ {
+ const TUint8* iterator = iJ2kInfo.iICCProfile->Ptr();
+ TUint8* origin = CONST_CAST( TUint8*, iJ2kInfo.iICCProfile->Ptr() );
+
+ // Skip the first 128 bytes
+ iterator += KICCSkipBytes;
+
+ // Get the tag count
+ TUint32 tagCount = PtrReadUtil::ReadBigEndianUint32Inc( iterator );
+
+ TUint32 tagSignature = 0;
+ TUint32 tagSize = 0;
+ TUint32 redXYZOffset = 0;
+ TUint32 greenXYZOffset = 0;
+ TUint32 blueXYZOffset = 0;
+ TUint32 trcOffset = 0;
+ TUint32 index = 0;
+ TInt32 i = 0;
+ TInt entries = 0;
+ HBufC16* redTRC = 0;
+ HBufC16* greenTRC = 0;
+ HBufC16* blueTRC = 0;
+ HBufC16* grayTRC = 0;
+ TUint8 isColor = EFalse;
+ TReal value = 0.0;
+
+ for ( index = 0; index < tagCount; ++index )
+ {
+ tagSignature = PtrReadUtil::ReadBigEndianUint32Inc( iterator );
+ switch ( tagSignature )
+ {
+ case KRedMatrixTag:
+ {
+ redXYZOffset = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) + 8;
+ iterator += 4;
+ break;
+ }
+ case KGreenMatrixTag:
+ {
+ greenXYZOffset = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) + 8;
+ iterator += 4;
+ break;
+ }
+ case KBlueMatrixTag:
+ {
+ blueXYZOffset = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) + 8;
+ iterator += 4;
+ break;
+ }
+ case KRedTrcTag:
+ {
+ isColor = ETrue;
+ trcOffset = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) + 12;
+ tagSize = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) - 12;
+ entries = tagSize >> 1;
+ redTRC = HBufC16::NewLC( entries );
+ TPtr16 tmpPtr = ( redTRC->Des() );
+
+ // Read bytes into the TRC values array
+ for( i = 0; i < entries; i++ )
+ {
+ tmpPtr.Append( (TUint16)( ( origin[trcOffset + 2 * i] << 8 ) |
+ origin[trcOffset + 2 * i + 1] ) );
+ }
+
+ break;
+ }
+ case KGreenTrcTag:
+ {
+ isColor = ETrue;
+ trcOffset = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) + 12;
+ tagSize = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) - 12;
+ entries = tagSize >> 1;
+ greenTRC = HBufC16::NewLC( entries );
+ TPtr16 tmpPtr = ( greenTRC->Des() );
+
+ // Read bytes into the TRC values array
+ for( i = 0; i < entries; i++ )
+ {
+ tmpPtr.Append( (TUint16)( ( origin[trcOffset + 2 * i] << 8 ) |
+ origin[trcOffset + 2 * i + 1] ) );
+ }
+
+ break;
+ }
+ case KBlueTrcTag:
+ {
+ isColor = ETrue;
+ trcOffset = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) + 12;
+ tagSize = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) - 12;
+ entries = tagSize >> 1;
+ blueTRC = HBufC16::NewLC( entries );
+ TPtr16 tmpPtr = ( blueTRC->Des() );
+
+ // Read bytes into the TRC values array
+ for( i = 0; i < entries; i++ )
+ {
+ tmpPtr.Append( (TUint16)( ( origin[trcOffset+2*i] << 8 ) |
+ origin[trcOffset+2*i+1] ) );
+ }
+
+ break;
+ }
+ case KGrayTrcTag:
+ {
+ trcOffset = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) + 12;
+ tagSize = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) - 12;
+ entries = tagSize >> 1;
+ grayTRC = HBufC16::NewLC( entries );
+ TPtr16 tmpPtr = ( grayTRC->Des() );
+
+ // Read bytes into the TRC values array
+ for( i = 0; i < entries; i++ )
+ {
+ tmpPtr.Append( (TUint16)( ( origin[trcOffset + 2 * i] << 8 ) |
+ origin[trcOffset + 2 * i + 1] ) );
+ }
+
+ break;
+ }
+ default:
+ {
+ iterator += 8;
+ break;
+ }
+ }
+ }
+
+ TReal gamma = 0.0;
+ TReal maxInput = 0.0;
+ TReal src = 0.0;
+ TUint32 numPerSample = 0;
+ TUint32 lutSize = 0;
+ if ( iJ2kInfo.iBPCList.Count() )
+ {
+ lutSize = 1 << ( iJ2kInfo.iBPCList[0] & 0x7f + 1 );
+ }
+ else
+ {
+ lutSize = 1 << iImageInfo.DepthOfComponent( 0 );
+ }
+
+ if ( isColor )
+ {
+ // Read the RGB( lin. ) -> XYZ conversion matrix coefficients
+ // The matrix is the following:
+ // _ _
+ // | redX greenX blueX |
+ // | redY greenY blueY |
+ // | redZ greenZ blueZ |
+ // |_ _|
+ //
+ TReal redX = ( TReal )PtrReadUtil::ReadBigEndianUint32( origin + redXYZOffset ) / KDivisor;
+ TReal redY = ( TReal )PtrReadUtil::ReadBigEndianUint32( origin + redXYZOffset + 4 ) / KDivisor;
+ TReal redZ = ( TReal )PtrReadUtil::ReadBigEndianUint32( origin + redXYZOffset + 8 ) / KDivisor;
+
+ TReal greenX = ( TReal )PtrReadUtil::ReadBigEndianUint32( origin + greenXYZOffset ) / KDivisor;
+ TReal greenY = ( TReal )PtrReadUtil::ReadBigEndianUint32( origin + greenXYZOffset + 4 ) / KDivisor;
+ TReal greenZ = ( TReal )PtrReadUtil::ReadBigEndianUint32( origin + greenXYZOffset + 8 ) / KDivisor;
+
+ TReal blueX = ( TReal )PtrReadUtil::ReadBigEndianUint32( origin + blueXYZOffset ) / KDivisor;
+ TReal blueY = ( TReal )PtrReadUtil::ReadBigEndianUint32( origin + blueXYZOffset + 4 ) / KDivisor;
+ TReal blueZ = ( TReal )PtrReadUtil::ReadBigEndianUint32( origin + blueXYZOffset + 8 ) / KDivisor;
+
+ // Combine the RGB( lin. ) -> XYZ and the XYZ -> sRGB( lin. ) conversions, i.e.
+ // perform the matrix multiplication. Store the result in "iMatrix".
+ iMatrix[0] = ( TInt32 )( KSRGBMaxIntShifted * ( KSRGB00 * redX + KSRGB01 * redY + KSRGB02 * redZ ) );
+ iMatrix[1] = ( TInt32 )( KSRGBMaxIntShifted * ( KSRGB00 * greenX + KSRGB01 * greenY + KSRGB02 * greenZ ) );
+ iMatrix[2] = ( TInt32 )( KSRGBMaxIntShifted * ( KSRGB00 * blueX + KSRGB01 * blueY + KSRGB02 * blueZ ) );
+
+ iMatrix[3] = ( TInt32 )( KSRGBMaxIntShifted * ( KSRGB10 * redX + KSRGB11 * redY + KSRGB12 * redZ ) );
+ iMatrix[4] = ( TInt32 )( KSRGBMaxIntShifted * ( KSRGB10 * greenX + KSRGB11 * greenY + KSRGB12 * greenZ ) );
+ iMatrix[5] = ( TInt32 )( KSRGBMaxIntShifted * ( KSRGB10 * blueX + KSRGB11 * blueY + KSRGB12 * blueZ ) );
+
+ iMatrix[6] = ( TInt32 )( KSRGBMaxIntShifted * ( KSRGB20 * redX + KSRGB21 * redY + KSRGB22 * redZ ) );
+ iMatrix[7] = ( TInt32 )( KSRGBMaxIntShifted * ( KSRGB20 * greenX + KSRGB21 * greenY + KSRGB22 * greenZ ) );
+ iMatrix[8] = ( TInt32 )( KSRGBMaxIntShifted * ( KSRGB20 * blueX + KSRGB21 * blueY + KSRGB22 * blueZ ) );
+
+ iRedTRCLut = STATIC_CAST( TInt32*, User::AllocL( lutSize * sizeof( TInt32 ) ) );
+ if ( redTRC->Length() == 1 )
+ {
+ gamma = (TReal)( *redTRC )[0] / KGamma;
+ maxInput = (TReal)( lutSize - 1 );
+ for ( index = 0; index < lutSize; ++index )
+ {
+ src = index / maxInput;
+ Math::Pow( value, src, gamma );
+ iRedTRCLut[index] = (TInt32)( value * KTRCShiftMultiplier + 0.5 );
+ }
+ }
+ else
+ {
+ numPerSample = lutSize / (TUint32)( redTRC->Length() );
+ if ( numPerSample )
+ {
+ for ( index = 0; index < lutSize; ++index )
+ {
+ value = ( *redTRC )[index / numPerSample] / KDivisor;
+ iRedTRCLut[index] = (TInt32)( value * KTRCShiftMultiplier + 0.5 );
+ }
+ }
+ }
+
+ if ( iJ2kInfo.iBPCList.Count() )
+ {
+ lutSize = 1 << ( iJ2kInfo.iBPCList[1] & 0x7f + 1 );
+ }
+ else
+ {
+ lutSize = 1 << iImageInfo.DepthOfComponent( 1 );
+ }
+
+ iGreenTRCLut = STATIC_CAST( TInt32*, User::AllocL( lutSize * sizeof( TInt32 ) ) );
+ if ( greenTRC->Length() == 1 )
+ {
+ gamma = (TReal)( *greenTRC )[0] / KGamma;
+ maxInput = (TReal)( lutSize - 1 );
+ for ( index = 0; index < lutSize; ++index )
+ {
+ src = index / maxInput;
+ Math::Pow( value, src, gamma );
+ iGreenTRCLut[index] = (TInt32)( value * KTRCShiftMultiplier + 0.5 );
+ }
+ }
+ else
+ {
+ numPerSample = lutSize / (TUint32)( greenTRC->Length() );
+ if ( numPerSample )
+ {
+ for ( index = 0; index < lutSize; ++index )
+ {
+ value = ( *greenTRC )[index / numPerSample] / KDivisor;
+ iGreenTRCLut[index] = (TInt32)( value * KTRCShiftMultiplier + 0.5 );
+ }
+ }
+ }
+
+ if ( iJ2kInfo.iBPCList.Count() )
+ {
+ lutSize = 1 << ( iJ2kInfo.iBPCList[2] & 0x7f + 1 );
+ }
+ else
+ {
+ lutSize = 1 << iImageInfo.DepthOfComponent( 2 );
+ }
+
+ iBlueTRCLut = STATIC_CAST( TInt32*, User::AllocL( lutSize * sizeof( TInt32 ) ) );
+ if ( blueTRC->Length() == 1 )
+ {
+ gamma = (TReal)( *blueTRC )[0] / KGamma;
+ maxInput = (TReal)( lutSize - 1 );
+ for ( index = 0; index < lutSize; ++index )
+ {
+ src = index / maxInput;
+ Math::Pow( value, src, gamma );
+ iBlueTRCLut[index] = (TInt32)( value * KTRCShiftMultiplier + 0.5 );
+ }
+ }
+ else
+ {
+ numPerSample = lutSize / (TUint32)( blueTRC->Length() );
+ if ( numPerSample )
+ {
+ for ( index = 0; index < lutSize; ++index )
+ {
+ value = ( *blueTRC )[index / numPerSample] / KDivisor;
+ iBlueTRCLut[index] = (TInt32)( value * KTRCShiftMultiplier + 0.5 );
+ }
+ }
+ }
+ }
+ else
+ {
+
+ iGrayTRCLut = STATIC_CAST( TInt32*, User::AllocL( lutSize * sizeof( TInt32 ) ) );
+ if ( grayTRC->Length() == 1 )
+ {
+
+ gamma = (TReal)( *grayTRC )[0] / KGamma;
+ maxInput = (TReal)( lutSize - 1 );
+ for ( index = 0; index < lutSize; ++index )
+ {
+ src = index / maxInput;
+ Math::Pow( value, src, gamma );
+ iGrayTRCLut[index] = (TInt32)( value*KSRGBMax+0.5 );
+ }
+ }
+ else
+ {
+ numPerSample = lutSize / (TUint32)( grayTRC->Length() );
+ if ( numPerSample )
+ {
+ for ( index = 0; index < lutSize; ++index )
+ {
+ value = ( *grayTRC )[index / numPerSample] / KDivisor;
+ iGrayTRCLut[index] = (TInt32)( value*KSRGBMax + 0.5 );
+ }
+ }
+ }
+ }
+
+ TUint16 cutoffIdx = 0; // Cutoff index for linear portion of output LUT
+ TReal linearSlope = 0.0; // Slope of output LUT in the linear region
+ TReal normalisation = 0.0; // Scale factor to normalize sRGB linear value to [0,1]
+
+ // Generate the final output LUT for converting linear sRGB to non-linear sRGB.
+ // Input values are in the range [0,KSRGBMax] and output will be 8-bit [0,255].
+ // Conversation values can be obtained in e.g. "JPEG2000 - Image compression
+ // fundamentals, standards and practice" book by Taubman and Marcellin.
+ cutoffIdx = (TUint16)( KSRGB_CUTOFF * KSRGBMax );
+ linearSlope = 255.0 * KSRGB_SLOPE / KSRGBMax;
+ normalisation = 1.0 / KSRGBMax;
+
+ iLinearsRGBLut = HBufC8::NewL( KSRGBMaxInt + 1 );
+
+ // Generate the output lin.sRGB -> non-lin.sRGB LUT
+ // Linear part
+ for ( index = 0; index <= cutoffIdx; ++index )
+ {
+ iLinearsRGBLut->Des().Append( (TUint8)( linearSlope * index ) );
+ }
+
+ // Non-linear part
+ for ( ; index <= (TUint32)KSRGBMaxInt; ++index )
+ {
+ gamma = index * normalisation;
+ Math::Pow( src, gamma , KSRGB_EXPONENT );
+ iLinearsRGBLut->Des().Append( (TUint8)( 255 * ( KSRGB_MULTIPLIER * src - KSRGB_SUBTRACT ) ) );
+ }
+
+ // We do not need iJ2kInfo.iICCProfile data anymore
+ delete iJ2kInfo.iICCProfile;
+ iJ2kInfo.iICCProfile = 0;
+
+ if ( isColor )
+ {
+ CleanupStack::PopAndDestroy( 3 );
+ }
+ else
+ {
+ CleanupStack::PopAndDestroy( 1 );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::InitializeOutputParametersL
+// Initialize the output parameters
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::InitializeOutputParametersL()
+ {
+ CJ2kWriterComponentInfo* component = 0;
+ TUint16 l = 0;
+ TUint16 m = 0;
+ TUint16 tileIndex = 0;
+ TUint16 tileYIndex = 0;
+ TPoint tileStart( 0, 0 );
+ TUint16 numOfHorizTiles = iImageInfo.NumOfHorizTiles();
+ TUint16 numOfVertTiles = iImageInfo.NumOfVertTiles();
+ TRect tileCanvas( 0, 0, 0, 0 );
+ TRect componentCanvas( 0, 0, 0, 0 );
+ const TSizMarker &sizMarker = iImageInfo.SizMarker();
+ TInt useHeight = 0;
+ TInt useWidth = 0;
+
+ // Prepare the tile coordinates for output image
+ for ( TUint16 compIndex = 0; compIndex < iNumComponents; compIndex++ )
+ {
+ component = iComponents[compIndex];
+
+ for ( l = 0; l < numOfVertTiles; l++ )
+ {
+ tileYIndex = (TUint16)( l * numOfHorizTiles );
+
+ for ( m = 0; m < numOfHorizTiles; m++ )
+ {
+ // Tile index
+ tileIndex = (TUint16)( tileYIndex + m );
+
+ // Tile canvas
+ tileCanvas.iTl = TPoint( Max( sizMarker.iXTOsiz + m * sizMarker.iXTsiz, sizMarker.iXOsiz ),
+ Max( sizMarker.iYTOsiz + l * sizMarker.iYTsiz, sizMarker.iYOsiz ) );
+
+ tileCanvas.iBr = TPoint( Min( sizMarker.iXTOsiz + ( m + 1 ) * sizMarker.iXTsiz, sizMarker.iXsiz ),
+ Min( sizMarker.iYTOsiz + ( l + 1 ) * sizMarker.iYTsiz, sizMarker.iYsiz ) );
+ // Component canvas
+ componentCanvas.iTl = TPoint( TJ2kUtils::Ceil( tileCanvas.iTl.iX, sizMarker.iXRsiz[compIndex] ),
+ TJ2kUtils::Ceil( tileCanvas.iTl.iY, sizMarker.iYRsiz[compIndex] ) );
+
+ componentCanvas.iBr = TPoint( TJ2kUtils::Ceil( tileCanvas.iBr.iX, sizMarker.iXRsiz[compIndex] ),
+ TJ2kUtils::Ceil( tileCanvas.iBr.iY, sizMarker.iYRsiz[compIndex] ) );
+
+ if ( m )
+ {
+ tileStart.iX = component->iTileStartList[tileIndex - 1].iX + useWidth;
+ }
+ else
+ {
+ tileStart.iX = 0;
+ }
+
+ // Width to be used on the next horizontal tile
+ useWidth = componentCanvas.Width();
+
+ if ( l )
+ {
+ tileStart.iY = component->iTileStartList[tileIndex - 1].iY + useHeight;
+ useHeight = 0;
+ }
+ else
+ {
+ tileStart.iY = 0;
+ }
+
+ User::LeaveIfError( component->iTileStartList.Append( tileStart ) );
+ }
+ // Height to be used on the next vertical tile
+ useHeight = componentCanvas.Height();
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::DoICCConversion
+// Perform XYZ to sRGB conversion with the ICC profile.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::DoICCConversion( TInt32 aX,
+ TInt32 aY,
+ TInt32 aZ,
+ TPrecInt& aR,
+ TPrecInt& aG,
+ TPrecInt& aB )
+ {
+ TInt32 tmpX = 0;
+ TInt32 tmpY = 0;
+ TInt32 tmpZ = 0;
+ TInt32 tmpR = 0;
+ TInt32 tmpG = 0;
+ TInt32 tmpB = 0;
+
+ // First perform the input linearization
+ tmpX = iRedTRCLut[aX];
+ tmpY = iGreenTRCLut[aY];
+ tmpZ = iBlueTRCLut[aZ];
+
+ // Then perform the matrix multiplication to obtain the nonlinear RGB
+ tmpR = ( iMatrix[0] * tmpX + iMatrix[1] * tmpY + iMatrix[2] * tmpZ ) >> KICCDownshift; //lint !e704 shifting is OK.
+ tmpG = ( iMatrix[3] * tmpX + iMatrix[4] * tmpY + iMatrix[5] * tmpZ ) >> KICCDownshift; //lint !e704 shifting is OK.
+ tmpB = ( iMatrix[6] * tmpX + iMatrix[7] * tmpY + iMatrix[8] * tmpZ ) >> KICCDownshift; //lint !e704 shifting is OK.
+
+ // Get rid of values outside the range of legal values
+ tmpR = CLIP2RANGE( tmpR, 0, KSRGBMaxInt );
+ tmpG = CLIP2RANGE( tmpG, 0, KSRGBMaxInt );
+ tmpB = CLIP2RANGE( tmpB, 0, KSRGBMaxInt );
+
+ // De-linearize the output RGB values
+ aR = ( *iLinearsRGBLut )[tmpR];
+ aG = ( *iLinearsRGBLut )[tmpG];
+ aB = ( *iLinearsRGBLut )[tmpB];
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::MapToEightBits
+// Map data less than 8 bits to 8 bits data
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::MapToEightBits( CJ2kWriterComponentInfo& aComponent,
+ const TSize& aSize,
+ TUint16 aBitDepth )
+ {
+ TPrecInt* imageRow;
+ TInt32 i = 0;
+ TInt32 j = 0;
+
+ // DC-shift is always non zero, since we map signed data to unsigned
+ if ( aBitDepth < 8 )
+ {
+ TPrecInt upshift = KByteBits - aBitDepth;
+ TPrecInt dcShiftUp = 1 << ( KByteBits - 1 );
+
+ for ( i = aSize.iHeight - 1; i >= 0; i-- )
+ {
+ imageRow = aComponent.Data()[i];
+ for ( j = aSize.iWidth - 1; j >= 0; j-- )
+ {
+ imageRow[j] = ( imageRow[j] * ( 1 << upshift ) ) + dcShiftUp;
+ }
+ }
+ }
+ else // The original bitdepth is more than eight
+ {
+ TPrecInt dcShift = 1 << ( aBitDepth - 1 );
+ TPrecInt downshift = aBitDepth - KByteBits;
+ for ( i = aSize.iHeight - 1; i >= 0; --i )
+ {
+ imageRow = aComponent.Data()[i];
+ for ( j = aSize.iWidth - 1; j >= 0; j-- )
+ {
+ imageRow[j] = ( imageRow[j] + dcShift ) >> downshift; //lint !e704 shifting is OK.
+ }
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::MapComponentsL
+// Map data using the component mapping box from JP2 file format
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::MapComponentsL( TUint16 aNumCSComp,
+ TUint16 aReducedLevels,
+ const TSize& aSize,
+ CJ2kTileInfo& aTile )
+ {
+ TInt32 i = 0;
+ TInt32 j = 0;
+ TInt32 k = 0; // Indices
+ TInt32 compIndex = 0; // Index of the component in the codestream
+ TInt32 paletteIndex = 0; // Index of the component in the palette
+ TInt32 value = 0;
+ TInt32 dcShift = 0;
+ TPrecInt*** tempData = 0; // temporary storage for codestream data
+ TUint8 bitdepth = 0;
+
+ CJ2kWriterComponentInfo* componentFrom = 0;
+ CJ2kWriterComponentInfo* componentTo = 0;
+ CJ2kSubband* subband = 0;
+
+ TSize subbandSize( 0, 0 );
+
+ // First allocate the temporary storage
+ tempData = STATIC_CAST( TPrecInt***, User::Alloc( aNumCSComp * sizeof( TPrecInt** ) ) );
+ if ( !tempData )
+ {
+ User::Leave( KErrNoMemory );
+ }
+ CleanupStack::PushL( tempData );
+ for ( i = 0; i < aNumCSComp; i++ )
+ {
+ subband = CONST_CAST( CJ2kSubband*, aTile.ComponentAt( (TUint16)i ).SubbandAt( (TUint8)aReducedLevels ) );
+
+ if( subband->SubbandResLevel() != 0 )
+ {
+ subband = subband->Parent();
+ }
+ subbandSize = subband->SubbandCanvasSize();
+
+ // Check that this component's size doesn't exceed the output size
+ if( subbandSize.iWidth > aSize.iWidth )
+ {
+ subbandSize.iWidth = aSize.iWidth;
+ }
+ if( subbandSize.iHeight > aSize.iHeight )
+ {
+ subbandSize.iHeight = aSize.iHeight;
+ }
+
+ // Allocate the temporary storage
+ tempData[i] = TJ2kUtils::Alloc2DArrayL( subbandSize.iHeight, subbandSize.iWidth );
+ CleanupStack::PushL( TCleanupItem( ( TCleanupOperation )&( TJ2kUtils::Free2DArray ), ( TAny* )tempData[i] ) );
+ componentFrom = iComponents[i];
+
+ for ( j = subbandSize.iHeight - 1; j >= 0; j-- )
+ {
+ Mem::Copy( tempData[i][j], componentFrom->Data()[j], subbandSize.iWidth * sizeof( TPrecInt ) );
+ }
+ }
+
+ for ( k = 0; k < iNumComponents; k++ )
+ {
+ // Get the channel in the codestream from which to map
+ compIndex = iJ2kInfo.iCMPList[k].iCmp;
+ componentFrom = iComponents[compIndex];
+
+ subband = CONST_CAST( CJ2kSubband*, aTile.ComponentAt( (TUint16)compIndex ).SubbandAt( (TUint8)aReducedLevels ) );
+
+ if( subband->SubbandResLevel() != 0 )
+ {
+ subband = subband->Parent();
+ }
+
+ subbandSize = subband->SubbandCanvasSize();
+
+ // Check that this component's size doesn't exceed the output size
+ if( subbandSize.iWidth > aSize.iWidth )
+ {
+ subbandSize.iWidth = aSize.iWidth;
+ }
+ if( subbandSize.iHeight > aSize.iHeight )
+ {
+ subbandSize.iHeight = aSize.iHeight;
+ }
+
+ // Get the output channel
+ componentTo = iComponents[k];
+
+ // Check if palette is used for mapping
+ if ( iJ2kInfo.iCMPList[k].iMtyp == 1 )
+ {
+ // Get the right palette channel for mapping
+ paletteIndex = iJ2kInfo.iCMPList[k].iPcol;
+
+ // Bitdepth is the lowest seven bits plus one for palettes
+ bitdepth = (TUint8)( ( iJ2kInfo.iPalette.iBList[paletteIndex] & 0x7f ) + 1 );
+ dcShift = 1 << ( bitdepth - 1 );
+
+ for ( i = 0; i < subbandSize.iHeight; i++ )
+ {
+ for ( j = 0; j < subbandSize.iWidth; j++ )
+ {
+ // Map the input codestream channel into the output component
+ // using the palette value.
+ value = tempData[compIndex][i][j] + dcShift;
+ if ( value < 0 )
+ {
+ value = 0;
+ }
+ if ( value >= iJ2kInfo.iPalette.iC2DArray.Count() )
+ {
+ value = iJ2kInfo.iPalette.iC2DArray.Count() - 1;
+ }
+
+ componentTo->iData[i][j] = ( *iJ2kInfo.iPalette.iC2DArray[value] )[paletteIndex] - dcShift;
+ }
+ }
+ }
+ else // Direct mapping
+ {
+ for ( i = subbandSize.iHeight - 1; i >= 0; --i )
+ {
+ for ( j = subbandSize.iWidth - 1; j >= 0; --j )
+ {
+ // Map the input codestream channel into the output component directly.
+ componentTo->iData[i][j] = componentFrom->iData[i][j];
+ }
+ }
+ }
+ }
+
+ CleanupStack::PopAndDestroy( aNumCSComp + 1 );
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::WriteOutputFile
+// Write the component to the single output file
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::WriteOutputFile( CJ2kTileInfo& aTile,
+ TUint16 aCompIndex,
+ const TSize& aSize,
+ TUint16 aBitDepth )
+ {
+ TPrecInt* imageRow = 0;
+ CJ2kWriterComponentInfo* currentComponent = iComponents[aCompIndex];
+ TSize outputSize = aSize;
+
+ TUint16 numLevels = aTile.ComponentAt( aCompIndex ).Levels();
+ TInt16 tempNumLevels = (TUint16)( numLevels - iImageInfo.LevelDrop() );
+
+ TPoint tileStartCoord = currentComponent->TileStartAt( aTile.SotMarker().iIsot );
+ currentComponent->UpdateNextTileStartAt( aTile.SotMarker().iIsot, aSize, iImageInfo );
+
+ if ( tempNumLevels < 0 )
+ {
+
+ TInt32 i;
+ TInt32 stepSize = 1;
+
+ // Compute the output step size, the stepSize indicates how much more
+ // resolution has to be dropped if the image didn't have enough wavelet
+ // levels to begin with. One indicates no extra resolution drop (write
+ // each sample) and for each extra drop skip half of the samples, i.e.
+ // stepSize is 2^extraLevels in case extra drop is needed.
+
+ // Adjust the tile starting points and the stepSize
+ for ( i = 0; i < (-tempNumLevels); i++ )
+ {
+ // Double the step size for every extra level dropped.
+ stepSize *= 2;
+ }
+
+ // Also take care of next tile's starting position
+ outputSize.iHeight /= stepSize;
+ outputSize.iWidth /= stepSize;
+ iComponents[0]->UpdateNextTileStartAt( aTile.SotMarker().iIsot, outputSize, iImageInfo );
+ }
+
+ TInt32 dcShift = 0;
+ TInt32 j = 0;
+ if ( aBitDepth == 8 )
+ {
+ if ( !( iImageInfo.SignOfComponent( aCompIndex ) ) )
+ {
+ dcShift = 1 << ( aBitDepth - 1 );
+ }
+ }
+
+ // Convert with an ICC profile if necessary
+ if( iICCProfile )
+ {
+ TInt32 value = 0;
+ TInt32 outputValue = 0;
+
+ // Compute the dcShift again, we must have dcShift != 0 for other than 8-bit input.
+ dcShift = 1 << ( iImageInfo.DepthOfComponent( 0 )-1 );
+
+ for ( TInt32 i = 0; i < outputSize.iHeight; i++ )
+ {
+ imageRow = currentComponent->Data()[i];
+
+ SetPixelPos( tileStartCoord.iX, tileStartCoord.iY + i );
+ for ( j = 0; j < outputSize.iWidth; j++ )
+ {
+ // Use a clipped value of input sample for an index to the grayscale TRC LUT.
+ value = iGrayTRCLut[CLIPINT( ( imageRow[j]+dcShift ), aBitDepth )];
+
+ // Get rid of values outside the range of legal values.
+ value = CLIP2RANGE( value, 0, KSRGBMaxInt );
+
+ // De-linearize the output values.
+ outputValue = ( *iLinearsRGBLut )[value];
+
+ iMonoPixelBlock[j] = (TUint32)( INT2BYTE( outputValue ) );
+ }
+
+ // Flush the row of grayscale pixels to image processor
+ iImageProcessor->SetMonoPixels( iMonoPixelBlock, outputSize.iWidth );
+ }
+
+ SetPixelPos( tileStartCoord );
+ }
+ else // No ICC profile was used.
+ {
+
+ // Take care of bitdepths != 8
+ if ( aBitDepth != 8 )
+ {
+ MapToEightBits( *currentComponent, outputSize, aBitDepth );
+ }
+
+ SetPixelPos( tileStartCoord );
+
+ for ( TInt32 i = 0; i < outputSize.iHeight; i++ )
+ {
+ imageRow = currentComponent->Data()[i];
+
+
+ SetPixelPos( tileStartCoord.iX, tileStartCoord.iY + i );
+
+ for ( j = 0; j < outputSize.iWidth; j++ )
+ {
+ // Store the value in the RGB "block"
+ iMonoPixelBlock[j] = (TUint32)( INT2BYTE( ( imageRow[j] + dcShift ) ) );
+ }
+
+ // Flush the row of grayscale pixels to image processor
+ iImageProcessor->SetMonoPixels( iMonoPixelBlock, outputSize.iWidth );
+ }
+
+ SetPixelPos( tileStartCoord );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::CombineOutputFile
+// Write all components of the tile to the single output file
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::CombineOutputFile( CJ2kTileInfo& aTile, const TSize& aSize )
+ {
+ TInt32 i = 0;
+ TInt32 j = 0;
+ TUint16 numLevels = aTile.ComponentAt( 0 ).Levels();
+ TInt16 tempNumLevels = (TUint16)( numLevels - iImageInfo.LevelDrop() );
+
+ TSize outputSize = aSize;
+ TPoint& tileStartCoord = iComponents[0]->TileStartAt( aTile.SotMarker().iIsot );
+ iComponents[0]->UpdateNextTileStartAt( aTile.SotMarker().iIsot, outputSize, iImageInfo );
+
+ if ( tempNumLevels < 0 )
+ {
+ TInt32 stepSize = 1;
+
+ // Compute the output step size, the stepSize indicates how much more
+ // resolution has to be dropped if the image didn't have enough wavelet
+ // levels to begin with. One indicates no extra resolution drop (write
+ // each sample) and for each extra drop skip half of the samples, i.e.
+ // stepSize is 2^extraLevels in case extra drop is needed.
+
+ // Adjust the tile starting points and the stepSize
+ for ( i = 0; i < (-tempNumLevels); i++ )
+ {
+ // Double the step size for every extra level dropped.
+ stepSize *= 2;
+ }
+
+ // Also take care of next tile's starting position
+ outputSize.iHeight /= stepSize;
+ outputSize.iWidth /= stepSize;
+ iComponents[0]->UpdateNextTileStartAt( aTile.SotMarker().iIsot, outputSize, iImageInfo );
+
+ tempNumLevels = 0;
+ }
+
+ TInt32 dcShift = 0;
+ if ( iImageInfo.DepthOfComponent( 0 ) == 8 )
+ {
+ if ( !( iImageInfo.SignOfComponent( 0 ) ) )
+ {
+ dcShift = 1 << ( iImageInfo.DepthOfComponent( 0 ) - 1 );
+ }
+ }
+
+ TSize subSamplingSize( 0, 0 );
+
+ // Due to subsampling we might have one more sample than the result of
+ // height/2 or width/2 will give thus we have to check whether we an
+ // extra row/column .
+ //
+ if ( iImageInfo.NumOfComponents() == 3 && iJ2kInfo.iEnumCS == 18 )
+ {
+ CJ2kSubband* subband = CONST_CAST( CJ2kSubband*, aTile.ComponentAt( 1 ).SubbandAt( (TUint8)tempNumLevels ) );
+
+ if ( subband->SubbandResLevel() != 0 )
+ {
+ subband = subband->Parent();
+ }
+
+ subSamplingSize = subband->SubbandCanvasSize();
+
+ if ( subSamplingSize.iWidth )
+ {
+ --subSamplingSize.iWidth;
+ }
+
+ if ( subSamplingSize.iHeight )
+ {
+ --subSamplingSize.iHeight;
+ }
+ }
+
+ TPrecInt** c1 = iComponents[0]->Data();
+ TPrecInt** c2 = iComponents[1]->Data();
+ TPrecInt** c3 = iComponents[2]->Data();
+
+ TPrecInt* c1Row = c1[0];
+ TPrecInt* c2Row = c2[0];
+ TPrecInt* c3Row = c3[0];
+
+ // For taking care of channel definition box order
+ if ( iJ2kInfo.iCNList.Count() > 0 )
+ {
+ for ( i = 0; i < 3; i++ )
+ {
+ if ( iJ2kInfo.iCNList[i].iAsoc == 1 )
+ {
+ c1 = iComponents[i]->Data();
+ }
+ else if ( iJ2kInfo.iCNList[i].iAsoc == 2 )
+ {
+ c2 = iComponents[i]->Data();
+ }
+ else if( iJ2kInfo.iCNList[i].iAsoc == 3 )
+ {
+ c3 = iComponents[i]->Data();
+ }
+ } //lint !e961 no else is needed here at the end of if...else if
+ }
+
+ // If dithering is needed the following lines should be used:
+ // TInt32 A = KDitherCoeffcient11 + dcShift;
+ // TInt32 B = KDitherCoeffcient12 + dcShift;
+ // TInt32 C = KDitherCoeffcient21 + dcShift;
+ // TInt32 D = KDitherCoeffcient22 + dcShift;
+ // Without dithering, use dcShift only.
+ //
+ TInt32 ditherA = dcShift;
+ TInt32 ditherB = dcShift;
+ TInt32 ditherC = dcShift;
+ TInt32 ditherD = dcShift;
+
+ TUint8 values[6];
+
+ // Convert with the ICC profile values if necessary.
+ if( iICCProfile )
+ {
+ TInt32 x = 0;
+ TInt32 y = 0;
+ TInt32 z = 0;
+ TPrecInt sR = 0;
+ TPrecInt sG = 0;
+ TPrecInt sB = 0;
+ TInt32 maxValue = 0;
+
+ // Compute the dcShift again, we must have dcShift != 0 for other than 8-bit input.
+ dcShift = 1 << ( iImageInfo.DepthOfComponent( 0 ) - 1 );
+ maxValue = ( 1 << iImageInfo.DepthOfComponent( 0 ) ) - 1; // Maximum value for this bitdepth
+
+ for( i = 0; i < outputSize.iHeight; i++ )
+ {
+
+ // Set the current coordinate in the output image
+ SetPixelPos( tileStartCoord.iX, tileStartCoord.iY + i );
+
+ for( j = 0; j < outputSize.iWidth; j++ )
+ {
+ x = CLIP2BITDEPTH( ( c1[i][j] + dcShift ),maxValue );
+ y = CLIP2BITDEPTH( ( c2[i][j] + dcShift ),maxValue );
+ z = CLIP2BITDEPTH( ( c3[i][j] + dcShift ),maxValue );
+
+ DoICCConversion( x,y,z,sR,sG,sB );
+
+ values[0] = INT2BYTE( sB );
+ values[1] = INT2BYTE( sG );
+ values[2]= INT2BYTE( sR );
+
+ WritePixel( values[2], values[1], values[0] );
+ }
+ }
+
+ // Set the current coordinate in the output image
+ SetPixelPos( tileStartCoord );
+ }
+ else
+ {
+
+ // To speed up output writing (for subsampled samples), compute the number of half the samples
+ TInt32 halfOfWidth = outputSize.iWidth / 2;
+
+ // If the bitdepth is not eight, shift values so that output is unsigned eight bit
+ for ( i = 0; i < iImageInfo.NumOfComponents(); i++ )
+ {
+ if ( iImageInfo.DepthOfComponent( ( TUint16 )i ) != 8 )
+ {
+ MapToEightBits( *iComponents[i], outputSize, iImageInfo.DepthOfComponent( (TUint16)i ) );
+ }
+ }
+
+ // Do the YUV to RGB conversion if needed
+ if ( iJ2kInfo.iEnumCS == 18 )
+ {
+ TPrecInt y1 = 0;
+ TPrecInt y2 = 0;
+ TPrecInt u = 0;
+ TPrecInt v = 0;
+ TPrecInt r = 0;
+ TPrecInt g = 0;
+ TPrecInt b = 0;
+ TPrecInt r1 = 0;
+ TPrecInt g1 = 0;
+ TPrecInt b1 = 0;
+ TPrecInt r2 = 0;
+ TPrecInt g2 = 0;
+ TPrecInt b2 = 0;
+
+ if ( iFileType == KYUV420 ) // YUV 4:2:0
+ {
+
+ TPrecInt* c1EvenRow = c1[0];
+ TPrecInt* c1OddRow = c1[0];
+ TPrecInt y3 = 0;
+ TPrecInt y4 = 0;
+ TPrecInt r3 = 0;
+ TPrecInt g3 = 0;
+ TPrecInt b3 = 0;
+ TPrecInt r4 = 0;
+ TPrecInt g4 = 0;
+ TPrecInt b4 = 0;
+
+ for ( i = 0; i < outputSize.iHeight / 2; i++ )
+ {
+ SetPixelPos( tileStartCoord.iX, ( tileStartCoord.iY + 2 * i ) );
+
+ c1EvenRow = c1[2 * i];
+ c1OddRow = c1[2 * i + 1];
+ c2Row = c2[i];
+ c3Row = c3[i];
+
+ for ( j = 0; j < halfOfWidth; j++ )
+ {
+ y1 = *c1EvenRow++;
+ y2 = *c1EvenRow++;
+ y3 = *c1OddRow++;
+ y4 = *c1OddRow++;
+ u = *c2Row++;
+ v = *c3Row++;
+
+ InverseICTTransform(y1,y2,y3,y4,u,v,r1,g1,b1,r2,g2,b2,r3,g3,b3,r4,g4,b4);
+
+ // Even rows, even columns
+ values[0] = INT2BYTE( ( r1 + ditherA ) );
+ values[1] = INT2BYTE( ( g1 + ditherA ) );
+ values[2] = INT2BYTE( ( b1 + ditherA ) );
+
+ // Even rows, odd columns:
+ values[3] = INT2BYTE( ( r2 + ditherB ) );
+ values[4] = INT2BYTE( ( g2 + ditherB ) );
+ values[5] = INT2BYTE( ( b2 + ditherB ) );
+
+ // Store the values in the RGB "block"
+ iColorPixelBlock[2 * j] = TRgb( values[0], values[1], values[2] );
+ iColorPixelBlock[2 * j + 1] = TRgb( values[3], values[4], values[5] );
+
+ // Now the odd row:
+ // Odd rows, even column
+ values[0] = INT2BYTE( ( r3 + ditherC ) );
+ values[1] = INT2BYTE( ( g3 + ditherC ) );
+ values[2] = INT2BYTE( ( b3 + ditherC ) );
+
+ // Odd rows, odd columns:
+ values[3] = INT2BYTE( ( r4 + ditherD ) );
+ values[4] = INT2BYTE( ( g4 + ditherD ) );
+ values[5] = INT2BYTE( ( b4 + ditherD ) );
+
+ // Store the values in the RGB "block"
+ iColorPixelBlock[KPixelsBlock + 2 * j] = TRgb( values[0], values[1], values[2] );
+ iColorPixelBlock[KPixelsBlock + 2 * j + 1] = TRgb( values[3], values[4], values[5] );
+ }
+
+ if ( outputSize.iWidth & 1 ) // If the width is odd:
+ {
+ // The even row:
+ y1 = c1[2 * i][outputSize.iWidth - 1];
+ // And the odd row:
+ y2 = c1[2 * i + 1][outputSize.iWidth - 1];
+ u = c2[i][subSamplingSize.iWidth];
+ v = c3[i][subSamplingSize.iWidth];
+
+ InverseICTTransform(y1,y2,u,v,r1,g1,b1,r2,g2,b2);
+
+ values[0] = INT2BYTE( ( r1 + ditherA ) );
+ values[1] = INT2BYTE( ( g1 + ditherA ) );
+ values[2] = INT2BYTE( ( b1 + ditherA ) );
+
+ // Store the value in the RGB "block"
+ iColorPixelBlock[outputSize.iWidth - 1] = TRgb( values[0], values[1], values[2] );
+
+ values[0] = INT2BYTE( ( r2 + ditherC ) );
+ values[1] = INT2BYTE( ( g2 + ditherC ) );
+ values[2] = INT2BYTE( ( b2 + ditherC ) );
+
+ // Store the value in the RGB "block"
+ iColorPixelBlock[KPixelsBlock + outputSize.iWidth - 1] = TRgb( values[0], values[1], values[2] );
+ }
+
+ // Flush the row of color pixels to image processor
+ iImageProcessor->SetPixels( iColorPixelBlock, outputSize.iWidth );
+
+ // Duplicated processing for the odd rows
+ SetPixelPos( tileStartCoord.iX, ( tileStartCoord.iY + 2 * i + 1 ) );
+
+ // Flush the row of color pixels to image processor
+ iImageProcessor->SetPixels( (iColorPixelBlock + KPixelsBlock), outputSize.iWidth );
+
+ } // End of loop on rows
+
+ if ( outputSize.iHeight & 1 ) // If the height is odd:
+ {
+ SetPixelPos( tileStartCoord.iX, ( tileStartCoord.iY + outputSize.iHeight - 1 ) );
+
+ c1Row = c1[outputSize.iHeight - 1];
+ c2Row = c2[subSamplingSize.iHeight];
+ c3Row = c3[subSamplingSize.iHeight];
+
+ for ( i = 0; i < halfOfWidth; i++ )
+ {
+ y1 = *c1Row++;
+ y2 = *c1Row++;
+ u = *c2Row++;
+ v = *c3Row++;
+
+ InverseICTTransform(y1,y2,u,v,r1,g1,b1,r2,g2,b2);
+
+ values[0] = INT2BYTE( ( r1 + ditherA ) );
+ values[1] = INT2BYTE( ( g1 + ditherA ) );
+ values[2] = INT2BYTE( ( b1 + ditherA ) );
+
+ values[3] = INT2BYTE( ( r2 + ditherB ) );
+ values[4] = INT2BYTE( ( g2 + ditherB ) );
+ values[5] = INT2BYTE( ( b2 + ditherB ) );
+
+ // Store the value in the RGB "block"
+ iColorPixelBlock[2 * i] = TRgb( values[0], values[1], values[2] );
+ iColorPixelBlock[2 * i + 1] = TRgb( values[3], values[4], values[5] );
+ }
+
+ if ( outputSize.iWidth & 1 ) // if the width is odd:
+ {
+ y1 = c1[outputSize.iHeight - 1][outputSize.iWidth - 1];
+ u = c2[subSamplingSize.iHeight][subSamplingSize.iWidth];
+ v = c3[subSamplingSize.iHeight][subSamplingSize.iWidth];
+
+ InverseICTTransform( y1, u, v, r, g, b );
+ values[0] = INT2BYTE( ( r + ditherA ) );
+ values[1] = INT2BYTE( ( g + ditherA ) );
+ values[2] = INT2BYTE( ( b + ditherA ) );
+
+ // Store the value in the RGB "block"
+ iColorPixelBlock[outputSize.iWidth - 1] = TRgb( values[0], values[1], values[2] );
+ }
+
+ // Flush the row of color pixels to image processor
+ iImageProcessor->SetPixels( iColorPixelBlock, outputSize.iWidth );
+
+ }
+
+ SetPixelPos( tileStartCoord );
+ }
+ else if ( iFileType == KYUV422 )
+ {
+
+ for ( i = 0; i < outputSize.iHeight; i++ )
+ {
+ SetPixelPos( tileStartCoord.iX, ( tileStartCoord.iY + 2 * i ) );
+
+ c1Row = c1[i];
+ c2Row = c2[i];
+ c3Row = c3[i];
+
+ for ( j = 0; j < halfOfWidth; j++ )
+ {
+ y1 = *c1Row++;
+ y2 = *c1Row++;
+ u = c2Row[j];
+ v = c3Row[j];
+
+ InverseICTTransform(y1,y2,u,v,r1,g1,b1,r2,g2,b2);
+
+ values[0] = INT2BYTE( ( r1 + dcShift ) );
+ values[1] = INT2BYTE( ( g1 + dcShift ) );
+ values[2] = INT2BYTE( ( b1 + dcShift ) );
+
+ values[3] = INT2BYTE( ( r2 + dcShift ) );
+ values[4] = INT2BYTE( ( g2 + dcShift ) );
+ values[5] = INT2BYTE( ( b2 + dcShift ) );
+
+ // Store the value in the RGB "block"
+ iColorPixelBlock[j] = TRgb( values[0], values[1], values[2] );
+ iColorPixelBlock[j+1] = TRgb( values[3], values[4], values[5] );
+ }
+
+ if ( outputSize.iWidth & 1 ) // if the width is odd:
+ {
+ y1 = c1Row[outputSize.iWidth - 1];
+ u = c2Row[subSamplingSize.iWidth];
+ v = c3Row[subSamplingSize.iWidth];
+
+ InverseICTTransform( y1, u, v, r, g, b );
+
+ values[0] = INT2BYTE( ( r + dcShift ) );
+ values[1] = INT2BYTE( ( g + dcShift ) );
+ values[2] = INT2BYTE( ( b + dcShift ) );
+
+ // Store the value in the RGB "block"
+ iColorPixelBlock[outputSize.iWidth-1] = TRgb( values[0], values[1], values[2] );
+ }
+
+ // Flush the row of color pixels to image processor
+ iImageProcessor->SetPixels( iColorPixelBlock, outputSize.iWidth );
+ }
+
+ SetPixelPos( tileStartCoord );
+ }
+ else // To take care of YUV 4:4:4
+ {
+
+ for ( i = 0; i < outputSize.iHeight; i++ )
+ {
+ SetPixelPos( tileStartCoord.iX, ( tileStartCoord.iY + i ) );
+
+ c1Row = c1[i];
+ c2Row = c2[i];
+ c3Row = c3[i];
+
+ for ( j = 0; j < outputSize.iWidth; j++ )
+ {
+ y1 = *c1Row++;
+ u = *c2Row++;
+ v = *c3Row++;
+
+ InverseICTTransform( y1, u, v, r, g, b );
+
+ values[0] = INT2BYTE( ( r + dcShift ) );
+ values[1] = INT2BYTE( ( g + dcShift ) );
+ values[2] = INT2BYTE( ( b + dcShift ) );
+
+ // Store the value in the RGB "block"
+ iColorPixelBlock[j] = TRgb( values[0], values[1], values[2] );
+ }
+
+ // Flush the row of color pixels to image processor
+ iImageProcessor->SetPixels( iColorPixelBlock, outputSize.iWidth );
+ }
+
+ SetPixelPos( tileStartCoord );
+ }
+ }
+ else // RGB
+ {
+ TInt32 r = 0;
+ TInt32 g = 0;
+ TInt32 b = 0;
+
+ for ( i = 0; i < outputSize.iHeight; i++ )
+ {
+
+ SetPixelPos( tileStartCoord.iX, tileStartCoord.iY + i );
+
+ c1Row = c1[i];
+ c2Row = c2[i];
+ c3Row = c3[i];
+
+ for ( j = 0; j < outputSize.iWidth; j++ )
+ {
+ r = *c1Row++;
+ g = *c2Row++;
+ b = *c3Row++;
+
+ values[0] = INT2BYTE( r + dcShift );
+ values[1] = INT2BYTE( g + dcShift );
+ values[2] = INT2BYTE( b + dcShift );
+
+ // Store the value in the RGB "block"
+ iColorPixelBlock[j] = TRgb( values[0], values[1], values[2] );
+ }
+
+ // Flush the row of color pixels to image processor
+ iImageProcessor->SetPixels( iColorPixelBlock, outputSize.iWidth );
+ }
+
+ SetPixelPos( tileStartCoord );
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::WritePixel
+// Write out a color pixel
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::WritePixel( TUint8 aR, TUint8 aG, TUint8 aB )
+ {
+ iImageProcessor->SetPixel( TRgb( aR, aG, aB ) );
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::WritePixel
+// Write out a grayscale pixel
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::WritePixel( TUint8 aGray256 )
+ {
+ iImageProcessor->SetMonoPixel( aGray256 );
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::SetPixelPos
+// Set the position of the pixel
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::SetPixelPos( const TPoint& aPosition )
+ {
+ iImageProcessor->SetPos( aPosition );
+ }
+
+// -----------------------------------------------------------------------------
+// CJ2kImageWriter::SetPixelPos
+// Set the position of the pixel
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJ2kImageWriter::SetPixelPos( const TInt aX, const TInt aY )
+ {
+ iImageProcessor->SetPos( TPoint( aX, aY ) );
+ }
+