work in progress, cleaned up the directories and split them up into folder which make more sense, Still need to compile libvitaboy and all the tools

This commit is contained in:
Jip 2024-05-13 18:38:21 +02:00
parent 66ce473514
commit 948bd8474c
1786 changed files with 571812 additions and 15332 deletions

View file

@ -0,0 +1,350 @@
/*
* Copyright (C)2011 D. R. Commander. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the libjpeg-turbo Project nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.libjpegturbo.turbojpeg;
/**
* TurboJPEG utility class (cannot be instantiated)
*/
final public class TJ {
/**
* The number of chrominance subsampling options
*/
final public static int NUMSAMP = 5;
/**
* 4:4:4 chrominance subsampling (no chrominance subsampling). The JPEG
* or YUV image will contain one chrominance component for every pixel in the
* source image.
*/
final public static int SAMP_444 = 0;
/**
* 4:2:2 chrominance subsampling. The JPEG or YUV image will contain one
* chrominance component for every 2x1 block of pixels in the source image.
*/
final public static int SAMP_422 = 1;
/**
* 4:2:0 chrominance subsampling. The JPEG or YUV image will contain one
* chrominance component for every 2x2 block of pixels in the source image.
*/
final public static int SAMP_420 = 2;
/**
* Grayscale. The JPEG or YUV image will contain no chrominance components.
*/
final public static int SAMP_GRAY = 3;
/**
* 4:4:0 chrominance subsampling. The JPEG or YUV image will contain one
* chrominance component for every 1x2 block of pixels in the source image.
*/
final public static int SAMP_440 = 4;
/**
* Returns the MCU block width for the given level of chrominance
* subsampling.
*
* @param subsamp the level of chrominance subsampling (one of
* <code>SAMP_*</code>)
*
* @return the MCU block width for the given level of chrominance subsampling
*/
public static int getMCUWidth(int subsamp) throws Exception {
if(subsamp < 0 || subsamp >= NUMSAMP)
throw new Exception("Invalid subsampling type");
return mcuWidth[subsamp];
}
final private static int mcuWidth[] = {
8, 16, 16, 8, 8
};
/**
* Returns the MCU block height for the given level of chrominance
* subsampling.
*
* @param subsamp the level of chrominance subsampling (one of
* <code>SAMP_*</code>)
*
* @return the MCU block height for the given level of chrominance
* subsampling
*/
public static int getMCUHeight(int subsamp) throws Exception {
if(subsamp < 0 || subsamp >= NUMSAMP)
throw new Exception("Invalid subsampling type");
return mcuHeight[subsamp];
}
final private static int mcuHeight[] = {
8, 8, 16, 8, 16
};
/**
* The number of pixel formats
*/
final public static int NUMPF = 11;
/**
* RGB pixel format. The red, green, and blue components in the image are
* stored in 3-byte pixels in the order R, G, B from lowest to highest byte
* address within each pixel.
*/
final public static int PF_RGB = 0;
/**
* BGR pixel format. The red, green, and blue components in the image are
* stored in 3-byte pixels in the order B, G, R from lowest to highest byte
* address within each pixel.
*/
final public static int PF_BGR = 1;
/**
* RGBX pixel format. The red, green, and blue components in the image are
* stored in 4-byte pixels in the order R, G, B from lowest to highest byte
* address within each pixel. The X component is ignored when compressing
* and undefined when decompressing.
*/
final public static int PF_RGBX = 2;
/**
* BGRX pixel format. The red, green, and blue components in the image are
* stored in 4-byte pixels in the order B, G, R from lowest to highest byte
* address within each pixel. The X component is ignored when compressing
* and undefined when decompressing.
*/
final public static int PF_BGRX = 3;
/**
* XBGR pixel format. The red, green, and blue components in the image are
* stored in 4-byte pixels in the order R, G, B from highest to lowest byte
* address within each pixel. The X component is ignored when compressing
* and undefined when decompressing.
*/
final public static int PF_XBGR = 4;
/**
* XRGB pixel format. The red, green, and blue components in the image are
* stored in 4-byte pixels in the order B, G, R from highest to lowest byte
* address within each pixel. The X component is ignored when compressing
* and undefined when decompressing.
*/
final public static int PF_XRGB = 5;
/**
* Grayscale pixel format. Each 1-byte pixel represents a luminance
* (brightness) level from 0 to 255.
*/
final public static int PF_GRAY = 6;
/**
* RGBA pixel format. This is the same as {@link #PF_RGBX}, except that when
* decompressing, the X byte is guaranteed to be 0xFF, which can be
* interpreted as an opaque alpha channel.
*/
final public static int PF_RGBA = 7;
/**
* BGRA pixel format. This is the same as {@link #PF_BGRX}, except that when
* decompressing, the X byte is guaranteed to be 0xFF, which can be
* interpreted as an opaque alpha channel.
*/
final public static int PF_BGRA = 8;
/**
* ABGR pixel format. This is the same as {@link #PF_XBGR}, except that when
* decompressing, the X byte is guaranteed to be 0xFF, which can be
* interpreted as an opaque alpha channel.
*/
final public static int PF_ABGR = 9;
/**
* ARGB pixel format. This is the same as {@link #PF_XRGB}, except that when
* decompressing, the X byte is guaranteed to be 0xFF, which can be
* interpreted as an opaque alpha channel.
*/
final public static int PF_ARGB = 10;
/**
* Returns the pixel size (in bytes) of the given pixel format.
*
* @param pixelFormat the pixel format (one of <code>PF_*</code>)
*
* @return the pixel size (in bytes) of the given pixel format
*/
public static int getPixelSize(int pixelFormat) throws Exception {
if(pixelFormat < 0 || pixelFormat >= NUMPF)
throw new Exception("Invalid pixel format");
return pixelSize[pixelFormat];
}
final private static int pixelSize[] = {
3, 3, 4, 4, 4, 4, 1, 4, 4, 4, 4
};
/**
* For the given pixel format, returns the number of bytes that the red
* component is offset from the start of the pixel. For instance, if a pixel
* of format <code>TJ.PF_BGRX</code> is stored in <code>char pixel[]</code>,
* then the red component will be
* <code>pixel[TJ.getRedOffset(TJ.PF_BGRX)]</code>.
*
* @param pixelFormat the pixel format (one of <code>PF_*</code>)
*
* @return the red offset for the given pixel format
*/
public static int getRedOffset(int pixelFormat) throws Exception {
if(pixelFormat < 0 || pixelFormat >= NUMPF)
throw new Exception("Invalid pixel format");
return redOffset[pixelFormat];
}
final private static int redOffset[] = {
0, 2, 0, 2, 3, 1, 0, 0, 2, 3, 1
};
/**
* For the given pixel format, returns the number of bytes that the green
* component is offset from the start of the pixel. For instance, if a pixel
* of format <code>TJ.PF_BGRX</code> is stored in <code>char pixel[]</code>,
* then the green component will be
* <code>pixel[TJ.getGreenOffset(TJ.PF_BGRX)]</code>.
*
* @param pixelFormat the pixel format (one of <code>PF_*</code>)
*
* @return the green offset for the given pixel format
*/
public static int getGreenOffset(int pixelFormat) throws Exception {
if(pixelFormat < 0 || pixelFormat >= NUMPF)
throw new Exception("Invalid pixel format");
return greenOffset[pixelFormat];
}
final private static int greenOffset[] = {
1, 1, 1, 1, 2, 2, 0, 1, 1, 2, 2
};
/**
* For the given pixel format, returns the number of bytes that the blue
* component is offset from the start of the pixel. For instance, if a pixel
* of format <code>TJ.PF_BGRX</code> is stored in <code>char pixel[]</code>,
* then the blue component will be
* <code>pixel[TJ.getBlueOffset(TJ.PF_BGRX)]</code>.
*
* @param pixelFormat the pixel format (one of <code>PF_*</code>)
*
* @return the blue offset for the given pixel format
*/
public static int getBlueOffset(int pixelFormat) throws Exception {
if(pixelFormat < 0 || pixelFormat >= NUMPF)
throw new Exception("Invalid pixel format");
return blueOffset[pixelFormat];
}
final private static int blueOffset[] = {
2, 0, 2, 0, 1, 3, 0, 2, 0, 1, 3
};
/**
* The uncompressed source/destination image is stored in bottom-up (Windows,
* OpenGL) order, not top-down (X11) order.
*/
final public static int FLAG_BOTTOMUP = 2;
/**
* Turn off CPU auto-detection and force TurboJPEG to use MMX code
* (IPP and 32-bit libjpeg-turbo versions only.)
*/
final public static int FLAG_FORCEMMX = 8;
/**
* Turn off CPU auto-detection and force TurboJPEG to use SSE code
* (32-bit IPP and 32-bit libjpeg-turbo versions only.)
*/
final public static int FLAG_FORCESSE = 16;
/**
* Turn off CPU auto-detection and force TurboJPEG to use SSE2 code
* (32-bit IPP and 32-bit libjpeg-turbo versions only.)
*/
final public static int FLAG_FORCESSE2 = 32;
/**
* Turn off CPU auto-detection and force TurboJPEG to use SSE3 code
*(64-bit IPP version only.)
*/
final public static int FLAG_FORCESSE3 = 128;
/**
* Use fast, inaccurate chrominance upsampling routines in the JPEG
* decompressor (libjpeg and libjpeg-turbo versions only.)
*/
final public static int FLAG_FASTUPSAMPLE = 256;
/**
* Returns the maximum size of the buffer (in bytes) required to hold a JPEG
* image with the given width and height, and level of chrominance
* subsampling.
*
* @param width the width (in pixels) of the JPEG image
*
* @param height the height (in pixels) of the JPEG image
*
* @param jpegSubsamp the level of chrominance subsampling to be used when
* generating the JPEG image (one of {@link TJ TJ.SAMP_*})
*
* @return the maximum size of the buffer (in bytes) required to hold a JPEG
* image with the given width and height, and level of chrominance
* subsampling
*/
public native static int bufSize(int width, int height, int jpegSubsamp)
throws Exception;
/**
* Returns the size of the buffer (in bytes) required to hold a YUV planar
* image with the given width, height, and level of chrominance subsampling.
*
* @param width the width (in pixels) of the YUV image
*
* @param height the height (in pixels) of the YUV image
*
* @param subsamp the level of chrominance subsampling used in the YUV
* image (one of {@link TJ TJ.SAMP_*})
*
* @return the size of the buffer (in bytes) required to hold a YUV planar
* image with the given width, height, and level of chrominance subsampling
*/
public native static int bufSizeYUV(int width, int height,
int subsamp)
throws Exception;
/**
* Returns a list of fractional scaling factors that the JPEG decompressor in
* this implementation of TurboJPEG supports.
*
* @return a list of fractional scaling factors that the JPEG decompressor in
* this implementation of TurboJPEG supports
*/
public native static TJScalingFactor[] getScalingFactors()
throws Exception;
static {
TJLoader.load();
}
};

