diff -r 000000000000 -r 469c91dae73b imagingmodules/jp2kcodec/Src/JP2KSynthesis.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imagingmodules/jp2kcodec/Src/JP2KSynthesis.cpp Thu Dec 17 09:22:31 2009 +0200 @@ -0,0 +1,2366 @@ +/* +* 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* 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*, &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* 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*, &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; iStepData()[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<= 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; + } + } + } +