use of kdu_jni.Siz_params in project imageio-ext by geosolutions-it.
the class JP2KKakaduImageWriter method initializeCodestream.
/**
* Initialize the codestream params in compliance with the provided arguments.
*
* @param codeStream
* the output codestream
* @param ycc
* the cycc parameter
* @param cLevels
* the number of DWT decomposition levels
* @param quality
* the quality factor (in the range 0.01 - 1. where 1 = LOSSLESS)
* @param qualityLayers
* the number of quality layers
* @param colorModel
* the input image's colorModel
* @param writeCodeStreamOnly
* <code>true</code> if we need to write only codestream.
* @param target
* the optional {@link Jp2_target} object in case we are
* writing only codestream.
* @param orgGen_plt
* if {@code true}, request the insertion of packet length information
* in the header of tile-parts.
* @param orgGen_tlm
* the Tile-part-lenght (TLM) marker marker segments in the main header.
* @param orgT_parts
* parameter setting the division of each tile's packets into tile-parts
* @param qGuard
* parameter setting the guard bits
* @param cOrder
* the {@link ProgressionOrder} to be used.
* @param cPrecincts
* the optional Precincts settings
* @return {@code false} in case we aren't writing codestream only
* and a proper {@link Jp2_target} haven't been provided
*
* @throws KduException
*/
private boolean initializeCodestream(final Kdu_codestream codeStream, final boolean ycc, final int cLevels, final double quality, final int qualityLayers, final ColorModel colorModel, final boolean writeCodeStreamOnly, final int dataType, final Jp2_target target, final byte[] geoJp2, final boolean orgGen_plt, final int orgGen_tlm, final String orgT_parts, final int qGuard, final ProgressionOrder cOrder, final String cPrecincts, final Compression compression) throws KduException {
final Siz_params params = codeStream.Access_siz();
// //
if (compression != null && compression == Compression.LOSSY) {
params.Parse_string("Creversible=no");
} else if (quality == 1 || colorModel instanceof IndexColorModel) {
params.Parse_string("Creversible=yes");
} else {
params.Parse_string("Creversible=no");
}
if (cPrecincts != null && cPrecincts.trim().length() > 0) {
params.Parse_string("Cuse_precincts=yes");
params.Parse_string("Cprecincts=" + cPrecincts);
}
params.Parse_string("Cycc=" + (ycc ? "yes" : "no"));
params.Parse_string("Clevels=" + cLevels);
params.Parse_string("Clayers=" + qualityLayers);
if (dataType == DataBuffer.TYPE_SHORT || dataType == DataBuffer.TYPE_USHORT) {
params.Parse_string("Qstep=0.0000152588");
}
if (qGuard > 0) {
params.Parse_string("Qguard=" + qGuard);
}
// //
//
// Setting ORG_params
//
// //
Kdu_params org = params.Access_cluster(Kdu_global.ORG_params);
if (orgGen_plt) {
org.Set("ORGgen_plt", 0, 0, true);
}
if (orgGen_tlm != JP2KKakaduImageWriteParam.UNSPECIFIED_ORG_GEN_TLM) {
org.Set("ORGgen_tlm", 0, 0, orgGen_tlm);
}
if (orgT_parts != null && orgT_parts.length() > 0) {
org.Parse_string("ORGt_parts=" + orgT_parts);
}
// //
//
// Setting COD_params
//
// //
Kdu_params cod = params.Access_cluster(Kdu_global.COD_params);
if (cOrder != null) {
cod.Set("Corder", 0, 0, cOrder.getValue());
}
// //
//
// Finalizing params
//
// //
params.Finalize_all();
if (!writeCodeStreamOnly) {
if (target == null) {
return false;
}
// //
//
// Writing header
//
// //
initializeHeader(target, params, colorModel);
if (geoJp2 != null && geoJp2.length > 0) {
// Add geoJP2 box here.
// This is a quick solution. The ideal would be to leverage on metadata or on top of a better
// set of entities/helpers
target.Open_next(UUIDBox.BOX_TYPE);
byte[] outByte = new byte[GEOJP2_UUID.length];
for (int i = 0; i < GEOJP2_UUID.length; i++) {
outByte[i] = (byte) GEOJP2_UUID[i];
}
target.Write(outByte, GEOJP2_UUID.length);
target.Write(geoJp2, geoJp2.length);
target.Close();
}
target.Open_codestream();
}
return true;
}
use of kdu_jni.Siz_params 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