View file

@ -0,0 +1,470 @@
/*
* Copyright (C)2011 D. R. Commander. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the libjpeg-turbo Project nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.libjpegturbo.turbojpeg;
import java.awt.image.*;
import java.nio.*;
/**
* TurboJPEG compressor
*/
public class TJCompressor {
private final static String NO_ASSOC_ERROR =
"No source image is associated with this instance";
/**
* Create a TurboJPEG compressor instance.
*/
public TJCompressor() throws Exception {
init();
}
/**
* Create a TurboJPEG compressor instance and associate the uncompressed
* source image stored in <code>srcImage</code> with the newly-created
* instance.
*
* @param srcImage see {@link #setSourceImage} for description
*
* @param width see {@link #setSourceImage} for description
*
* @param pitch see {@link #setSourceImage} for description
*
* @param height see {@link #setSourceImage} for description
*
* @param pixelFormat see {@link #setSourceImage} for description
*/
public TJCompressor(byte[] srcImage, int width, int pitch, int height,
int pixelFormat) throws Exception {
setSourceImage(srcImage, width, pitch, height, pixelFormat);
}
/**
* Associate an uncompressed source image with this compressor instance.
*
* @param srcImage image buffer containing RGB or grayscale pixels to be
* compressed
*
* @param width width (in pixels) of the source image
*
* @param pitch bytes per line of the source image. Normally, this should be
* <code>width * TJ.pixelSize(pixelFormat)</code> if the source image is
* unpadded, but you can use this parameter to, for instance, specify that
* the scanlines in the source image are padded to 4-byte boundaries, as is
* the case for Windows bitmaps. You can also be clever and use this
* parameter to skip lines, etc. Setting this parameter to 0 is the
* equivalent of setting it to <code>width *
* TJ.pixelSize(pixelFormat)</code>.
*
* @param height height (in pixels) of the source image
*
* @param pixelFormat pixel format of the source image (one of
* {@link TJ TJ.PF_*})
*/
public void setSourceImage(byte[] srcImage, int width, int pitch,
int height, int pixelFormat) throws Exception {
if(handle == 0) init();
if(srcImage == null || width < 1 || height < 1 || pitch < 0
|| pixelFormat < 0 || pixelFormat >= TJ.NUMPF)
throw new Exception("Invalid argument in setSourceImage()");
srcBuf = srcImage;
srcWidth = width;
if(pitch == 0) srcPitch = width * TJ.getPixelSize(pixelFormat);
else srcPitch = pitch;
srcHeight = height;
srcPixelFormat = pixelFormat;
}
/**
* Set the level of chrominance subsampling for subsequent compress/encode
* operations.
*
* @param newSubsamp the new level of chrominance subsampling (one of
* {@link TJ TJ.SAMP_*})
*/
public void setSubsamp(int newSubsamp) throws Exception {
if(newSubsamp < 0 || newSubsamp >= TJ.NUMSAMP)
throw new Exception("Invalid argument in setSubsamp()");
subsamp = newSubsamp;
}
/**
* Set the JPEG image quality level for subsequent compress operations.
*
* @param quality the new JPEG image quality level (1 to 100, 1 = worst,
* 100 = best)
*/
public void setJPEGQuality(int quality) throws Exception {
if(quality < 1 || quality > 100)
throw new Exception("Invalid argument in setJPEGQuality()");
jpegQuality = quality;
}
/**
* Compress the uncompressed source image associated with this compressor
* instance and output a JPEG image to the given destination buffer.
*
* @param dstBuf buffer that will receive the JPEG image. Use
* {@link TJ#bufSize} to determine the maximum size for this buffer based on
* the image width and height.
*
* @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
*/
public void compress(byte[] dstBuf, int flags) throws Exception {
if(dstBuf == null || flags < 0)
throw new Exception("Invalid argument in compress()");
if(srcBuf == null) throw new Exception(NO_ASSOC_ERROR);
if(jpegQuality < 0) throw new Exception("JPEG Quality not set");
if(subsamp < 0) throw new Exception("Subsampling level not set");
compressedSize = compress(srcBuf, srcWidth, srcPitch,
srcHeight, srcPixelFormat, dstBuf, subsamp, jpegQuality, flags);
}
/**
* Compress the uncompressed source image associated with this compressor
* instance and return a buffer containing a JPEG image.
*
* @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
*
* @return a buffer containing a JPEG image. The length of this buffer will
* not be equal to the size of the JPEG image. Use {@link
* #getCompressedSize} to obtain the size of the JPEG image.
*/
public byte[] compress(int flags) throws Exception {
if(srcWidth < 1 || srcHeight < 1)
throw new Exception(NO_ASSOC_ERROR);
byte[] buf = new byte[TJ.bufSize(srcWidth, srcHeight, subsamp)];
compress(buf, flags);
return buf;
}
/**
* Compress the uncompressed source image stored in <code>srcImage</code>
* and output a JPEG image to the given destination buffer.
*
* @param srcImage a <code>BufferedImage</code> instance containing RGB or
* grayscale pixels to be compressed
*
* @param dstBuf buffer that will receive the JPEG image. Use
* {@link TJ#bufSize} to determine the maximum size for this buffer based on
* the image width and height.
*
* @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
*/
public void compress(BufferedImage srcImage, byte[] dstBuf, int flags)
throws Exception {
if(srcImage == null || dstBuf == null || flags < 0)
throw new Exception("Invalid argument in compress()");
int width = srcImage.getWidth();
int height = srcImage.getHeight();
int pixelFormat; boolean intPixels = false;
if(byteOrder == null)
byteOrder = ByteOrder.nativeOrder();
switch(srcImage.getType()) {
case BufferedImage.TYPE_3BYTE_BGR:
pixelFormat = TJ.PF_BGR; break;
case BufferedImage.TYPE_4BYTE_ABGR:
case BufferedImage.TYPE_4BYTE_ABGR_PRE:
pixelFormat = TJ.PF_XBGR; break;
case BufferedImage.TYPE_BYTE_GRAY:
pixelFormat = TJ.PF_GRAY; break;
case BufferedImage.TYPE_INT_BGR:
if(byteOrder == ByteOrder.BIG_ENDIAN)
pixelFormat = TJ.PF_XBGR;
else
pixelFormat = TJ.PF_RGBX;
intPixels = true; break;
case BufferedImage.TYPE_INT_RGB:
case BufferedImage.TYPE_INT_ARGB:
case BufferedImage.TYPE_INT_ARGB_PRE:
if(byteOrder == ByteOrder.BIG_ENDIAN)
pixelFormat = TJ.PF_XRGB;
else
pixelFormat = TJ.PF_BGRX;
intPixels = true; break;
default:
throw new Exception("Unsupported BufferedImage format");
}
WritableRaster wr = srcImage.getRaster();
if(jpegQuality < 0) throw new Exception("JPEG Quality not set");
if(subsamp < 0) throw new Exception("Subsampling level not set");
if(intPixels) {
SinglePixelPackedSampleModel sm =
(SinglePixelPackedSampleModel)srcImage.getSampleModel();
int pitch = sm.getScanlineStride();
DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
int[] buf = db.getData();
compressedSize = compress(buf, width, pitch, height, pixelFormat, dstBuf,
subsamp, jpegQuality, flags);
}
else {
ComponentSampleModel sm =
(ComponentSampleModel)srcImage.getSampleModel();
int pixelSize = sm.getPixelStride();
if(pixelSize != TJ.getPixelSize(pixelFormat))
throw new Exception("Inconsistency between pixel format and pixel size in BufferedImage");
int pitch = sm.getScanlineStride();
DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
byte[] buf = db.getData();
compressedSize = compress(buf, width, pitch, height, pixelFormat, dstBuf,
subsamp, jpegQuality, flags);
}
}
/**
* Compress the uncompressed source image stored in <code>srcImage</code>
* and return a buffer containing a JPEG image.
*
* @param srcImage a <code>BufferedImage</code> instance containing RGB or
* grayscale pixels to be compressed
*
* @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
*
* @return a buffer containing a JPEG image. The length of this buffer will
* not be equal to the size of the JPEG image. Use {@link
* #getCompressedSize} to obtain the size of the JPEG image.
*/
public byte[] compress(BufferedImage srcImage, int flags) throws Exception {
int width = srcImage.getWidth();
int height = srcImage.getHeight();
byte[] buf = new byte[TJ.bufSize(width, height, subsamp)];
compress(srcImage, buf, flags);
return buf;
}
/**
* Encode the uncompressed source image associated with this compressor
* instance and output a YUV planar image to the given destination buffer.
* This method uses the accelerated color conversion routines in
* TurboJPEG's underlying codec to produce a planar YUV image that is
* suitable for direct video display. Specifically, if the chrominance
* components are subsampled along the horizontal dimension, then the width
* of the luminance plane is padded to 2 in the output image (same goes for
* the height of the luminance plane, if the chrominance components are
* subsampled along the vertical dimension.) Also, each line of each plane
* in the output image is padded to 4 bytes. Although this will work with
* any subsampling option, it is really only useful in combination with
* {@link TJ#SAMP_420}, which produces an image compatible with the I420 (AKA
* "YUV420P") format.
*
* @param dstBuf buffer that will receive the YUV planar image. Use
* {@link TJ#bufSizeYUV} to determine the appropriate size for this buffer
* based on the image width, height, and level of chrominance subsampling.
*
* @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
*/
public void encodeYUV(byte[] dstBuf, int flags) throws Exception {
if(dstBuf == null || flags < 0)
throw new Exception("Invalid argument in compress()");
if(srcBuf == null) throw new Exception(NO_ASSOC_ERROR);
if(subsamp < 0) throw new Exception("Subsampling level not set");
encodeYUV(srcBuf, srcWidth, srcPitch, srcHeight,
srcPixelFormat, dstBuf, subsamp, flags);
compressedSize = TJ.bufSizeYUV(srcWidth, srcHeight, subsamp);
}
/**
* Encode the uncompressed source image associated with this compressor
* instance and return a buffer containing a YUV planar image. See
* {@link #encodeYUV(byte[], int)} for more detail.
*
* @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
*
* @return a buffer containing a YUV planar image
*/
public byte[] encodeYUV(int flags) throws Exception {
if(srcWidth < 1 || srcHeight < 1)
throw new Exception(NO_ASSOC_ERROR);
if(subsamp < 0) throw new Exception("Subsampling level not set");
byte[] buf = new byte[TJ.bufSizeYUV(srcWidth, srcHeight, subsamp)];
encodeYUV(buf, flags);
return buf;
}
/**
* Encode the uncompressed source image stored in <code>srcImage</code>
* and output a YUV planar image to the given destination buffer. See
* {@link #encodeYUV(byte[], int)} for more detail.
*
* @param srcImage a <code>BufferedImage</code> instance containing RGB or
* grayscale pixels to be encoded
*
* @param dstBuf buffer that will receive the YUV planar image. Use
* {@link TJ#bufSizeYUV} to determine the appropriate size for this buffer
* based on the image width, height, and level of chrominance subsampling.
*
* @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
*/
public void encodeYUV(BufferedImage srcImage, byte[] dstBuf, int flags)
throws Exception {
if(srcImage == null || dstBuf == null || flags < 0)
throw new Exception("Invalid argument in encodeYUV()");
int width = srcImage.getWidth();
int height = srcImage.getHeight();
int pixelFormat; boolean intPixels = false;
if(byteOrder == null)
byteOrder = ByteOrder.nativeOrder();
switch(srcImage.getType()) {
case BufferedImage.TYPE_3BYTE_BGR:
pixelFormat = TJ.PF_BGR; break;
case BufferedImage.TYPE_4BYTE_ABGR:
case BufferedImage.TYPE_4BYTE_ABGR_PRE:
pixelFormat = TJ.PF_XBGR; break;
case BufferedImage.TYPE_BYTE_GRAY:
pixelFormat = TJ.PF_GRAY; break;
case BufferedImage.TYPE_INT_BGR:
if(byteOrder == ByteOrder.BIG_ENDIAN)
pixelFormat = TJ.PF_XBGR;
else
pixelFormat = TJ.PF_RGBX;
intPixels = true; break;
case BufferedImage.TYPE_INT_RGB:
case BufferedImage.TYPE_INT_ARGB:
case BufferedImage.TYPE_INT_ARGB_PRE:
if(byteOrder == ByteOrder.BIG_ENDIAN)
pixelFormat = TJ.PF_XRGB;
else
pixelFormat = TJ.PF_BGRX;
intPixels = true; break;
default:
throw new Exception("Unsupported BufferedImage format");
}
WritableRaster wr = srcImage.getRaster();
if(subsamp < 0) throw new Exception("Subsampling level not set");
if(intPixels) {
SinglePixelPackedSampleModel sm =
(SinglePixelPackedSampleModel)srcImage.getSampleModel();
int pitch = sm.getScanlineStride();
DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
int[] buf = db.getData();
encodeYUV(buf, width, pitch, height, pixelFormat, dstBuf, subsamp,
flags);
}
else {
ComponentSampleModel sm =
(ComponentSampleModel)srcImage.getSampleModel();
int pixelSize = sm.getPixelStride();
if(pixelSize != TJ.getPixelSize(pixelFormat))
throw new Exception("Inconsistency between pixel format and pixel size in BufferedImage");
int pitch = sm.getScanlineStride();
DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
byte[] buf = db.getData();
encodeYUV(buf, width, pitch, height, pixelFormat, dstBuf, subsamp,
flags);
}
compressedSize = TJ.bufSizeYUV(width, height, subsamp);
}
/**
* Encode the uncompressed source image stored in <code>srcImage</code>
* and return a buffer containing a YUV planar image. See
* {@link #encodeYUV(byte[], int)} for more detail.
*
* @param srcImage a <code>BufferedImage</code> instance containing RGB or
* grayscale pixels to be encoded
*
* @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
*
* @return a buffer containing a YUV planar image
*/
public byte[] encodeYUV(BufferedImage srcImage, int flags)
throws Exception {
if(subsamp < 0) throw new Exception("Subsampling level not set");
int width = srcImage.getWidth();
int height = srcImage.getHeight();
byte[] buf = new byte[TJ.bufSizeYUV(width, height, subsamp)];
encodeYUV(srcImage, buf, flags);
return buf;
}
/**
* Returns the size of the image (in bytes) generated by the most recent
* compress/encode operation.
*
* @return the size of the image (in bytes) generated by the most recent
* compress/encode operation
*/
public int getCompressedSize() {
return compressedSize;
}
/**
* Free the native structures associated with this compressor instance.
*/
public void close() throws Exception {
destroy();
}
protected void finalize() throws Throwable {
try {
close();
}
catch(Exception e) {}
finally {
super.finalize();
}
};
private native void init() throws Exception;
private native void destroy() throws Exception;
// JPEG size in bytes is returned
private native int compress(byte[] srcBuf, int width, int pitch,
int height, int pixelFormat, byte[] dstbuf, int jpegSubsamp, int jpegQual,
int flags) throws Exception;
private native int compress(int[] srcBuf, int width, int pitch,
int height, int pixelFormat, byte[] dstbuf, int jpegSubsamp, int jpegQual,
int flags) throws Exception;
private native void encodeYUV(byte[] srcBuf, int width, int pitch,
int height, int pixelFormat, byte[] dstbuf, int subsamp, int flags)
throws Exception;
private native void encodeYUV(int[] srcBuf, int width, int pitch,
int height, int pixelFormat, byte[] dstbuf, int subsamp, int flags)
throws Exception;
static {
TJLoader.load();
}
private long handle = 0;
private byte[] srcBuf = null;
private int srcWidth = 0;
private int srcHeight = 0;
private int srcPitch = 0;
private int srcPixelFormat = -1;
private int subsamp = -1;
private int jpegQuality = -1;
private int compressedSize = 0;
private ByteOrder byteOrder = null;
};

