/* JP2K Kakadu Image Writer V. 1.0
*
* (c) 2008 Quality Nighthawk Teleradiology Group, Inc.
* Contact: info@qualitynighthawk.com
*
* Produced by GeoSolutions, Eng. Daniele Romagnoli and Eng. Simone Giannecchini
* GeoSolutions S.A.S. --- Via Carignoni 51, 55041 Camaiore (LU) Italy
* Contact: info@geo-solutions.it
*
* Released under the Gnu Lesser General Public License version 3.
* All rights otherwise reserved.
*
* JP2K Kakadu Image Writer is distributed on an "AS IS" basis,
* WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU Lesser General Public License version 3 for more details.
* http://www.fsf.org/licensing/licenses/lgpl.html
*/
package it.geosolutions.imageio.plugins.jp2k;
import javax.imageio.ImageWriteParam;
import kdu_jni.Kdu_global;
/**
* Class holding Write parameters to customize the write operations, and set several fields, tags,
* markers through the kakadu machinery.
*
* @author Daniele Romagnoli, GeoSolutions
* @author Simone Giannecchini, GeoSolutions
*/
public class JP2KKakaduImageWriteParam extends ImageWriteParam {
public static final int UNSPECIFIED_ORG_GEN_TLM = -1;
public enum ProgressionOrder{
LRCP {
int getValue(){
return Kdu_global.Corder_LRCP;
}
},
RLCP {
int getValue(){
return Kdu_global.Corder_RLCP;
}
},
RPCL {
int getValue(){
return Kdu_global.Corder_RPCL;
}
},
PCRL {
int getValue(){
return Kdu_global.Corder_PCRL;
}
},
CPRL {
int getValue(){
return Kdu_global.Corder_CPRL;
}
};
abstract int getValue();
};
/**
* Type of compression to better customize the quality specification.
*/
public enum Compression {
NUMERICALLY_LOSSLESS, LOSSY, UNDEFINED
}
/**
* Default Constructor.
*/
public JP2KKakaduImageWriteParam() {
cLevels = DEFAULT_C_LEVELS;
quality = DEFAULT_QUALITY;
qualityLayers = 1;
canWriteCompressed = true;
compressionMode = MODE_EXPLICIT;
}
@Override
public boolean canWriteTiles() {
return true;
}
/**
* Specifies whether write only the jpeg2000 code stream. The output will be
* a raw codestream.
*/
private boolean writeCodeStreamOnly = false;
/**
* Specifies the quality of the output image as a compression ratio. As an
* instance, a value of 0.2 means a 5:1 compression ratio.
*/
private double quality;
/**
* The default number of decomposition levels.
*/
final static double DEFAULT_QUALITY = 1.0;
/**
* Specify the number of quality layers
*/
private int qualityLayers;
/**
* Specify the number of guard bits
*/
private int qGuard = -1;
/**
* Specify the progression order parameter.
*/
private ProgressionOrder cOrder;
/**
* Specify the number of decompositions levels.
*/
private int cLevels;
/**
* if true, request the insertion of packet length information in the header of tile-parts
*/
private boolean orgGen_plt;
/**
* Controls the division of each tile's packets into tile-parts
*/
private String orgT_parts;
/**
* the cPrecincts settings
*/
private String cPrecincts;
/**
* the bit rate for each quality layers
*/
private double qualityLayersBitRates[];
/**
* The type of compression.
*/
private Compression compression = Compression.UNDEFINED;
/**
* Specify the TLM (tile-part-length) marker segments in the main header.
*/
private int orgGen_tlm = UNSPECIFIED_ORG_GEN_TLM;
/**
* The default number of decomposition levels.
*/
final static int DEFAULT_C_LEVELS = 5;
/**
* The default SProfile, actually: Profile2
*/
final static int DEFAULT_SPROFILE = 2;
/**
*
*/
private byte[] geoJp2 = null;
/**
* Field to override the static property related to adding Comment Markers
* whithin the produced image.
*/
private boolean addCommentMarker = true;
/**
* Restricted profile to which the code-stream conforms.
*/
private int sProfile = DEFAULT_SPROFILE;
/**
* Sets <code>writeCodeStreamOnly</code>.
*
* @param value
* Whether the jpeg2000 code stream only or the jp2 format
* will be written into the output.
* @see #isWriteCodeStreamOnly()
*/
public void setWriteCodeStreamOnly(final boolean writeCodeStreamOnly) {
this.writeCodeStreamOnly = writeCodeStreamOnly;
}
/**
* Gets <code>writeCodeStreamOnly</code>.
*
* @return whether the jpeg2000 code stream only or the jp2 format will be
* written into the output.
* @see #setWriteCodeStreamOnly(boolean)
*/
public boolean isWriteCodeStreamOnly() {
return writeCodeStreamOnly;
}
/**
* Gets <code>quality</code>.
*
* @return the quality parameter.
*
* @see #setQuality(double)
*/
public double getQuality() {
return quality;
}
/**
* Sets <code>quality</code>.
*
* @param quality
* a quality parameter representing a compression ratio. As
* an instance, a 0.2 quality represents a 5:1 compression
* ratio. This parameter will be ignored in case the
* qualityLayersBitRates parameter have been specified or
* in case the Compression parameter has been specified
* through the {@link #setCompression(Compression)} method
* using a {@link Compression#NUMERICALLY_LOSSLESS}
*
* @see #getQuality()
* @see #setQualityLayersBitRates(double[])
* @see #setCompression(Compression)
*/
public void setQuality(final double quality) {
this.quality = quality;
}
/**
* Gets <code>cLevels</code>.
*
* @return the number of decomposition levels.
*
* @see #setCLevels(int)
*/
public int getCLevels() {
return cLevels;
}
/**
* Sets <code>cLevels</code>.
*
* @param cLevels
* the number of decomposition levels.
*
* @see #getCLevels()()
*/
public void setCLevels(final int cLevels) {
this.cLevels = cLevels;
}
/**
* Gets <code>qualityLayers</code>.
*
* @return the number of quality layers.
*
* @see #setQualityLayers(int)
*/
public int getQualityLayers() {
return qualityLayers;
}
/**
* Sets <code>qualityLayers</code>.
*
* @param qualityLayers
* the number of quality layers.
*
* @see #getQualityLayers()
* @see #setQualityLayersBitRates(double[])
* @see #setCompression(Compression)
*/
public void setQualityLayers(final int qualityLayers) {
this.qualityLayers = qualityLayers;
}
public byte[] getGeoJp2() {
return geoJp2;
}
public void setGeoJp2(byte[] geoJp2) {
this.geoJp2 = geoJp2;
}
public void setOrgGen_plt(boolean orgGen_plt) {
this.orgGen_plt = orgGen_plt;
}
public boolean isOrgGen_plt() {
return orgGen_plt;
}
public void setOrgGen_tlm(int orgGen_tlm) {
this.orgGen_tlm = orgGen_tlm;
}
public int getOrgGen_tlm() {
return orgGen_tlm;
}
public void setOrgT_parts(String orgT_parts) {
this.orgT_parts = orgT_parts;
}
public String getOrgT_parts() {
return orgT_parts;
}
public ProgressionOrder getcOrder() {
return cOrder;
}
public void setcOrder(ProgressionOrder cOrder) {
this.cOrder = cOrder;
}
public int getqGuard() {
return qGuard;
}
public void setqGuard(int qGuard) {
this.qGuard = qGuard;
}
public String getcPrecincts() {
return cPrecincts;
}
public void setcPrecincts(String cPrecincts) {
this.cPrecincts = cPrecincts;
}
/**
* Set the qualityLayer bitRates. This parameter will override any quality value specified with
* {@link #setQuality(double)}
*
* @param qualityLayersBitRates an array representing the cumulative bitRate
* for each qualityLayer. The length of the array should be equals
* to the specified qualityLayers value.
*
* @see #setQualityLayers
* @see #setCompression(Compression)
*/
public void setQualityLayersBitRates(double qualityLayersBitRates[]) {
this.qualityLayersBitRates = qualityLayersBitRates;
}
public double[] getQualityLayersBitRates() {
return qualityLayersBitRates;
}
public boolean isAddCommentMarker() {
return addCommentMarker;
}
public void setAddCommentMarker(boolean addCommentMarker) {
this.addCommentMarker = addCommentMarker;
}
public int getsProfile() {
return sProfile;
}
public void setsProfile(int sProfile) {
this.sProfile = sProfile;
}
/**
* Set the compression type. One of {@link Compression#NUMERICALLY_LOSSLESS},
* {@link Compression#LOSSY}.
*
* @param compression the type of compression to apply which could be numerically lossless,
* visually lossless (leveraging on quality bitrates) or lossy (leveraging on quality factor).
* <UL>
* <LI>Use NUMERICALLY_LOSSLESS if you want to specify a LossLess (reversible) compression
* (which is equivalent to specifying a quality = 1 parameter). The quality parameter will be
* ignored.
* Optionally specify a qualityLayersBitRate parameter (make sure to set 0 as the last value
* of the array) if you want to specify the quality layers structure. Otherwise the
* quality layers structure will be built using a dicothomic scale.</LI>
* <LI>Use LOSSY if you want to specify a Visually LossLess compression (which is still lossy).
* You need to specify a qualityLayersBitRate parameter when using this value.
* The quality parameter will be ignored.
* </LI>
* <LI>Use LOSSY if you want to specify a Lossy compression leveraging on the quality
* parameter which should be < 1. In order to leverage on the quality parameter, the
* qualityLayersBitRates parameter shouldn't be specified.
* </LI>
* </UL>
*
* @see #setQualityLayers
* @see #setQuality(double)
* @see #setQualityLayersBitRates(double[])
*/
public void setCompression(Compression compression) {
this.compression = compression;
}
public Compression getCompression() {
return compression;
}
@Override
public String toString() {
return "JP2KKakaduImageWriteParam [writeCodeStreamOnly="
+ writeCodeStreamOnly + ", quality=" + quality
+ ", qualityLayers=" + qualityLayers + ", cOrder="
+ cOrder + ", cLevels=" + cLevels + ", ORGgen_plt="
+ orgGen_plt + ", cPrecincts=" + cPrecincts + ", ORGgen_tlm="
+ orgGen_tlm + ", ORGt_parts=" + orgT_parts +", tilingMode="
+ tilingMode + ", tileWidth=" + tileWidth
+ ", tileHeight=" + tileHeight + "]";
}
}