use of kdu_jni.Kdu_codestream 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.Kdu_codestream 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;
}
use of kdu_jni.Kdu_codestream in project imageio-ext by geosolutions-it.
the class JP2KKakaduImageWriter method write.
@Override
public void write(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param) throws IOException {
// ////////////////////////////////////////////////////////////////////
//
// Variables initialization
//
// ////////////////////////////////////////////////////////////////////
final String fileName = outputFile.getAbsolutePath();
JP2KKakaduImageWriteParam jp2Kparam;
final boolean writeCodeStreamOnly;
final double quality;
int cLayers = 1;
int cLevels;
final boolean cycc;
byte[] geoJp2 = null;
final boolean orgGen_plt;
int orgGen_tlm = JP2KKakaduImageWriteParam.UNSPECIFIED_ORG_GEN_TLM;
int qGuard = -1;
String orgT_parts = null;
String cPrecincts = null;
boolean setTiling = false;
int tileW = Integer.MIN_VALUE;
int tileH = Integer.MIN_VALUE;
ProgressionOrder cOrder = null;
double[] bitRates = null;
boolean addCommentMarker = ADD_COMMENT_MARKER;
int sProfile = JP2KKakaduImageWriteParam.DEFAULT_SPROFILE;
Compression compression = Compression.UNDEFINED;
// //
if (param == null) {
param = getDefaultWriteParam();
}
if (param instanceof JP2KKakaduImageWriteParam) {
jp2Kparam = (JP2KKakaduImageWriteParam) param;
writeCodeStreamOnly = jp2Kparam.isWriteCodeStreamOnly();
bitRates = jp2Kparam.getQualityLayersBitRates();
double q = jp2Kparam.getQuality();
if (q < 0.01) {
q = 0.01;
if (LOGGER.isLoggable(Level.FINE))
LOGGER.fine("Quality level should be in the range 0.01 - 1. /n Reassigning it to 0.01");
}
quality = q;
geoJp2 = jp2Kparam.getGeoJp2();
setTiling = jp2Kparam.getTilingMode() == ImageWriteParam.MODE_EXPLICIT;
if (setTiling) {
tileH = jp2Kparam.getTileHeight();
tileW = jp2Kparam.getTileWidth();
}
// COD PARAMS
cOrder = jp2Kparam.getcOrder();
cPrecincts = jp2Kparam.getcPrecincts();
cLevels = jp2Kparam.getCLevels();
cLayers = jp2Kparam.getQualityLayers();
// ORG PARAMS
orgGen_plt = jp2Kparam.isOrgGen_plt();
orgGen_tlm = jp2Kparam.getOrgGen_tlm();
orgT_parts = jp2Kparam.getOrgT_parts();
qGuard = jp2Kparam.getqGuard();
addCommentMarker &= jp2Kparam.isAddCommentMarker();
sProfile = jp2Kparam.getsProfile();
compression = jp2Kparam.getCompression();
if (bitRates != null && bitRates.length != cLayers) {
throw new IllegalArgumentException(" Specified bitRates parameter's length " + bitRates.length + " should match the quality layers parameter " + "(cLayers): " + cLayers);
}
if (compression != null) {
switch(compression) {
case LOSSY:
if (bitRates != null) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("Applying lossy compression leveraging on provided quality bit rates");
}
} else {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("Applying lossy compression leveraging on quality factor");
}
}
break;
case NUMERICALLY_LOSSLESS:
if (bitRates != null) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("Applying numerically lossless compression leveraging on " + "provided quality bit rates");
}
if (KakaduUtilities.notEqual(bitRates[bitRates.length - 1], 0)) {
throw new IllegalArgumentException("Asking for a Numerically Lossless " + "but the last quality layer's bit rate should be 0 " + " instead of " + bitRates[bitRates.length - 1]);
}
} else {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("Applying numerically lossless compression");
}
}
break;
}
} else {
compression = Compression.UNDEFINED;
}
} else {
orgGen_plt = false;
writeCodeStreamOnly = true;
quality = JP2KKakaduImageWriteParam.DEFAULT_QUALITY;
cLevels = JP2KKakaduImageWriteParam.DEFAULT_C_LEVELS;
}
// ////////////////////////////////////////////////////////////////////
//
// Image properties initialization
//
// ////////////////////////////////////////////////////////////////////
final RenderedImage inputRenderedImage = image.getRenderedImage();
final int sourceWidth = inputRenderedImage.getWidth();
final int sourceHeight = inputRenderedImage.getHeight();
final int sourceMinX = inputRenderedImage.getMinX();
final int sourceMinY = inputRenderedImage.getMinY();
final SampleModel sm = inputRenderedImage.getSampleModel();
final int dataType = sm.getDataType();
final boolean isDataSigned = (dataType != DataBuffer.TYPE_USHORT && dataType != DataBuffer.TYPE_BYTE);
final ColorModel colorModel = inputRenderedImage.getColorModel();
final boolean hasPalette = colorModel instanceof IndexColorModel ? true : false;
final int[] numberOfBits = colorModel.getComponentSize();
// The number of bytes used by header, markers, boxes
int bytesOverHead = 0;
// We suppose all bands share the same bitDepth
final int bits = numberOfBits[0];
int nComponents = sm.getNumBands();
// Array to store optional look up table entries
byte[] reds = null;
byte[] greens = null;
byte[] blues = null;
// //
if (hasPalette) {
cycc = false;
cLevels = 1;
IndexColorModel icm = (IndexColorModel) colorModel;
final int lutSize = icm.getMapSize();
final int numColorComponents = colorModel.getNumColorComponents();
// Updating the number of components to write as RGB (3 bands)
if (writeCodeStreamOnly) {
nComponents = numColorComponents;
// //
//
// Caching look up table for future accesses.
//
// //
reds = new byte[lutSize];
blues = new byte[lutSize];
greens = new byte[lutSize];
icm.getReds(reds);
icm.getGreens(greens);
icm.getBlues(blues);
} else {
// adding pclr and cmap boxes overhead bytes
// NE + NC + Bi
bytesOverHead += (4 + 2 + numColorComponents + 1);
// pclr LUT
bytesOverHead += lutSize * numColorComponents + 4;
// cmap
bytesOverHead += 20;
}
} else if (quality == 1) {
cycc = false;
} else {
cycc = true;
}
// //
//
// Setting regions and sizes and retrieving parameters
//
// //
final int xSubsamplingFactor = param.getSourceXSubsampling();
final int ySubsamplingFactor = param.getSourceYSubsampling();
final Rectangle originalBounds = new Rectangle(sourceMinX, sourceMinY, sourceWidth, sourceHeight);
final Rectangle imageBounds = (Rectangle) originalBounds.clone();
final Dimension destSize = new Dimension();
KakaduUtilities.computeRegions(imageBounds, destSize, param);
boolean resampleInputImage = false;
if (xSubsamplingFactor != 1 || ySubsamplingFactor != 1 || !imageBounds.equals(originalBounds)) {
resampleInputImage = true;
}
// Destination sizes
final int destinationWidth = destSize.width;
final int destinationHeight = destSize.height;
final int rowSize = (destinationWidth * nComponents);
final int bandSize = destinationHeight * destinationWidth;
final int imageSize = bandSize * nComponents;
// ////////////////////////////////////////////////////////////////////
//
// Kakadu objects initialization
//
// ////////////////////////////////////////////////////////////////////
Kdu_compressed_target outputTarget = null;
Jp2_target target = null;
Jp2_family_tgt familyTarget = null;
// Setting decomposition levels
cLevels = setDecompositionLevels(cLevels, destinationWidth);
try {
if (writeCodeStreamOnly) {
// Open a simple file target
outputTarget = new Kdu_simple_file_target();
((Kdu_simple_file_target) outputTarget).Open(fileName);
final int extensionIndex = fileName.lastIndexOf(".");
final String suffix = fileName.substring(extensionIndex, fileName.length());
if (suffix.equalsIgnoreCase(".jp2") && LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("When writing codestreams, the \".j2c\" file suffix is suggested instead of \".jp2\"");
}
} else {
familyTarget = new Jp2_family_tgt();
familyTarget.Open(fileName);
target = new Jp2_target();
target.Open(familyTarget);
// Adding signature, fileType, image header, Jp2Header box bytes
// + jp2c marker.
bytesOverHead += 84;
if (geoJp2 != null) {
bytesOverHead += geoJp2.length;
}
}
bytesOverHead += addMarkerBytes(nComponents, destinationWidth, destinationHeight, tileW, tileH, orgGen_tlm, addCommentMarker);
if (bytesOverHead >= imageSize) {
bytesOverHead = 0;
}
final long qualityLayersSize = bitRates != null ? imageSize : (long) ((imageSize - bytesOverHead) * quality * bits * KakaduUtilities.BIT_TO_BYTE_FACTOR);
// //
//
// Parameters initialization
//
// //
final Kdu_codestream codeStream = new Kdu_codestream();
Siz_params params = new Siz_params();
initializeParams(params, destinationWidth, destinationHeight, bits, nComponents, isDataSigned, tileW, tileH, sProfile);
// Create a codestream on the proper output object.
if (writeCodeStreamOnly) {
codeStream.Create(params, outputTarget, null);
} else {
codeStream.Create(params, target, null);
}
if (!initializeCodestream(codeStream, cycc, cLevels, quality, cLayers, colorModel, writeCodeStreamOnly, dataType, target, geoJp2, orgGen_plt, orgGen_tlm, orgT_parts, qGuard, cOrder, cPrecincts, compression)) {
throw new IOException("Unable to initialize the codestream due to a missing " + "Jp2_target object");
}
// //
//
// Preparing parameters for stripe compression
//
// //
final Kdu_stripe_compressor compressor = new Kdu_stripe_compressor();
// Array with one entry for each image component, identifying the
// number of lines supplied 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[] sampleGaps = 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[] rowGaps = 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[] sampleOffsets = new int[nComponents];
// Array with one entry for each image component, identifying the
// number of significant bits used to represent each sample.
final int[] precisions = new int[nComponents];
initializeStripeCompressor(compressor, codeStream, quality, cLayers, qualityLayersSize, bitRates, compression, rowSize, destinationHeight, destinationWidth, nComponents, stripeHeights, sampleGaps, rowGaps, sampleOffsets, precisions, numberOfBits, addCommentMarker);
// ////////////////////////////////////////////////////////////////
//
// Pushing Stripes
//
// ////////////////////////////////////////////////////////////////
pushStripes(compressor, inputRenderedImage, imageBounds, originalBounds, isDataSigned, resampleInputImage, writeCodeStreamOnly, hasPalette, nComponents, bits, destinationWidth, destinationHeight, xSubsamplingFactor, ySubsamplingFactor, stripeHeights, sampleGaps, rowGaps, sampleOffsets, precisions, reds, greens, blues);
// ////////////////////////////////////////////////////////////////
//
// Kakadu Objects Finalization
//
// ////////////////////////////////////////////////////////////////
compressor.Finish();
compressor.Native_destroy();
codeStream.Destroy();
} catch (KduException e) {
throw (IOException) new IOException("Error caused by a Kakadu exception during write operation").initCause(e);
} finally {
// //
if (!writeCodeStreamOnly && target != null) {
try {
if (target.Exists())
target.Close();
} catch (Throwable e) {
// Does Nothing
}
try {
target.Native_destroy();
} catch (Throwable e) {
// Does Nothing
}
if (familyTarget != null) {
try {
if (familyTarget.Exists())
familyTarget.Close();
} catch (Throwable e) {
// Does Nothing
}
try {
familyTarget.Native_destroy();
} catch (Throwable e) {
// Does Nothing
}
}
} else if (writeCodeStreamOnly && outputTarget != null) {
try {
outputTarget.Close();
} catch (Throwable e) {
// Does Nothing
}
try {
outputTarget.Native_destroy();
} catch (Throwable e) {
// Does Nothing
}
}
// //
if (outputStream != null) {
writeOnStream();
}
}
}
Aggregations