View file

@ -0,0 +1,76 @@
/*
* Copyright (C)2011 D. R. Commander. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the libjpeg-turbo Project nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.libjpegturbo.turbojpeg;
import java.awt.*;
import java.nio.*;
/**
* Custom filter callback interface
*/
public interface TJCustomFilter {
/**
* A callback function that can be used to modify the DCT coefficients after
* they are losslessly transformed but before they are transcoded to a new
* JPEG file. This allows for custom filters or other transformations to be
* applied in the frequency domain.
*
* @param coeffBuffer a buffer containing transformed DCT coefficients.
* (NOTE: this buffer is not guaranteed to be valid once the callback
* returns, so applications wishing to hand off the DCT coefficients to
* another function or library should make a copy of them within the body of
* the callback.)
*
* @param bufferRegion rectangle containing the width and height of
* <code>coeffBuffer</code> as well as its offset relative to the component
* plane. TurboJPEG implementations may choose to split each component plane
* into multiple DCT coefficient buffers and call the callback function once
* for each buffer.
*
* @param planeRegion rectangle containing the width and height of the
* component plane to which <code>coeffBuffer</code> belongs
*
* @param componentID ID number of the component plane to which
* <code>coeffBuffer</code>belongs (Y, Cb, and Cr have, respectively, ID's of
* 0, 1, and 2 in typical JPEG images.)
*
* @param transformID ID number of the transformed image to which
* <code>coeffBuffer</code> belongs. This is the same as the index of the
* transform in the transforms array that was passed to {@link
* TJTransformer#transform TJTransformer.transform()}.
*
* @param transform a {@link TJTransform} instance that specifies the
* parameters and/or cropping region for this transform
*/
public void customFilter(ShortBuffer coeffBuffer, Rectangle bufferRegion,
Rectangle planeRegion, int componentID, int transformID,
TJTransform transform)
throws Exception;
}

