/*
* 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: CJ2kSynthesis class used to perform inverse quantization and
* inverse DWT.
*
*/
// INCLUDE FILES
#include "JP2KTileInfo.h"
#include "JP2KImageInfo.h"
#include "JP2KImageWriter.h"
#include "JP2KEntropyDecoder.h"
#include "JP2KCodeBlock.h"
#include "JP2KPacket.h"
#include "JP2KSubband.h"
#include "JP2KComponentInfo.h"
#include "JP2KSynthesis.h"
// EXTERNAL DATA STRUCTURES
// EXTERNAL FUNCTION PROTOTYPES
// CONSTANTS
// MACROS
// LOCAL CONSTANTS AND MACROS
// MODULE DATA STRUCTURES
// LOCAL FUNCTION PROTOTYPES
// FORWARD DECLARATIONS
// ============================ MEMBER FUNCTIONS ===============================
// -----------------------------------------------------------------------------
// CJ2kSynthesis::CJ2kSynthesis
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CJ2kSynthesis::CJ2kSynthesis()
{
// Set up the filter taps for irreversible filter
iTapsLow[0] = KFixedLow9x70;
iTapsLow[1] = KFixedLow9x71;
iTapsLow[2] = KFixedLow9x72;
iTapsLow[3] = KFixedLow9x73;
iTapsHigh[0] = KFixedHigh9x70;
iTapsHigh[1] = KFixedHigh9x71;
iTapsHigh[2] = KFixedHigh9x72;
iTapsHigh[3] = KFixedHigh9x73;
iTapsHigh[4] = KFixedHigh9x74;
}
// Destructor
CJ2kSynthesis::~CJ2kSynthesis()
{
if ( iInputBuffer )
{
iInputBuffer -= ( KFilterExtension + 1 );
User::Free( iInputBuffer );
iInputBuffer = 0;
}
if ( iOutputBuffer )
{
iOutputBuffer -= ( KFilterExtension + 1 );
User::Free( iOutputBuffer );
iOutputBuffer = 0;
}
}
// -----------------------------------------------------------------------------
// CJ2kSynthesis::DecodeTileL
// Decode a single tile
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSynthesis::DecodeTileL( CJ2kImageWriter& aImageWriter,
CJ2kEntropyDecoder& aEntropyDecoder,
CJ2kImageInfo& aImageInfo,
CJ2kTileInfo& aTile )
{
if ( aImageInfo.Crop() )
{
// If this tile doesn't belong to the crop area, continue
if ( !aImageInfo.TileMaskAt( aTile.SotMarker().iIsot ) )
{
return;
}
}
CJ2kComponentInfo* componentInfo = 0;
TInt32 maxSize = 0;
TUint16 compIndex = 0;
TUint16 numOfComponents = aImageInfo.NumOfComponents();
// Find the largest width or height
for ( compIndex = 0; compIndex < numOfComponents; ++compIndex )
{
componentInfo = CONST_CAST( CJ2kComponentInfo*, &aTile.ComponentAt( compIndex ) );
maxSize = Max( maxSize, Max( componentInfo->ComponentCanvas().Height(),
componentInfo->ComponentCanvas().Width() ) );
}
maxSize += 2 * ( KFilterExtension + 1 );
AllocBufferL( maxSize );
TSize subbandSize( 0, 0 );
TUint16 bandIndex = 0;
TUint16 blockIndex = 0;
CJ2kSubband* subband = 0;
CJ2kPacket* packet = 0;
CJ2kCodeBlock* codeblock = 0;
TUint8 quantStyle = 0;
TUint8 bitDepth = 0;
TUint8 cblkStyle = 0;
TUint8 levelIndex = 0;
TUint32 packetIndex = 0;
CJ2kWriterComponentInfo* component = 0;
RPointerArray<CJ2kPacket>* packetList;
aEntropyDecoder.SetNewSizeL( aImageInfo.MaxBlockSize() );
// For each component in the tile
for ( compIndex = 0; compIndex < aImageInfo.NumOfComponents(); ++compIndex )
{
componentInfo = CONST_CAST( CJ2kComponentInfo*, &aTile.ComponentAt( compIndex ) );
// Skip the component when height or width is 0
if ( componentInfo->ComponentCanvas().Height() == 0 ||
componentInfo->ComponentCanvas().Width() == 0 )
{
continue; //lint !e960 Continue is OK.
}
// Check for component truncation
if ( aImageInfo.ComponentDrop() )
{
if ( aImageWriter.SingleFileOutput() )
{
if ( compIndex == ( aImageInfo.ComponentDrop() - 1 ) )
{
numOfComponents = compIndex;
}
else
{
continue; //lint !e960 Continue is OK.
}
}
else
{
if ( compIndex != ( aImageInfo.ComponentDrop() - 1 ) )
{
continue; //lint !e960 Continue is OK.
}
}
}
// Get the resolution level for this component
iWaveletLevels = (TInt16)( componentInfo->Levels() - aImageInfo.LevelDrop() );
TInt32 stepSize = 1;
if ( iWaveletLevels < 0 )
{
TInt32 i;
// 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 < (-iWaveletLevels); i++ )
{
// Double the step size for every extra level dropped.
stepSize *= 2;
}
iWaveletLevels = 0;
}
// Get the top subband ( original image )
subband = CONST_CAST( CJ2kSubband*, componentInfo->SubbandAt( (TUint8)iWaveletLevels ) );
if ( subband->SubbandResLevel() != 0 )
{
subband = subband->Parent();
}
subbandSize = subband->SubbandCanvasSize();
// Skip the component when subband's height or width is 0
if ( subbandSize.iWidth == 0 || subbandSize.iHeight == 0 )
{
continue; //lint !e960 Continue is OK.
}
component = CONST_CAST( CJ2kWriterComponentInfo*, &aImageWriter.WriterComponentAt( compIndex ) );
// Have to allocate memory for each component in the image writer
component->AllocDataL( subbandSize );
bitDepth = aImageInfo.DepthOfComponent( compIndex );
// Get the right number of levels and transform type
// reversible == 1 for 5x3 filter and == 0 for 9x7 filter
iReversible = componentInfo->IsReversible();
iROIShift = componentInfo->RoiShift();
quantStyle = componentInfo->QuantizationStyle();
cblkStyle = componentInfo->CodeBlockStyle();
// For each resolution level in the component
for ( levelIndex = 0; levelIndex <= iWaveletLevels; levelIndex++ )
{
subband = CONST_CAST( CJ2kSubband*, componentInfo->SubbandAt( levelIndex ) );
// For each subband in the resolution level
do
{
bandIndex = ( quantStyle == 1 ) ? (TUint16)0 : subband->SubbandTreeIndex();
// Get the right magnitude bits for this band
iMagnitudeBitsHere = componentInfo->MagnitudeBits( bandIndex );
// Compute the Quantization parameters here, so we don't repeat that for every codeblock/precinct
ComputeQuantizationParameters( *componentInfo, bandIndex, subband->SubbandGain(), bitDepth );
// Set the lookup table for entropy decoder
aEntropyDecoder.SetCurrentZCLUT( (TUint8)( subband->SubbandType() ) );
packetList = CONST_CAST( RPointerArray<CJ2kPacket>*, &subband->PacketList() ); //lint !e665 the first parameter cannot be parenthesized here
// For each packet in the subband
for ( packetIndex = 0; packetIndex < componentInfo->NumOfPackets( levelIndex ); ++packetIndex )
{
packet = ( *packetList )[packetIndex];
// For each codeblock in the packet
for ( blockIndex = 0; blockIndex < packet->NumOfBlocks(); ++blockIndex )
{
codeblock = CONST_CAST( CJ2kCodeBlock*, &packet->CodeBlockAt( blockIndex ) );
// There is coded data in the codeblock
if ( codeblock->DataLength() )
{
// Decode the codeblock
aEntropyDecoder.DecodeCodeblock( *codeblock, cblkStyle, (TUint8)( iMagnitudeBitsHere + iROIShift ) );
// Copy data from the decoded codeblock for inverse quantization and ROI shifting
CopyDataToImage( aEntropyDecoder, component->Data(), *subband, *codeblock, quantStyle );
}
} // end of each codeblock
} // end of each packet
// Get the sibling subband
subband = subband->NextSubbandRaster();
} while ( subband ); // end of each subband in the resolution level
} // end of each resolution level in the component
// Point to the LL-band before calling inverse wavelet transform
subband = CONST_CAST( CJ2kSubband*, componentInfo->SubbandAt( 0 ) );
// Perform a full inverse wavelet transformation
FullWaveletInverse( component->Data(), subband );
// Check whether extra downsampling is needed
if(stepSize > 1)
{
TInt32 i,j;
TInt32 iStep,jStep;
// If the stepSize is larger than one it means that we have to downsample
// the output. This is because there were not enough wavelet levels to do
// the resolution dropping for this component.
// The reason why downsampling is done here and not in the ImageWriter is
// that different components might have different number of wavlet levels
// and thus it is easier to downsample the components here (so that we can
// just write out the samples normally in ImageWriter.
for(i = 0,iStep = 0; iStep < subbandSize.iHeight; i++,iStep += stepSize)
{
for(j = 0,jStep = 0; jStep < subbandSize.iWidth; j++,jStep += stepSize)
{
// Downsample the component so that downsampled image is in the
// upper left-hand corner.
component->Data()[i][j] = component->Data()[iStep][jStep];
}
}
}
if ( numOfComponents >= 3 )
{
if ( aTile.ColorTransformation() ||
( aImageWriter.CSCode() == 18 || aImageWriter.CSCode() == 16 ) )
{
// Wait til we finish decoding all components before writing out the image
if ( compIndex < 2 )
{
continue; //lint !e960 Continue is OK.
}
}
else if ( aImageWriter.CSCode() == 0 )
{
// This case is also valid when no CSCode is defined, e.g. no file format is present
if( numOfComponents <= 3 )
{
if ( compIndex < 2 )
{
continue; //lint !e960 Continue is OK.
}
}
else
{
// Proceed to outputImageL
}
}
} //lint !e961 no else is needed here at the end of if...else if
// Write out the tile image
aImageWriter.OutputImageL( aTile, compIndex );
} // end of each component in the tile
}
// -----------------------------------------------------------------------------
// CJ2kSynthesis::DecodeTileBlockL
// Decode a single tile with lower memory using 256x256 blocks
// for the inverse wavelet transform
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSynthesis::DecodeTileBlockL( CJ2kImageWriter& aImageWriter,
CJ2kEntropyDecoder& aEntropyDecoder,
CJ2kImageInfo& aImageInfo,
CJ2kTileInfo& aTile )
{
if ( aImageInfo.Crop() )
{
// If this tile doesn't belong to the crop area, continue
if ( !aImageInfo.TileMaskAt( aTile.SotMarker().iIsot ) )
{
return;
}
}
CJ2kComponentInfo* componentInfo = 0;
TInt32 maxSize = 0;
TUint16 compIndex = 0;
TUint16 numOfComponents = aImageInfo.NumOfComponents();
// Find the largest width or height
for ( compIndex = 0; compIndex < numOfComponents; ++compIndex )
{
componentInfo = CONST_CAST( CJ2kComponentInfo*, &aTile.ComponentAt( compIndex ) );
maxSize = Max( maxSize, Max( componentInfo->ComponentCanvas().Height(),
componentInfo->ComponentCanvas().Width() ) );
}
maxSize = KMaxBlockSupportSize;
maxSize += 2 * ( KFilterExtension + 1 );
AllocBufferL( maxSize );
TSize subbandSize( 0, 0 );
TUint16 bandIndex = 0;
TUint16 blockIndex = 0;
CJ2kSubband* subband = 0;
CJ2kPacket* packet = 0;
CJ2kCodeBlock* codeblock = 0;
TUint8 quantStyle = 0;
TUint8 bitDepth = 0;
TUint8 cblkStyle = 0;
TUint8 levelIndex = 0;
TUint32 packetIndex = 0;
TUint32 blockXCoord = 0;
TUint32 blockYCoord = 0;
TUint32 compXCoord = 0;
TUint32 compYCoord = 0;
TInt32 blockXEnd = 0;
TInt32 blockYEnd = 0;
TRect supportRegion( 0, 0, 0 , 0 );
TRect parentSupportRegion( 0, 0, 0 , 0 );
TPoint regionOffset( 0, 0 );
TInt16 tmpLevelIndex = 0;
TSize thisCompSize( 0, 0 );
TSize firstCompSize( 0, 0 );
TSize regionSize( 0, 0 );
TPoint tileEndPoint( 0, 0 );
TPoint tileStartPoint( 0, 0 );
TPoint blockStepSize( 0, 0 );
CJ2kWriterComponentInfo* component = 0;
RPointerArray<CJ2kPacket>* packetList;
TSizMarker& sizMarker = CONST_CAST( TSizMarker&, aImageInfo.SizMarker() );
aEntropyDecoder.SetNewSizeL( aImageInfo.MaxBlockSize() );
componentInfo = CONST_CAST( CJ2kComponentInfo*, &aTile.ComponentAt( 0 ) );
// Get the resolution level for this component
iWaveletLevels = (TInt16)( componentInfo->Levels() - aImageInfo.LevelDrop() );
if ( iWaveletLevels < 0 )
{
iWaveletLevels = 0;
}
// Get the top subband ( original image )
subband = CONST_CAST( CJ2kSubband*, componentInfo->SubbandAt( (TUint8)iWaveletLevels ) );
if ( subband->SubbandResLevel() != 0 )
{
subband = subband->Parent();
}
subbandSize = subband->SubbandCanvasSize();
tileEndPoint.iX = subbandSize.iWidth;
tileEndPoint.iY = subbandSize.iHeight;
tileStartPoint.iX = componentInfo->ComponentCanvas().iTl.iX;
tileStartPoint.iY = componentInfo->ComponentCanvas().iTl.iY;
// Loop on 256x256 blocks to reduce the memory required to perform the inverse wavelet
// First set as starting point the canvas coordinates of this component
blockXCoord = 0;
blockYCoord = 0;
blockStepSize.iX = KWaveletBlockSize;
blockStepSize.iY = KWaveletBlockSize;
for ( ; blockYCoord < (TUint32)tileEndPoint.iY; blockYCoord += KWaveletBlockSize )
{
// Start from the left border of this tile
blockXCoord = 0;
for ( ; blockXCoord < ( TUint32 )tileEndPoint.iX; blockXCoord += KWaveletBlockSize )
{
// For each component in the tile
for ( compIndex = 0; compIndex < aImageInfo.NumOfComponents(); ++compIndex )
{
compXCoord = blockXCoord;
compYCoord = blockYCoord;
componentInfo = CONST_CAST( CJ2kComponentInfo*, &aTile.ComponentAt( compIndex ) );
// Skip the component when height or width is 0
if ( componentInfo->ComponentCanvas().Height() == 0 ||
componentInfo->ComponentCanvas().Width() == 0 )
{
continue; //lint !e960 Continue is OK.
}
// Here we have to add a check that if we have sub sampled component together with color transform,
// we have to subsample also the block dimensions ( so that the inverse color transform is performed
// correctly.
blockStepSize.iX = KWaveletBlockSize;
blockStepSize.iY = KWaveletBlockSize;
if ( aImageInfo.NumOfComponents() == 3 )
{
if ( sizMarker.iXRsiz[1] == 2 * sizMarker.iXRsiz[0] &&
sizMarker.iXRsiz[2] == 2 * sizMarker.iXRsiz[0] )
{
if ( sizMarker.iXRsiz[1] == 2 * sizMarker.iXRsiz[0] &&
sizMarker.iXRsiz[2] == 2 * sizMarker.iXRsiz[0] )
{
if( compIndex == 1 || compIndex == 2 )
{
blockStepSize.iX = KWaveletBlockSize >> 1;
blockStepSize.iY = KWaveletBlockSize >> 1;
compXCoord >>= 1;
compYCoord >>= 1;
}
}
else
{
if( compIndex == 1 || compIndex == 2 )
{
blockStepSize.iX = KWaveletBlockSize >> 1;
compXCoord >>= 1;
blockStepSize.iY = KWaveletBlockSize;
}
}
}
}
// Check for component truncation
if ( aImageInfo.ComponentDrop() )
{
if ( aImageWriter.SingleFileOutput() )
{
if ( compIndex == ( aImageInfo.ComponentDrop() - 1 ) )
{
numOfComponents = compIndex;
}
else
{
continue; //lint !e960 Continue is OK.
}
}
else
{
if ( compIndex != ( aImageInfo.ComponentDrop() - 1 ) )
{
continue; //lint !e960 Continue is OK.
}
}
}
// Get the resolution level for this component
iWaveletLevels = (TInt16)( componentInfo->Levels() - aImageInfo.LevelDrop() );
TInt32 stepSize = 1;
if ( iWaveletLevels < 0 )
{
TInt32 i;
// 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 < (-iWaveletLevels); i++ )
{
// Double the step size for every extra level dropped.
stepSize *= 2;
}
iWaveletLevels = 0;
}
// Get the top subband ( original image )
subband = CONST_CAST( CJ2kSubband*, componentInfo->SubbandAt( (TUint8)iWaveletLevels ) );
if ( subband->SubbandResLevel() != 0 )
{
subband = subband->Parent();
}
subbandSize = subband->SubbandCanvasSize();
// Skip the component when subband's height or width is 0
if ( subbandSize.iWidth == 0 || subbandSize.iHeight == 0 )
{
continue; //lint !e960 Continue is OK.
}
// Check that the block doesn't exceed the boundary of this component
if( (TInt32)compXCoord+blockStepSize.iX > subbandSize.iWidth )
{
blockXEnd = subbandSize.iWidth;
}
else
{
blockXEnd = compXCoord+blockStepSize.iX;
}
if( (TInt32)compYCoord+blockStepSize.iY > subbandSize.iHeight )
{
blockYEnd = subbandSize.iHeight;
}
else
{
blockYEnd = compYCoord+blockStepSize.iY;
}
// Store the block size on the first component in case the others are sub sampled
if( compIndex == 0 )
{
firstCompSize.iWidth = blockXEnd - blockXCoord;
firstCompSize.iHeight = blockYEnd - blockYCoord;
}
// Store the block size of this component
thisCompSize.iWidth = blockXEnd - compXCoord;
thisCompSize.iHeight = blockYEnd - compYCoord;
// This component could be sampled so that the block doesn't "exist"
// in this component, if so move to next component
if( thisCompSize.iWidth <= 0 || thisCompSize.iHeight <= 0 )
{
continue; //lint !e960 Continue is OK.
}
component = CONST_CAST( CJ2kWriterComponentInfo*, &aImageWriter.WriterComponentAt( compIndex ) );
// Have to allocate memory for each component in the image writer
subbandSize.iWidth = subbandSize.iHeight = KMaxBlockSupportSize;
component->AllocDataL( subbandSize );
bitDepth = aImageInfo.DepthOfComponent( compIndex );
// Get the right number of levels and transform type
// reversible == 1 for 5x3 filter and == 0 for 9x7 filter
iReversible = componentInfo->IsReversible();
iROIShift = componentInfo->RoiShift();
quantStyle = componentInfo->QuantizationStyle();
cblkStyle = componentInfo->CodeBlockStyle();
// The support region is the region needed on current level to
// compute the samples in current block.
supportRegion.iTl.iX = compXCoord;
supportRegion.iTl.iY = compYCoord;
supportRegion.iBr.iX = blockXEnd;
supportRegion.iBr.iY = blockYEnd;
// For each resolution level in the component
for ( levelIndex = 0; levelIndex <= iWaveletLevels; levelIndex++ )
{
// The support region is the region needed on current level to compute the samples in current block.
supportRegion.iTl.iX = compXCoord;
supportRegion.iTl.iY = compYCoord;
supportRegion.iBr.iX = blockXEnd;
supportRegion.iBr.iY = blockYEnd;
parentSupportRegion = supportRegion;
regionOffset.iX = regionOffset.iY = 0;
// Compute the support region of the parent level of the bands that are to be processed
// The support region is computed depending on the level we process currently.
for( tmpLevelIndex = iWaveletLevels; tmpLevelIndex > levelIndex; tmpLevelIndex-- )
{
// Get the subband on this ( temp )level in order to find out if high-pass first is true or not
subband = CONST_CAST( CJ2kSubband*, componentInfo->SubbandAt( (TUint8)( tmpLevelIndex ) ) );
// Level zero has the same support as level 1, so don't update the support for level zero.
if( tmpLevelIndex != 1 )
{
// Compute the new crop coordinates for the subbands on this level
if( iReversible )
{
// Support region for low-pass bands for 5x3 filter
// If this band is computed high-pass first, then one extra low-pass coefficient is needed from left.
// This is due to the fact that for Output[2n+1], we need five samples H[n-1], L[n], H[n], L[n+1] and H[n+1], but when high-pass
// is computed first, we actually need samples H[n-1], L[n-1], H[n], L[n] and H[n+1], where L are the low-pass filtered samples
// and H are the high-pass filtered samples.
if( subband->Parent()->HighPassFirst().iX )
{
parentSupportRegion.iTl.iX = ( ( ( parentSupportRegion.iTl.iX >> 1 ) - 1 ) > 0 ) ? //lint !e702 The shifted values cannot be negative here
( ( parentSupportRegion.iTl.iX >> 1 ) - 1 ) : 0; //lint !e702 The shifted values cannot be negative here
}
else
{
parentSupportRegion.iTl.iX = parentSupportRegion.iTl.iX >> 1; //lint !e702 The shifted values cannot be negative here
}
// If this band is computed high-pass first, then one extra low-pass coefficient is needed from above.
if( subband->Parent()->HighPassFirst().iY )
{
parentSupportRegion.iTl.iY = ( ( ( parentSupportRegion.iTl.iY >> 1 ) - 1 )>0 ) ? //lint !e702 The shifted values cannot be negative here
( ( parentSupportRegion.iTl.iY >> 1 ) - 1 ) : 0; //lint !e702 The shifted values cannot be negative here
}
else
{
parentSupportRegion.iTl.iY = parentSupportRegion.iTl.iY >> 1; //lint !e702 The shifted values cannot be negative here
}
parentSupportRegion.iBr.iX = ( ( parentSupportRegion.iBr.iX ) >> 1 ) + 1; //lint !e702 The shifted values cannot be negative here
parentSupportRegion.iBr.iY = ( ( parentSupportRegion.iBr.iY ) >> 1 ) + 1; //lint !e702 The shifted values cannot be negative here
}
else
{
// Support region for low-pass bands for 9x7 filter
// If this band is computed high-pass first, then one extra low-pass coefficient is needed ( from left ).
if( subband->Parent()->HighPassFirst().iX )
{
parentSupportRegion.iTl.iX = ( ( parentSupportRegion.iTl.iX >> 1 )-2 > 0 ) ? //lint !e702 The shifted values cannot be negative here
( parentSupportRegion.iTl.iX >> 1 )-2 : 0; //lint !e702 the shifted values cannot be negative here
}
else
{
parentSupportRegion.iTl.iX = ( ( ( parentSupportRegion.iTl.iX >> 1 ) - 1 ) > 0 ) ? //lint !e702 The shifted values cannot be negative here
( ( parentSupportRegion.iTl.iX >> 1 ) - 1 ) : 0; //lint !e702 the shifted values cannot be negative here
}
if( subband->Parent()->HighPassFirst().iY )
{
parentSupportRegion.iTl.iY = ( ( ( parentSupportRegion.iTl.iY >> 1 ) - 2 ) > 0 ) ? //lint !e702 The shifted values cannot be negative here
( ( parentSupportRegion.iTl.iY >> 1 ) - 2 ) : 0; //lint !e702 the shifted values cannot be negative here
}
else
{
parentSupportRegion.iTl.iY = ( ( ( parentSupportRegion.iTl.iY >> 1 ) - 1 ) > 0 ) ? //lint !e702 The shifted values cannot be negative here
( ( parentSupportRegion.iTl.iY >> 1 ) - 1 ) : 0; //lint !e702 the shifted values cannot be negative here
}
parentSupportRegion.iBr.iX = ( ( parentSupportRegion.iBr.iX ) >> 1 ) + 2; //lint !e702 the shifted values cannot be negative here
parentSupportRegion.iBr.iY = ( ( parentSupportRegion.iBr.iY ) >> 1 ) + 2; //lint !e702 the shifted values cannot be negative here
}
}
}
subband = CONST_CAST( CJ2kSubband*, componentInfo->SubbandAt( levelIndex ) );
// For each subband in the resolution level
do
{
bandIndex = ( quantStyle == 1 ) ? (TUint16)0 : subband->SubbandTreeIndex();
// Get the right magnitude_bits for this band
iMagnitudeBitsHere = componentInfo->MagnitudeBits( bandIndex );
// If iWaveletLevels == 0, do not update the supportRegion, since there is no wavelet decomposition ( zero levels )
if( iWaveletLevels != 0 )
{
// Now compute the support region for this band depending on whether it is LL, LH, HL or HH
// Use the support region of the parent for computation.
//
if( iReversible )
{
if( ( subband->SubbandType() ) == 0 || ( subband->SubbandType() ) == 2 )
{
if( subband->Parent()->HighPassFirst().iX )
{
supportRegion.iTl.iX = ( ( parentSupportRegion.iTl.iX >> 1 )-1 > 0 ) ? //lint !e702 The shifted values cannot be negative here
( parentSupportRegion.iTl.iX >> 1 )-1 : 0; //lint !e702 the shifted values cannot be negative here
}
else
{
supportRegion.iTl.iX = parentSupportRegion.iTl.iX >> 1; //lint !e702 the shifted value cannot be negative here
}
}
else
{
supportRegion.iTl.iX = ( ( parentSupportRegion.iTl.iX >> 1 )-1 > 0 ) ? //lint !e702 The shifted values cannot be negative here
( parentSupportRegion.iTl.iX >> 1 )-1 : 0; //lint !e702 the shifted values cannot be negative here
}
if( ( subband->SubbandType() ) == 0 || ( subband->SubbandType() ) == 1 )
{
if( subband->Parent()->HighPassFirst().iY )
{
supportRegion.iTl.iY = ( ( parentSupportRegion.iTl.iY >> 1 )-1 > 0 ) ? //lint !e702 The shifted values cannot be negative here
( parentSupportRegion.iTl.iY >> 1 )-1 : 0; //lint !e702 the shifted values cannot be negative here
}
else
{
supportRegion.iTl.iY = parentSupportRegion.iTl.iY >>1; //lint !e702 the shifted value cannot be negative here
}
}
else
{
supportRegion.iTl.iY = ( ( parentSupportRegion.iTl.iY >> 1 )-1 > 0 ) ? //lint !e702 The shifted values cannot be negative here
( parentSupportRegion.iTl.iY >> 1 )-1 : 0; //lint !e702 the shifted values cannot be negative here
}
// Compute the offset for this level
regionOffset.iX = parentSupportRegion.iTl.iX - 2*supportRegion.iTl.iX;
regionOffset.iY = parentSupportRegion.iTl.iY - 2*supportRegion.iTl.iY;
// Support region's bottom right corner for each band is ( supportParent.iBr>>1 )+1
supportRegion.iBr.iX = ( ( parentSupportRegion.iBr.iX ) >> 1 ) + 1; //lint !e702 the shifted value cannot be negative here
supportRegion.iBr.iY = ( ( parentSupportRegion.iBr.iY ) >> 1 ) + 1; //lint !e702 the shifted value cannot be negative here
}
else // irreversible ( 9x7 ) filter
{
// For low-pass filtering, the offset for the output is 1
if( ( subband->SubbandType() ) == 0 || ( subband->SubbandType() ) == 2 )
{
if( subband->Parent()->HighPassFirst().iX )
{
supportRegion.iTl.iX = ( ( parentSupportRegion.iTl.iX >> 1 )-2 > 0 ) ? //lint !e702 The shifted values cannot be negative here
( parentSupportRegion.iTl.iX >> 1 )-2 : 0; //lint !e702 the shifted values cannot be negative here
}
else
{
supportRegion.iTl.iX = ( ( parentSupportRegion.iTl.iX >> 1 )-1 > 0 ) ? //lint !e702 The shifted values cannot be negative here
( parentSupportRegion.iTl.iX >> 1 )-1 : 0; //lint !e702 the shifted values cannot be negative here
}
}
else
{
supportRegion.iTl.iX = ( ( parentSupportRegion.iTl.iX >> 1 )-2 > 0 ) ? //lint !e702 The shifted values cannot be negative here
( parentSupportRegion.iTl.iX >> 1 )-2 : 0; //lint !e702 the shifted values cannot be negative here
}
if( ( subband->SubbandType() ) == 0 || ( subband->SubbandType() ) == 1 )
{
if( subband->Parent()->HighPassFirst().iY )
{
supportRegion.iTl.iY = ( ( parentSupportRegion.iTl.iY >> 1 )-2 > 0 ) ? //lint !e702 The shifted values cannot be negative here
( parentSupportRegion.iTl.iY >> 1 )-2 : 0; //lint !e702 the shifted values cannot be negative here
}
else
{
supportRegion.iTl.iY = ( ( parentSupportRegion.iTl.iY >> 1 )-1 > 0 ) ? //lint !e702 The shifted values cannot be negative here
( parentSupportRegion.iTl.iY >> 1 )-1 : 0; //lint !e702 the shifted values cannot be negative here
}
}
else
{
supportRegion.iTl.iY = ( ( parentSupportRegion.iTl.iY >> 1 )-2 > 0 ) ? //lint !e702 The shifted values cannot be negative here
( parentSupportRegion.iTl.iY >> 1 )-2 : 0; //lint !e702 the shifted values cannot be negative here
}
// Compute the offset for this level
regionOffset.iY = parentSupportRegion.iTl.iY - 2*supportRegion.iTl.iY;
regionOffset.iX = parentSupportRegion.iTl.iX - 2*supportRegion.iTl.iX;
// Support region's bottom right corner for each band is ( supportParent.iBr>>1 )+2
supportRegion.iBr.iX = ( ( parentSupportRegion.iBr.iX ) >> 1 ) + 2; //lint !e702 the shifted value cannot be negative here
supportRegion.iBr.iY = ( ( parentSupportRegion.iBr.iY ) >> 1 ) + 2; //lint !e702 the shifted value cannot be negative here
}
}
// Check that the support region doesn't exceed the band boundaries
if( supportRegion.iBr.iX > subband->SubbandCanvasSize().iWidth )
{
supportRegion.iBr.iX = subband->SubbandCanvasSize().iWidth;
}
if( supportRegion.iBr.iY > subband->SubbandCanvasSize().iHeight )
{
supportRegion.iBr.iY = subband->SubbandCanvasSize().iHeight;
}
// Store the low-band's dimensions here to later compute the size of the whole region ( low-band plus high-band ).
if( subband->SubbandType() == 2 )
{
regionSize.iWidth = supportRegion.Width();
}
if( subband->SubbandType() == 1 )
{
regionSize.iHeight = supportRegion.Height();
}
// Compute the Quantization parameters here, so we don't repeat that for every codeblock/precinct
ComputeQuantizationParameters( *componentInfo, bandIndex, subband->SubbandGain(), bitDepth );
// Set the lookup table for entropy decoder
aEntropyDecoder.SetCurrentZCLUT( (TUint8)( subband->SubbandType() ) );
packetList = CONST_CAST( RPointerArray<CJ2kPacket>*, &subband->PacketList() ); //lint !e665 the first parameter cannot be parenthesized here
// For each packet in the subband
for ( packetIndex = 0; packetIndex < componentInfo->NumOfPackets( levelIndex );
++packetIndex )
{
packet = ( *packetList )[packetIndex];
// For each codeblock in the packet
for ( blockIndex = 0; blockIndex < packet->NumOfBlocks(); ++blockIndex )
{
codeblock = CONST_CAST( CJ2kCodeBlock*, &packet->CodeBlockAt( blockIndex ) );
const TRect& cbCanvas = codeblock->CodeBlockCanvas();
TInt32 startRow = cbCanvas.iTl.iY - subband->SubbandCanvas().iTl.iY;
TInt32 startCol = cbCanvas.iTl.iX - subband->SubbandCanvas().iTl.iX;
TInt32 cblkHeight = cbCanvas.Height();
TInt32 cblkWidth = cbCanvas.Width();
TInt32 startRowCblk = 0;
TInt32 startColCblk = 0;
TInt32 startRowImage = 0;
TInt32 startColImage = 0;
if( startRow >= supportRegion.iBr.iY || startCol >= supportRegion.iBr.iX ||
( startRow+cblkHeight ) <= supportRegion.iTl.iY ||
( startCol+cblkWidth ) <= supportRegion.iTl.iX )
{
}
else
{
// Compute the start column from which to copy from ( in the codeblock ) and where to copy to ( in the image block )
if( startCol <= supportRegion.iTl.iX )
{
startColCblk = supportRegion.iTl.iX - startCol; // Ignore samples outside supportRegion
startColImage = 0; // First block, start from supportRegion's start
cblkWidth -= startColCblk; // Ignore samples outside supportRegion
}
else
{
startColCblk = 0; // First block, start from supportRegion's start
startColImage = startCol-supportRegion.iTl.iX; // First block, start from supportRegion's start
}
// If the last block extends outside supportRegion, we have to adjust codeblock's width
if( ( startCol+cbCanvas.Width() ) > supportRegion.iBr.iX )
{
cblkWidth -= ( ( startCol+cbCanvas.Width() ) - supportRegion.iBr.iX ); // Ignore samples outside supportRegion
}
// Compute the start row from which to copy from ( in the codeblock ) and where to copy to ( in the image block )
if( startRow <= supportRegion.iTl.iY )
{
startRowCblk = supportRegion.iTl.iY - startRow; // ignore samples outside supportRegion
startRowImage = 0; // First block, start from supportRegion's start
cblkHeight -= startRowCblk; // Ignore samples outside supportRegion
}
else
{
startRowCblk = 0; // First block, start from supportRegion's start
startRowImage = startRow-supportRegion.iTl.iY; // First block, start from supportRegion's start
}
// If the last block extends outside supportRegion, we have to adjust codeblock's height
if( ( startRow+cbCanvas.Height() ) > supportRegion.iBr.iY )
{
cblkHeight -= ( ( startRow+cbCanvas.Height() ) - supportRegion.iBr.iY ); // ignore samples outside supportRegion
}
// There is coded data in the codeblock
if ( codeblock->DataLength() )
{
// Decode the codeblock
aEntropyDecoder.DecodeCodeblock( *codeblock, cblkStyle,
(TUint8)( iMagnitudeBitsHere + iROIShift ) );
codeblock->SetCodeBlockDecoded();
CopyDataToBlock( aEntropyDecoder, component->Data(), *subband, quantStyle,
startRowCblk, startColCblk, startRowImage,
startColImage, cblkHeight, cblkWidth );
}
else
{
// Empty codeblock, fill the corresponding area with zero, since other wise there might be data left from lower levels.
FillDataWithZeros( component->Data(), *subband, startRowImage, startColImage, cblkHeight, cblkWidth );
}
}
} // end of each codeblock
} // end of each packet
// Get the sibling subband
subband = subband->NextSubbandRaster();
} while ( subband ); // end of each subband in the resolution level
// Now that we have processed all the blocks on this level, we can perform inverse wavelet transform on this level
// On resolution level zero, we don't have to inverse transform
if( levelIndex != 0 )
{
// The size of the inverse transformed region is the size of the low- ( stored in "regionSize" )
// and high-pass ( the supportRegion is always for HH-band, when we reach this point ) parts combined
regionSize = regionSize + supportRegion.Size();
subband = CONST_CAST( CJ2kSubband*, componentInfo->SubbandAt( levelIndex ) );
SingleLevelWaveletInverse( component->Data(), subband, regionOffset, regionSize, levelIndex );
}
} // end of each resolution level in the component
// Check whether extra downsampling is needed
if( stepSize > 1 )
{
TInt32 i,j;
TInt32 iStep,jStep;
// If the stepSize is larger than one it means that we have to downsample
// the output. This is because there were not enough wavelet levels to do
// the resolution dropping for this component.
// The reason why downsampling is done here and not in the ImageWriter is
// that different components might have different number of wavlet levels
// and thus it is easier to downsample the components here (so that we can
// just write out the samples normally in ImageWriter.
for( i = 0,iStep = 0; iStep<KMaxBlockSupportSize; i++,iStep += stepSize)
{
for( j = 0,jStep = 0; jStep<KMaxBlockSupportSize; j++,jStep += stepSize)
{
// Downsample the component so that downsampled image is in the
// upper left-hand corner.
component->Data()[i][j] = component->Data()[iStep][jStep];
}
}
}
if ( numOfComponents >= 3 )
{
if ( aTile.ColorTransformation() ||
( aImageWriter.CSCode() == 18 || aImageWriter.CSCode() == 16 ) )
{
// Wait til we finish decoding all components before writing out the image
if ( compIndex < 2 )
{
continue; //lint !e960 Continue is OK.
}
}
else if ( aImageWriter.CSCode() == 0 )
{
// This case is also valid when no CSCode is defined, e.g. no file format is present
if( numOfComponents <= 3 )
{
if ( compIndex < 2 )
{
continue; //lint !e960 Continue is OK.
}
}
else
{
// Proceed to outputBlockL
}
}
} //lint !e961 no else is needed here at the end of if...else if
aImageWriter.OutputBlockL( aTile, compIndex, blockXCoord, blockYCoord, firstCompSize, thisCompSize );
} // end of each component in the tile
} // end of loop on the 256x256 blocks
}
}
// -----------------------------------------------------------------------------
// CJ2kSynthesis::OneDimReversibleFilter
// Perform one dimensional synthesis using reversible 5/3 filter
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSynthesis::OneDimReversibleFilter( TInt32 aStartPos, TInt32 aEndPos )
{
if ( ( aEndPos - aStartPos ) == 1 )
{
if ( aStartPos )
{
iOutputBuffer[aStartPos] = iInputBuffer[aStartPos] / 2;
}
else
{
iOutputBuffer[aStartPos] = iInputBuffer[aStartPos];
}
}
else
{
aEndPos++;
TInt32 idx = 0;
for ( idx = 0; idx < aEndPos; idx += 2 )
{
iOutputBuffer[idx] = iInputBuffer[idx] -
( ( iInputBuffer[idx - 1] + iInputBuffer[idx + 1] + 2 ) >> 2 ); //lint !e704 shifting is OK.
}
for ( idx = 1; idx < aEndPos; idx += 2 )
{
iOutputBuffer[idx] = iInputBuffer[idx] +
( ( iOutputBuffer[idx - 1] + iOutputBuffer[idx + 1] ) >> 1 ); //lint !e704 shifting is OK.
}
}
}
// -----------------------------------------------------------------------------
// CJ2kSynthesis::PerformExtension
// Performs one dimensional symmetric extension of the line of pixels from
// the 2 extensions of the line.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSynthesis::PerformExtension( TInt32 aStartPos, TInt32 aEndPos )
{
TInt32* high = iInputBuffer + aEndPos - 1;
TInt32 dir = 1;
TInt32 posLeft = aStartPos;
TInt32 posRight = aEndPos - 1;
for ( TInt32 idx = 1; idx <= KFilterExtension; ++idx )
{
posLeft += dir;
posRight -= dir;
iInputBuffer[aStartPos - idx] = iInputBuffer[posLeft];
high[idx] = iInputBuffer[posRight];
if ( posLeft == ( aEndPos - 1 ) )
{
dir = -1;
}
if ( dir == -1 )
{
if ( posLeft == aStartPos )
{
dir = 1;
}
}
}
}
// -----------------------------------------------------------------------------
// CJ2kSynthesis::OneDimIrrevFilter
// Perform one dimensional synthesis using irreversible 9/7 filter
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSynthesis::OneDimIrrevFilter( TInt32 aStartPos,
TInt32 aEndPos,
TUint8 aLevel,
TUint8 aVertical )
{
if ( ( aEndPos - aStartPos ) == 1 )
{
if ( aStartPos )
{
iOutputBuffer[aStartPos] = iInputBuffer[aStartPos] / 2;
}
else
{
iOutputBuffer[aStartPos] = iInputBuffer[aStartPos];
}
}
else
{
// First the low-pass parts
TInt32 idx = aStartPos + ( aStartPos % 2 );
for ( ; idx < aEndPos; idx += 2 )
{
iOutputBuffer[idx] = iTapsLow[0] * iInputBuffer[idx] +
iTapsLow[2] * ( iInputBuffer[idx - 2] + iInputBuffer[idx + 2] );
}
idx = aStartPos + ( ( aStartPos + 1 ) % 2 );
for ( ; idx < aEndPos; idx += 2 )
{
iOutputBuffer[idx] = iTapsLow[1] * ( iInputBuffer[idx - 1] + iInputBuffer[idx + 1] ) +
iTapsLow[3] * ( iInputBuffer[idx - 3] + iInputBuffer[idx + 3] );
}
// Then the high-pass parts
idx = aStartPos + ( ( aStartPos + 1 ) % 2 );
for ( ; idx < aEndPos; idx += 2 )
{
iOutputBuffer[idx] += iTapsHigh[0] * iInputBuffer[idx] +
iTapsHigh[2] * ( iInputBuffer[idx - 2] + iInputBuffer[idx + 2] ) +
iTapsHigh[4] * ( iInputBuffer[idx - 4] + iInputBuffer[idx + 4] );
}
idx = aStartPos + ( aStartPos % 2 );
for ( ; idx < aEndPos; idx += 2 )
{
iOutputBuffer[idx] += iTapsHigh[1] * ( iInputBuffer[idx - 1] + iInputBuffer[idx + 1] ) +
iTapsHigh[3] * ( iInputBuffer[idx - 3] + iInputBuffer[idx + 3] );
}
TInt32 offset = 0;
TInt32 downshift = 0;
// Finally downshift all the samples
if ( !aVertical || ( aLevel != 0 ) )
{
downshift = KFilterShift;
}
else
{
downshift = KFilterShift + KWaveletShift;
}
offset = ( (TUint32)( 1 << downshift ) >> 1 );
idx = aStartPos;
for ( ; idx < aEndPos; idx++ )
{
iOutputBuffer[idx] = ( iOutputBuffer[idx] + offset ) >> downshift; //lint !e704 shifting is OK.
}
}
}
// -----------------------------------------------------------------------------
// CJ2kSynthesis::OneDimFiltering
// Perform one dimensional filtering
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSynthesis::OneDimFiltering( TInt32 aStartPos,
TInt32 aEndPos,
TUint8 aLevel,
TUint8 aVertical )
{
// Extend the signals ( at the start and end )
PerformExtension( aStartPos, aEndPos );
if ( iReversible )
{
OneDimReversibleFilter( aStartPos, aEndPos );
}
else
{
OneDimIrrevFilter( aStartPos, aEndPos, aLevel, aVertical );
}
}
// -----------------------------------------------------------------------------
// CJ2kSynthesis::HorizontalFilter
// Perform one dimensional horizontal filtering
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSynthesis::HorizontalFilter( TPrecInt** aImage,
TInt32 aRow,
TUint32 aXtcSiz,
CJ2kSubband* aSubband )
{
TInt32 endPos = 0;
TInt32 startPos = aSubband->HighPassFirst().iX;
TInt32* rowImage = (TInt32*)aImage[aRow];
TInt32* rowImageHigh = rowImage + aSubband->ChildAt( CJ2kSubband::EBandLL )->SubbandCanvasSize().iWidth;
TInt32* iterator = iInputBuffer;
// Low-pass is first
if ( !startPos )
{
for ( endPos = aXtcSiz >> 1; endPos > 0; endPos-- )
{
*iterator++ = *rowImage++;
*iterator++ = *rowImageHigh++;
}
if ( aXtcSiz % 2 ) // One extra sample for low-pass
{
*iterator = *rowImage;
}
}
else // High-pass is first
{
iterator++;
for ( endPos = aXtcSiz >> 1; endPos > 0; endPos-- )
{
*iterator++ = *rowImageHigh++;
*iterator++ = *rowImage++;
}
if ( aXtcSiz % 2 ) // One extra sample for high-pass
{
*iterator = *rowImageHigh;
}
}
endPos = aXtcSiz + startPos;
OneDimFiltering( startPos, endPos, aSubband->SubbandLevel(), 0 );
Mem::Copy( aImage[aRow], iOutputBuffer + startPos, aXtcSiz * sizeof( TPrecInt ) );
}
// -----------------------------------------------------------------------------
// CJ2kSynthesis::VerticalFilter
// Perform one dimensional vertical filtering
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSynthesis::VerticalFilter( TPrecInt **aImage,
TInt32 aColumn,
TUint32 aYtcSiz,
CJ2kSubband *aSubband )
{
TInt32 startPos = aSubband->HighPassFirst().iY;
TInt32 highStart = aSubband->ChildAt( CJ2kSubband::EBandLL )->SubbandCanvasSize().iHeight;
TInt32 highStop = aSubband->SubbandCanvasSize().iHeight;
TInt32 *iterator = iInputBuffer;
TInt32 lowIndex = 0;
TInt32 highIndex = highStart;
if ( !startPos )
{
for ( ; highIndex < highStop; lowIndex++, highIndex++ )
{
*iterator++ = aImage[lowIndex][aColumn];
*iterator++ = aImage[highIndex][aColumn];
}
if ( aYtcSiz % 2 )
{
*iterator = aImage[lowIndex][aColumn];
}
}
else
{
iterator++;
for ( ; lowIndex < highStart; highIndex++, lowIndex++ )
{
*iterator++ = aImage[highIndex][aColumn];
*iterator++ = aImage[lowIndex][aColumn];
}
if ( aYtcSiz % 2 )
{
*iterator = aImage[highIndex][aColumn];
}
}
OneDimFiltering( startPos, startPos + aYtcSiz, aSubband->SubbandLevel(), 1 );
iOutputBuffer += ( startPos + aYtcSiz - 1 );
for ( lowIndex = aYtcSiz - 1; lowIndex >= 0; lowIndex-- )
{
aImage[lowIndex][aColumn] = *iOutputBuffer--;
}
iOutputBuffer += ( 1 - startPos );
}
// -----------------------------------------------------------------------------
// CJ2kSynthesis::TwoDimFiltering
// Perform two dimensional inverse wavelet transformation
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSynthesis::TwoDimFiltering( TPrecInt **aImage,
TInt32 aXtcSiz,
TInt32 aYtcSiz,
CJ2kSubband *aSubband )
{
TInt32 index = 0;
for ( index = aYtcSiz - 1; index >= 0; index-- )
{
HorizontalFilter( aImage, index, aXtcSiz, aSubband );
}
for ( index = aXtcSiz - 1; index >= 0; index-- )
{
VerticalFilter( aImage, index, aYtcSiz, aSubband );
}
}
// -----------------------------------------------------------------------------
// CJ2kSynthesis::FullWaveletInverse
// Perform a full inverse wavelet transformation
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSynthesis::FullWaveletInverse( TPrecInt **aImage, CJ2kSubband *aSubband )
{
TSize canvas( 0, 0 );
TUint8 reduceLevels = 0;
// If truncating resolution levels, we have to compute the reduced levels,
// so that the final WAVELET_SHIFT in case of 9x7 filter is performed.
if ( aSubband->SubbandLevel() > iWaveletLevels )
{
reduceLevels = (TUint8)( aSubband->SubbandLevel() - iWaveletLevels );
}
for ( TUint8 levelIndex = (TUint8)iWaveletLevels; levelIndex > 0; levelIndex-- )
{
// The next lines assume that subband points to the LL-band and
// it is then moved to point to the parent i.e. to the last
// _decomposition level_ of the wavelet transform.
aSubband = aSubband->Parent();
// Adjust the level in case of resolution truncation
aSubband->SetSubbandLevel( (TUint8)( aSubband->SubbandLevel() - reduceLevels ) );
canvas = aSubband->SubbandCanvasSize();
if ( canvas.iWidth > 0 && canvas.iHeight > 0 )
{
TwoDimFiltering( aImage, canvas.iWidth, canvas.iHeight, aSubband );
}
}
}
// -----------------------------------------------------------------------------
// CJ2kSynthesis::ComputeQuantizationParameters
// Compute the quantization parameters for a particular subband in the component
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSynthesis::ComputeQuantizationParameters( const CJ2kComponentInfo& aComponentInfo,
TInt16 aBandIndex,
TUint8 aBandGain,
TUint8 aBitDepth )
{
if ( iROIShift != 0 )
{
// ROI shifting is used
if ( aComponentInfo.QuantizationStyle() == 0 )
{
// Compute the shift for the codeblock's data, which is
// IMPLEMENTATION PRECISION -1( for sign ) - subband's range -
// the guard bits.
iDataShift = ( KImplementationPrecision - 1 ) - iMagnitudeBitsHere;
}
else // Irreversible case
{
// Because we have integer arithmetic only, we subtract WAVELET_SHIFT from the shift.
// This is to compensate for the fractional bits of the inverse quantized wavelet
// coefficients.
iDataShift = ( KImplementationPrecision - 1 ) - iMagnitudeBitsHere - KWaveletShift;
// The quantization step is computed from the equation
// step = ( 2^( Range-Exponent ) )*( 1+( Mantissa/( 2^11 ) ) ), where Range is the dynamic
// range of this subband ( = bitdepth + gain ). ( see Annex E of the standard for more
// information ).
//
// The "iStepExponent" is the shift needed to remove "iStepValue"'s fractional
// bits. The "iStepValue" is the shifted quantization step. Shifting back
// is done right after computing the quantized coefficient.
iStepExponent = aBitDepth + aBandGain - aComponentInfo.Exponent( aBandIndex ) - KStepBits;
iStepValue = aComponentInfo.Mantissa( aBandIndex ) + ( 1 << KStepBits );
}
// Compute the shift for the data inside the ROI
iROIDataShift = iDataShift - iROIShift;
}
else
{
// ROI is not present
if ( aComponentInfo.QuantizationStyle() == 0 )
{
// Compute the shift for the codeblock's data, which is
// IMPLEMENTATION PRECISION-1( for sign ) - subband's range -
// the guard bits.
iDataShift = ( KImplementationPrecision - 1 ) - iMagnitudeBitsHere;
// Shift all the samples in the codeblock
}
else // Irreversible case
{
// Because we have integer arithmetic only, we subtract WAVELET_SHIFT from the shift.
// This is to compensate for the fractional bits of the inverse quantized wavelet
// coefficients.
iDataShift = ( KImplementationPrecision - 1 ) - iMagnitudeBitsHere - KWaveletShift;
// To prevent overflows we check if the "shift" is at least 12. The minimum downshift of 12 is
// derived from the computation of "value*iStepValue", where "value" is downshifted previously by "shift"
// and "iStepValue" is at maximum 12 bits ( since iStepValue = mantissa + 1<<KStepBits, where mantissa is
// a 11-bit value and KStepBits is 11 ).
//
TInt32 iExtraBits = 0;
// If the implementation precision is 16 then we don't have to check if the shift is at least 12.
// This is because we use 32 bits for the computation and thus have at least 16 zero most significant
// bits at the "value".
if ( iDataShift < 12 ) // Test to prevent overflows
{
iExtraBits = 12 - iDataShift;
iDataShift += iExtraBits;
}
// The quantization step is computed from the equation
// step = ( 2^( Range-Exponent ) )*( 1+( Mantissa/( 2^11 ) ) ), where Range is the dynamic
// range of this subband ( = bitdepth + gain ). ( see Annex E of the standard for more
// information ).
//
// The "iStepExponent" is the shift needed to remove "iStepValue"'s fractional
// bits. The "iStepValue" is the shifted quantization step. Shifting back
// is done right after computing the quantized coefficient.
//
iStepExponent = aBitDepth + aBandGain - aComponentInfo.Exponent( aBandIndex ) - KStepBits;
// Test to prevent overflows
iStepExponent += iExtraBits;
iStepValue = aComponentInfo.Mantissa( aBandIndex ) + ( 1 << KStepBits );
}
}
}
// -----------------------------------------------------------------------------
// CJ2kSynthesis::CopyDataToImage
// Apply inverse quantization and ROI shifting on the decoded
// codeblock and copy to the image writer
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSynthesis::CopyDataToImage( CJ2kEntropyDecoder& aEntropyDecoder, TPrecInt** aImageBlock,
CJ2kSubband& aSubband, CJ2kCodeBlock& aCodeblock,
TUint8 aQuantizationStyle )
{
TPrecInt* buffer = 0; // To buffer one row of the aImageBlock
TPrecInt* imageRow = 0; // One row of the image
TPrecInt valueInt = 0;
TInt32 value = 0;
TInt32 j = 0;
const TRect& cbCanvas = aCodeblock.CodeBlockCanvas();
TInt32 startRow = cbCanvas.iTl.iY - aSubband.SubbandCanvas().iTl.iY + aSubband.SubbandOrigin().iY;
TInt32 startCol = cbCanvas.iTl.iX - aSubband.SubbandCanvas().iTl.iX + aSubband.SubbandOrigin().iX;
TInt32 endRow = startRow + cbCanvas.Height() - 1;
TInt32 endCol = startCol + cbCanvas.Width();
TInt32 cols = endCol - startCol - 1;
if ( iROIShift ) // ROI shifting is used
{
// Compute mask to determine which samples are in ROI
// for mask ROI coefficients
TInt32 mask = ( ( 1 << iMagnitudeBitsHere ) - 1 ) << ( ( KImplementationPrecision - 1 ) - iMagnitudeBitsHere );
TInt32 mask2 = ( ~mask ) & KMaximumPrecisionInteger;
TInt32 mask3 = ( ( 1 << iROIShift ) - 1 ) << ( ( KImplementationPrecision - 1 ) - iROIShift );
TInt32 maskShift = ( ~mask3 ) & KMaximumPrecisionInteger;
if ( !aQuantizationStyle )
{
// Shift all the samples in the codeblock
TInt32 roiDataShift = ( iROIDataShift < 0 ) ? -iROIDataShift : iROIDataShift;
for ( ; endRow >= startRow; endRow-- )
{
buffer = aEntropyDecoder.iData[endRow - startRow] + cols;
for ( j = endCol - 1; j >= startCol; j-- )
{
value = ( *buffer-- );
if ( !( value & mask ) ) // Background
{
// iROIDataShift can never be negative here!
if ( iROIDataShift < 0 )
{
aImageBlock[endRow][j] = ( value < 0 ) ? -( ( value & KMaximumPrecisionInteger ) << roiDataShift )
: ( value << roiDataShift ); //lint !e704 value is positive here
}
else
{
aImageBlock[endRow][j] = ( value < 0 ) ? -( ( value & maskShift ) >> roiDataShift ) //lint !e704 value&maskShift is positive, so no risk of right shifting negative values
: ( ( value & maskShift ) >> roiDataShift ); //lint !e704 value&maskShift is positive
}
}
else // ROI
{
if ( value & mask2 )
{
// Decoded more than magbits bit-planes, set
// quantization mid-interval approx. bit just after
// the magbits.
value &= ( ~mask2 );
}
aImageBlock[endRow][j] = ( value < 0 ) ? -( ( value & KMaximumPrecisionInteger ) >> iDataShift )
: ( value >> iDataShift ); //lint !e704 value is positive here
}
}
}
}
else // Irreversible case
{
// Shift all the samples in the codeblock
TInt32 stepExponent = ( iStepExponent < 0 ) ? -iStepExponent : iStepExponent;
// Divide into two cases depending on the sign of the iStepExponent to speed up coding
if ( iStepExponent < 0 )
{
for ( ; endRow >= startRow; endRow-- )
{
buffer = aEntropyDecoder.iData[endRow - startRow] + cols;
for ( j = endCol - 1; j >= startCol; j-- )
{
value = ( *buffer-- );
// Divide into two cases depending on whether value is negative
if ( value < 0 )
{
if ( !( value & mask ) ) // Background
{
value = ( ( value & maskShift ) >> iROIDataShift ); //lint !e704 value&maskShift is positive
valueInt = -( ( value * iStepValue ) >> stepExponent ); //lint !e704 ( value*iStepValue )&KMaximumPrecisionInteger is positive
}
else // ROI
{
if ( value & mask2 )
{
// Decoded more than magbits bit-planes, set
// quantization mid-interval approx. bit just after
// the magbits.
value = ( value & ( ~mask2 ) ) | ( 1 << ( KImplementationPrecision - 2 - iMagnitudeBitsHere ) );
}
value = ( ( value & KMaximumPrecisionInteger ) >> iDataShift );
valueInt = -( ( value * iStepValue ) >> stepExponent ); //lint !e704 ( value*iStepValue )&KMaximumPrecisionInteger is positive
}
}
else // Value is non-negative
{
if ( !( value & mask ) ) // background
{
value = ( ( value & maskShift ) >> iROIDataShift ); //lint !e704 value&maskShift is positive
valueInt = ( ( value * iStepValue ) >> stepExponent ); //lint !e704 value*iStepValue is positive
}
else // ROI
{
if ( value & mask2 )
{
// Decoded more than magbits bit-planes, set
// quantization mid-interval approx. bit just after
// the magbits.
value = ( value & ( ~mask2 ) ) | ( 1 << ( KImplementationPrecision - 2 - iMagnitudeBitsHere ) );
}
value = ( ( value & KMaximumPrecisionInteger ) >> iDataShift );
valueInt = ( ( value * iStepValue ) >> stepExponent ); //lint !e704 value*iStepValue is positive
}
}
aImageBlock[endRow][j] = valueInt;
}
}
}
else // iStepExponent is non-negative
{
for ( ; endRow >= startRow; endRow-- )
{
buffer = aEntropyDecoder.iData[endRow - startRow] + cols;
for ( j = endCol - 1; j >= startCol; j-- )
{
value = ( *buffer-- );
// Divide into two cases depending on whether value is negative
if ( value < 0 )
{
// Change value to be positive
value = -value;
if ( !( value & mask ) ) // Background
{
value = ( ( value & maskShift ) >> iROIDataShift ); //lint !e704 value&maskShift is positive
valueInt = ( ( value * iStepValue ) << stepExponent );
}
else // ROI
{
if ( value & mask2 )
{
// Decoded more than magbits bit-planes, set
// quantization mid-interval approx. bit just after
// the magbits.
value = ( value & ( ~mask2 ) ) | ( 1 << ( KImplementationPrecision - 2 - iMagnitudeBitsHere ) );
}
value = ( ( value & KMaximumPrecisionInteger ) >> iDataShift );
valueInt = ( ( value * iStepValue ) << stepExponent );
}
// Change the sign back to negative
aImageBlock[endRow][j] = -valueInt;
}
else // Value is non-negative
{
if ( !( value & mask ) ) // Background
{
value = ( ( value & maskShift ) >> iROIDataShift ); //lint !e704 value&maskShift is positive
valueInt = ( ( value * iStepValue ) << stepExponent );
}
else // ROI
{
if ( value & mask2 )
{
// Decoded more than magbits bit-planes, set
// quantization mid-interval approx. bit just after
// the magbits.
value = ( value & ( ~mask2 ) ) | ( 1 << ( KImplementationPrecision - 2 - iMagnitudeBitsHere ) );
}
value = ( ( value & KMaximumPrecisionInteger ) >> iDataShift );
valueInt = ( ( value * iStepValue ) << stepExponent );
}
aImageBlock[endRow][j] = valueInt;
}
}
}
}
}
}
else // ROI is not present
{
if ( !aQuantizationStyle )
{
// Shift all the samples in the codeblock
TInt32 i = endRow - startRow;
for ( ; endRow >= startRow; endRow--, i-- )
{
imageRow = aImageBlock[endRow] + endCol - 1;
buffer = aEntropyDecoder.iData[i] + cols;
for ( j = endCol - 1; j >= startCol; j-- )
{
value = *buffer--;
if ( value < 0 )
{
*imageRow-- = -( ( value & KMaximumPrecisionInteger ) >> iDataShift );
}
else
{
*imageRow-- = value >> iDataShift; //lint !e704 value is positive here
}
}
}
}
else // Irreversible case
{
// Shift all the samples in the codeblock
TInt32 stepExponent = ( iStepExponent < 0 ) ? -iStepExponent : iStepExponent;
// Divide into two cases depending on the sign of the iStepExponent to speed up coding
if ( iStepExponent < 0 )
{
for ( ; endRow >= startRow; endRow-- )
{
buffer = aEntropyDecoder.iData[endRow - startRow] + cols;
for ( j = endCol - 1; j >= startCol; j-- )
{
value = ( *buffer-- );
if ( value < 0 ) // Negative value
{
value = ( ( value & KMaximumPrecisionInteger ) >> iDataShift );
aImageBlock[endRow][j] = (TPrecInt)( -( ( value * iStepValue ) >> stepExponent ) ); //lint !e704 value*iStepValue is positive
}
else
{
value = ( ( value & KMaximumPrecisionInteger ) >> iDataShift );
aImageBlock[endRow][j] = (TPrecInt)( ( value * iStepValue ) >> stepExponent ); //lint !e704 value*iStepValue is positive
}
}
}
}
else // iStepExponent is non-negative
{
for ( ; endRow >= startRow; endRow-- )
{
buffer = aEntropyDecoder.iData[endRow - startRow] + cols;
for ( j = endCol - 1; j >= startCol; j-- )
{
value = ( *buffer-- );
if ( value < 0 ) // Negative value
{
value = ( ( value & KMaximumPrecisionInteger ) >> iDataShift );
aImageBlock[endRow][j] = (TPrecInt)( -( ( value * iStepValue ) << stepExponent ) );
}
else
{
value = ( ( value & KMaximumPrecisionInteger ) >> iDataShift );
aImageBlock[endRow][j] = (TPrecInt)( ( value * iStepValue ) << stepExponent );
}
}
}
}
}
}
// If number of levels is zero then we have to do the
// inverse wavelet shifting here.
//
if ( iWaveletLevels == 0 )
{
endRow = startRow + cbCanvas.Height();
endCol = startCol + cbCanvas.Width();
if ( aQuantizationStyle )
{
for ( TInt32 i = endRow - 1; i >= startRow; i-- )
{
for ( j = endCol - 1; j >= startCol; j-- )
{
aImageBlock[i][j] >>= KWaveletShift; //lint !e704 shifting is OK.
}
}
}
}
}
// -----------------------------------------------------------------------------
// CJ2kSynthesis::AllocBufferL
// Allocate internal buffer based on the requested size
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSynthesis::AllocBufferL( TInt32 aSize )
{
// Allocate memory for the input and output buffers
TInt32 totalSize = aSize * sizeof( TInt32 );
if ( iIOBufferSize )
{
// Resize only when the request buffer is larger than current buffer
if ( iIOBufferSize < totalSize )
{
iInputBuffer -= ( KFilterExtension + 1 );
TInt32* tmpBuffer = STATIC_CAST( TInt32*, User::ReAlloc( iInputBuffer, totalSize ) );
if ( !tmpBuffer )
{
iInputBuffer += ( KFilterExtension + 1 );
User::Leave( KErrNoMemory );
}
iInputBuffer = tmpBuffer;
iInputBuffer += ( KFilterExtension + 1 );
iOutputBuffer -= ( KFilterExtension + 1 );
tmpBuffer = STATIC_CAST( TInt32*, User::ReAlloc( iOutputBuffer, totalSize ) );
if ( !tmpBuffer )
{
iOutputBuffer += ( KFilterExtension + 1 );
User::Leave( KErrNoMemory );
}
iOutputBuffer = tmpBuffer;
iOutputBuffer += ( KFilterExtension + 1 );
iIOBufferSize = totalSize;
}
}
else
{
// First time buffer allocation
iInputBuffer = STATIC_CAST( TInt32*, User::Alloc( totalSize ) );
if ( !iInputBuffer )
{
User::Leave( KErrNoMemory );
}
iInputBuffer += ( KFilterExtension + 1 );
iOutputBuffer = STATIC_CAST( TInt32*, User::Alloc( totalSize ) );
if ( !iOutputBuffer )
{
User::Leave( KErrNoMemory );
}
iOutputBuffer += ( KFilterExtension + 1 );
iIOBufferSize = totalSize;
}
}
// -----------------------------------------------------------------------------
// CJ2kSynthesis::HorizontalBlockFilter
// Perform one dimensional horizontal filtering ( block-based ).
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSynthesis::HorizontalBlockFilter( TPrecInt** aImage, TInt32 aRow,
TUint32 aXtcSiz, CJ2kSubband* aSubband,
TInt32 aXOffset, TUint8 aCurrentLevel )
{
TInt32 endPos = 0;
TInt32 startPos = aSubband->HighPassFirst().iX;
TInt32* rowImage = (TInt32*)aImage[aRow];
TInt32* rowImageHigh = rowImage + KWaveletBlockMidPoint;
TInt32* iterator = iInputBuffer;
// Insert one extra ( dummy, i.e. zero-valued ) low-pass sample.
// This sample is not actually needed in computations, but now we can use the same
// functions for filtering for block-based and normal wavelet.
if( !startPos && ( aXOffset > 0 ) )
{
// The need for one extra sample derives from the fact that the support region
// for the high-pass is extends one sample further than the low-pass region.
*iterator++ = 0;
*iterator++ = *rowImageHigh++;
// Increment aXtcSiz by one to account for the dummy sample
aXtcSiz++;
}
if ( !startPos ) // Low-pass first
{
for ( endPos = aXtcSiz >> 1; endPos > 0; endPos-- )
{
*iterator++ = *rowImage++;
*iterator++ = *rowImageHigh++;
}
if ( aXtcSiz % 2 ) // One extra sample for low-pass
{
*iterator = *rowImage;
}
}
else // High-pass first
{
iterator++;
for ( endPos = aXtcSiz >> 1; endPos > 0; endPos-- )
{
*iterator++ = *rowImageHigh++;
*iterator++ = *rowImage++;
}
if ( aXtcSiz % 2 ) // One extra sample for high-pass
{
*iterator = *rowImageHigh;
}
}
endPos = aXtcSiz + startPos;
OneDimFiltering( startPos, endPos, (TUint8)( iWaveletLevels - aCurrentLevel ), 0 );
// Copy row back to image, take care of offset
Mem::Copy( aImage[aRow], iOutputBuffer + startPos + ( aXOffset ), ( aXtcSiz - ( aXOffset ) ) * sizeof( TPrecInt ) );
}
// -----------------------------------------------------------------------------
// CJ2kSynthesis::VerticalBlockFilter
// Perform one dimensional vertical filtering ( block-based )
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSynthesis::VerticalBlockFilter( TPrecInt** aImage, TInt32 aColumn, TUint32 aYtcSiz,
CJ2kSubband* aSubband, TInt32 aYOffset,
TUint8 aCurrentLevel )
{
TInt32 startPos = aSubband->HighPassFirst().iY;
TInt32 highStart = KWaveletBlockMidPoint;
TInt32* iterator = iInputBuffer;
TInt32 lowIndex = 0;
TInt32 highIndex = highStart;
// Insert one extra ( dummy, i.e. zero-valued ) low-pass sample.
if( !startPos && ( aYOffset > 0 ) )
{
*iterator++ = 0;
*iterator++ = aImage[highIndex++][aColumn];
// Increment aYtcSiz by one to account for the dummy sample
aYtcSiz++;
}
TInt32 highStop = KWaveletBlockMidPoint + ( aYtcSiz >> 1 );
TInt32 lowStop = aYtcSiz >> 1;
if ( !startPos )
{
for ( ; highIndex < highStop; lowIndex++, highIndex++ )
{
*iterator++ = aImage[lowIndex][aColumn];
*iterator++ = aImage[highIndex][aColumn];
}
if ( aYtcSiz % 2 )
{
*iterator = aImage[lowIndex][aColumn];
}
}
else
{
iterator++;
for ( ; lowIndex < lowStop; highIndex++, lowIndex++ )
{
*iterator++ = aImage[highIndex][aColumn];
*iterator++ = aImage[lowIndex][aColumn];
}
if ( aYtcSiz % 2 )
{
*iterator = aImage[highIndex][aColumn];
}
}
OneDimFiltering( startPos, startPos + aYtcSiz, (TUint8)( iWaveletLevels - aCurrentLevel ), 1 );
iOutputBuffer += ( startPos + aYtcSiz - 1 );
// Copy column back to image, take care of offset
for ( lowIndex = ( aYtcSiz - 1 - aYOffset ); lowIndex >= 0; lowIndex-- )
{
aImage[lowIndex][aColumn] = *iOutputBuffer--;
}
iOutputBuffer += ( 1 - startPos - aYOffset );
}
// -----------------------------------------------------------------------------
// CJ2kSynthesis::TwoDimBlockFiltering
// Perform two dimensional inverse wavelet transformation ( block-based )
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSynthesis::TwoDimBlockFiltering( TPrecInt** aImage, TSize aRegion, CJ2kSubband* aSubband,
TPoint aOffset, TUint8 aCurrentLevel )
{
TInt32 index = 0;
TUint32 xtcSiz = aRegion.iWidth;
TUint32 ytcSiz = aRegion.iHeight;
// For block filtering we have the data in two blocks ( column-wise ),
// from 0 to ( ytcsiz+1 )>>1 ( +1 to take care of odd number of samples )
// and from KWaveletBlockMidPoint to KWaveletBlockMidPoint+( ( ytcsiz+1 )>>1 ).
index = KWaveletBlockMidPoint + ( ( ytcSiz+1 ) >> 1 ) - 1;
// First apply horizontal filter to the ( vertically ) high-pass samples
for ( ; index >= KWaveletBlockMidPoint; index-- )
{
HorizontalBlockFilter( aImage, index, xtcSiz, aSubband, aOffset.iX, aCurrentLevel );
}
// Then apply horizontal filter to the ( vertically ) low-pass samples
index = ( ( ytcSiz+1 ) >> 1 ) - 1;
for ( ; index >= 0; index-- )
{
HorizontalBlockFilter( aImage, index, xtcSiz, aSubband, aOffset.iX, aCurrentLevel );
}
// Because of the horizontal filtering, the data is now in one block row-wise, thus
// two loops are not needed for vertical fitering.
index = xtcSiz-1-( (TUint32)( aOffset.iX ) >> 1 );
for ( ; index >= 0; index-- )
{
VerticalBlockFilter( aImage, index, ytcSiz, aSubband, aOffset.iY, aCurrentLevel );
}
}
// -----------------------------------------------------------------------------
// CJ2kSynthesis::SingleLevelWaveletInverse
// Perform a full inverse wavelet transformation ( block-based )
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSynthesis::SingleLevelWaveletInverse( TPrecInt **aImage, CJ2kSubband *aSubband,
TPoint aOffset, TSize aRegion, TUint8 aCurrentLevel )
{
if ( aRegion.iWidth > 0 && aRegion.iHeight > 0 )
{
aSubband = aSubband->Parent();
TwoDimBlockFiltering( aImage, aRegion, aSubband, aOffset, aCurrentLevel );
}
}
// -----------------------------------------------------------------------------
// CJ2kSynthesis::CopyDataToBlock
// Apply inverse quantization and ROI shifting on the decoded
// codeblock and copy to the image writer ( block-based ).
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSynthesis::CopyDataToBlock( CJ2kEntropyDecoder& aEntropyDecoder, TPrecInt** aImageBlock,
CJ2kSubband& aSubband, TUint8 aQuantizationStyle,
TInt32 aStartRowCblk, TInt32 aStartColCblk,
TInt32 aStartRowImage, TInt32 aStartColImage,
TInt32 aCblkHeight, TInt32 aCblkWidth )
{
TPrecInt* buffer = 0; // To buffer one row of the image_block
TPrecInt* imageRow = 0; // One row of the image
TPrecInt valueInt = 0;
TInt32 value = 0;
TInt32 j = 0;
TInt32 startRowImageBlock = aStartRowImage; // Start row's index in the image to copy to
TInt32 startColImageBlock = aStartColImage; // Start column's index in the image to copy to
TUint8 aBandIndex = (TUint8)( aSubband.SubbandType() );
// Adjust the place where to copy the data according to the subband type
// ( i.e. whether we have LL, HL, LH or HH band ).
if( aBandIndex == 1 )
{
startColImageBlock += KWaveletBlockMidPoint;
}
else if( aBandIndex == 2 )
{
startRowImageBlock += KWaveletBlockMidPoint;
}
else if( aBandIndex == 3 )
{
startRowImageBlock += KWaveletBlockMidPoint;
startColImageBlock += KWaveletBlockMidPoint;
}
// Compute the end of the copy region
TInt32 endRowImageBlock = startRowImageBlock + aCblkHeight - 1; //lint !e961 no else is needed here at the end of if...else if
TInt32 endColImageBlock = startColImageBlock + aCblkWidth;
// Index of the row to copy from in the codeblock
TInt32 codeblockRow = aStartRowCblk + aCblkHeight-1;
// Index of the row to copy from in the codeblock
TInt32 codeblockColumn = aStartColCblk + aCblkWidth-1;
if ( iROIShift ) // ROI shifting is used
{
// Compute mask to determine which samples are in ROI
// for mask ROI coefficients
TInt32 mask = ( ( 1 << iMagnitudeBitsHere ) - 1 ) << ( ( KImplementationPrecision - 1 ) - iMagnitudeBitsHere );
TInt32 mask2 = ( ~mask ) & KMaximumPrecisionInteger;
TInt32 mask3 = ( ( 1 << iROIShift ) - 1 ) << ( ( KImplementationPrecision - 1 ) - iROIShift );
TInt32 maskShift = ( ~mask3 ) & KMaximumPrecisionInteger;
if ( !aQuantizationStyle )
{
// Shift all the samples in the codeblock
TInt32 roiDataShift = ( iROIDataShift < 0 ) ? -iROIDataShift : iROIDataShift;
for ( ; endRowImageBlock >= startRowImageBlock; endRowImageBlock--,codeblockRow-- )
{
buffer = aEntropyDecoder.iData[codeblockRow] + codeblockColumn;
for ( j = endColImageBlock-1; j >= startColImageBlock; j-- )
{
value = ( *buffer-- );
if ( !( value & mask ) ) // Background
{
if ( iROIDataShift < 0 )
{
aImageBlock[endRowImageBlock][j] = ( value < 0 ) ? -( ( value & KMaximumPrecisionInteger ) << roiDataShift )
: ( value << roiDataShift );
}
else
{
aImageBlock[endRowImageBlock][j] = ( value < 0 ) ? -( ( value & maskShift ) >> roiDataShift ) //lint !e704 value&maskShift is positive, so no risk of right shifting negative values
: ( ( value & maskShift ) >> roiDataShift ); //lint !e704 value&maskShift is positive, so no risk of right shifting negative values
}
}
else // ROI
{
if ( value & mask2 )
{
// Decoded more than magbits bit-planes, set
// quantization mid-interval approx. bit just after
// the magbits.
value &= ( ~mask2 );
}
aImageBlock[endRowImageBlock][j] = ( value < 0 ) ? -( ( value & KMaximumPrecisionInteger ) >> iDataShift )
: ( value >> iDataShift ); //lint !e704 value is positive here
}
}
}
}
else // Irreversible case
{
// Shift all the samples in the codeblock
TInt32 stepExponent = ( iStepExponent < 0 ) ? -iStepExponent : iStepExponent;
// Divide into two cases depending on the sign of the iStepExponent to speed up coding
if ( iStepExponent < 0 )
{
for ( ; endRowImageBlock >= startRowImageBlock; endRowImageBlock--, codeblockRow-- )
{
buffer = aEntropyDecoder.iData[codeblockRow] + codeblockColumn;
for ( j = endColImageBlock-1; j >= startColImageBlock; j-- )
{
value = ( *buffer-- );
// Divide into two cases depending on whether value is negative
if ( value < 0 )
{
if ( !( value & mask ) ) // Background
{
value = ( ( value & maskShift ) >> iROIDataShift ); //lint !e704 value&maskShift is positive, so no risk of right shifting negative values
valueInt = -( ( value * iStepValue ) >> stepExponent ); //lint !e704 value*iStepValue is positive
}
else // ROI
{
if ( value & mask2 )
{
// Decoded more than magbits bit-planes, set
// quantization mid-interval approx. bit just after
// the magbits.
value = ( value & ( ~mask2 ) ) | ( 1 << ( KImplementationPrecision - 2 - iMagnitudeBitsHere ) );
}
value = ( ( value & KMaximumPrecisionInteger ) >> iDataShift );
valueInt = -( ( value * iStepValue ) >> stepExponent ); //lint !e704 value*iStepValue is positive
}
}
else // Value is non-negative
{
if ( !( value & mask ) ) // Background
{
value = ( ( value & maskShift ) >> iROIDataShift ); //lint !e704 value&maskShift is positive, so no risk of right shifting negative values
valueInt = ( ( value * iStepValue ) >> stepExponent ); //lint !e704 value*iStepValue is positive
}
else // ROI
{
if ( value & mask2 )
{
// Decoded more than magbits bit-planes, set
// quantization mid-interval approx. bit just after
// the magbits.
value = ( value & ( ~mask2 ) ) | ( 1 << ( KImplementationPrecision - 2 - iMagnitudeBitsHere ) );
}
value = ( ( value & KMaximumPrecisionInteger ) >> iDataShift );
valueInt = ( ( value * iStepValue ) >> stepExponent ); //lint !e704 value*iStepValue is positive
}
}
aImageBlock[endRowImageBlock][j] = valueInt;
}
}
}
else // iStepExponent is non-negative
{
for ( ; endRowImageBlock >= startRowImageBlock; endRowImageBlock--,codeblockRow-- )
{
buffer = aEntropyDecoder.iData[codeblockRow] + codeblockColumn;
for ( j = endColImageBlock-1; j >= startColImageBlock; j-- )
{
value = ( *buffer-- );
if ( !( value & mask ) ) // Background
{
if ( value < 0 ) // Get the sign
{
value = -( ( value & maskShift ) >> iROIDataShift ); //lint !e704 value&maskShift is positive, so no risk of right shifting negative values
}
else
{
value = ( ( value & maskShift ) >> iROIDataShift ); //lint !e704 value&maskShift is positive, so no risk of right shifting negative values
}
valueInt = ( ( value * iStepValue ) << stepExponent );
}
else // ROI
{
if ( value & mask2 )
{
// Decoded more than magbits bit-planes, set
// quantization mid-interval approx. bit just after
// the magbits.
value = ( value & ( ~mask2 ) ) | ( 1 << ( KImplementationPrecision - 2 - iMagnitudeBitsHere ) );
}
if ( value < 0 )
{
value = -( ( value & KMaximumPrecisionInteger ) >> iDataShift );
}
else
{
value = ( ( value & KMaximumPrecisionInteger ) >> iDataShift );
}
valueInt = ( ( value * iStepValue ) << stepExponent );
}
aImageBlock[endRowImageBlock][j] = valueInt;
}
}
}
}
}
else // ROI is not present
{
if ( !aQuantizationStyle )
{
// Shift all the samples in the codeblock
TInt32 i = codeblockRow;
for ( ; endRowImageBlock >= startRowImageBlock; endRowImageBlock--, i-- )
{
imageRow = aImageBlock[endRowImageBlock] + endColImageBlock - 1;
buffer = aEntropyDecoder.iData[i] + codeblockColumn;
for ( j = endColImageBlock-1; j >= startColImageBlock; j-- )
{
value = *buffer--;
if ( value < 0 )
{
*imageRow-- = -( ( value & KMaximumPrecisionInteger ) >> iDataShift );
}
else
{
*imageRow-- = value >> iDataShift; //lint !e704 value is positive here
}
}
}
}
else // Irreversible case
{
// Shift all the samples in the codeblock
TInt32 stepExponent = ( iStepExponent < 0 ) ? -iStepExponent : iStepExponent;
// Divide into two cases depending on the sign of the iStepExponent to speed up coding
if ( iStepExponent < 0 )
{
for ( ; endRowImageBlock >= startRowImageBlock; endRowImageBlock--,codeblockRow-- )
{
buffer = aEntropyDecoder.iData[codeblockRow] + codeblockColumn;
for ( j = endColImageBlock-1; j >= startColImageBlock; j-- )
{
value = ( *buffer-- );
if ( value < 0 ) // Negative value
{
value = ( ( value & KMaximumPrecisionInteger ) >> iDataShift );
aImageBlock[endRowImageBlock][j] = (TPrecInt)( -( ( value * iStepValue ) >> stepExponent ) ); //lint !e704 value*iStepValue is positive
}
else
{
value = ( ( value & KMaximumPrecisionInteger ) >> iDataShift );
aImageBlock[endRowImageBlock][j] = (TPrecInt)( ( value * iStepValue ) >> stepExponent ); //lint !e704 value*iStepValue is positive
}
}
}
}
else // iStepExponent is non-negative
{
for ( ; endRowImageBlock >= startRowImageBlock; endRowImageBlock--,codeblockRow-- )
{
buffer = aEntropyDecoder.iData[codeblockRow] + codeblockColumn;
for ( j = endColImageBlock-1; j >= startColImageBlock; j-- )
{
value = ( *buffer-- );
if ( value < 0 ) // Negative value
{
value = ( ( value & KMaximumPrecisionInteger ) >> iDataShift );
aImageBlock[endRowImageBlock][j] = (TPrecInt)( -( ( value * iStepValue ) << stepExponent ) );
}
else
{
value = ( ( value & KMaximumPrecisionInteger ) >> iDataShift );
aImageBlock[endRowImageBlock][j] = (TPrecInt)( ( value * iStepValue ) << stepExponent );
}
}
}
}
}
}
// If number of levels is zero then we have to do the
// inverse wavelet shifting here.
//
if ( iWaveletLevels == 0 )
{
endRowImageBlock = startRowImageBlock + aCblkHeight;
endColImageBlock = startColImageBlock + aCblkWidth;
if ( aQuantizationStyle )
{
for ( TInt32 i = endRowImageBlock - 1; i >= startRowImageBlock; i-- )
{
for ( j = endColImageBlock - 1; j >= startColImageBlock; j-- )
{
aImageBlock[i][j] >>= KWaveletShift; //lint !e704 shifting is OK.
}
}
}
}
}
// -----------------------------------------------------------------------------
// CJ2kSynthesis::FillDataWithZeros
// Fill a block in image writer with zeros ( corresponding to an empty block )
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSynthesis::FillDataWithZeros( TPrecInt** aImageBlock, CJ2kSubband& aSubband,
TInt32 aStartRowImage, TInt32 aStartColImage,
TInt32 aCblkHeight, TInt32 aCblkWidth )
{
TPrecInt* imageRow = 0; // One row of the image
TInt32 j = 0;
TInt32 startRowImageBlock = aStartRowImage; // Start row's index in the image to copy to
TInt32 startColImageBlock = aStartColImage; // Start column's index in the image to copy to
TUint8 aBandIndex = (TUint8)( aSubband.SubbandType() );
// Adjust the place where to copy the data according to the subband type
// ( i.e. whether we have LL, HL, LH or HH band ).
if( aBandIndex == 1 )
{
startColImageBlock += KWaveletBlockMidPoint;
}
else if( aBandIndex == 2 )
{
startRowImageBlock += KWaveletBlockMidPoint;
}
else if( aBandIndex == 3 )
{
startRowImageBlock += KWaveletBlockMidPoint;
startColImageBlock += KWaveletBlockMidPoint;
}
// Compute the end of the copy region
TInt32 endRowImageBlock = startRowImageBlock + aCblkHeight - 1; //lint !e961 no else is needed here at the end of if...else if
TInt32 endColImageBlock = startColImageBlock + aCblkWidth;
// Shift all the samples in the codeblock
for ( ; endRowImageBlock >= startRowImageBlock; endRowImageBlock-- )
{
imageRow = aImageBlock[endRowImageBlock] + endColImageBlock - 1;
for ( j = endColImageBlock-1; j >= startColImageBlock; j-- )
{
*imageRow-- = 0;
}
}
}