2 * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium
3 * Copyright (c) 2002-2014, Professor Benoit Macq
4 * Copyright (c) 2002-2007, Patrick Piscaglia, Telemis s.a.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
30 import java.util.Vector;
32 /** This class decodes one J2K codestream into an image (width + height + depth + pixels[],
33 * using the OpenJPEG.org library.
34 * To be able to log messages, the called must register a IJavaJ2KDecoderLogger object.
36 public class OpenJPEGJavaDecoder {
38 public interface IJavaJ2KDecoderLogger {
39 public void logDecoderMessage(String message);
40 public void logDecoderError(String message);
43 private static boolean isInitialized = false;
45 // ===== decompression parameters =============>
46 // These value may be changed for each image
47 private String[] decoder_arguments = null;
48 /** number of resolutions decompositions */
49 private int nbResolutions = -1;
50 /** the quality layers */
51 private int[] layers = null;
53 /** Contains the 8 bpp version of the image. May NOT be filled together with image16 or image24.<P>
54 * We store in Java the 8 or 16 bpp version of the image while the decoder uses a 32 bpp version, because <UL>
55 * <LI> the storage capacity required is smaller
56 * <LI> the transfer Java <-- C will be faster
57 * <LI> the conversion byte/short ==> int will be done faster by the C
59 private byte[] image8 = null;
60 /** Contains the 16 bpp version of the image. May NOT be filled together with image8 or image24*/
61 private short[] image16 = null;
62 /** Contains the 24 bpp version of the image. May NOT be filled together with image8 or image16 */
63 private int[] image24 = null;
64 /** Holds the J2K compressed bytecode to decode */
65 private byte compressedStream[] = null;
66 /** Holds the compressed version of the index file, to be used by the decoder */
67 private byte compressedIndex[] = null;
68 /** Width and Height of the image */
69 private int width = -1;
70 private int height = -1;
71 private int depth = -1;
72 /** This parameter is never used in Java but is read by the C library to know the number of resolutions to skip when decoding,
73 * i.e. if there are 5 resolutions and skipped=1 ==> decode until resolution 4. */
74 private int skippedResolutions = 0;
76 private Vector<IJavaJ2KDecoderLogger> loggers = new Vector();
79 public OpenJPEGJavaDecoder(String openJPEGlibraryFullPathAndName, IJavaJ2KDecoderLogger messagesAndErrorsLogger) throws ExceptionInInitializerError
81 this(openJPEGlibraryFullPathAndName);
82 loggers.addElement(messagesAndErrorsLogger);
85 public OpenJPEGJavaDecoder(String openJPEGlibraryFullPathAndName) throws ExceptionInInitializerError
89 System.load(openJPEGlibraryFullPathAndName);
91 } catch (Throwable t) {
92 throw new ExceptionInInitializerError("OpenJPEG Java Decoder: probably impossible to find the C library");
97 public void addLogger(IJavaJ2KDecoderLogger messagesAndErrorsLogger) {
98 loggers.addElement(messagesAndErrorsLogger);
101 public void removeLogger(IJavaJ2KDecoderLogger messagesAndErrorsLogger) {
102 loggers.removeElement(messagesAndErrorsLogger);
105 public int decodeJ2KtoImage() {
106 if ((image16 == null || (image16 != null && image16.length != width*height)) && (depth==-1 || depth==16)) {
107 image16 = new short[width*height];
108 logMessage("OpenJPEGJavaDecoder.decompressImage: image16 length = " + image16.length + " (" + width + " x " + height + ") ");
110 if ((image8 == null || (image8 != null && image8.length != width*height)) && (depth==-1 || depth==8)) {
111 image8 = new byte[width*height];
112 logMessage("OpenJPEGJavaDecoder.decompressImage: image8 length = " + image8.length + " (" + width + " x " + height + ") ");
114 if ((image24 == null || (image24 != null && image24.length != width*height)) && (depth==-1 || depth==24)) {
115 image24 = new int[width*height];
116 logMessage("OpenJPEGJavaDecoder.decompressImage: image24 length = " + image24.length + " (" + width + " x " + height + ") ");
119 String[] arguments = new String[0 + (decoder_arguments != null ? decoder_arguments.length : 0)];
121 if (decoder_arguments != null) {
122 for (int i=0; i<decoder_arguments.length; i++) {
123 arguments[i+offset] = decoder_arguments[i];
127 return internalDecodeJ2KtoImage(arguments);
131 * Decode the j2k stream given in the codestream byte[] and fills the image8, image16 or image24 array, according to the bit depth.
133 private native int internalDecodeJ2KtoImage(String[] parameters);
135 /** Image depth in bpp */
136 public int getDepth() {
140 /** Image depth in bpp */
141 public void setDepth(int depth) {
145 /** Image height in pixels */
146 public int getHeight() {
150 /** Image height in pixels */
151 public void setHeight(int height) {
152 this.height = height;
155 /** Number of resolutions contained in the image */
156 public int getNbResolutions() {
157 return nbResolutions;
160 /** Number of resolutions contained in the image */
161 public void setNbResolutions(int nbResolutions) {
162 this.nbResolutions = nbResolutions;
165 /** Width of the image in pixels */
166 public int getWidth() {
170 /** Width of the image in pixels */
171 public void setWidth(int width) {
175 /** Contains the decompressed version of the image, if the depth in is [9,16] bpp.
176 * Returns NULL otherwise.
178 public short[] getImage16() {
182 /** Contains the decompressed version of the image, if the depth in is [17,24] bpp and the image is in color.
183 * Returns NULL otherwise.
185 public int[] getImage24() {
189 /** Contains the decompressed version of the image, if the depth in is [1,8] bpp.
190 * Returns NULL otherwise.
192 public byte[] getImage8() {
196 /** Sets the compressed version of the index file for this image.
197 * This index file is used by the decompressor
199 public void setCompressedIndex(byte[] compressedIndex) {
200 this.compressedIndex = compressedIndex;
203 /** Sets the codestream to be decoded */
204 public void setCompressedStream(byte[] compressedStream) {
205 this.compressedStream = compressedStream;
208 /** @return the compressed code stream length, or -1 if not defined */
209 public long getCodestreamLength() {
210 if (compressedStream == null)
212 else return compressedStream.length;
215 /** This method is called either directly or by the C methods */
216 public void logMessage(String message) {
217 for (IJavaJ2KDecoderLogger logger:loggers)
218 logger.logDecoderMessage(message);
221 /** This method is called either directly or by the C methods */
222 public void logError(String error) {
223 for (IJavaJ2KDecoderLogger logger:loggers)
224 logger.logDecoderError(error);
227 public void reset() {
233 compressedStream = null;
234 compressedIndex = null;
240 public void setSkippedResolutions(int numberOfSkippedResolutions) {
241 skippedResolutions = numberOfSkippedResolutions;
244 /** Contains all the decoding arguments other than the input/output file */
245 public void setDecoderArguments(String[] argumentsForTheDecoder) {
246 decoder_arguments = argumentsForTheDecoder;