use of kdu_jni.Jpx_codestream_source in project imageio-ext by geosolutions-it.
the class JP2KKakaduImageReader method setInput.
public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) {
// //
//
// Reset the reader prior to do anything with it
//
// //
reset();
// //
if (input == null)
throw new NullPointerException("The provided input is null!");
// Checking if the provided input is a File
if (input instanceof File) {
inputFile = (File) input;
// Checking if the provided input is a FileImageInputStreamExt
} else if (input instanceof FileImageInputStreamExt) {
inputFile = ((FileImageInputStreamExt) input).getFile();
// Checking if the provided input is a URL
} else if (input instanceof URL) {
final URL tempURL = (URL) input;
if (tempURL.getProtocol().equalsIgnoreCase("file")) {
inputFile = Utilities.urlToFile(tempURL);
}
} else if (input instanceof ImageInputStream) {
try {
inputFile = File.createTempFile("buffer", ".j2c");
FileOutputStream fos = new FileOutputStream(inputFile);
final byte[] buff = new byte[TEMP_BUFFER_SIZE];
int bytesRead = 0;
while ((bytesRead = ((ImageInputStream) input).read(buff)) != -1) fos.write(buff, 0, bytesRead);
fos.close();
input = inputFile;
deleteInputFile = true;
} catch (IOException ioe) {
throw new RuntimeException("Unable to create a temp file", ioe);
}
}
if (this.inputFile == null)
throw new IllegalArgumentException("Invalid source provided.");
fileName = inputFile.getAbsolutePath();
// //
//
// Open it up
//
// //
// Must be disposed last
Kdu_simple_file_source rawSource = null;
// Dispose
final Jp2_family_src familySource = new Jp2_family_src();
// last
// Dispose in the
final Jpx_source wrappedSource = new Jpx_source();
// middle
Kdu_codestream codestream = new Kdu_codestream();
try {
// Open input file as raw codestream or a JP2/JPX file
familySource.Open(fileName);
final int success = wrappedSource.Open(familySource, true);
if (success < 0) {
// //
//
// Must open as raw file
//
// //
familySource.Close();
wrappedSource.Close();
rawSource = new Kdu_simple_file_source(fileName);
if (rawSource != null) {
if (fileName != null) {
FileInputStream fis = new FileInputStream(new File(fileName));
byte[] jp2SocMarker = new byte[2];
fis.read(jp2SocMarker);
if (jp2SocMarker[0] != (byte) 0xFF || jp2SocMarker[1] != (byte) 0x4F)
throw new IllegalArgumentException("Not a JP2K source.");
fis.close();
}
isRawSource = true;
if (LOGGER.isLoggable(Level.FINE))
LOGGER.fine("Detected raw source");
numImages = 1;
}
} else {
// we have a valid jp2/jpx file
isRawSource = false;
// //
//
// get the number of codestreams in this jpeg2000 file
//
// //
final int[] count = new int[1];
if (wrappedSource.Count_codestreams(count))
numImages = count[0];
else
numImages = 0;
}
if (!isRawSource)
fileWalker = new JP2KFileWalker(this.fileName);
for (int cs = 0; cs < numImages; cs++) {
if (isRawSource) {
codestream.Create(rawSource);
} else {
final Jpx_codestream_source stream = wrappedSource.Access_codestream(cs);
final Jpx_input_box inputbox = stream.Open_stream();
codestream.Create(inputbox);
}
final JP2KCodestreamProperties codestreamP = new JP2KCodestreamProperties();
// //
//
// Initializing size-related properties (Image dims, Tiles)
//
// //
final Kdu_dims imageDims = new Kdu_dims();
codestream.Access_siz().Finalize_all();
codestream.Get_dims(-1, imageDims, false);
final Kdu_dims tileSize = new Kdu_dims();
codestream.Get_tile_dims(new Kdu_coords(0, 0), -1, tileSize);
int tileWidth = tileSize.Access_size().Get_x();
int tileHeight = tileSize.Access_size().Get_y();
// maximum integer
if ((float) tileWidth * tileHeight >= Integer.MAX_VALUE) {
// TODO: Customize these settings
tileHeight = 1024;
tileWidth = 1024;
}
codestreamP.setTileWidth(tileWidth);
codestreamP.setTileHeight(tileHeight);
codestreamP.setWidth(imageDims.Access_size().Get_x());
codestreamP.setHeight(imageDims.Access_size().Get_y());
final int nComponents = codestream.Get_num_components();
int maxBitDepth = -1;
int[] componentIndexes = new int[nComponents];
int[] bitsPerComponent = new int[nComponents];
boolean isSigned = false;
for (int i = 0; i < nComponents; i++) {
// TODO: FIX THIS
bitsPerComponent[i] = codestream.Get_bit_depth(i);
if (maxBitDepth < bitsPerComponent[i]) {
maxBitDepth = bitsPerComponent[i];
}
isSigned |= codestream.Get_signed(i);
componentIndexes[i] = i;
}
codestreamP.setNumComponents(nComponents);
codestreamP.setBitsPerComponent(bitsPerComponent);
codestreamP.setComponentIndexes(componentIndexes);
codestreamP.setMaxBitDepth(maxBitDepth);
codestreamP.setSigned(isSigned);
// Initializing Resolution levels and Quality Layers
final int sourceDWTLevels = codestream.Get_min_dwt_levels();
codestreamP.setSourceDWTLevels(sourceDWTLevels);
codestreamP.setMaxSupportedSubSamplingFactor(1 << sourceDWTLevels);
Kdu_coords tileCoords = new Kdu_coords();
tileCoords.Set_x(0);
tileCoords.Set_y(0);
codestream.Open_tile(tileCoords);
codestreamP.setMaxAvailableQualityLayers(codestream.Get_max_tile_layers());
initializeSampleModelAndColorModel(codestreamP);
codestream.Destroy();
multipleCodestreams.add(codestreamP);
if (isRawSource)
break;
}
} catch (KduException e) {
throw new RuntimeException("Error caused by a Kakadu exception during creation of key objects!", e);
} catch (FileNotFoundException e) {
throw new RuntimeException("Exception occurred during kakadu reader initialization", e);
} catch (IOException e) {
throw new RuntimeException("Exception occurred during kakadu reader initialization", e);
} finally {
if (!isRawSource && wrappedSource != null) {
try {
if (wrappedSource.Exists())
wrappedSource.Close();
} catch (Throwable e) {
// yeah I am eating this
}
try {
wrappedSource.Native_destroy();
} catch (Throwable e) {
// yeah I am eating this
}
if (familySource != null) {
try {
if (familySource.Exists())
familySource.Close();
} catch (Throwable e) {
// yeah I am eating this
}
try {
familySource.Native_destroy();
} catch (Throwable e) {
// yeah I am eating this
}
}
} else if (isRawSource && rawSource != null) {
try {
if (wrappedSource.Exists())
wrappedSource.Close();
} catch (Throwable e) {
// yeah I am eating this
}
}
}
// //
//
// Setting input for superclass
//
// //
super.setInput(input, seekForwardOnly, ignoreMetadata);
}
use of kdu_jni.Jpx_codestream_source 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