View file

@ -0,0 +1,520 @@
/*
* Copyright (C)2011 D. R. Commander. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the libjpeg-turbo Project nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.libjpegturbo.turbojpeg;
import java.awt.image.*;
import java.nio.*;
/**
* TurboJPEG decompressor
*/
public class TJDecompressor {
private final static String NO_ASSOC_ERROR =
"No JPEG image is associated with this instance";
/**
* Create a TurboJPEG decompresssor instance.
*/
public TJDecompressor() throws Exception {
init();
}
/**
* Create a TurboJPEG decompressor instance and associate the JPEG image
* stored in <code>jpegImage</code> with the newly-created instance.
*
* @param jpegImage JPEG image buffer (size of the JPEG image is assumed to
* be the length of the array)
*/
public TJDecompressor(byte[] jpegImage) throws Exception {
init();
setJPEGImage(jpegImage, jpegImage.length);
}
/**
* Create a TurboJPEG decompressor instance and associate the JPEG image
* of length <code>imageSize</code> bytes stored in <code>jpegImage</code>
* with the newly-created instance.
*
* @param jpegImage JPEG image buffer
*
* @param imageSize size of the JPEG image (in bytes)
*/
public TJDecompressor(byte[] jpegImage, int imageSize) throws Exception {
init();
setJPEGImage(jpegImage, imageSize);
}
/**
* Associate the JPEG image of length <code>imageSize</code> bytes stored in
* <code>jpegImage</code> with this decompressor instance. This image will
* be used as the source image for subsequent decompress operations.
*
* @param jpegImage JPEG image buffer
*
* @param imageSize size of the JPEG image (in bytes)
*/
public void setJPEGImage(byte[] jpegImage, int imageSize) throws Exception {
if(jpegImage == null || imageSize < 1)
throw new Exception("Invalid argument in setJPEGImage()");
jpegBuf = jpegImage;
jpegBufSize = imageSize;
decompressHeader(jpegBuf, jpegBufSize);
}
/**
* Returns the width of the JPEG image associated with this decompressor
* instance.
*
* @return the width of the JPEG image associated with this decompressor
* instance
*/
public int getWidth() throws Exception {
if(jpegWidth < 1) throw new Exception(NO_ASSOC_ERROR);
return jpegWidth;
}
/**
* Returns the height of the JPEG image associated with this decompressor
* instance.
*
* @return the height of the JPEG image associated with this decompressor
* instance
*/
public int getHeight() throws Exception {
if(jpegHeight < 1) throw new Exception(NO_ASSOC_ERROR);
return jpegHeight;
}
/**
* Returns the level of chrominance subsampling used in the JPEG image
* associated with this decompressor instance.
*
* @return the level of chrominance subsampling used in the JPEG image
* associated with this decompressor instance
*/
public int getSubsamp() throws Exception {
if(jpegSubsamp < 0) throw new Exception(NO_ASSOC_ERROR);
if(jpegSubsamp >= TJ.NUMSAMP)
throw new Exception("JPEG header information is invalid");
return jpegSubsamp;
}
/**
* Returns the JPEG image buffer associated with this decompressor instance.
*
* @return the JPEG image buffer associated with this decompressor instance
*/
public byte[] getJPEGBuf() throws Exception {
if(jpegBuf == null) throw new Exception(NO_ASSOC_ERROR);
return jpegBuf;
}
/**
* Returns the size of the JPEG image (in bytes) associated with this
* decompressor instance.
*
* @return the size of the JPEG image (in bytes) associated with this
* decompressor instance
*/
public int getJPEGSize() throws Exception {
if(jpegBufSize < 1) throw new Exception(NO_ASSOC_ERROR);
return jpegBufSize;
}
/**
* Returns the width of the largest scaled down image that the TurboJPEG
* decompressor can generate without exceeding the desired image width and
* height.
*
* @param desiredWidth desired width (in pixels) of the decompressed image.
* Setting this to 0 is the same as setting it to the width of the JPEG image
* (in other words, the width will not be considered when determining the
* scaled image size.)
*
* @param desiredHeight desired height (in pixels) of the decompressed image.
* Setting this to 0 is the same as setting it to the height of the JPEG
* image (in other words, the height will not be considered when determining
* the scaled image size.)
*
* @return the width of the largest scaled down image that the TurboJPEG
* decompressor can generate without exceeding the desired image width and
* height
*/
public int getScaledWidth(int desiredWidth, int desiredHeight)
throws Exception {
if(jpegWidth < 1 || jpegHeight < 1)
throw new Exception(NO_ASSOC_ERROR);
if(desiredWidth < 0 || desiredHeight < 0)
throw new Exception("Invalid argument in getScaledWidth()");
TJScalingFactor sf[] = TJ.getScalingFactors();
if(desiredWidth == 0) desiredWidth = jpegWidth;
if(desiredHeight == 0) desiredHeight = jpegHeight;
int scaledWidth = jpegWidth, scaledHeight = jpegHeight;
for(int i = 0; i < sf.length; i++) {
scaledWidth = sf[i].getScaled(jpegWidth);
scaledHeight = sf[i].getScaled(jpegHeight);
if(scaledWidth <= desiredWidth && scaledHeight <= desiredHeight)
break;
}
if(scaledWidth > desiredWidth || scaledHeight > desiredHeight)
throw new Exception("Could not scale down to desired image dimensions");
return scaledWidth;
}
/**
* Returns the height of the largest scaled down image that the TurboJPEG
* decompressor can generate without exceeding the desired image width and
* height.
*
* @param desiredWidth desired width (in pixels) of the decompressed image.
* Setting this to 0 is the same as setting it to the width of the JPEG image
* (in other words, the width will not be considered when determining the
* scaled image size.)
*
* @param desiredHeight desired height (in pixels) of the decompressed image.
* Setting this to 0 is the same as setting it to the height of the JPEG
* image (in other words, the height will not be considered when determining
* the scaled image size.)
*
* @return the height of the largest scaled down image that the TurboJPEG
* decompressor can generate without exceeding the desired image width and
* height
*/
public int getScaledHeight(int desiredWidth, int desiredHeight)
throws Exception {
if(jpegWidth < 1 || jpegHeight < 1)
throw new Exception(NO_ASSOC_ERROR);
if(desiredWidth < 0 || desiredHeight < 0)
throw new Exception("Invalid argument in getScaledHeight()");
TJScalingFactor sf[] = TJ.getScalingFactors();
if(desiredWidth == 0) desiredWidth = jpegWidth;
if(desiredHeight == 0) desiredHeight = jpegHeight;
int scaledWidth = jpegWidth, scaledHeight = jpegHeight;
for(int i = 0; i < sf.length; i++) {
scaledWidth = sf[i].getScaled(jpegWidth);
scaledHeight = sf[i].getScaled(jpegHeight);
if(scaledWidth <= desiredWidth && scaledHeight <= desiredHeight)
break;
}
if(scaledWidth > desiredWidth || scaledHeight > desiredHeight)
throw new Exception("Could not scale down to desired image dimensions");
return scaledHeight;
}
/**
* Decompress the JPEG source image associated with this decompressor
* instance and output a decompressed image to the given destination buffer.
*
* @param dstBuf buffer that will receive the decompressed image. This
* buffer should normally be <code>pitch * scaledHeight</code> bytes in size,
* where <code>scaledHeight</code> can be determined by calling <code>
* scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegHeight)
* </code> with one of the scaling factors returned from {@link
* TJ#getScalingFactors} or by calling {@link #getScaledHeight}.
*
* @param desiredWidth desired width (in pixels) of the decompressed image.
* If the desired image dimensions are smaller than the dimensions of the
* JPEG image being decompressed, then TurboJPEG will use scaling in the JPEG
* decompressor to generate the largest possible image that will fit within
* the desired dimensions. Setting this to 0 is the same as setting it to
* the width of the JPEG image (in other words, the width will not be
* considered when determining the scaled image size.)
*
* @param pitch bytes per line of the destination image. Normally, this
* should be set to <code>scaledWidth * TJ.pixelSize(pixelFormat)</code> if
* the decompressed image is unpadded, but you can use this to, for instance,
* pad each line of the decompressed image to a 4-byte boundary. NOTE:
* <code>scaledWidth</code> can be determined by calling <code>
* scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegWidth)
* </code> or by calling {@link #getScaledWidth}. Setting this parameter to
* 0 is the equivalent of setting it to <code>scaledWidth *
* TJ.pixelSize(pixelFormat)</code>.
*
* @param desiredHeight desired height (in pixels) of the decompressed image.
* If the desired image dimensions are smaller than the dimensions of the
* JPEG image being decompressed, then TurboJPEG will use scaling in the JPEG
* decompressor to generate the largest possible image that will fit within
* the desired dimensions. Setting this to 0 is the same as setting it to
* the height of the JPEG image (in other words, the height will not be
* considered when determining the scaled image size.)
*
* @param pixelFormat pixel format of the decompressed image (one of
* {@link TJ TJ.PF_*})
*
* @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
*/
public void decompress(byte[] dstBuf, int desiredWidth, int pitch,
int desiredHeight, int pixelFormat, int flags) throws Exception {
if(jpegBuf == null) throw new Exception(NO_ASSOC_ERROR);
if(dstBuf == null || desiredWidth < 0 || pitch < 0 || desiredHeight < 0
|| pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
throw new Exception("Invalid argument in decompress()");
decompress(jpegBuf, jpegBufSize, dstBuf, desiredWidth, pitch,
desiredHeight, pixelFormat, flags);
}
/**
* Decompress the JPEG source image associated with this decompressor
* instance and return a buffer containing the decompressed image.
*
* @param desiredWidth see
* {@link #decompress(byte[], int, int, int, int, int)} for description
*
* @param pitch see
* {@link #decompress(byte[], int, int, int, int, int)} for description
*
* @param desiredHeight see
* {@link #decompress(byte[], int, int, int, int, int)} for description
*
* @param pixelFormat pixel format of the decompressed image (one of
* {@link TJ TJ.PF_*})
*
* @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
*
* @return a buffer containing the decompressed image
*/
public byte[] decompress(int desiredWidth, int pitch, int desiredHeight,
int pixelFormat, int flags) throws Exception {
if(desiredWidth < 0 || pitch < 0 || desiredHeight < 0
|| pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
throw new Exception("Invalid argument in decompress()");
int pixelSize = TJ.getPixelSize(pixelFormat);
int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
if(pitch == 0) pitch = scaledWidth * pixelSize;
byte[] buf = new byte[pitch * scaledHeight];
decompress(buf, desiredWidth, pitch, desiredHeight, pixelFormat, flags);
return buf;
}
/**
* Decompress the JPEG source image associated with this decompressor
* instance and output a YUV planar image to the given destination buffer.
* This method performs JPEG decompression but leaves out the color
* conversion step, so a planar YUV image is generated instead of an RGB
* image. The padding of the planes in this image is the same as the images
* generated by {@link TJCompressor#encodeYUV(byte[], int)}. Note that, if
* the width or height of the image is not an even multiple of the MCU block
* size (see {@link TJ#getMCUWidth} and {@link TJ#getMCUHeight}), then an
* intermediate buffer copy will be performed within TurboJPEG.
*
* @param dstBuf buffer that will receive the YUV planar image. Use
* {@link TJ#bufSizeYUV} to determine the appropriate size for this buffer
* based on the image width, height, and level of chrominance subsampling.
*
* @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
*/
public void decompressToYUV(byte[] dstBuf, int flags) throws Exception {
if(jpegBuf == null) throw new Exception(NO_ASSOC_ERROR);
if(dstBuf == null || flags < 0)
throw new Exception("Invalid argument in decompressToYUV()");
decompressToYUV(jpegBuf, jpegBufSize, dstBuf, flags);
}
/**
* Decompress the JPEG source image associated with this decompressor
* instance and return a buffer containing a YUV planar image. See {@link
* #decompressToYUV(byte[], int)} for more detail.
*
* @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
*
* @return a buffer containing a YUV planar image
*/
public byte[] decompressToYUV(int flags) throws Exception {
if(flags < 0)
throw new Exception("Invalid argument in decompressToYUV()");
if(jpegWidth < 1 || jpegHeight < 1 || jpegSubsamp < 0)
throw new Exception(NO_ASSOC_ERROR);
if(jpegSubsamp >= TJ.NUMSAMP)
throw new Exception("JPEG header information is invalid");
byte[] buf = new byte[TJ.bufSizeYUV(jpegWidth, jpegHeight, jpegSubsamp)];
decompressToYUV(buf, flags);
return buf;
}
/**
* Decompress the JPEG source image associated with this decompressor
* instance and output a decompressed image to the given
* <code>BufferedImage</code> instance.
*
* @param dstImage a <code>BufferedImage</code> instance that will receive
* the decompressed image
*
* @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
*/
public void decompress(BufferedImage dstImage, int flags) throws Exception {
if(dstImage == null || flags < 0)
throw new Exception("Invalid argument in decompress()");
int desiredWidth = dstImage.getWidth();
int desiredHeight = dstImage.getHeight();
int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
if(scaledWidth != desiredWidth || scaledHeight != desiredHeight)
throw new Exception("BufferedImage dimensions do not match a scaled image size that TurboJPEG is capable of generating.");
int pixelFormat; boolean intPixels = false;
if(byteOrder == null)
byteOrder = ByteOrder.nativeOrder();
switch(dstImage.getType()) {
case BufferedImage.TYPE_3BYTE_BGR:
pixelFormat = TJ.PF_BGR; break;
case BufferedImage.TYPE_4BYTE_ABGR:
case BufferedImage.TYPE_4BYTE_ABGR_PRE:
pixelFormat = TJ.PF_XBGR; break;
case BufferedImage.TYPE_BYTE_GRAY:
pixelFormat = TJ.PF_GRAY; break;
case BufferedImage.TYPE_INT_BGR:
if(byteOrder == ByteOrder.BIG_ENDIAN)
pixelFormat = TJ.PF_XBGR;
else
pixelFormat = TJ.PF_RGBX;
intPixels = true; break;
case BufferedImage.TYPE_INT_RGB:
if(byteOrder == ByteOrder.BIG_ENDIAN)
pixelFormat = TJ.PF_XRGB;
else
pixelFormat = TJ.PF_BGRX;
intPixels = true; break;
case BufferedImage.TYPE_INT_ARGB:
case BufferedImage.TYPE_INT_ARGB_PRE:
if(byteOrder == ByteOrder.BIG_ENDIAN)
pixelFormat = TJ.PF_ARGB;
else
pixelFormat = TJ.PF_BGRA;
intPixels = true; break;
default:
throw new Exception("Unsupported BufferedImage format");
}
WritableRaster wr = dstImage.getRaster();
if(intPixels) {
SinglePixelPackedSampleModel sm =
(SinglePixelPackedSampleModel)dstImage.getSampleModel();
int pitch = sm.getScanlineStride();
DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
int[] buf = db.getData();
if(jpegBuf == null) throw new Exception(NO_ASSOC_ERROR);
decompress(jpegBuf, jpegBufSize, buf, scaledWidth, pitch, scaledHeight,
pixelFormat, flags);
}
else {
ComponentSampleModel sm =
(ComponentSampleModel)dstImage.getSampleModel();
int pixelSize = sm.getPixelStride();
if(pixelSize != TJ.getPixelSize(pixelFormat))
throw new Exception("Inconsistency between pixel format and pixel size in BufferedImage");
int pitch = sm.getScanlineStride();
DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
byte[] buf = db.getData();
decompress(buf, scaledWidth, pitch, scaledHeight, pixelFormat, flags);
}
}
/**
* Decompress the JPEG source image associated with this decompressor
* instance and return a <code>BufferedImage</code> instance containing the
* decompressed image.
*
* @param desiredWidth see
* {@link #decompress(byte[], int, int, int, int, int)} for description
*
* @param desiredHeight see
* {@link #decompress(byte[], int, int, int, int, int)} for description
*
* @param bufferedImageType the image type of the newly-created
* <code>BufferedImage</code> instance (for instance,
* <code>BufferedImage.TYPE_INT_RGB</code>)
*
* @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
*
* @return a <code>BufferedImage</code> instance containing the
* decompressed image
*/
public BufferedImage decompress(int desiredWidth, int desiredHeight,
int bufferedImageType, int flags) throws Exception {
if(desiredWidth < 0 || desiredHeight < 0 || flags < 0)
throw new Exception("Invalid argument in decompress()");
int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
BufferedImage img = new BufferedImage(scaledWidth, scaledHeight,
bufferedImageType);
decompress(img, flags);
return img;
}
/**
* Free the native structures associated with this decompressor instance.
*/
public void close() throws Exception {
destroy();
}
protected void finalize() throws Throwable {
try {
close();
}
catch(Exception e) {}
finally {
super.finalize();
}
};
private native void init() throws Exception;
private native void destroy() throws Exception;
private native void decompressHeader(byte[] srcBuf, int size)
throws Exception;
private native void decompress(byte[] srcBuf, int size, byte[] dstBuf,
int desiredWidth, int pitch, int desiredHeight, int pixelFormat, int flags)
throws Exception;
private native void decompress(byte[] srcBuf, int size, int[] dstBuf,
int desiredWidth, int pitch, int desiredHeight, int pixelFormat, int flags)
throws Exception;
private native void decompressToYUV(byte[] srcBuf, int size, byte[] dstBuf,
int flags)
throws Exception;
static {
TJLoader.load();
}
protected long handle = 0;
protected byte[] jpegBuf = null;
protected int jpegBufSize = 0;
protected int jpegWidth = 0;
protected int jpegHeight = 0;
protected int jpegSubsamp = -1;
private ByteOrder byteOrder = null;
};

View file

@ -0,0 +1,35 @@
/*
* Copyright (C)2011 D. R. Commander. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the libjpeg-turbo Project nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.libjpegturbo.turbojpeg;
final class TJLoader {
static void load() {
System.loadLibrary("turbojpeg");
}
};

View file

@ -0,0 +1,35 @@
/*
* Copyright (C)2011 D. R. Commander. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the libjpeg-turbo Project nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.libjpegturbo.turbojpeg;
final class TJLoader {
static void load() {
System.loadLibrary("@TURBOJPEG_DLL_NAME@");
}
};

View file

@ -0,0 +1,98 @@
/*
* Copyright (C)2011 D. R. Commander. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the libjpeg-turbo Project nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.libjpegturbo.turbojpeg;
/**
* Fractional scaling factor
*/
public class TJScalingFactor {
public TJScalingFactor(int num, int denom) throws Exception {
if(num < 1 || denom < 1)
throw new Exception("Numerator and denominator must be >= 1");
this.num = num;
this.denom = denom;
}
/**
* Returns numerator
* @return numerator
*/
public int getNum() {
return num;
}
/**
* Returns denominator
* @return denominator
*/
public int getDenom() {
return denom;
}
/**
* Returns the scaled value of <code>dimension</code>. This function
* performs the integer equivalent of
* <code>ceil(dimension * scalingFactor)</code>.
* @return the scaled value of <code>dimension</code>
*/
public int getScaled(int dimension) {
return (dimension * num + denom - 1) / denom;
}
/**
* Returns true or false, depending on whether this instance and
* <code>other</code> have the same numerator and denominator.
* @return true or false, depending on whether this instance and
* <code>other</code> have the same numerator and denominator
*/
public boolean equals(TJScalingFactor other) {
return (this.num == other.num && this.denom == other.denom);
}
/**
* Returns true or false, depending on whether this instance is equal to
* 1/1.
* @return true or false, depending on whether this instance is equal to
* 1/1
*/
public boolean isOne() {
return (num == 1 && denom == 1);
}
/**
* Numerator
*/
private int num = 1;
/**
* Denominator
*/
private int denom = 1;
};

View file

@ -0,0 +1,202 @@
/*
* Copyright (C)2011 D. R. Commander. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the libjpeg-turbo Project nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.libjpegturbo.turbojpeg;
import java.awt.*;
/**
* Lossless transform parameters
*/
public class TJTransform extends Rectangle {
private static final long serialVersionUID = -127367705761430371L;
/**
* The number of lossless transform operations
*/
final public static int NUMOP = 8;
/**
* Do not transform the position of the image pixels.
*/
final public static int OP_NONE = 0;
/**
* Flip (mirror) image horizontally. This transform is imperfect if there
* are any partial MCU blocks on the right edge.
* @see #OPT_PERFECT
*/
final public static int OP_HFLIP = 1;
/**
* Flip (mirror) image vertically. This transform is imperfect if there are
* any partial MCU blocks on the bottom edge.
* @see #OPT_PERFECT
*/
final public static int OP_VFLIP = 2;
/**
* Transpose image (flip/mirror along upper left to lower right axis). This
* transform is always perfect.
* @see #OPT_PERFECT
*/
final public static int OP_TRANSPOSE = 3;
/**
* Transverse transpose image (flip/mirror along upper right to lower left
* axis). This transform is imperfect if there are any partial MCU blocks in
* the image.
* @see #OPT_PERFECT
*/
final public static int OP_TRANSVERSE = 4;
/**
* Rotate image clockwise by 90 degrees. This transform is imperfect if
* there are any partial MCU blocks on the bottom edge.
* @see #OPT_PERFECT
*/
final public static int OP_ROT90 = 5;
/**
* Rotate image 180 degrees. This transform is imperfect if there are any
* partial MCU blocks in the image.
* @see #OPT_PERFECT
*/
final public static int OP_ROT180 = 6;
/**
* Rotate image counter-clockwise by 90 degrees. This transform is imperfect
* if there are any partial MCU blocks on the right edge.
* @see #OPT_PERFECT
*/
final public static int OP_ROT270 = 7;
/**
* This option will cause {@link TJTransformer#transform
* TJTransformer.transform()} to throw an exception if the transform is not
* perfect. Lossless transforms operate on MCU blocks, whose size depends on
* the level of chrominance subsampling used. If the image's width or height
* is not evenly divisible by the MCU block size (see {@link TJ#getMCUWidth}
* and {@link TJ#getMCUHeight}), then there will be partial MCU blocks on the
* right and/or bottom edges. It is not possible to move these partial MCU
* blocks to the top or left of the image, so any transform that would
* require that is "imperfect." If this option is not specified, then any
* partial MCU blocks that cannot be transformed will be left in place, which
* will create odd-looking strips on the right or bottom edge of the image.
*/
final public static int OPT_PERFECT = 1;
/**
* This option will discard any partial MCU blocks that cannot be
* transformed.
*/
final public static int OPT_TRIM = 2;
/**
* This option will enable lossless cropping.
*/
final public static int OPT_CROP = 4;
/**
* This option will discard the color data in the input image and produce
* a grayscale output image.
*/
final public static int OPT_GRAY = 8;
/**
* This option will prevent {@link TJTransformer#transform
* TJTransformer.transform()} from outputting a JPEG image for this
* particular transform. This can be used in conjunction with a custom
* filter to capture the transformed DCT coefficients without transcoding
* them.
*/
final public static int OPT_NOOUTPUT = 16;
/**
* Create a new lossless transform instance.
*/
public TJTransform() {
}
/**
* Create a new lossless transform instance with the given parameters.
*
* @param x the left boundary of the cropping region. This must be evenly
* divisible by the MCU block width (see {@link TJ#getMCUWidth})
*
* @param y the upper boundary of the cropping region. This must be evenly
* divisible by the MCU block height (see {@link TJ#getMCUHeight})
*
* @param w the width of the cropping region. Setting this to 0 is the
* equivalent of setting it to the width of the source JPEG image - x.
*
* @param h the height of the cropping region. Setting this to 0 is the
* equivalent of setting it to the height of the source JPEG image - y.
*
* @param op one of the transform operations (<code>OP_*</code>)
*
* @param options the bitwise OR of one or more of the transform options
* (<code>OPT_*</code>)
*
* @param cf an instance of an object that implements the {@link
* TJCustomFilter} interface, or null if no custom filter is needed
*/
public TJTransform(int x, int y, int w, int h, int op, int options,
TJCustomFilter cf) throws Exception {
super(x, y, w, h);
this.op = op; this.options = options; this.cf = cf;
}
/**
* Create a new lossless transform instance with the given parameters.
*
* @param r a <code>Rectangle</code> instance that specifies the cropping
* region. See {@link
* #TJTransform(int, int, int, int, int, int, TJCustomFilter)} for more
* detail.
*
* @param op one of the transform operations (<code>OP_*</code>)
*
* @param options the bitwise OR of one or more of the transform options
* (<code>OPT_*</code>)
*
* @param cf an instance of an object that implements the {@link
* TJCustomFilter} interface, or null if no custom filter is needed
*/
public TJTransform(Rectangle r, int op, int options,
TJCustomFilter cf) throws Exception {
super(r);
this.op = op; this.options = options; this.cf = cf;
}
/**
* Transform operation (one of <code>OP_*</code>)
*/
public int op = 0;
/**
* Transform options (bitwise OR of one or more of <code>OPT_*</code>)
*/
public int options = 0;
/**
* Custom filter instance
*/
public TJCustomFilter cf = null;
}

View file

@ -0,0 +1,158 @@
/*
* Copyright (C)2011 D. R. Commander. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the libjpeg-turbo Project nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.libjpegturbo.turbojpeg;
/**
* TurboJPEG lossless transformer
*/
public class TJTransformer extends TJDecompressor {
/**
* Create a TurboJPEG lossless transformer instance.
*/
public TJTransformer() throws Exception {
init();
}
/**
* Create a TurboJPEG lossless transformer instance and associate the JPEG
* image stored in <code>jpegImage</code> with the newly-created instance.
*
* @param jpegImage JPEG image buffer (size of the JPEG image is assumed to
* be the length of the array)
*/
public TJTransformer(byte[] jpegImage) throws Exception {
init();
setJPEGImage(jpegImage, jpegImage.length);
}
/**
* Create a TurboJPEG lossless transformer instance and associate the JPEG
* image of length <code>imageSize</code> bytes stored in
* <code>jpegImage</code> with the newly-created instance.
*
* @param jpegImage JPEG image buffer
*
* @param imageSize size of the JPEG image (in bytes)
*/
public TJTransformer(byte[] jpegImage, int imageSize) throws Exception {
init();
setJPEGImage(jpegImage, imageSize);
}
/**
* Losslessly transform the JPEG image associated with this transformer
* instance into one or more JPEG images stored in the given destination
* buffers. Lossless transforms work by moving the raw coefficients from one
* JPEG image structure to another without altering the values of the
* coefficients. While this is typically faster than decompressing the
* image, transforming it, and re-compressing it, lossless transforms are not
* free. Each lossless transform requires reading and Huffman decoding all
* of the coefficients in the source image, regardless of the size of the
* destination image. Thus, this method provides a means of generating
* multiple transformed images from the same source or of applying multiple
* transformations simultaneously, in order to eliminate the need to read the
* source coefficients multiple times.
*
* @param dstBufs an array of image buffers. <code>dstbufs[i]</code> will
* receive a JPEG image that has been transformed using the parameters in
* <code>transforms[i]</code>. Use {@link TJ#bufSize} to determine the
* maximum size for each buffer based on the cropped width and height.
*
* @param transforms an array of {@link TJTransform} instances, each of
* which specifies the transform parameters and/or cropping region for the
* corresponding transformed output image
*
* @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
*/
public void transform(byte[][] dstBufs, TJTransform[] transforms,
int flags) throws Exception {
if(jpegBuf == null) throw new Exception("JPEG buffer not initialized");
transformedSizes = transform(jpegBuf, jpegBufSize, dstBufs, transforms,
flags);
}
/**
* Losslessly transform the JPEG image associated with this transformer
* instance and return an array of {@link TJDecompressor} instances, each of
* which has a transformed JPEG image associated with it.
*
* @param transforms an array of {@link TJTransform} instances, each of
* which specifies the transform parameters and/or cropping region for the
* corresponding transformed output image
*
* @return an array of {@link TJDecompressor} instances, each of
* which has a transformed JPEG image associated with it
*
* @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
*/
public TJDecompressor[] transform(TJTransform[] transforms, int flags)
throws Exception {
byte[][] dstBufs = new byte[transforms.length][];
if(jpegWidth < 1 || jpegHeight < 1)
throw new Exception("JPEG buffer not initialized");
for(int i = 0; i < transforms.length; i++) {
int w = jpegWidth, h = jpegHeight;
if((transforms[i].options & TJTransform.OPT_CROP) != 0) {
if(transforms[i].width != 0) w = transforms[i].width;
if(transforms[i].height != 0) h = transforms[i].height;
}
dstBufs[i] = new byte[TJ.bufSize(w, h, jpegSubsamp)];
}
TJDecompressor[] tjd = new TJDecompressor[transforms.length];
transform(dstBufs, transforms, flags);
for(int i = 0; i < transforms.length; i++)
tjd[i] = new TJDecompressor(dstBufs[i], transformedSizes[i]);
return tjd;
}
/**
* Returns an array containing the sizes of the transformed JPEG images from
* the most recent call to {@link #transform transform()}.
*
* @return an array containing the sizes of the transformed JPEG images from
* the most recent call to {@link #transform transform()}
*/
public int[] getTransformedSizes() throws Exception {
if(transformedSizes == null)
throw new Exception("No image has been transformed yet");
return transformedSizes;
}
private native void init() throws Exception;
private native int[] transform(byte[] srcBuf, int srcSize, byte[][] dstBufs,
TJTransform[] transforms, int flags) throws Exception;
static {
TJLoader.load();
}
private int[] transformedSizes = null;
};