TJDecompressor.java revision 4f1580cc0e7c33385e88bca7fe08602b87d29aeb
1/*
2 * Copyright (C)2011 D. R. Commander.  All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * - Redistributions of source code must retain the above copyright notice,
8 *   this list of conditions and the following disclaimer.
9 * - Redistributions in binary form must reproduce the above copyright notice,
10 *   this list of conditions and the following disclaimer in the documentation
11 *   and/or other materials provided with the distribution.
12 * - Neither the name of the libjpeg-turbo Project nor the names of its
13 *   contributors may be used to endorse or promote products derived from this
14 *   software without specific prior written permission.
15 *
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 HOLDERS 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.
27 */
28
29package org.libjpegturbo.turbojpeg;
30
31import java.awt.image.*;
32
33public class TJDecompressor {
34
35  public TJDecompressor() throws Exception {
36    init();
37  }
38
39  public TJDecompressor(byte [] buf) throws Exception {
40    setJPEGBuffer(buf, buf.length);
41  }
42
43  public TJDecompressor(byte [] buf, int bufSize) throws Exception {
44    setJPEGBuffer(buf, bufSize);
45  }
46
47  public void setJPEGBuffer(byte [] buf, int bufSize) throws Exception {
48    if(handle == 0) init();
49    if(buf == null || bufSize < 1)
50      throw new Exception("Invalid argument in setJPEGBuffer()");
51    jpegBuf = buf;
52    jpegBufSize = bufSize;
53    decompressHeader(jpegBuf, jpegBufSize);
54  }
55
56  public int getWidth() throws Exception {
57    if(jpegWidth < 1) throw new Exception("JPEG buffer not initialized");
58    return jpegWidth;
59  }
60
61  public int getHeight() throws Exception {
62    if(jpegHeight < 1) throw new Exception("JPEG buffer not initialized");
63    return jpegHeight;
64  }
65
66  public int getSubsamp() throws Exception {
67    if(jpegSubsamp < 0) throw new Exception("JPEG buffer not initialized");
68    if(jpegSubsamp >= TJ.NUMSAMPOPT)
69      throw new Exception("JPEG header information is invalid");
70    return jpegSubsamp;
71  }
72
73  public int getScaledWidth(int desiredWidth, int desiredHeight)
74    throws Exception {
75    if(jpegWidth < 1 || jpegHeight < 1)
76      throw new Exception("JPEG buffer not initialized");
77    if(desiredWidth < 0 || desiredHeight < 0)
78      throw new Exception("Invalid argument in getScaledWidth()");
79    return getScaledWidth(jpegWidth, jpegHeight, desiredWidth,
80      desiredHeight);
81  }
82
83  public int getScaledHeight(int desiredWidth, int desiredHeight)
84    throws Exception {
85    if(jpegWidth < 1 || jpegHeight < 1)
86      throw new Exception("JPEG buffer not initialized");
87    if(desiredWidth < 0 || desiredHeight < 0)
88      throw new Exception("Invalid argument in getScaledHeight()");
89    return getScaledHeight(jpegWidth, jpegHeight, desiredWidth,
90      desiredHeight);
91  }
92
93  public void decompress(byte [] dstBuf, int desiredWidth, int pitch,
94    int desiredHeight, int pixelFormat, int flags) throws Exception {
95    if(jpegBuf == null) throw new Exception("JPEG buffer not initialized");
96    if(dstBuf == null || desiredWidth < 0 || pitch < 0 || desiredHeight < 0
97      || pixelFormat < 0 || pixelFormat >= TJ.NUMPFOPT || flags < 0)
98      throw new Exception("Invalid argument in decompress()");
99    decompress(jpegBuf, jpegBufSize, dstBuf, desiredWidth, pitch,
100      desiredHeight, pixelFormat, flags);
101  }
102
103  public byte [] decompress(int desiredWidth, int pitch, int desiredHeight,
104    int pixelFormat, int flags) throws Exception {
105    if(desiredWidth < 0 || pitch < 0 || desiredHeight < 0
106      || pixelFormat < 0 || pixelFormat >= TJ.NUMPFOPT || flags < 0)
107      throw new Exception("Invalid argument in decompress()");
108    int pixelSize = TJ.getPixelSize(pixelFormat);
109    int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
110    int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
111    if(pitch == 0) pitch = scaledWidth * pixelSize;
112    byte [] buf = new byte[pitch * scaledHeight];
113    decompress(buf, desiredWidth, pitch, desiredHeight, pixelFormat, flags);
114    return buf;
115  }
116
117  public void decompressToYUV(byte [] dstBuf, int flags) throws Exception {
118    if(jpegBuf == null) throw new Exception("JPEG buffer not initialized");
119    if(dstBuf == null || flags < 0)
120      throw new Exception("Invalid argument in decompressToYUV()");
121    decompressToYUV(jpegBuf, jpegBufSize, dstBuf, flags);
122  }
123
124  public byte [] decompressToYUV(int flags) throws Exception {
125    if(flags < 0)
126      throw new Exception("Invalid argument in decompressToYUV()");
127    if(jpegWidth < 1 || jpegHeight < 1 || jpegSubsamp < 0)
128      throw new Exception("JPEG buffer not initialized");
129    if(jpegSubsamp >= TJ.NUMSAMPOPT)
130      throw new Exception("JPEG header information is invalid");
131    byte [] buf = new byte[TJ.bufSizeYUV(jpegWidth, jpegHeight, jpegSubsamp)];
132    decompressToYUV(buf, flags);
133    return buf;
134  }
135
136  public void decompress(BufferedImage dstImage, int flags) throws Exception {
137    if(dstImage == null || flags < 0)
138      throw new Exception("Invalid argument in decompress()");
139    int desiredWidth = dstImage.getWidth();
140    int desiredHeight = dstImage.getHeight();
141    int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
142    int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
143    if(scaledWidth != desiredWidth || scaledHeight != desiredHeight)
144      throw new Exception("BufferedImage dimensions do not match a scaled image size that TurboJPEG is capable of generating.");
145    int pixelFormat;  boolean intPixels=false;
146    switch(dstImage.getType()) {
147      case BufferedImage.TYPE_3BYTE_BGR:
148        pixelFormat=TJ.PF_BGR;  break;
149      case BufferedImage.TYPE_BYTE_GRAY:
150        pixelFormat=TJ.PF_GRAY;  break;
151      case BufferedImage.TYPE_INT_BGR:
152        pixelFormat=TJ.PF_RGBX;  intPixels=true;  break;
153      case BufferedImage.TYPE_INT_RGB:
154        pixelFormat=TJ.PF_BGRX;  intPixels=true;  break;
155      default:
156        throw new Exception("Unsupported BufferedImage format");
157    }
158    WritableRaster wr = dstImage.getRaster();
159    if(intPixels) {
160      SinglePixelPackedSampleModel sm =
161        (SinglePixelPackedSampleModel)dstImage.getSampleModel();
162      int pitch = sm.getScanlineStride();
163      DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
164      int [] buf = db.getData();
165      if(jpegBuf == null) throw new Exception("JPEG buffer not initialized");
166      decompress(jpegBuf, jpegBufSize, buf, scaledWidth, pitch, scaledHeight,
167        pixelFormat, flags);
168    }
169    else {
170      ComponentSampleModel sm =
171        (ComponentSampleModel)dstImage.getSampleModel();
172      int pixelSize = sm.getPixelStride();
173      if(pixelSize != TJ.getPixelSize(pixelFormat))
174        throw new Exception("Inconsistency between pixel format and pixel size in BufferedImage");
175      int pitch = sm.getScanlineStride();
176      DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
177      byte [] buf = db.getData();
178      decompress(buf, scaledWidth, pitch, scaledHeight, pixelFormat, flags);
179    }
180  }
181
182  public BufferedImage decompress(int desiredWidth, int desiredHeight,
183    int bufferedImageType, int flags) throws Exception {
184    if(desiredWidth < 0 || desiredHeight < 0 || flags < 0)
185      throw new Exception("Invalid argument in decompress()");
186    int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
187    int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
188    BufferedImage img = new BufferedImage(scaledWidth, scaledHeight,
189      bufferedImageType);
190    decompress(img, flags);
191    return img;
192  }
193
194  public void close() throws Exception {
195    destroy();
196  }
197
198  protected void finalize() throws Throwable {
199    try {
200      close();
201    } catch(Exception e) {
202    }
203    finally {
204      super.finalize();
205    }
206  };
207
208  private native void init() throws Exception;
209
210  private native void destroy() throws Exception;
211
212  private native void decompressHeader(byte [] srcBuf, int size)
213    throws Exception;
214
215  private native void decompress(byte [] srcBuf, int size, byte [] dstBuf,
216    int desiredWidth, int pitch, int desiredHeight, int pixelFormat, int flags)
217    throws Exception;
218
219  private native void decompress(byte [] srcBuf, int size, int [] dstBuf,
220    int desiredWidth, int pitch, int desiredHeight, int pixelFormat, int flags)
221    throws Exception;
222
223  private native void decompressToYUV(byte [] srcBuf, int size, byte [] dstBuf,
224    int flags)
225    throws Exception;
226
227  private native int getScaledWidth(int jpegWidth, int jpegHeight,
228    int desiredWidth, int desiredHeight) throws Exception;
229
230  private native int getScaledHeight(int jpegWidth, int jpegHeight,
231    int desiredWidth, int desiredHeight) throws Exception;
232
233  static {
234    System.loadLibrary("turbojpeg");
235  }
236
237  private long handle = 0;
238  private byte [] jpegBuf = null;
239  private int jpegBufSize = 0;
240  private int jpegWidth = 0;
241  private int jpegHeight = 0;
242  private int jpegSubsamp = -1;
243};
244