123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931 |
- /*
- * Copyright (C)2011-2015, 2018 D. R. Commander. All Rights Reserved.
- * Copyright (C)2015 Viktor Szathmáry. 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.*;
- import java.io.*;
- /**
- * TurboJPEG decompressor
- */
- public class TJDecompressor implements Closeable {
- private static final String NO_ASSOC_ERROR =
- "No JPEG image is associated with this instance";
- /**
- * Create a TurboJPEG decompresssor instance.
- */
- public TJDecompressor() throws TJException {
- init();
- }
- /**
- * Create a TurboJPEG decompressor instance and associate the JPEG source
- * 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.) This buffer is not modified.
- */
- public TJDecompressor(byte[] jpegImage) throws TJException {
- init();
- setSourceImage(jpegImage, jpegImage.length);
- }
- /**
- * Create a TurboJPEG decompressor instance and associate the JPEG source
- * image of length <code>imageSize</code> bytes stored in
- * <code>jpegImage</code> with the newly created instance.
- *
- * @param jpegImage JPEG image buffer. This buffer is not modified.
- *
- * @param imageSize size of the JPEG image (in bytes)
- */
- public TJDecompressor(byte[] jpegImage, int imageSize) throws TJException {
- init();
- setSourceImage(jpegImage, imageSize);
- }
- /**
- * Create a TurboJPEG decompressor instance and associate the YUV planar
- * source image stored in <code>yuvImage</code> with the newly created
- * instance.
- *
- * @param yuvImage {@link YUVImage} instance containing a YUV planar
- * image to be decoded. This image is not modified.
- */
- @SuppressWarnings("checkstyle:HiddenField")
- public TJDecompressor(YUVImage yuvImage) throws TJException {
- init();
- setSourceImage(yuvImage);
- }
- /**
- * 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. This buffer is not modified.
- *
- * @param imageSize size of the JPEG image (in bytes)
- */
- public void setSourceImage(byte[] jpegImage, int imageSize)
- throws TJException {
- if (jpegImage == null || imageSize < 1)
- throw new IllegalArgumentException("Invalid argument in setSourceImage()");
- jpegBuf = jpegImage;
- jpegBufSize = imageSize;
- decompressHeader(jpegBuf, jpegBufSize);
- yuvImage = null;
- }
- /**
- * @deprecated Use {@link #setSourceImage(byte[], int)} instead.
- */
- @SuppressWarnings("checkstyle:JavadocMethod")
- @Deprecated
- public void setJPEGImage(byte[] jpegImage, int imageSize)
- throws TJException {
- setSourceImage(jpegImage, imageSize);
- }
- /**
- * Associate the specified YUV planar source image with this decompressor
- * instance. Subsequent decompress operations will decode this image into an
- * RGB or grayscale destination image.
- *
- * @param srcImage {@link YUVImage} instance containing a YUV planar image to
- * be decoded. This image is not modified.
- */
- public void setSourceImage(YUVImage srcImage) {
- if (srcImage == null)
- throw new IllegalArgumentException("Invalid argument in setSourceImage()");
- yuvImage = srcImage;
- jpegBuf = null;
- jpegBufSize = 0;
- }
- /**
- * Returns the width of the source image (JPEG or YUV) associated with this
- * decompressor instance.
- *
- * @return the width of the source image (JPEG or YUV) associated with this
- * decompressor instance.
- */
- public int getWidth() {
- if (yuvImage != null)
- return yuvImage.getWidth();
- if (jpegWidth < 1)
- throw new IllegalStateException(NO_ASSOC_ERROR);
- return jpegWidth;
- }
- /**
- * Returns the height of the source image (JPEG or YUV) associated with this
- * decompressor instance.
- *
- * @return the height of the source image (JPEG or YUV) associated with this
- * decompressor instance.
- */
- public int getHeight() {
- if (yuvImage != null)
- return yuvImage.getHeight();
- if (jpegHeight < 1)
- throw new IllegalStateException(NO_ASSOC_ERROR);
- return jpegHeight;
- }
- /**
- * Returns the level of chrominance subsampling used in the source image
- * (JPEG or YUV) associated with this decompressor instance. See
- * {@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.
- */
- public int getSubsamp() {
- if (yuvImage != null)
- return yuvImage.getSubsamp();
- if (jpegSubsamp < 0)
- throw new IllegalStateException(NO_ASSOC_ERROR);
- if (jpegSubsamp >= TJ.NUMSAMP)
- throw new IllegalStateException("JPEG header information is invalid");
- return jpegSubsamp;
- }
- /**
- * Returns the colorspace used in the source image (JPEG or YUV) associated
- * with this decompressor instance. See {@link TJ#CS_RGB TJ.CS_*}. If the
- * 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.
- */
- public int getColorspace() {
- if (yuvImage != null)
- return TJ.CS_YCbCr;
- if (jpegColorspace < 0)
- throw new IllegalStateException(NO_ASSOC_ERROR);
- if (jpegColorspace >= TJ.NUMCS)
- throw new IllegalStateException("JPEG header information is invalid");
- return jpegColorspace;
- }
- /**
- * Returns the JPEG image buffer associated with this decompressor instance.
- *
- * @return the JPEG image buffer associated with this decompressor instance.
- */
- public byte[] getJPEGBuf() {
- if (jpegBuf == null)
- throw new IllegalStateException(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() {
- if (jpegBufSize < 1)
- throw new IllegalStateException(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) {
- if (jpegWidth < 1 || jpegHeight < 1)
- throw new IllegalStateException(NO_ASSOC_ERROR);
- if (desiredWidth < 0 || desiredHeight < 0)
- throw new IllegalArgumentException("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 IllegalArgumentException("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) {
- if (jpegWidth < 1 || jpegHeight < 1)
- throw new IllegalStateException(NO_ASSOC_ERROR);
- if (desiredWidth < 0 || desiredHeight < 0)
- throw new IllegalArgumentException("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 IllegalArgumentException("Could not scale down to desired image dimensions");
- return scaledHeight;
- }
- /**
- * Decompress the JPEG source image or decode the YUV source image associated
- * with this decompressor instance and output a grayscale, RGB, or CMYK image
- * to the given destination buffer.
- * <p>
- * NOTE: The output image is fully recoverable if this method throws a
- * non-fatal {@link TJException} (unless
- * {@link TJ#FLAG_STOPONWARNING TJ.FLAG_STOPONWARNING} is specified.)
- *
- * @param dstBuf buffer that will receive the decompressed/decoded image.
- * If the source image is a JPEG image, then 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}. If the
- * source image is a YUV image, then this buffer should normally be
- * <code>pitch * height</code> bytes in size, where <code>height</code> is
- * the height of the YUV image. However, the buffer may also be larger than
- * the dimensions of the source image, in which case the <code>x</code>,
- * <code>y</code>, and <code>pitch</code> parameters can be used to specify
- * the region into which the source image should be decompressed/decoded.
- *
- * @param x x offset (in pixels) of the region in the destination image into
- * which the source image should be decompressed/decoded
- *
- * @param y y offset (in pixels) of the region in the destination image into
- * which the source image should be decompressed/decoded
- *
- * @param desiredWidth If the source image is a JPEG image, then this
- * specifies the desired width (in pixels) of the decompressed image (or
- * image region.) If the desired destination image dimensions are different
- * than the source image dimensions, 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.) This parameter is
- * ignored if the source image is a YUV image.
- *
- * @param pitch bytes per line of the destination image. Normally, this
- * should be set to <code>scaledWidth * TJ.pixelSize(pixelFormat)</code> if
- * the destination image is unpadded, but you can use this to, for instance,
- * pad each line of the destination image to a 4-byte boundary or to
- * decompress/decode the source image into a region of a larger image. NOTE:
- * if the source image is a JPEG image, then <code>scaledWidth</code> can be
- * determined by calling <code>
- * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegWidth)
- * </code> or by calling {@link #getScaledWidth}. If the source image is a
- * YUV image, then <code>scaledWidth</code> is the width of the YUV image.
- * Setting this parameter to 0 is the equivalent of setting it to
- * <code>scaledWidth * TJ.pixelSize(pixelFormat)</code>.
- *
- * @param desiredHeight If the source image is a JPEG image, then this
- * specifies the desired height (in pixels) of the decompressed image (or
- * image region.) If the desired destination image dimensions are different
- * than the source image dimensions, 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.) This parameter is
- * ignored if the source image is a YUV image.
- *
- * @param pixelFormat pixel format of the decompressed/decoded image (one of
- * {@link TJ#PF_RGB TJ.PF_*})
- *
- * @param flags the bitwise OR of one or more of
- * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
- */
- public void decompress(byte[] dstBuf, int x, int y, int desiredWidth,
- int pitch, int desiredHeight, int pixelFormat,
- int flags) throws TJException {
- if (jpegBuf == null && yuvImage == null)
- throw new IllegalStateException(NO_ASSOC_ERROR);
- if (dstBuf == null || x < 0 || y < 0 || pitch < 0 ||
- (yuvImage != null && (desiredWidth < 0 || desiredHeight < 0)) ||
- pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
- throw new IllegalArgumentException("Invalid argument in decompress()");
- if (yuvImage != null)
- 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,
- desiredHeight, pixelFormat, flags);
- else
- decompress(jpegBuf, jpegBufSize, dstBuf, desiredWidth, pitch,
- desiredHeight, pixelFormat, flags);
- }
- }
- /**
- * @deprecated Use
- * {@link #decompress(byte[], int, int, int, int, int, int, int)} instead.
- */
- @SuppressWarnings("checkstyle:JavadocMethod")
- @Deprecated
- public void decompress(byte[] dstBuf, int desiredWidth, int pitch,
- int desiredHeight, int pixelFormat, int flags)
- throws TJException {
- decompress(dstBuf, 0, 0, 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, int, int)}
- * for description
- *
- * @param pitch see
- * {@link #decompress(byte[], int, int, int, int, int, int, int)}
- * for description
- *
- * @param desiredHeight see
- * {@link #decompress(byte[], int, int, int, int, int, int, int)}
- * for description
- *
- * @param pixelFormat pixel format of the decompressed image (one of
- * {@link TJ#PF_RGB TJ.PF_*})
- *
- * @param flags the bitwise OR of one or more of
- * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
- *
- * @return a buffer containing the decompressed image.
- */
- public byte[] decompress(int desiredWidth, int pitch, int desiredHeight,
- int pixelFormat, int flags) throws TJException {
- if (pitch < 0 ||
- (yuvImage == null && (desiredWidth < 0 || desiredHeight < 0)) ||
- pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
- throw new IllegalArgumentException("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 into a YUV planar image and store it in the given
- * <code>YUVImage</code> instance. 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.
- * <p>
- * NOTE: The YUV planar output image is fully recoverable if this method
- * throws a non-fatal {@link TJException} (unless
- * {@link TJ#FLAG_STOPONWARNING TJ.FLAG_STOPONWARNING} is specified.)
- *
- * @param dstImage {@link YUVImage} instance that will receive the YUV planar
- * image. The level of subsampling specified in this <code>YUVImage</code>
- * instance must match that of the JPEG image, and the width and height
- * specified in the <code>YUVImage</code> instance must match one of the
- * scaled image sizes that TurboJPEG is capable of generating from the JPEG
- * source image.
- *
- * @param flags the bitwise OR of one or more of
- * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
- */
- public void decompressToYUV(YUVImage dstImage, int flags)
- throws TJException {
- if (jpegBuf == null)
- throw new IllegalStateException(NO_ASSOC_ERROR);
- if (dstImage == null || flags < 0)
- throw new IllegalArgumentException("Invalid argument in decompressToYUV()");
- int scaledWidth = getScaledWidth(dstImage.getWidth(),
- dstImage.getHeight());
- int scaledHeight = getScaledHeight(dstImage.getWidth(),
- dstImage.getHeight());
- if (scaledWidth != dstImage.getWidth() ||
- scaledHeight != dstImage.getHeight())
- throw new IllegalArgumentException("YUVImage dimensions do not match one of the scaled image sizes that TurboJPEG is capable of generating.");
- if (jpegSubsamp != dstImage.getSubsamp())
- throw new IllegalArgumentException("YUVImage subsampling level does not match that of the JPEG image");
- decompressToYUV(jpegBuf, jpegBufSize, dstImage.getPlanes(),
- dstImage.getOffsets(), dstImage.getWidth(),
- dstImage.getStrides(), dstImage.getHeight(), flags);
- }
- /**
- * @deprecated Use {@link #decompressToYUV(YUVImage, int)} instead.
- */
- @SuppressWarnings("checkstyle:JavadocMethod")
- @Deprecated
- public void decompressToYUV(byte[] dstBuf, int flags) throws TJException {
- YUVImage dstYUVImage = new YUVImage(dstBuf, jpegWidth, 4, jpegHeight,
- jpegSubsamp);
- decompressToYUV(dstYUVImage, flags);
- }
- /**
- * Decompress the JPEG source image associated with this decompressor
- * 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 TJException {
- if (flags < 0)
- throw new IllegalArgumentException("Invalid argument in decompressToYUV()");
- if (jpegWidth < 1 || jpegHeight < 1 || jpegSubsamp < 0)
- throw new IllegalStateException(NO_ASSOC_ERROR);
- if (jpegSubsamp >= TJ.NUMSAMP)
- throw new IllegalStateException("JPEG header information is invalid");
- if (yuvImage != null)
- throw new IllegalStateException("Source image is the wrong type");
- int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
- int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
- YUVImage dstYUVImage = new YUVImage(scaledWidth, null, scaledHeight,
- jpegSubsamp);
- decompressToYUV(dstYUVImage, flags);
- return dstYUVImage;
- }
- /**
- * 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
- * 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 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
- * 2.)
- *
- * @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 pad, int desiredHeight,
- int flags) throws TJException {
- if (flags < 0)
- throw new IllegalArgumentException("Invalid argument in decompressToYUV()");
- if (jpegWidth < 1 || jpegHeight < 1 || jpegSubsamp < 0)
- throw new IllegalStateException(NO_ASSOC_ERROR);
- if (jpegSubsamp >= TJ.NUMSAMP)
- throw new IllegalStateException("JPEG header information is invalid");
- if (yuvImage != null)
- throw new IllegalStateException("Source image is the wrong type");
- int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
- int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
- YUVImage dstYUVImage = new YUVImage(scaledWidth, pad, scaledHeight,
- jpegSubsamp);
- decompressToYUV(dstYUVImage, flags);
- return dstYUVImage;
- }
- /**
- * @deprecated Use {@link #decompressToYUV(int, int, int, int)} instead.
- */
- @SuppressWarnings("checkstyle:JavadocMethod")
- @Deprecated
- public byte[] decompressToYUV(int flags) throws TJException {
- YUVImage dstYUVImage = new YUVImage(jpegWidth, 4, jpegHeight, jpegSubsamp);
- decompressToYUV(dstYUVImage, flags);
- return dstYUVImage.getBuf();
- }
- /**
- * Decompress the JPEG source image or decode the YUV source image associated
- * with this decompressor instance and output a grayscale, RGB, or CMYK image
- * to the given destination buffer.
- * <p>
- * NOTE: The output image is fully recoverable if this method throws a
- * non-fatal {@link TJException} (unless
- * {@link TJ#FLAG_STOPONWARNING TJ.FLAG_STOPONWARNING} is specified.)
- *
- * @param dstBuf buffer that will receive the decompressed/decoded image.
- * If the source image is a JPEG image, then this buffer should normally be
- * <code>stride * scaledHeight</code> pixels 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}. If the
- * source image is a YUV image, then this buffer should normally be
- * <code>stride * height</code> pixels in size, where <code>height</code> is
- * the height of the YUV image. However, the buffer may also be larger than
- * the dimensions of the JPEG image, in which case the <code>x</code>,
- * <code>y</code>, and <code>stride</code> parameters can be used to specify
- * the region into which the source image should be decompressed.
- *
- * @param x x offset (in pixels) of the region in the destination image into
- * which the source image should be decompressed/decoded
- *
- * @param y y offset (in pixels) of the region in the destination image into
- * which the source image should be decompressed/decoded
- *
- * @param desiredWidth If the source image is a JPEG image, then this
- * specifies the desired width (in pixels) of the decompressed image (or
- * image region.) If the desired destination image dimensions are different
- * than the source image dimensions, 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.) This parameter is
- * ignored if the source image is a YUV image.
- *
- * @param stride pixels per line of the destination image. Normally, this
- * should be set to <code>scaledWidth</code>, but you can use this to, for
- * instance, decompress the JPEG image into a region of a larger image.
- * NOTE: if the source image is a JPEG image, then <code>scaledWidth</code>
- * can be determined by calling <code>
- * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegWidth)
- * </code> or by calling {@link #getScaledWidth}. If the source image is a
- * YUV image, then <code>scaledWidth</code> is the width of the YUV image.
- * Setting this parameter to 0 is the equivalent of setting it to
- * <code>scaledWidth</code>.
- *
- * @param desiredHeight If the source image is a JPEG image, then this
- * specifies the desired height (in pixels) of the decompressed image (or
- * image region.) If the desired destination image dimensions are different
- * than the source image dimensions, 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.) This parameter is
- * ignored if the source image is a YUV image.
- *
- * @param pixelFormat pixel format of the decompressed image (one of
- * {@link TJ#PF_RGB TJ.PF_*})
- *
- * @param flags the bitwise OR of one or more of
- * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
- */
- public void decompress(int[] dstBuf, int x, int y, int desiredWidth,
- int stride, int desiredHeight, int pixelFormat,
- int flags) throws TJException {
- if (jpegBuf == null && yuvImage == null)
- throw new IllegalStateException(NO_ASSOC_ERROR);
- if (dstBuf == null || x < 0 || y < 0 || stride < 0 ||
- (yuvImage != null && (desiredWidth < 0 || desiredHeight < 0)) ||
- pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
- throw new IllegalArgumentException("Invalid argument in decompress()");
- if (yuvImage != null)
- 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);
- }
- /**
- * Decompress the JPEG source image or decode the YUV source image associated
- * with this decompressor instance and output a decompressed/decoded image to
- * the given <code>BufferedImage</code> instance.
- * <p>
- * NOTE: The output image is fully recoverable if this method throws a
- * non-fatal {@link TJException} (unless
- * {@link TJ#FLAG_STOPONWARNING TJ.FLAG_STOPONWARNING} is specified.)
- *
- * @param dstImage a <code>BufferedImage</code> instance that will receive
- * the decompressed/decoded image. If the source image is a JPEG image, then
- * the width and height of the <code>BufferedImage</code> instance must match
- * one of the scaled image sizes that TurboJPEG is capable of generating from
- * the JPEG image. If the source image is a YUV image, then the width and
- * height of the <code>BufferedImage</code> instance must match the width and
- * height of the YUV image.
- *
- * @param flags the bitwise OR of one or more of
- * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
- */
- public void decompress(BufferedImage dstImage, int flags)
- throws TJException {
- if (dstImage == null || flags < 0)
- throw new IllegalArgumentException("Invalid argument in decompress()");
- int desiredWidth = dstImage.getWidth();
- int desiredHeight = dstImage.getHeight();
- int scaledWidth, scaledHeight;
- if (yuvImage != null) {
- if (desiredWidth != yuvImage.getWidth() ||
- desiredHeight != yuvImage.getHeight())
- throw new IllegalArgumentException("BufferedImage dimensions do not match the dimensions of the source image.");
- scaledWidth = yuvImage.getWidth();
- scaledHeight = yuvImage.getHeight();
- } else {
- scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
- scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
- if (scaledWidth != desiredWidth || scaledHeight != desiredHeight)
- throw new IllegalArgumentException("BufferedImage dimensions do not match one of the scaled image sizes 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 IllegalArgumentException("Unsupported BufferedImage format");
- }
- WritableRaster wr = dstImage.getRaster();
- if (intPixels) {
- SinglePixelPackedSampleModel sm =
- (SinglePixelPackedSampleModel)dstImage.getSampleModel();
- int stride = sm.getScanlineStride();
- DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
- int[] buf = db.getData();
- if (yuvImage != null)
- decodeYUV(yuvImage.getPlanes(), yuvImage.getOffsets(),
- yuvImage.getStrides(), yuvImage.getSubsamp(), buf, 0, 0,
- yuvImage.getWidth(), stride, yuvImage.getHeight(),
- pixelFormat, flags);
- else {
- if (jpegBuf == null)
- throw new IllegalStateException(NO_ASSOC_ERROR);
- decompress(jpegBuf, jpegBufSize, buf, 0, 0, scaledWidth, stride,
- scaledHeight, pixelFormat, flags);
- }
- } else {
- ComponentSampleModel sm =
- (ComponentSampleModel)dstImage.getSampleModel();
- int pixelSize = sm.getPixelStride();
- if (pixelSize != TJ.getPixelSize(pixelFormat))
- throw new IllegalArgumentException("Inconsistency between pixel format and pixel size in BufferedImage");
- int pitch = sm.getScanlineStride();
- DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
- byte[] buf = db.getData();
- decompress(buf, 0, 0, scaledWidth, pitch, scaledHeight, pixelFormat,
- flags);
- }
- }
- /**
- * Decompress the JPEG source image or decode the YUV source image associated
- * with this decompressor instance and return a <code>BufferedImage</code>
- * instance containing the decompressed/decoded image.
- *
- * @param desiredWidth see
- * {@link #decompress(byte[], int, int, int, int, int, int, int)} for
- * description
- *
- * @param desiredHeight see
- * {@link #decompress(byte[], int, int, int, int, int, int, int)} for
- * description
- *
- * @param bufferedImageType the image type of the <code>BufferedImage</code>
- * instance that will be created (for instance,
- * <code>BufferedImage.TYPE_INT_RGB</code>)
- *
- * @param flags the bitwise OR of one or more of
- * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
- *
- * @return a <code>BufferedImage</code> instance containing the
- * decompressed/decoded image.
- */
- public BufferedImage decompress(int desiredWidth, int desiredHeight,
- int bufferedImageType, int flags)
- throws TJException {
- if ((yuvImage == null && (desiredWidth < 0 || desiredHeight < 0)) ||
- flags < 0)
- throw new IllegalArgumentException("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.
- */
- @Override
- public void close() throws TJException {
- if (handle != 0)
- destroy();
- }
- @SuppressWarnings("checkstyle:DesignForExtension")
- @Override
- protected void finalize() throws Throwable {
- try {
- close();
- } catch (TJException e) {
- } finally {
- super.finalize();
- }
- };
- private native void init() throws TJException;
- private native void destroy() throws TJException;
- private native void decompressHeader(byte[] srcBuf, int size)
- throws TJException;
- @Deprecated
- private native void decompress(byte[] srcBuf, int size, byte[] dstBuf,
- int desiredWidth, int pitch, int desiredHeight, int pixelFormat, int flags)
- throws TJException;
- private native void decompress(byte[] srcBuf, int size, byte[] dstBuf, int x,
- int y, int desiredWidth, int pitch, int desiredHeight, int pixelFormat,
- int flags) throws TJException;
- @Deprecated
- private native void decompress(byte[] srcBuf, int size, int[] dstBuf,
- int desiredWidth, int stride, int desiredHeight, int pixelFormat,
- int flags) throws TJException;
- private native void decompress(byte[] srcBuf, int size, int[] dstBuf, int x,
- int y, int desiredWidth, int stride, int desiredHeight, int pixelFormat,
- int flags) throws TJException;
- @Deprecated
- private native void decompressToYUV(byte[] srcBuf, int size, byte[] dstBuf,
- int flags) throws TJException;
- private native void decompressToYUV(byte[] srcBuf, int size,
- byte[][] dstPlanes, int[] dstOffsets, int desiredWidth, int[] dstStrides,
- int desiredheight, int flags) throws TJException;
- 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 TJException;
- 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 TJException;
- static {
- TJLoader.load();
- }
- protected long handle = 0;
- protected byte[] jpegBuf = null;
- protected int jpegBufSize = 0;
- protected YUVImage yuvImage = null;
- protected int jpegWidth = 0;
- protected int jpegHeight = 0;
- protected int jpegSubsamp = -1;
- protected int jpegColorspace = -1;
- private ByteOrder byteOrder = null;
- }
|