aboutsummaryrefslogtreecommitdiff
path: root/java/org/libjpegturbo
diff options
context:
space:
mode:
Diffstat (limited to 'java/org/libjpegturbo')
-rw-r--r--java/org/libjpegturbo/turbojpeg/TJ.java82
-rw-r--r--java/org/libjpegturbo/turbojpeg/TJCompressor.java79
-rw-r--r--java/org/libjpegturbo/turbojpeg/TJDecompressor.java175
-rw-r--r--java/org/libjpegturbo/turbojpeg/TJScalingFactor.java11
-rw-r--r--java/org/libjpegturbo/turbojpeg/TJTransformer.java4
-rw-r--r--java/org/libjpegturbo/turbojpeg/YUVImage.java298
6 files changed, 501 insertions, 148 deletions
diff --git a/java/org/libjpegturbo/turbojpeg/TJ.java b/java/org/libjpegturbo/turbojpeg/TJ.java
index ac4a4dd..644a197 100644
--- a/java/org/libjpegturbo/turbojpeg/TJ.java
+++ b/java/org/libjpegturbo/turbojpeg/TJ.java
@@ -84,7 +84,8 @@ public final class TJ {
* @param subsamp the level of chrominance subsampling (one of
* <code>SAMP_*</code>)
*
- * @return the MCU block width for the given level of chrominance subsampling
+ * @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)
@@ -105,7 +106,7 @@ public final class TJ {
* <code>SAMP_*</code>)
*
* @return the MCU block height for the given level of chrominance
- * subsampling
+ * subsampling.
*/
public static int getMCUHeight(int subsamp) throws Exception {
if (subsamp < 0 || subsamp >= NUMSAMP)
@@ -214,7 +215,7 @@ public final class TJ {
*
* @param pixelFormat the pixel format (one of <code>PF_*</code>)
*
- * @return the pixel size (in bytes) for the given pixel format
+ * @return the pixel size (in bytes) for the given pixel format.
*/
public static int getPixelSize(int pixelFormat) throws Exception {
if (pixelFormat < 0 || pixelFormat >= NUMPF)
@@ -236,7 +237,7 @@ public final class TJ {
*
* @param pixelFormat the pixel format (one of <code>PF_*</code>)
*
- * @return the red offset for the given pixel format
+ * @return the red offset for the given pixel format.
*/
public static int getRedOffset(int pixelFormat) throws Exception {
if (pixelFormat < 0 || pixelFormat >= NUMPF)
@@ -258,7 +259,7 @@ public final class TJ {
*
* @param pixelFormat the pixel format (one of <code>PF_*</code>)
*
- * @return the green offset for the given pixel format
+ * @return the green offset for the given pixel format.
*/
public static int getGreenOffset(int pixelFormat) throws Exception {
if (pixelFormat < 0 || pixelFormat >= NUMPF)
@@ -280,7 +281,7 @@ public final class TJ {
*
* @param pixelFormat the pixel format (one of <code>PF_*</code>)
*
- * @return the blue offset for the given pixel format
+ * @return the blue offset for the given pixel format.
*/
public static int getBlueOffset(int pixelFormat) throws Exception {
if (pixelFormat < 0 || pixelFormat >= NUMPF)
@@ -404,7 +405,7 @@ public final class TJ {
* 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, height, and level of chrominance subsampling
+ * image with the given width, height, and level of chrominance subsampling.
*/
public static native int bufSize(int width, int height, int jpegSubsamp)
throws Exception;
@@ -416,8 +417,7 @@ public final class TJ {
* @param width the width (in pixels) of the YUV image
*
* @param pad the width of each line in each plane of the image is padded to
- * the nearest multiple of this number of bytes (must be a power of
- * 2.)
+ * the nearest multiple of this number of bytes (must be a power of 2.)
*
* @param height the height (in pixels) of the YUV image
*
@@ -425,7 +425,7 @@ public final class TJ {
* 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
+ * image with the given width, height, and level of chrominance subsampling.
*/
public static native int bufSizeYUV(int width, int pad, int height,
int subsamp)
@@ -439,11 +439,71 @@ public final class TJ {
throws Exception;
/**
+ * Returns the size of the buffer (in bytes) required to hold a YUV image
+ * plane with the given parameters.
+ *
+ * @param componentID ID number of the image plane (0 = Y, 1 = U/Cb,
+ * 2 = V/Cr)
+ *
+ * @param width width (in pixels) of the YUV image. NOTE: this is the width
+ * of the whole image, not the plane width.
+ *
+ * @param stride bytes per line in the image plane.
+ *
+ * @param height height (in pixels) of the YUV image. NOTE: this is the
+ * height of the whole image, not the plane height.
+ *
+ * @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 parameters.
+ */
+ public static native int planeSizeYUV(int componentID, int width, int stride,
+ int height, int subsamp)
+ throws Exception;
+
+ /**
+ * Returns the plane width of a YUV image plane with the given parameters.
+ * Refer to {@link YUVImage YUVImage} for a description of plane width.
+ *
+ * @param componentID ID number of the image plane (0 = Y, 1 = U/Cb,
+ * 2 = V/Cr)
+ *
+ * @param width width (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 plane width of a YUV image plane with the given parameters.
+ */
+ public static native int planeWidth(int componentID, int width, int subsamp)
+ throws Exception;
+
+ /**
+ * Returns the plane height of a YUV image plane with the given parameters.
+ * Refer to {@link YUVImage YUVImage} for a description of plane height.
+ *
+ * @param componentID ID number of the image plane (0 = Y, 1 = U/Cb,
+ * 2 = V/Cr)
+ *
+ * @param height 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 plane height of a YUV image plane with the given parameters.
+ */
+ public static native int planeHeight(int componentID, 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
+ * this implementation of TurboJPEG supports.
*/
public static native TJScalingFactor[] getScalingFactors()
throws Exception;
diff --git a/java/org/libjpegturbo/turbojpeg/TJCompressor.java b/java/org/libjpegturbo/turbojpeg/TJCompressor.java
index 0debf53..c4a8cc5 100644
--- a/java/org/libjpegturbo/turbojpeg/TJCompressor.java
+++ b/java/org/libjpegturbo/turbojpeg/TJCompressor.java
@@ -332,9 +332,10 @@ public class TJCompressor {
throw new Exception("Subsampling level not set");
if (srcYUVImage != null)
- compressedSize = compressFromYUV(srcYUVImage.getBuf(),
+ compressedSize = compressFromYUV(srcYUVImage.getPlanes(),
+ srcYUVImage.getOffsets(),
srcYUVImage.getWidth(),
- srcYUVImage.getPad(),
+ srcYUVImage.getStrides(),
srcYUVImage.getHeight(),
srcYUVImage.getSubsamp(),
dstBuf, jpegQuality, flags);
@@ -429,14 +430,14 @@ public class TJCompressor {
if (srcBufInt != null) {
encodeYUV(srcBufInt, srcX, srcY, srcWidth, srcStride, srcHeight,
- srcPixelFormat, dstImage.getBuf(), dstImage.getPad(),
- dstImage.getSubsamp(), flags);
+ srcPixelFormat, dstImage.getPlanes(), dstImage.getOffsets(),
+ dstImage.getStrides(), dstImage.getSubsamp(), flags);
} else {
encodeYUV(srcBuf, srcX, srcY, srcWidth, srcPitch, srcHeight,
- srcPixelFormat, dstImage.getBuf(), dstImage.getPad(),
- dstImage.getSubsamp(), flags);
+ srcPixelFormat, dstImage.getPlanes(), dstImage.getOffsets(),
+ dstImage.getStrides(), dstImage.getSubsamp(), flags);
}
- compressedSize = dstImage.getSize();
+ compressedSize = 0;
}
/**
@@ -456,11 +457,11 @@ public class TJCompressor {
/**
* Encode the uncompressed source image associated with this compressor
- * instance into a YUV planar image and return a <code>YUVImage</code>
- * instance containing the encoded image. This method uses the accelerated
- * color conversion routines in TurboJPEG's underlying codec but does not
- * execute any of the other steps in the JPEG compression process. Encoding
- * CMYK source images to YUV is not supported.
+ * instance into a unified YUV planar image buffer and return a
+ * <code>YUVImage</code> instance containing the encoded image. This method
+ * uses the accelerated color conversion routines in TurboJPEG's underlying
+ * codec but does not execute any of the other steps in the JPEG compression
+ * process. Encoding CMYK source images to YUV is not supported.
*
* @param pad the width of each line in each plane of the YUV image will be
* padded to the nearest multiple of this number of bytes (must be a power of
@@ -469,7 +470,7 @@ public class TJCompressor {
* @param flags the bitwise OR of one or more of
* {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
*
- * @return a YUV planar image
+ * @return a YUV planar image.
*/
public YUVImage encodeYUV(int pad, int flags) throws Exception {
if (srcWidth < 1 || srcHeight < 1)
@@ -484,6 +485,37 @@ public class TJCompressor {
}
/**
+ * Encode the uncompressed source image associated with this compressor
+ * instance into separate Y, U (Cb), and V (Cr) image planes and return a
+ * <code>YUVImage</code> instance containing the encoded image planes. This
+ * method uses the accelerated color conversion routines in TurboJPEG's
+ * underlying codec but does not execute any of the other steps in the JPEG
+ * compression process. Encoding CMYK source images to YUV is not supported.
+ *
+ * @param strides an array of integers, each specifying the number of bytes
+ * per line in the corresponding plane of the output image. Setting the
+ * stride for any plane to 0 is the same as setting it to the component width
+ * of the plane. If <code>strides</code> is null, then the strides for all
+ * planes will be set to their respective component widths. You can adjust
+ * the strides in order to add an arbitrary amount of line padding to each
+ * plane.
+ *
+ * @param flags the bitwise OR of one or more of
+ * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
+ *
+ * @return a YUV planar image.
+ */
+ public YUVImage encodeYUV(int[] strides, 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");
+ YUVImage yuvImage = new YUVImage(srcWidth, strides, srcHeight, subsamp);
+ encodeYUV(yuvImage, flags);
+ return yuvImage;
+ }
+
+ /**
* @deprecated Use {@link #encodeYUV(int, int)} instead.
*/
@Deprecated
@@ -512,7 +544,7 @@ public class TJCompressor {
/**
* @deprecated Use
* {@link #setSourceImage(BufferedImage, int, int, int, int)} and
- * {@link #encodeYUV(int)} instead.
+ * {@link #encodeYUV(int, int)} instead.
*/
@Deprecated
public byte[] encodeYUV(BufferedImage srcImage, int flags) throws Exception {
@@ -522,10 +554,10 @@ public class TJCompressor {
/**
* Returns the size of the image (in bytes) generated by the most recent
- * compress/encode operation.
+ * compress operation.
*
* @return the size of the image (in bytes) generated by the most recent
- * compress/encode operation
+ * compress operation.
*/
public int getCompressedSize() {
return compressedSize;
@@ -568,8 +600,9 @@ public class TJCompressor {
int stride, int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp,
int jpegQual, int flags) throws Exception;
- private native int compressFromYUV(byte[] srcBuf, int width, int pad,
- int height, int subsamp, byte[] dstBuf, int jpegQual, int flags)
+ private native int compressFromYUV(byte[][] srcPlanes, int[] srcOffsets,
+ int width, int[] srcStrides, int height, int subsamp, byte[] dstBuf,
+ int jpegQual, int flags)
throws Exception;
private native void encodeYUV(byte[] srcBuf, int width, int pitch,
@@ -577,16 +610,18 @@ public class TJCompressor {
throws Exception; // deprecated
private native void encodeYUV(byte[] srcBuf, int x, int y, int width,
- int pitch, int height, int pixelFormat, byte[] dstBuf, int pad,
- int subsamp, int flags) throws Exception;
+ int pitch, int height, int pixelFormat, byte[][] dstPlanes,
+ int[] dstOffsets, int[] dstStrides, int subsamp, int flags)
+ throws Exception;
private native void encodeYUV(int[] srcBuf, int width, int stride,
int height, int pixelFormat, byte[] dstBuf, int subsamp, int flags)
throws Exception; // deprecated
private native void encodeYUV(int[] srcBuf, int x, int y, int width,
- int pitch, int height, int pixelFormat, byte[] dstBuf, int pad,
- int subsamp, int flags) throws Exception;
+ int srcStride, int height, int pixelFormat, byte[][] dstPlanes,
+ int[] dstOffsets, int[] dstStrides, int subsamp, int flags)
+ throws Exception;
static {
TJLoader.load();
diff --git a/java/org/libjpegturbo/turbojpeg/TJDecompressor.java b/java/org/libjpegturbo/turbojpeg/TJDecompressor.java
index c71ce77..1a2774c 100644
--- a/java/org/libjpegturbo/turbojpeg/TJDecompressor.java
+++ b/java/org/libjpegturbo/turbojpeg/TJDecompressor.java
@@ -87,18 +87,18 @@ public class TJDecompressor {
/**
* Associate the JPEG image of length <code>imageSize</code> bytes stored in
- * <code>srcImage</code> with this decompressor instance. This image will
+ * <code>jpegImage</code> with this decompressor instance. This image will
* be used as the source image for subsequent decompress operations.
*
- * @param srcImage JPEG image buffer
+ * @param jpegImage JPEG image buffer
*
* @param imageSize size of the JPEG image (in bytes)
*/
- public void setSourceImage(byte[] srcImage, int imageSize)
+ public void setSourceImage(byte[] jpegImage, int imageSize)
throws Exception {
- if (srcImage == null || imageSize < 1)
+ if (jpegImage == null || imageSize < 1)
throw new Exception("Invalid argument in setSourceImage()");
- jpegBuf = srcImage;
+ jpegBuf = jpegImage;
jpegBufSize = imageSize;
decompressHeader(jpegBuf, jpegBufSize);
yuvImage = null;
@@ -134,7 +134,7 @@ public class TJDecompressor {
* decompressor instance.
*
* @return the width of the source image (JPEG or YUV) associated with this
- * decompressor instance
+ * decompressor instance.
*/
public int getWidth() throws Exception {
if (yuvImage != null)
@@ -149,7 +149,7 @@ public class TJDecompressor {
* decompressor instance.
*
* @return the height of the source image (JPEG or YUV) associated with this
- * decompressor instance
+ * decompressor instance.
*/
public int getHeight() throws Exception {
if (yuvImage != null)
@@ -165,7 +165,7 @@ public class TJDecompressor {
* {@link TJ#SAMP_444 TJ.SAMP_*}.
*
* @return the level of chrominance subsampling used in the source image
- * (JPEG or YUV) associated with this decompressor instance
+ * (JPEG or YUV) associated with this decompressor instance.
*/
public int getSubsamp() throws Exception {
if (yuvImage != null)
@@ -183,7 +183,7 @@ public class TJDecompressor {
* source image is YUV, then this always returns {@link TJ#CS_YCbCr}.
*
* @return the colorspace used in the source image (JPEG or YUV) associated
- * with this decompressor instance
+ * with this decompressor instance.
*/
public int getColorspace() throws Exception {
if (yuvImage != null)
@@ -196,23 +196,10 @@ public class TJDecompressor {
}
/**
- * Returns the source image buffer associated with this decompressor
- * instance.
+ * Returns the JPEG image buffer associated with this decompressor instance.
*
- * @return the source image buffer associated with this decompressor instance
+ * @return the JPEG image buffer associated with this decompressor instance.
*/
- public byte[] getSourceBuf() throws Exception {
- if (yuvImage != null)
- return yuvImage.getBuf();
- if (jpegBuf == null)
- throw new Exception(NO_ASSOC_ERROR);
- return jpegBuf;
- }
-
- /**
- * @deprecated Use {@link #getSourceBuf} instead.
- */
- @Deprecated
public byte[] getJPEGBuf() throws Exception {
if (jpegBuf == null)
throw new Exception(NO_ASSOC_ERROR);
@@ -220,24 +207,12 @@ public class TJDecompressor {
}
/**
- * Returns the size of the source image (in bytes) associated with this
+ * Returns the size of the JPEG image (in bytes) associated with this
* decompressor instance.
*
- * @return the size of the source image (in bytes) associated with this
- * decompressor instance
- */
- public int getSourceSize() throws Exception {
- if (yuvImage != null)
- return yuvImage.getSize();
- if (jpegBufSize < 1)
- throw new Exception(NO_ASSOC_ERROR);
- return jpegBufSize;
- }
-
- /**
- * @deprecated Use {@link #getSourceSize} instead.
+ * @return the size of the JPEG image (in bytes) associated with this
+ * decompressor instance.
*/
- @Deprecated
public int getJPEGSize() throws Exception {
if (jpegBufSize < 1)
throw new Exception(NO_ASSOC_ERROR);
@@ -261,7 +236,7 @@ public class TJDecompressor {
*
* @return the width of the largest scaled-down image that the TurboJPEG
* decompressor can generate without exceeding the desired image width and
- * height
+ * height.
*/
public int getScaledWidth(int desiredWidth, int desiredHeight)
throws Exception {
@@ -303,7 +278,7 @@ public class TJDecompressor {
*
* @return the height of the largest scaled-down image that the TurboJPEG
* decompressor can generate without exceeding the desired image width and
- * height
+ * height.
*/
public int getScaledHeight(int desiredWidth, int desiredHeight)
throws Exception {
@@ -402,9 +377,10 @@ public class TJDecompressor {
pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
throw new Exception("Invalid argument in decompress()");
if (yuvImage != null)
- decodeYUV(yuvImage.getBuf(), yuvImage.getPad(), yuvImage.getSubsamp(),
- dstBuf, x, y, yuvImage.getWidth(), pitch, yuvImage.getHeight(),
- pixelFormat, flags);
+ decodeYUV(yuvImage.getPlanes(), yuvImage.getOffsets(),
+ yuvImage.getStrides(), yuvImage.getSubsamp(), dstBuf, x, y,
+ yuvImage.getWidth(), pitch, yuvImage.getHeight(), pixelFormat,
+ flags);
else {
if (x > 0 || y > 0)
decompress(jpegBuf, jpegBufSize, dstBuf, x, y, desiredWidth, pitch,
@@ -449,7 +425,7 @@ public class TJDecompressor {
* @param flags the bitwise OR of one or more of
* {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
*
- * @return a buffer containing the decompressed image
+ * @return a buffer containing the decompressed image.
*/
public byte[] decompress(int desiredWidth, int pitch, int desiredHeight,
int pixelFormat, int flags) throws Exception {
@@ -500,9 +476,9 @@ public class TJDecompressor {
if (jpegSubsamp != dstImage.getSubsamp())
throw new Exception("YUVImage subsampling level does not match that of the JPEG image");
- decompressToYUV(jpegBuf, jpegBufSize, dstImage.getBuf(),
- dstImage.getWidth(), dstImage.getPad(),
- dstImage.getHeight(), flags);
+ decompressToYUV(jpegBuf, jpegBufSize, dstImage.getPlanes(),
+ dstImage.getOffsets(), dstImage.getWidth(),
+ dstImage.getStrides(), dstImage.getHeight(), flags);
}
/**
@@ -517,12 +493,70 @@ public class TJDecompressor {
/**
* Decompress the JPEG source image associated with this decompressor
- * instance into a YUV planar image and return a <code>YUVImage</code>
- * instance containing the decompressed image. This method performs JPEG
- * decompression but leaves out the color conversion step, so a planar YUV
- * image is generated instead of an RGB or grayscale image. This method
- * cannot be used to decompress JPEG source images with the CMYK or YCCK
- * colorspace.
+ * instance into a set of Y, U (Cb), and V (Cr) image planes and return a
+ * <code>YUVImage</code> instance containing the decompressed image planes.
+ * This method performs JPEG decompression but leaves out the color
+ * conversion step, so a planar YUV image is generated instead of an RGB or
+ * grayscale image. This method cannot be used to decompress JPEG source
+ * images with the CMYK or YCCK colorspace.
+ *
+ * @param desiredWidth desired width (in pixels) of the YUV image. If the
+ * desired image dimensions are different 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 strides an array of integers, each specifying the number of bytes
+ * per line in the corresponding plane of the output image. Setting the
+ * stride for any plane to 0 is the same as setting it to the scaled
+ * component width of the plane. If <tt>strides</tt> is NULL, then the
+ * strides for all planes will be set to their respective scaled component
+ * widths. You can adjust the strides in order to add an arbitrary amount of
+ * line padding to each plane.
+ *
+ * @param desiredHeight desired height (in pixels) of the YUV image. If the
+ * desired image dimensions are different 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 flags the bitwise OR of one or more of
+ * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
+ *
+ * @return a YUV planar image.
+ */
+ public YUVImage decompressToYUV(int desiredWidth, int[] strides,
+ int desiredHeight,
+ 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");
+ if (yuvImage != null)
+ throw new Exception("Source image is the wrong type");
+
+ int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
+ int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
+ YUVImage yuvImage = new YUVImage(scaledWidth, null, scaledHeight,
+ jpegSubsamp);
+ decompressToYUV(yuvImage, flags);
+ return yuvImage;
+ }
+
+ /**
+ * Decompress the JPEG source image associated with this decompressor
+ * instance into a unified YUV planar image buffer and return a
+ * <code>YUVImage</code> instance containing the decompressed image. This
+ * method performs JPEG decompression but leaves out the color conversion
+ * step, so a planar YUV image is generated instead of an RGB or grayscale
+ * image. This method cannot be used to decompress JPEG source images with
+ * the CMYK or YCCK colorspace.
*
* @param desiredWidth desired width (in pixels) of the YUV image. If the
* desired image dimensions are different than the dimensions of the JPEG
@@ -547,7 +581,7 @@ public class TJDecompressor {
* @param flags the bitwise OR of one or more of
* {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
*
- * @return a YUV planar image
+ * @return a YUV planar image.
*/
public YUVImage decompressToYUV(int desiredWidth, int pad, int desiredHeight,
int flags) throws Exception {
@@ -650,9 +684,10 @@ public class TJDecompressor {
pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
throw new Exception("Invalid argument in decompress()");
if (yuvImage != null)
- decodeYUV(yuvImage.getBuf(), yuvImage.getPad(), yuvImage.getSubsamp(),
- dstBuf, x, y, yuvImage.getWidth(), stride,
- yuvImage.getHeight(), pixelFormat, flags);
+ decodeYUV(yuvImage.getPlanes(), yuvImage.getOffsets(),
+ yuvImage.getStrides(), yuvImage.getSubsamp(), dstBuf, x, y,
+ yuvImage.getWidth(), stride, yuvImage.getHeight(), pixelFormat,
+ flags);
else
decompress(jpegBuf, jpegBufSize, dstBuf, x, y, desiredWidth, stride,
desiredHeight, pixelFormat, flags);
@@ -734,8 +769,9 @@ public class TJDecompressor {
DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
int[] buf = db.getData();
if (yuvImage != null)
- decodeYUV(yuvImage.getBuf(), yuvImage.getPad(), yuvImage.getSubsamp(),
- buf, 0, 0, yuvImage.getWidth(), stride, yuvImage.getHeight(),
+ decodeYUV(yuvImage.getPlanes(), yuvImage.getOffsets(),
+ yuvImage.getStrides(), yuvImage.getSubsamp(), buf, 0, 0,
+ yuvImage.getWidth(), stride, yuvImage.getHeight(),
pixelFormat, flags);
else {
if (jpegBuf == null)
@@ -778,7 +814,7 @@ public class TJDecompressor {
* {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
*
* @return a <code>BufferedImage</code> instance containing the
- * decompressed/decoded image
+ * decompressed/decoded image.
*/
public BufferedImage decompress(int desiredWidth, int desiredHeight,
int bufferedImageType, int flags)
@@ -836,16 +872,17 @@ public class TJDecompressor {
private native void decompressToYUV(byte[] srcBuf, int size, byte[] dstBuf,
int flags) throws Exception; // deprecated
- private native void decompressToYUV(byte[] srcBuf, int size, byte[] dstBuf,
- int desiredWidth, int pad, int desiredheight, int flags) throws Exception;
+ private native void decompressToYUV(byte[] srcBuf, int size,
+ byte[][] dstPlanes, int[] dstOffsets, int desiredWidth, int[] dstStrides,
+ int desiredheight, int flags) throws Exception;
- private native void decodeYUV(byte[] srcBuf, int pad, int subsamp,
- byte[] dstBuf, int x, int y, int width, int pitch, int height,
- int pixelFormat, int flags) throws Exception;
+ private native void decodeYUV(byte[][] srcPlanes, int[] srcOffsets,
+ int[] srcStrides, int subsamp, byte[] dstBuf, int x, int y, int width,
+ int pitch, int height, int pixelFormat, int flags) throws Exception;
- private native void decodeYUV(byte[] srcBuf, int pad, int subsamp,
- int[] dstBuf, int x, int y, int width, int stride, int height,
- int pixelFormat, int flags) throws Exception;
+ private native void decodeYUV(byte[][] srcPlanes, int[] srcOffsets,
+ int[] srcStrides, int subsamp, int[] dstBuf, int x, int y, int width,
+ int stride, int height, int pixelFormat, int flags) throws Exception;
static {
TJLoader.load();
diff --git a/java/org/libjpegturbo/turbojpeg/TJScalingFactor.java b/java/org/libjpegturbo/turbojpeg/TJScalingFactor.java
index 4e7363f..e00fdf7 100644
--- a/java/org/libjpegturbo/turbojpeg/TJScalingFactor.java
+++ b/java/org/libjpegturbo/turbojpeg/TJScalingFactor.java
@@ -42,6 +42,7 @@ public class TJScalingFactor {
/**
* Returns numerator
+ *
* @return numerator
*/
public int getNum() {
@@ -50,6 +51,7 @@ public class TJScalingFactor {
/**
* Returns denominator
+ *
* @return denominator
*/
public int getDenom() {
@@ -60,7 +62,8 @@ public class TJScalingFactor {
* 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>
+ *
+ * @return the scaled value of <code>dimension</code>.
*/
public int getScaled(int dimension) {
return (dimension * num + denom - 1) / denom;
@@ -69,8 +72,9 @@ public class TJScalingFactor {
/**
* 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
+ * <code>other</code> have the same numerator and denominator.
*/
public boolean equals(TJScalingFactor other) {
return (this.num == other.num && this.denom == other.denom);
@@ -79,8 +83,9 @@ public class TJScalingFactor {
/**
* 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
+ * 1/1.
*/
public boolean isOne() {
return (num == 1 && denom == 1);
diff --git a/java/org/libjpegturbo/turbojpeg/TJTransformer.java b/java/org/libjpegturbo/turbojpeg/TJTransformer.java
index a62f410..cf773fa 100644
--- a/java/org/libjpegturbo/turbojpeg/TJTransformer.java
+++ b/java/org/libjpegturbo/turbojpeg/TJTransformer.java
@@ -111,7 +111,7 @@ public class TJTransformer extends TJDecompressor {
* corresponding transformed output image
*
* @return an array of {@link TJDecompressor} instances, each of
- * which has a transformed JPEG image associated with it
+ * which has a transformed JPEG image associated with it.
*
* @param flags the bitwise OR of one or more of
* {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
@@ -141,7 +141,7 @@ public class TJTransformer extends TJDecompressor {
* generated by the most recent transform operation.
*
* @return an array containing the sizes of the transformed JPEG images
- * generated by the most recent transform operation
+ * generated by the most recent transform operation.
*/
public int[] getTransformedSizes() throws Exception {
if (transformedSizes == null)
diff --git a/java/org/libjpegturbo/turbojpeg/YUVImage.java b/java/org/libjpegturbo/turbojpeg/YUVImage.java
index 27b1b70..2d790e9 100644
--- a/java/org/libjpegturbo/turbojpeg/YUVImage.java
+++ b/java/org/libjpegturbo/turbojpeg/YUVImage.java
@@ -43,20 +43,18 @@ package org.libjpegturbo.turbojpeg;
* image format consisting of Y, Cb, and Cr image planes.
* <p>
* Each plane is simply a 2D array of bytes, each byte representing the value
- * of one of the components at a particular location in the image. The
- * "component width" and "component height" of each plane are determined by the
- * image width, height, and level of chrominance subsampling. For the
- * luminance plane, the component width is the image width padded to the
- * nearest multiple of the horizontal subsampling factor (2 in the case of
- * 4:2:0 and 4:2:2, 4 in the case of 4:1:1, 1 in the case of 4:4:4 or
- * grayscale.) Similarly, the component height of the luminance plane is the
- * image height padded to the nearest multiple of the vertical subsampling
- * factor (2 in the case of 4:2:0 or 4:4:0, 1 in the case of 4:4:4 or
- * grayscale.) The component width of the chrominance planes is equal to the
- * component width of the luminance plane divided by the horizontal subsampling
- * factor, and the component height of the chrominance planes is equal to the
- * component height of the luminance plane divided by the vertical subsampling
- * factor.
+ * of one of the components (Y, Cb, or Cr) at a particular location in the
+ * image. The width and height of each plane are determined by the image
+ * width, height, and level of chrominance subsampling. The luminance plane
+ * width is the image width padded to the nearest multiple of the horizontal
+ * subsampling factor (2 in the case of 4:2:0 and 4:2:2, 4 in the case of
+ * 4:1:1, 1 in the case of 4:4:4 or grayscale.) Similarly, the luminance plane
+ * height is the image height padded to the nearest multiple of the vertical
+ * subsampling factor (2 in the case of 4:2:0 or 4:4:0, 1 in the case of 4:4:4
+ * or grayscale.) The chrominance plane width is equal to the luminance plane
+ * width divided by the horizontal subsampling factor, and the chrominance
+ * plane height is equal to the luminance plane height divided by the vertical
+ * subsampling factor.
* <p>
* For example, if the source image is 35 x 35 pixels and 4:2:2 subsampling is
* used, then the luminance plane would be 36 x 35 bytes, and each of the
@@ -67,10 +65,35 @@ package org.libjpegturbo.turbojpeg;
public class YUVImage {
private static final String NO_ASSOC_ERROR =
- "No YUV buffer is associated with this instance";
+ "No image data is associated with this instance";
/**
- * Create a <code>YUVImage</code> instance with a new image buffer.
+ * Create a new <code>YUVImage</code> instance backed by separate image
+ * planes, and allocate memory for the image planes.
+ *
+ * @param width width (in pixels) of the YUV image
+ *
+ * @param strides an array of integers, each specifying the number of bytes
+ * per line in the corresponding plane of the YUV image. Setting the stride
+ * for any plane to 0 is the same as setting it to the plane width (see
+ * {@link YUVImage above}.) If <code>strides</code> is null, then the
+ * strides for all planes will be set to their respective plane widths. When
+ * using this constructor, the stride for each plane must be equal to or
+ * greater than the plane width.
+ *
+ * @param height height (in pixels) of the YUV image
+ *
+ * @param subsamp the level of chrominance subsampling to be used in the YUV
+ * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
+ */
+ public YUVImage(int width, int[] strides, int height, int subsamp)
+ throws Exception {
+ setBuf(null, null, width, strides, height, subsamp, true);
+ }
+
+ /**
+ * Create a new <code>YUVImage</code> instance backed by a unified image
+ * buffer, and allocate memory for the image buffer.
*
* @param width width (in pixels) of the YUV image
*
@@ -83,13 +106,52 @@ public class YUVImage {
* image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
*/
public YUVImage(int width, int pad, int height, int subsamp)
- throws Exception {
+ throws Exception {
setBuf(new byte[TJ.bufSizeYUV(width, pad, height, subsamp)], width, pad,
height, subsamp);
}
/**
- * Create a <code>YUVImage</code> instance from an existing YUV planar image
+ * Create a new <code>YUVImage</code> instance from a set of existing image
+ * planes.
+ *
+ * @param planes an array of buffers representing the Y, U (Cb), and V (Cr)
+ * image planes (or just the Y plane, if the image is grayscale.) These
+ * planes can be contiguous or non-contiguous in memory. Plane
+ * <code>i</code> should be at least <code>offsets[i] +
+ * {@link TJ#planeSizeYUV TJ.planeSizeYUV}(i, width, strides[i], height, subsamp)</code>
+ * bytes in size.
+ *
+ * @param offsets If this <code>YUVImage</code> instance represents a
+ * subregion of a larger image, then <code>offsets[i]</code> specifies the
+ * offset (in bytes) of the subregion within plane <code>i</code> of the
+ * larger image. Setting this to null is the same as setting the offsets for
+ * all planes to 0.
+ *
+ * @param width width (in pixels) of the new YUV image (or subregion)
+ *
+ * @param strides an array of integers, each specifying the number of bytes
+ * per line in the corresponding plane of the YUV image. Setting the stride
+ * for any plane to 0 is the same as setting it to the plane width (see
+ * {@link YUVImage above}.) If <code>strides</code> is null, then the
+ * strides for all planes will be set to their respective plane widths. You
+ * can adjust the strides in order to add an arbitrary amount of line padding
+ * to each plane or to specify that this <code>YUVImage</code> instance is a
+ * subregion of a larger image (in which case, <code>strides[i]</code> should
+ * be set to the plane width of plane <code>i</code> in the larger image.)
+ *
+ * @param height height (in pixels) of the new YUV image (or subregion)
+ *
+ * @param subsamp the level of chrominance subsampling used in the YUV
+ * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
+ */
+ public YUVImage(byte[][] planes, int[] offsets, int width, int[] strides,
+ int height, int subsamp) throws Exception {
+ setBuf(planes, offsets, width, strides, height, subsamp, false);
+ }
+
+ /**
+ * Create a new <code>YUVImage</code> instance from an existing unified image
* buffer.
*
* @param yuvImage image buffer that contains or will contain YUV planar
@@ -115,8 +177,89 @@ public class YUVImage {
}
/**
- * Assign an existing YUV planar image buffer to this <code>YUVImage</code>
- * instance.
+ * Assign a set of image planes to this <code>YUVImage</code> instance.
+ *
+ * @param planes an array of buffers representing the Y, U (Cb), and V (Cr)
+ * image planes (or just the Y plane, if the image is grayscale.) These
+ * planes can be contiguous or non-contiguous in memory. Plane
+ * <code>i</code> should be at least <code>offsets[i] +
+ * {@link TJ#planeSizeYUV TJ.planeSizeYUV}(i, width, strides[i], height, subsamp)</code>
+ * bytes in size.
+ *
+ * @param offsets If this <code>YUVImage</code> instance represents a
+ * subregion of a larger image, then <code>offsets[i]</code> specifies the
+ * offset (in bytes) of the subregion within plane <code>i</code> of the
+ * larger image. Setting this to null is the same as setting the offsets for
+ * all planes to 0.
+ *
+ * @param width width (in pixels) of the YUV image (or subregion)
+ *
+ * @param strides an array of integers, each specifying the number of bytes
+ * per line in the corresponding plane of the YUV image. Setting the stride
+ * for any plane to 0 is the same as setting it to the plane width (see
+ * {@link YUVImage above}.) If <code>strides</code> is null, then the
+ * strides for all planes will be set to their respective plane widths. You
+ * can adjust the strides in order to add an arbitrary amount of line padding
+ * to each plane or to specify that this <code>YUVImage</code> image is a
+ * subregion of a larger image (in which case, <code>strides[i]</code> should
+ * be set to the plane width of plane <code>i</code> in the larger image.)
+ *
+ * @param height height (in pixels) of the YUV image (or subregion)
+ *
+ * @param subsamp the level of chrominance subsampling used in the YUV
+ * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
+ */
+ public void setBuf(byte[][] planes, int[] offsets, int width, int strides[],
+ int height, int subsamp) throws Exception {
+ setBuf(planes, offsets, width, strides, height, subsamp, false);
+ }
+
+ private void setBuf(byte[][] planes, int[] offsets, int width, int strides[],
+ int height, int subsamp, boolean alloc) throws Exception {
+ if ((planes == null && !alloc) || width < 1 || height < 1 || subsamp < 0 ||
+ subsamp >= TJ.NUMSAMP)
+ throw new Exception("Invalid argument in YUVImage::setBuf()");
+
+ int nc = (subsamp == TJ.SAMP_GRAY ? 1 : 3);
+ if (planes.length != nc || (offsets != null && offsets.length != nc) ||
+ (strides != null && strides.length != nc))
+ throw new Exception("YUVImage::setBuf(): planes, offsets, or strides array is the wrong size");
+
+ if (offsets == null)
+ offsets = new int[nc];
+ if (strides == null)
+ strides = new int[nc];
+
+ for (int i = 0; i < nc; i++) {
+ int pw = TJ.planeWidth(i, width, subsamp);
+ int ph = TJ.planeHeight(i, height, subsamp);
+ int planeSize = TJ.planeSizeYUV(i, width, strides[i], height, subsamp);
+
+ if (strides[i] == 0)
+ strides[i] = pw;
+ if (alloc) {
+ if (strides[i] < pw)
+ throw new Exception("Stride must be >= plane width when allocating a new YUV image");
+ planes[i] = new byte[strides[i] * ph];
+ }
+ if (planes[i] == null || offsets[i] < 0)
+ throw new Exception("Invalid argument in YUVImage::setBuf()");
+ if (strides[i] < 0 && offsets[i] - planeSize + pw < 0)
+ throw new Exception("Stride for plane " + i + " would cause memory to be accessed below plane boundary");
+ if (planes[i].length < offsets[i] + planeSize)
+ throw new Exception("Image plane " + i + " is not large enough");
+ }
+
+ yuvPlanes = planes;
+ yuvOffsets = offsets;
+ yuvWidth = width;
+ yuvStrides = strides;
+ yuvHeight = height;
+ yuvSubsamp = subsamp;
+ }
+
+ /**
+ * Assign a unified image buffer to this <code>YUVImage</code> instance.
*
* @param yuvImage image buffer that contains or will contain YUV planar
* image data. Use {@link TJ#bufSizeYUV} to determine the minimum size for
@@ -139,20 +282,34 @@ public class YUVImage {
int subsamp) throws Exception {
if (yuvImage == null || width < 1 || pad < 1 || ((pad & (pad - 1)) != 0) ||
height < 1 || subsamp < 0 || subsamp >= TJ.NUMSAMP)
- throw new Exception("Invalid argument in YUVImage()");
+ throw new Exception("Invalid argument in YUVImage::setBuf()");
if (yuvImage.length < TJ.bufSizeYUV(width, pad, height, subsamp))
throw new Exception("YUV image buffer is not large enough");
- yuvBuf = yuvImage;
- yuvWidth = width;
+
+ int nc = (subsamp == TJ.SAMP_GRAY ? 1 : 3);
+ byte[][] planes = new byte[nc][];
+ int[] strides = new int[nc];
+ int[] offsets = new int[nc];
+
+ planes[0] = yuvImage;
+ strides[0] = PAD(TJ.planeWidth(0, width, subsamp), pad);
+ if (subsamp != TJ.SAMP_GRAY) {
+ strides[1] = strides[2] = PAD(TJ.planeWidth(1, width, subsamp), pad);
+ planes[1] = planes[2] = yuvImage;
+ offsets[1] = offsets[0] +
+ strides[0] * TJ.planeHeight(0, height, subsamp);
+ offsets[2] = offsets[1] +
+ strides[1] * TJ.planeHeight(1, height, subsamp);
+ }
+
yuvPad = pad;
- yuvHeight = height;
- yuvSubsamp = subsamp;
+ setBuf(planes, offsets, width, strides, height, subsamp);
}
/**
- * Returns the width of the YUV image.
+ * Returns the width of the YUV image (or subregion.)
*
- * @return the width of the YUV image
+ * @return the width of the YUV image (or subregion)
*/
public int getWidth() throws Exception {
if (yuvWidth < 1)
@@ -161,9 +318,9 @@ public class YUVImage {
}
/**
- * Returns the height of the YUV image.
+ * Returns the height of the YUV image (or subregion.)
*
- * @return the height of the YUV image
+ * @return the height of the YUV image (or subregion)
*/
public int getHeight() throws Exception {
if (yuvHeight < 1)
@@ -172,17 +329,44 @@ public class YUVImage {
}
/**
- * Returns the line padding used in the YUV image buffer.
+ * Returns the line padding used in the YUV image buffer (if this image is
+ * stored in a unified buffer rather than separate image planes.)
*
* @return the line padding used in the YUV image buffer
*/
public int getPad() throws Exception {
- if (yuvPad < 1 || ((yuvPad & (yuvPad - 1)) != 0))
+ if (yuvPlanes == null)
throw new Exception(NO_ASSOC_ERROR);
+ if (yuvPad < 1 || ((yuvPad & (yuvPad - 1)) != 0))
+ throw new Exception("Image is not stored in a unified buffer");
return yuvPad;
}
/**
+ * Returns the number of bytes per line of each plane in the YUV image.
+ *
+ * @return the number of bytes per line of each plane in the YUV image
+ */
+ public int[] getStrides() throws Exception {
+ if (yuvStrides == null)
+ throw new Exception(NO_ASSOC_ERROR);
+ return yuvStrides;
+ }
+
+ /**
+ * Returns the offsets (in bytes) of each plane within the planes of a larger
+ * YUV image.
+ *
+ * @return the offsets (in bytes) of each plane within the planes of a larger
+ * YUV image
+ */
+ public int[] getOffsets() throws Exception {
+ if (yuvOffsets == null)
+ throw new Exception(NO_ASSOC_ERROR);
+ return yuvOffsets;
+ }
+
+ /**
* Returns the level of chrominance subsampling used in the YUV image. See
* {@link TJ#SAMP_444 TJ.SAMP_*}.
*
@@ -195,29 +379,61 @@ public class YUVImage {
}
/**
- * Returns the YUV image buffer
+ * Returns the YUV image planes. If the image is stored in a unified buffer,
+ * then all image planes will point to that buffer.
+ *
+ * @return the YUV image planes
+ */
+ public byte[][] getPlanes() throws Exception {
+ if (yuvPlanes == null)
+ throw new Exception(NO_ASSOC_ERROR);
+ return yuvPlanes;
+ }
+
+ /**
+ * Returns the YUV image buffer (if this image is stored in a unified
+ * buffer rather than separate image planes.)
*
* @return the YUV image buffer
*/
public byte[] getBuf() throws Exception {
- if (yuvBuf == null)
+ if (yuvPlanes == null || yuvSubsamp < 0 || yuvSubsamp >= TJ.NUMSAMP)
throw new Exception(NO_ASSOC_ERROR);
- return yuvBuf;
+ int nc = (yuvSubsamp == TJ.SAMP_GRAY ? 1 : 3);
+ for (int i = 1; i < nc; i++) {
+ if (yuvPlanes[i] != yuvPlanes[0])
+ throw new Exception("Image is not stored in a unified buffer");
+ }
+ return yuvPlanes[0];
}
/**
- * Returns the size (in bytes) of the YUV image buffer
+ * Returns the size (in bytes) of the YUV image buffer (if this image is
+ * stored in a unified buffer rather than separate image planes.)
*
* @return the size (in bytes) of the YUV image buffer
*/
- public int getSize() throws Exception {
- if (yuvBuf == null)
- throw new Exception(NO_ASSOC_ERROR);
- return TJ.bufSizeYUV(yuvWidth, yuvPad, yuvHeight, yuvSubsamp);
- }
+ public int getSize() throws Exception {
+ if (yuvPlanes == null || yuvSubsamp < 0 || yuvSubsamp >= TJ.NUMSAMP)
+ throw new Exception(NO_ASSOC_ERROR);
+ int nc = (yuvSubsamp == TJ.SAMP_GRAY ? 1 : 3);
+ if (yuvPad < 1)
+ throw new Exception("Image is not stored in a unified buffer");
+ for (int i = 1; i < nc; i++) {
+ if (yuvPlanes[i] != yuvPlanes[0])
+ throw new Exception("Image is not stored in a unified buffer");
+ }
+ return TJ.bufSizeYUV(yuvWidth, yuvPad, yuvHeight, yuvSubsamp);
+ }
+
+ private static final int PAD(int v, int p) {
+ return (v + p - 1) & (~(p - 1));
+ }
protected long handle = 0;
- protected byte[] yuvBuf = null;
+ protected byte[][] yuvPlanes = null;
+ protected int[] yuvOffsets = null;
+ protected int[] yuvStrides = null;
protected int yuvPad = 0;
protected int yuvWidth = 0;
protected int yuvHeight = 0;