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