use of kdu_jni.Kdu_stripe_decompressor in project imageio-ext by geosolutions-it.
the class JP2KKakaduImageReader method read.
/**
* Read the image and returns it as a complete <code>BufferedImage</code>,
* using a supplied <code>ImageReadParam</code>.
*
* @param imageIndex
* the index of the desired image.
*/
public BufferedImage read(int imageIndex, ImageReadParam param) throws IOException {
checkImageIndex(imageIndex);
// ///////////////////////////////////////////////////////////
//
// STEP 0.
// -------
// Setting local variables for i-th codestream
//
// ///////////////////////////////////////////////////////////
JP2KCodestreamProperties codestreamP = multipleCodestreams.get(imageIndex);
final int maxAvailableQualityLayers = codestreamP.getMaxAvailableQualityLayers();
final int[] componentIndexes = codestreamP.getComponentIndexes();
final int nComponents = codestreamP.getNumComponents();
final int maxBitDepth = codestreamP.getMaxBitDepth();
final int height = codestreamP.getHeight();
final int width = codestreamP.getWidth();
final ColorModel cm = codestreamP.getColorModel();
final SampleModel sm = codestreamP.getSampleModel();
Kdu_simple_file_source localRawSource = null;
Jp2_family_src localFamilySource = null;
Jpx_source localWrappedSource = null;
// get a default set of ImageReadParam if needed.
if (param == null)
param = getDefaultReadParam();
// ///////////////////////////////////////////////////////////
//
// STEP 1.
// -------
// local variables initialization
//
// ///////////////////////////////////////////////////////////
// The destination image properties
final Rectangle destinationRegion = new Rectangle(0, 0, -1, -1);
// The source region image properties
final Rectangle sourceRegion = new Rectangle(0, 0, -1, -1);
// The properties of the image we need to load from Kakadu
final Rectangle requiredRegion = new Rectangle(0, 0, -1, -1);
// Subsampling Factors
int xSubsamplingFactor = -1;
int ySubsamplingFactor = -1;
// boolean used to specify when resampling is required (as an instance,
// different subsampling factors (xSS != ySS) require resampling)
boolean resamplingIsRequired = false;
// ///////////////////////////////////////////////////////////
if (!(param instanceof JP2KKakaduImageReadParam)) {
// The parameter is not of JP2KakaduImageReadParam type but
// simply an ImageReadParam instance (the superclass)
// we need to build a proper JP2KakaduImageReadParam prior
// to start parameters parsing.
JP2KKakaduImageReadParam jp2kParam = (JP2KKakaduImageReadParam) getDefaultReadParam();
jp2kParam.initialize(param);
param = jp2kParam;
}
// selected interpolation type
final int interpolationType = ((JP2KKakaduImageReadParam) param).getInterpolationType();
// specified quality layers
int qualityLayers = ((JP2KKakaduImageReadParam) param).getQualityLayers();
if (qualityLayers != -1) {
// qualityLayers != -1 means that the user have specified that value
if (qualityLayers > maxAvailableQualityLayers)
// correct the user defined qualityLayers parameter if this
// exceed the max number of available quality layers
qualityLayers = maxAvailableQualityLayers;
} else
qualityLayers = 0;
// SubSampling variables initialization
xSubsamplingFactor = param.getSourceXSubsampling();
ySubsamplingFactor = param.getSourceYSubsampling();
// //
// Retrieving Information about Source Region and doing additional
// initialization operations.
// //
computeRegions(width, height, param, sourceRegion, destinationRegion);
// ////////////////////////////////////////////////////////////////////
//
// STEP 3.
// -------
// check if the image need to be resampled/rescaled and find the proper
// scale factor as well as the size of the required region we need to
// provide to kakadu.
//
// ////////////////////////////////////////////////////////////////////
final int[] resolutionInfo = new int[2];
resamplingIsRequired = getRequiredRegionsAndResolutions(codestreamP, xSubsamplingFactor, ySubsamplingFactor, sourceRegion, destinationRegion, requiredRegion, resolutionInfo);
final int nDiscardLevels = resolutionInfo[1];
// Setting the destination Buffer Size which will contains the samples
// coming from stripe_decompressor
BufferedImage bi = null;
try {
DataBuffer imageBuffer = null;
// ////////////////////////////////////////////////////////////////
//
// STEP 4.
// -------
// Initialize sources and codestream
// ////////////////////////////////////////////////////////////////
// Opening data source
Kdu_codestream codestream = new Kdu_codestream();
if (!isRawSource) {
localFamilySource = new Jp2_family_src();
localWrappedSource = new Jpx_source();
localFamilySource.Open(fileName);
localWrappedSource.Open(localFamilySource, true);
final Jpx_codestream_source stream = localWrappedSource.Access_codestream(imageIndex);
final Jpx_input_box inputbox = stream.Open_stream();
codestream.Create(inputbox);
} else {
localRawSource = new Kdu_simple_file_source(fileName);
codestream.Create(localRawSource);
}
// ////////////////////////////////////////////////////////////////
//
// STEP 5.
// -------
// Set parameters for stripe decompression
// ////////////////////////////////////////////////////////////////
final Kdu_dims dims = new Kdu_dims();
codestream.Apply_input_restrictions(0, nComponents, nDiscardLevels, qualityLayers, null, Kdu_global.KDU_WANT_OUTPUT_COMPONENTS);
if (LOGGER.isLoggable(Level.FINE)) {
final Kdu_dims original_dims = new Kdu_dims();
codestream.Get_dims(-1, original_dims);
StringBuilder sb = new StringBuilder("Original Hi-Res Image Region is: x=").append(original_dims.Access_pos().Get_x()).append(" y=").append(original_dims.Access_pos().Get_y()).append(" w=").append(original_dims.Access_size().Get_x()).append(" h=").append(original_dims.Access_size().Get_y());
LOGGER.fine(sb.toString());
}
final Kdu_dims dimsROI = new Kdu_dims();
codestream.Get_dims(0, dims);
if (LOGGER.isLoggable(Level.FINE)) {
final int mappedX = dims.Access_pos().Get_x();
final int mappedY = dims.Access_pos().Get_y();
final int mappedWidth = dims.Access_size().Get_x();
final int mappedHeight = dims.Access_size().Get_y();
StringBuilder sb = new StringBuilder("Mapped Region is: x=").append(mappedX).append(" y=").append(mappedY).append(" w=").append(mappedWidth).append(" h=").append(mappedHeight);
LOGGER.fine(sb.toString());
}
// Checks on the required region and mapped region, in compliance with
// Formula 11.1 of Taubman's JPEG2000 compression book.
checkBounds(dims, requiredRegion);
final int destBufferSize = (requiredRegion.height * requiredRegion.width) * nComponents;
setDimsForCrop(dims, requiredRegion);
// Getting a region of interest.
codestream.Map_region(0, dims, dimsROI);
if (LOGGER.isLoggable(Level.FINE)) {
final int mappedROIWidth = dimsROI.Access_size().Get_x();
final int mappedROIHeight = dimsROI.Access_size().Get_y();
final int mappedROIX = dimsROI.Access_pos().Get_x();
final int mappedROIY = dimsROI.Access_pos().Get_y();
StringBuilder sb = new StringBuilder("ROI Region is: x=").append(mappedROIX).append(" y=").append(mappedROIY).append(" w=").append(mappedROIWidth).append(" h=").append(mappedROIHeight);
LOGGER.fine(sb.toString());
}
codestream.Apply_input_restrictions(nComponents, componentIndexes, nDiscardLevels, qualityLayers, dimsROI, Kdu_global.KDU_WANT_OUTPUT_COMPONENTS);
// //
//
// Setting parameters for stripe decompression
//
// //
// Array with one entry for each image component, identifying the
// number of lines to be decompressed for that component in the
// present call. All entries must be non-negative.
final int[] stripeHeights = new int[nComponents];
// Array with one entry for each image component, identifying
// the separation between horizontally adjacent samples within the
// corresponding stripe buffer found in the stripe_bufs array.
final int[] sampleGap = new int[nComponents];
// Array with one entry for each image component, identifying
// the separation between vertically adjacent samples within the
// corresponding stripe buffer found in the stripe_bufs array.
final int[] rowGap = new int[nComponents];
// Array with one entry for each image component, identifying the
// position of the first sample of that component within the buffer
// array.
final int[] sampleOffset = new int[nComponents];
// Array with one entry for each image component, identifying the
// number of significant bits used to represent each sample.
// There is no implied connection between the precision values, P,
// and the bit-depth, B, of each image component, as found in the
// code-stream's SIZ marker segment, and returned via
// kdu_codestream::get_bit_depth. The original image sample
// bit-depth, B, may be larger or smaller than the value of P
// supplied via the precisions argument. The samples returned by
// pull_stripe all have a nominally signed representation unless
// otherwise indicated by a non-NULL isSigned argument
final int[] precision = new int[nComponents];
for (int component = 0; component < nComponents; component++) {
stripeHeights[component] = requiredRegion.height;
sampleGap[component] = nComponents;
rowGap[component] = requiredRegion.width * nComponents;
sampleOffset[component] = component;
precision[component] = codestream.Get_bit_depth(component);
}
// ////////////////////////////////////////////////////////////////
//
// STEP 6.
// -------
// Stripe decompressor data loading
// ////////////////////////////////////////////////////////////////
Kdu_stripe_decompressor decompressor = new Kdu_stripe_decompressor();
decompressor.Start(codestream);
/**
* @todo: actually, we only handle fixed point types. No float or
* double data are handled.
*/
if (maxBitDepth <= 8) {
final byte[] bufferValues = new byte[destBufferSize];
decompressor.Pull_stripe(bufferValues, stripeHeights, sampleOffset, sampleGap, rowGap, precision);
imageBuffer = new DataBufferByte(bufferValues, destBufferSize);
} else if (maxBitDepth > 8 && maxBitDepth <= 16) {
final boolean[] isSigned = new boolean[nComponents];
for (int i = 0; i < isSigned.length; i++) isSigned[i] = codestream.Get_signed(i);
final short[] bufferValues = new short[destBufferSize];
decompressor.Pull_stripe(bufferValues, stripeHeights, sampleOffset, sampleGap, rowGap, precision, isSigned);
imageBuffer = new DataBufferUShort(bufferValues, destBufferSize);
} else if (maxBitDepth > 16 && maxBitDepth <= 32) {
final int[] bufferValues = new int[destBufferSize];
decompressor.Pull_stripe(bufferValues, stripeHeights, sampleOffset, sampleGap, rowGap, precision);
imageBuffer = new DataBufferInt(bufferValues, destBufferSize);
}
// ////////////////////////////////////////////////////////////////
//
// STEP 6.bis
// ----------
// Kakadu items deallocation/finalization
// ////////////////////////////////////////////////////////////////
decompressor.Finish();
decompressor.Native_destroy();
codestream.Destroy();
// ////////////////////////////////////////////////////////////////
//
// STEP 7.
// -------
// BufferedImage Creation
//
// ////////////////////////////////////////////////////////////////
final SampleModel sampleModel = sm.createCompatibleSampleModel(requiredRegion.width, requiredRegion.height);
bi = new BufferedImage(cm, Raster.createWritableRaster(sampleModel, imageBuffer, null), false, null);
} catch (KduException e) {
throw new RuntimeException("Error caused by a Kakadu exception during creation of key objects! ", e);
} catch (RasterFormatException rfe) {
throw new RuntimeException("Error during raster creation", rfe);
} finally {
if (!isRawSource) {
try {
if (localWrappedSource.Exists())
localWrappedSource.Close();
} catch (KduException e) {
}
localWrappedSource.Native_destroy();
try {
if (localFamilySource.Exists())
localFamilySource.Close();
} catch (KduException e) {
}
localFamilySource.Native_destroy();
} else {
localRawSource.Native_destroy();
}
if (deleteInputFile && inputFile.exists()) {
inputFile.delete();
}
}
// ////////////////////////////////////////////////////////////////
if (resamplingIsRequired && bi != null)
return KakaduUtilities.subsampleImage(codestreamP.getColorModel(), bi, destinationRegion.width, destinationRegion.height, interpolationType);
return bi;
}
Aggregations