TJCompressor.java revision fac3bea8dae8664110951427434d94bcd139d17b
1c5a419970eb91c85844002901210484b29e25fb1DRC/*
2fac3bea8dae8664110951427434d94bcd139d17bDRC * Copyright (C)2011-2012 D. R. Commander.  All Rights Reserved.
3c5a419970eb91c85844002901210484b29e25fb1DRC *
4c5a419970eb91c85844002901210484b29e25fb1DRC * Redistribution and use in source and binary forms, with or without
5c5a419970eb91c85844002901210484b29e25fb1DRC * modification, are permitted provided that the following conditions are met:
6c5a419970eb91c85844002901210484b29e25fb1DRC *
7c5a419970eb91c85844002901210484b29e25fb1DRC * - Redistributions of source code must retain the above copyright notice,
8c5a419970eb91c85844002901210484b29e25fb1DRC *   this list of conditions and the following disclaimer.
9c5a419970eb91c85844002901210484b29e25fb1DRC * - Redistributions in binary form must reproduce the above copyright notice,
10c5a419970eb91c85844002901210484b29e25fb1DRC *   this list of conditions and the following disclaimer in the documentation
11c5a419970eb91c85844002901210484b29e25fb1DRC *   and/or other materials provided with the distribution.
12c5a419970eb91c85844002901210484b29e25fb1DRC * - Neither the name of the libjpeg-turbo Project nor the names of its
13c5a419970eb91c85844002901210484b29e25fb1DRC *   contributors may be used to endorse or promote products derived from this
14c5a419970eb91c85844002901210484b29e25fb1DRC *   software without specific prior written permission.
15c5a419970eb91c85844002901210484b29e25fb1DRC *
16c5a419970eb91c85844002901210484b29e25fb1DRC * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
17c5a419970eb91c85844002901210484b29e25fb1DRC * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18c5a419970eb91c85844002901210484b29e25fb1DRC * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19c5a419970eb91c85844002901210484b29e25fb1DRC * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20c5a419970eb91c85844002901210484b29e25fb1DRC * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21c5a419970eb91c85844002901210484b29e25fb1DRC * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22c5a419970eb91c85844002901210484b29e25fb1DRC * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23c5a419970eb91c85844002901210484b29e25fb1DRC * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24c5a419970eb91c85844002901210484b29e25fb1DRC * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25c5a419970eb91c85844002901210484b29e25fb1DRC * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26c5a419970eb91c85844002901210484b29e25fb1DRC * POSSIBILITY OF SUCH DAMAGE.
27c5a419970eb91c85844002901210484b29e25fb1DRC */
28c5a419970eb91c85844002901210484b29e25fb1DRC
29c5a419970eb91c85844002901210484b29e25fb1DRCpackage org.libjpegturbo.turbojpeg;
30c5a419970eb91c85844002901210484b29e25fb1DRC
3184a1bcca6fd0f21091a84f04b820b29012c60857DRCimport java.awt.image.*;
321f014c32e66e00f4e6934f31beefae57ab51a477DRCimport java.nio.*;
3384a1bcca6fd0f21091a84f04b820b29012c60857DRC
3492549de2c2b139070294aec12ec39b7c86a56b52DRC/**
3592549de2c2b139070294aec12ec39b7c86a56b52DRC * TurboJPEG compressor
3692549de2c2b139070294aec12ec39b7c86a56b52DRC */
37c5a419970eb91c85844002901210484b29e25fb1DRCpublic class TJCompressor {
38c5a419970eb91c85844002901210484b29e25fb1DRC
392c74e5124d25112809bdc26cbc36aa764e8870c3DRC  private final static String NO_ASSOC_ERROR =
402c74e5124d25112809bdc26cbc36aa764e8870c3DRC    "No source image is associated with this instance";
412c74e5124d25112809bdc26cbc36aa764e8870c3DRC
4292549de2c2b139070294aec12ec39b7c86a56b52DRC  /**
4392549de2c2b139070294aec12ec39b7c86a56b52DRC   * Create a TurboJPEG compressor instance.
4492549de2c2b139070294aec12ec39b7c86a56b52DRC   */
45c5a419970eb91c85844002901210484b29e25fb1DRC  public TJCompressor() throws Exception {
46c5a419970eb91c85844002901210484b29e25fb1DRC    init();
47c5a419970eb91c85844002901210484b29e25fb1DRC  }
48c5a419970eb91c85844002901210484b29e25fb1DRC
4992549de2c2b139070294aec12ec39b7c86a56b52DRC  /**
5092549de2c2b139070294aec12ec39b7c86a56b52DRC   * Create a TurboJPEG compressor instance and associate the uncompressed
512c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * source image stored in <code>srcImage</code> with the newly-created
522c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * instance.
5392549de2c2b139070294aec12ec39b7c86a56b52DRC   *
542c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * @param srcImage see {@link #setSourceImage} for description
5592549de2c2b139070294aec12ec39b7c86a56b52DRC   *
562c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * @param width see {@link #setSourceImage} for description
5792549de2c2b139070294aec12ec39b7c86a56b52DRC   *
582c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * @param pitch see {@link #setSourceImage} for description
5992549de2c2b139070294aec12ec39b7c86a56b52DRC   *
602c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * @param height see {@link #setSourceImage} for description
6192549de2c2b139070294aec12ec39b7c86a56b52DRC   *
622c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * @param pixelFormat see {@link #setSourceImage} for description
6392549de2c2b139070294aec12ec39b7c86a56b52DRC   */
642c74e5124d25112809bdc26cbc36aa764e8870c3DRC  public TJCompressor(byte[] srcImage, int width, int pitch, int height,
6536336fcddc4cc9f74988e3f03c4683c88c8fce45DRC    int pixelFormat) throws Exception {
662c74e5124d25112809bdc26cbc36aa764e8870c3DRC    setSourceImage(srcImage, width, pitch, height, pixelFormat);
6736336fcddc4cc9f74988e3f03c4683c88c8fce45DRC  }
6836336fcddc4cc9f74988e3f03c4683c88c8fce45DRC
6992549de2c2b139070294aec12ec39b7c86a56b52DRC  /**
70fac3bea8dae8664110951427434d94bcd139d17bDRC   * Create a TurboJPEG compressor instance and associate the uncompressed
71fac3bea8dae8664110951427434d94bcd139d17bDRC   * source image stored in <code>srcImage</code> with the newly-created
72fac3bea8dae8664110951427434d94bcd139d17bDRC   * instance.
73fac3bea8dae8664110951427434d94bcd139d17bDRC   *
74fac3bea8dae8664110951427434d94bcd139d17bDRC   * @param srcImage see {@link #setSourceImage} for description
75fac3bea8dae8664110951427434d94bcd139d17bDRC   *
76fac3bea8dae8664110951427434d94bcd139d17bDRC   * @param x see {@link #setSourceImage} for description
77fac3bea8dae8664110951427434d94bcd139d17bDRC   *
78fac3bea8dae8664110951427434d94bcd139d17bDRC   * @param y see {@link #setSourceImage} for description
79fac3bea8dae8664110951427434d94bcd139d17bDRC   *
80fac3bea8dae8664110951427434d94bcd139d17bDRC   * @param width see {@link #setSourceImage} for description
81fac3bea8dae8664110951427434d94bcd139d17bDRC   *
82fac3bea8dae8664110951427434d94bcd139d17bDRC   * @param pitch see {@link #setSourceImage} for description
83fac3bea8dae8664110951427434d94bcd139d17bDRC   *
84fac3bea8dae8664110951427434d94bcd139d17bDRC   * @param height see {@link #setSourceImage} for description
85fac3bea8dae8664110951427434d94bcd139d17bDRC   *
86fac3bea8dae8664110951427434d94bcd139d17bDRC   * @param pixelFormat see {@link #setSourceImage} for description
87fac3bea8dae8664110951427434d94bcd139d17bDRC   */
88fac3bea8dae8664110951427434d94bcd139d17bDRC  public TJCompressor(byte[] srcImage, int x, int y, int width, int pitch,
89fac3bea8dae8664110951427434d94bcd139d17bDRC    int height, int pixelFormat) throws Exception {
90fac3bea8dae8664110951427434d94bcd139d17bDRC    setSourceImage(srcImage, x, y, width, pitch, height, pixelFormat);
91fac3bea8dae8664110951427434d94bcd139d17bDRC  }
92fac3bea8dae8664110951427434d94bcd139d17bDRC
93fac3bea8dae8664110951427434d94bcd139d17bDRC  /**
9492549de2c2b139070294aec12ec39b7c86a56b52DRC   * Associate an uncompressed source image with this compressor instance.
9592549de2c2b139070294aec12ec39b7c86a56b52DRC   *
962c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * @param srcImage image buffer containing RGB or grayscale pixels to be
9792549de2c2b139070294aec12ec39b7c86a56b52DRC   * compressed
9892549de2c2b139070294aec12ec39b7c86a56b52DRC   *
99fac3bea8dae8664110951427434d94bcd139d17bDRC   * @param x x offset (in pixels) of the region from which the JPEG image
100fac3bea8dae8664110951427434d94bcd139d17bDRC   * should be compressed, relative to the start of <code>srcImage</code>.
101fac3bea8dae8664110951427434d94bcd139d17bDRC   *
102fac3bea8dae8664110951427434d94bcd139d17bDRC   * @param y y offset (in pixels) of the region from which the JPEG image
103fac3bea8dae8664110951427434d94bcd139d17bDRC   * should be compressed, relative to the start of <code>srcImage</code>.
104fac3bea8dae8664110951427434d94bcd139d17bDRC   *
105fac3bea8dae8664110951427434d94bcd139d17bDRC   * @param width width (in pixels) of the region in the source image from
106fac3bea8dae8664110951427434d94bcd139d17bDRC   * which the JPEG image should be compressed.
10792549de2c2b139070294aec12ec39b7c86a56b52DRC   *
10892549de2c2b139070294aec12ec39b7c86a56b52DRC   * @param pitch bytes per line of the source image.  Normally, this should be
10992549de2c2b139070294aec12ec39b7c86a56b52DRC   * <code>width * TJ.pixelSize(pixelFormat)</code> if the source image is
11092549de2c2b139070294aec12ec39b7c86a56b52DRC   * unpadded, but you can use this parameter to, for instance, specify that
111fac3bea8dae8664110951427434d94bcd139d17bDRC   * the scanlines in the source image are padded to a 4-byte boundary or to
112fac3bea8dae8664110951427434d94bcd139d17bDRC   * compress a JPEG image from a region of a larger source image.  You can
113fac3bea8dae8664110951427434d94bcd139d17bDRC   * also be clever and use this parameter to skip lines, etc.  Setting this
114fac3bea8dae8664110951427434d94bcd139d17bDRC   * parameter to 0 is the equivalent of setting it to <code>width *
11592549de2c2b139070294aec12ec39b7c86a56b52DRC   * TJ.pixelSize(pixelFormat)</code>.
11692549de2c2b139070294aec12ec39b7c86a56b52DRC   *
117fac3bea8dae8664110951427434d94bcd139d17bDRC   * @param height height (in pixels) of the region in the source image from
118fac3bea8dae8664110951427434d94bcd139d17bDRC   * which the JPEG image should be compressed.
11992549de2c2b139070294aec12ec39b7c86a56b52DRC   *
1202c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * @param pixelFormat pixel format of the source image (one of
1212c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * {@link TJ TJ.PF_*})
12292549de2c2b139070294aec12ec39b7c86a56b52DRC   */
123fac3bea8dae8664110951427434d94bcd139d17bDRC  public void setSourceImage(byte[] srcImage, int x, int y, int width,
124fac3bea8dae8664110951427434d94bcd139d17bDRC    int pitch, int height, int pixelFormat) throws Exception {
12536336fcddc4cc9f74988e3f03c4683c88c8fce45DRC    if(handle == 0) init();
126fac3bea8dae8664110951427434d94bcd139d17bDRC    if(srcImage == null || x < 0 || y < 0 || width < 1 || height < 1
127fac3bea8dae8664110951427434d94bcd139d17bDRC      || pitch < 0 || pixelFormat < 0 || pixelFormat >= TJ.NUMPF)
1282c74e5124d25112809bdc26cbc36aa764e8870c3DRC      throw new Exception("Invalid argument in setSourceImage()");
1292c74e5124d25112809bdc26cbc36aa764e8870c3DRC    srcBuf = srcImage;
1302c74e5124d25112809bdc26cbc36aa764e8870c3DRC    srcWidth = width;
1312c74e5124d25112809bdc26cbc36aa764e8870c3DRC    if(pitch == 0) srcPitch = width * TJ.getPixelSize(pixelFormat);
1322c74e5124d25112809bdc26cbc36aa764e8870c3DRC    else srcPitch = pitch;
1332c74e5124d25112809bdc26cbc36aa764e8870c3DRC    srcHeight = height;
1342c74e5124d25112809bdc26cbc36aa764e8870c3DRC    srcPixelFormat = pixelFormat;
135fac3bea8dae8664110951427434d94bcd139d17bDRC    srcX = x;
136fac3bea8dae8664110951427434d94bcd139d17bDRC    srcY = y;
13736336fcddc4cc9f74988e3f03c4683c88c8fce45DRC  }
13836336fcddc4cc9f74988e3f03c4683c88c8fce45DRC
13992549de2c2b139070294aec12ec39b7c86a56b52DRC  /**
140fac3bea8dae8664110951427434d94bcd139d17bDRC   * Associate an uncompressed source image with this compressor instance.
141fac3bea8dae8664110951427434d94bcd139d17bDRC   *
142fac3bea8dae8664110951427434d94bcd139d17bDRC   * @param srcImage see
143fac3bea8dae8664110951427434d94bcd139d17bDRC   * {@link #setSourceImage(byte[], int, int, int, int, int, int)} for
144fac3bea8dae8664110951427434d94bcd139d17bDRC   * description
145fac3bea8dae8664110951427434d94bcd139d17bDRC   *
146fac3bea8dae8664110951427434d94bcd139d17bDRC   * @param width see
147fac3bea8dae8664110951427434d94bcd139d17bDRC   * {@link #setSourceImage(byte[], int, int, int, int, int, int)} for
148fac3bea8dae8664110951427434d94bcd139d17bDRC   * description
149fac3bea8dae8664110951427434d94bcd139d17bDRC   *
150fac3bea8dae8664110951427434d94bcd139d17bDRC   * @param pitch see
151fac3bea8dae8664110951427434d94bcd139d17bDRC   * {@link #setSourceImage(byte[], int, int, int, int, int, int)} for
152fac3bea8dae8664110951427434d94bcd139d17bDRC   * description
153fac3bea8dae8664110951427434d94bcd139d17bDRC   *
154fac3bea8dae8664110951427434d94bcd139d17bDRC   * @param height see
155fac3bea8dae8664110951427434d94bcd139d17bDRC   * {@link #setSourceImage(byte[], int, int, int, int, int, int)} for
156fac3bea8dae8664110951427434d94bcd139d17bDRC   * description
157fac3bea8dae8664110951427434d94bcd139d17bDRC   *
158fac3bea8dae8664110951427434d94bcd139d17bDRC   * @param pixelFormat pixel format of the source image (one of
159fac3bea8dae8664110951427434d94bcd139d17bDRC   * {@link TJ TJ.PF_*})
160fac3bea8dae8664110951427434d94bcd139d17bDRC   */
161fac3bea8dae8664110951427434d94bcd139d17bDRC
162fac3bea8dae8664110951427434d94bcd139d17bDRC  public void setSourceImage(byte[] srcImage, int width, int pitch,
163fac3bea8dae8664110951427434d94bcd139d17bDRC    int height, int pixelFormat) throws Exception {
164fac3bea8dae8664110951427434d94bcd139d17bDRC    setSourceImage(srcImage, 0, 0, width, pitch, height, pixelFormat);
165fac3bea8dae8664110951427434d94bcd139d17bDRC    srcX = srcY = -1;
166fac3bea8dae8664110951427434d94bcd139d17bDRC  }
167fac3bea8dae8664110951427434d94bcd139d17bDRC
168fac3bea8dae8664110951427434d94bcd139d17bDRC
169fac3bea8dae8664110951427434d94bcd139d17bDRC  /**
17092549de2c2b139070294aec12ec39b7c86a56b52DRC   * Set the level of chrominance subsampling for subsequent compress/encode
17192549de2c2b139070294aec12ec39b7c86a56b52DRC   * operations.
17292549de2c2b139070294aec12ec39b7c86a56b52DRC   *
1732c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * @param newSubsamp the new level of chrominance subsampling (one of
1742c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * {@link TJ TJ.SAMP_*})
17592549de2c2b139070294aec12ec39b7c86a56b52DRC   */
1764f1580cc0e7c33385e88bca7fe08602b87d29aebDRC  public void setSubsamp(int newSubsamp) throws Exception {
1772c74e5124d25112809bdc26cbc36aa764e8870c3DRC    if(newSubsamp < 0 || newSubsamp >= TJ.NUMSAMP)
178f7f3ea404cc8618305efc059c34d881566206ed9DRC      throw new Exception("Invalid argument in setSubsamp()");
1794f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    subsamp = newSubsamp;
1804f1580cc0e7c33385e88bca7fe08602b87d29aebDRC  }
1814f1580cc0e7c33385e88bca7fe08602b87d29aebDRC
18292549de2c2b139070294aec12ec39b7c86a56b52DRC  /**
18392549de2c2b139070294aec12ec39b7c86a56b52DRC   * Set the JPEG image quality level for subsequent compress operations.
18492549de2c2b139070294aec12ec39b7c86a56b52DRC   *
18592549de2c2b139070294aec12ec39b7c86a56b52DRC   * @param quality the new JPEG image quality level (1 to 100, 1 = worst,
18692549de2c2b139070294aec12ec39b7c86a56b52DRC   * 100 = best)
18792549de2c2b139070294aec12ec39b7c86a56b52DRC   */
1884f1580cc0e7c33385e88bca7fe08602b87d29aebDRC  public void setJPEGQuality(int quality) throws Exception {
1894f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    if(quality < 1 || quality > 100)
190f7f3ea404cc8618305efc059c34d881566206ed9DRC      throw new Exception("Invalid argument in setJPEGQuality()");
1914f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    jpegQuality = quality;
1924f1580cc0e7c33385e88bca7fe08602b87d29aebDRC  }
1934f1580cc0e7c33385e88bca7fe08602b87d29aebDRC
19492549de2c2b139070294aec12ec39b7c86a56b52DRC  /**
19592549de2c2b139070294aec12ec39b7c86a56b52DRC   * Compress the uncompressed source image associated with this compressor
19692549de2c2b139070294aec12ec39b7c86a56b52DRC   * instance and output a JPEG image to the given destination buffer.
19792549de2c2b139070294aec12ec39b7c86a56b52DRC   *
19880803ae5fe6ca228d0783b1921e7e800c9a28964DRC   * @param dstBuf buffer that will receive the JPEG image.  Use
19992549de2c2b139070294aec12ec39b7c86a56b52DRC   * {@link TJ#bufSize} to determine the maximum size for this buffer based on
20092549de2c2b139070294aec12ec39b7c86a56b52DRC   * the image width and height.
20192549de2c2b139070294aec12ec39b7c86a56b52DRC   *
2022c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
20392549de2c2b139070294aec12ec39b7c86a56b52DRC   */
204f7f3ea404cc8618305efc059c34d881566206ed9DRC  public void compress(byte[] dstBuf, int flags) throws Exception {
2054f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    if(dstBuf == null || flags < 0)
2064f1580cc0e7c33385e88bca7fe08602b87d29aebDRC      throw new Exception("Invalid argument in compress()");
2072c74e5124d25112809bdc26cbc36aa764e8870c3DRC    if(srcBuf == null) throw new Exception(NO_ASSOC_ERROR);
2084f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    if(jpegQuality < 0) throw new Exception("JPEG Quality not set");
2094f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    if(subsamp < 0) throw new Exception("Subsampling level not set");
210fac3bea8dae8664110951427434d94bcd139d17bDRC    if (srcX >= 0 && srcY >= 0)
211fac3bea8dae8664110951427434d94bcd139d17bDRC      compressedSize = compress(srcBuf, srcX, srcY, srcWidth, srcPitch,
212fac3bea8dae8664110951427434d94bcd139d17bDRC        srcHeight, srcPixelFormat, dstBuf, subsamp, jpegQuality, flags);
213fac3bea8dae8664110951427434d94bcd139d17bDRC    else
214fac3bea8dae8664110951427434d94bcd139d17bDRC      compressedSize = compress(srcBuf, srcWidth, srcPitch,
215fac3bea8dae8664110951427434d94bcd139d17bDRC        srcHeight, srcPixelFormat, dstBuf, subsamp, jpegQuality, flags);
2164f1580cc0e7c33385e88bca7fe08602b87d29aebDRC  }
2174f1580cc0e7c33385e88bca7fe08602b87d29aebDRC
21892549de2c2b139070294aec12ec39b7c86a56b52DRC  /**
21992549de2c2b139070294aec12ec39b7c86a56b52DRC   * Compress the uncompressed source image associated with this compressor
22092549de2c2b139070294aec12ec39b7c86a56b52DRC   * instance and return a buffer containing a JPEG image.
22192549de2c2b139070294aec12ec39b7c86a56b52DRC   *
2222c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
22392549de2c2b139070294aec12ec39b7c86a56b52DRC   *
22492549de2c2b139070294aec12ec39b7c86a56b52DRC   * @return a buffer containing a JPEG image.  The length of this buffer will
22592549de2c2b139070294aec12ec39b7c86a56b52DRC   * not be equal to the size of the JPEG image.  Use {@link
22692549de2c2b139070294aec12ec39b7c86a56b52DRC   * #getCompressedSize} to obtain the size of the JPEG image.
22792549de2c2b139070294aec12ec39b7c86a56b52DRC   */
228f7f3ea404cc8618305efc059c34d881566206ed9DRC  public byte[] compress(int flags) throws Exception {
2292c74e5124d25112809bdc26cbc36aa764e8870c3DRC    if(srcWidth < 1 || srcHeight < 1)
2302c74e5124d25112809bdc26cbc36aa764e8870c3DRC      throw new Exception(NO_ASSOC_ERROR);
2319b49f0e4c77c727648c6d3a4915eefdf5436de4aDRC    byte[] buf = new byte[TJ.bufSize(srcWidth, srcHeight, subsamp)];
2324f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    compress(buf, flags);
2334f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    return buf;
2344f1580cc0e7c33385e88bca7fe08602b87d29aebDRC  }
2354f1580cc0e7c33385e88bca7fe08602b87d29aebDRC
23692549de2c2b139070294aec12ec39b7c86a56b52DRC  /**
23792549de2c2b139070294aec12ec39b7c86a56b52DRC   * Compress the uncompressed source image stored in <code>srcImage</code>
23892549de2c2b139070294aec12ec39b7c86a56b52DRC   * and output a JPEG image to the given destination buffer.
23992549de2c2b139070294aec12ec39b7c86a56b52DRC   *
24092549de2c2b139070294aec12ec39b7c86a56b52DRC   * @param srcImage a <code>BufferedImage</code> instance containing RGB or
24192549de2c2b139070294aec12ec39b7c86a56b52DRC   * grayscale pixels to be compressed
24292549de2c2b139070294aec12ec39b7c86a56b52DRC   *
24380803ae5fe6ca228d0783b1921e7e800c9a28964DRC   * @param dstBuf buffer that will receive the JPEG image.  Use
24492549de2c2b139070294aec12ec39b7c86a56b52DRC   * {@link TJ#bufSize} to determine the maximum size for this buffer based on
24592549de2c2b139070294aec12ec39b7c86a56b52DRC   * the image width and height.
24692549de2c2b139070294aec12ec39b7c86a56b52DRC   *
2472c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
24892549de2c2b139070294aec12ec39b7c86a56b52DRC   */
249f7f3ea404cc8618305efc059c34d881566206ed9DRC  public void compress(BufferedImage srcImage, byte[] dstBuf, int flags)
2504f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    throws Exception {
2514f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    if(srcImage == null || dstBuf == null || flags < 0)
2524f1580cc0e7c33385e88bca7fe08602b87d29aebDRC      throw new Exception("Invalid argument in compress()");
2534f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    int width = srcImage.getWidth();
2544f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    int height = srcImage.getHeight();
255f7f3ea404cc8618305efc059c34d881566206ed9DRC    int pixelFormat;  boolean intPixels = false;
2561f014c32e66e00f4e6934f31beefae57ab51a477DRC    if(byteOrder == null)
2571f014c32e66e00f4e6934f31beefae57ab51a477DRC      byteOrder = ByteOrder.nativeOrder();
2584f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    switch(srcImage.getType()) {
2594f1580cc0e7c33385e88bca7fe08602b87d29aebDRC      case BufferedImage.TYPE_3BYTE_BGR:
260f7f3ea404cc8618305efc059c34d881566206ed9DRC        pixelFormat = TJ.PF_BGR;  break;
261c08e8c15bc73e7931ac5b87b992b17bbbda7f332DRC      case BufferedImage.TYPE_4BYTE_ABGR:
262c08e8c15bc73e7931ac5b87b992b17bbbda7f332DRC      case BufferedImage.TYPE_4BYTE_ABGR_PRE:
263c08e8c15bc73e7931ac5b87b992b17bbbda7f332DRC        pixelFormat = TJ.PF_XBGR;  break;
2644f1580cc0e7c33385e88bca7fe08602b87d29aebDRC      case BufferedImage.TYPE_BYTE_GRAY:
265f7f3ea404cc8618305efc059c34d881566206ed9DRC        pixelFormat = TJ.PF_GRAY;  break;
2664f1580cc0e7c33385e88bca7fe08602b87d29aebDRC      case BufferedImage.TYPE_INT_BGR:
2671f014c32e66e00f4e6934f31beefae57ab51a477DRC        if(byteOrder == ByteOrder.BIG_ENDIAN)
2681f014c32e66e00f4e6934f31beefae57ab51a477DRC          pixelFormat = TJ.PF_XBGR;
2691f014c32e66e00f4e6934f31beefae57ab51a477DRC        else
2701f014c32e66e00f4e6934f31beefae57ab51a477DRC          pixelFormat = TJ.PF_RGBX;
2711f014c32e66e00f4e6934f31beefae57ab51a477DRC        intPixels = true;  break;
2724f1580cc0e7c33385e88bca7fe08602b87d29aebDRC      case BufferedImage.TYPE_INT_RGB:
273c08e8c15bc73e7931ac5b87b992b17bbbda7f332DRC      case BufferedImage.TYPE_INT_ARGB:
274c08e8c15bc73e7931ac5b87b992b17bbbda7f332DRC      case BufferedImage.TYPE_INT_ARGB_PRE:
2751f014c32e66e00f4e6934f31beefae57ab51a477DRC        if(byteOrder == ByteOrder.BIG_ENDIAN)
2761f014c32e66e00f4e6934f31beefae57ab51a477DRC          pixelFormat = TJ.PF_XRGB;
2771f014c32e66e00f4e6934f31beefae57ab51a477DRC        else
2781f014c32e66e00f4e6934f31beefae57ab51a477DRC          pixelFormat = TJ.PF_BGRX;
2791f014c32e66e00f4e6934f31beefae57ab51a477DRC        intPixels = true;  break;
2804f1580cc0e7c33385e88bca7fe08602b87d29aebDRC      default:
2814f1580cc0e7c33385e88bca7fe08602b87d29aebDRC        throw new Exception("Unsupported BufferedImage format");
2824f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    }
2834f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    WritableRaster wr = srcImage.getRaster();
2844f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    if(jpegQuality < 0) throw new Exception("JPEG Quality not set");
2854f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    if(subsamp < 0) throw new Exception("Subsampling level not set");
2864f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    if(intPixels) {
2874f1580cc0e7c33385e88bca7fe08602b87d29aebDRC      SinglePixelPackedSampleModel sm =
2884f1580cc0e7c33385e88bca7fe08602b87d29aebDRC        (SinglePixelPackedSampleModel)srcImage.getSampleModel();
2894f1580cc0e7c33385e88bca7fe08602b87d29aebDRC      int pitch = sm.getScanlineStride();
2904f1580cc0e7c33385e88bca7fe08602b87d29aebDRC      DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
291f7f3ea404cc8618305efc059c34d881566206ed9DRC      int[] buf = db.getData();
292fac3bea8dae8664110951427434d94bcd139d17bDRC      if (srcX >= 0 && srcY >= 0)
293fac3bea8dae8664110951427434d94bcd139d17bDRC        compressedSize = compress(buf, srcX, srcY, width, pitch, height,
294fac3bea8dae8664110951427434d94bcd139d17bDRC          pixelFormat, dstBuf, subsamp, jpegQuality, flags);
295fac3bea8dae8664110951427434d94bcd139d17bDRC      else
296fac3bea8dae8664110951427434d94bcd139d17bDRC        compressedSize = compress(buf, width, pitch, height, pixelFormat,
297fac3bea8dae8664110951427434d94bcd139d17bDRC          dstBuf, subsamp, jpegQuality, flags);
2984f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    }
2994f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    else {
3004f1580cc0e7c33385e88bca7fe08602b87d29aebDRC      ComponentSampleModel sm =
3014f1580cc0e7c33385e88bca7fe08602b87d29aebDRC        (ComponentSampleModel)srcImage.getSampleModel();
3024f1580cc0e7c33385e88bca7fe08602b87d29aebDRC      int pixelSize = sm.getPixelStride();
3034f1580cc0e7c33385e88bca7fe08602b87d29aebDRC      if(pixelSize != TJ.getPixelSize(pixelFormat))
3044f1580cc0e7c33385e88bca7fe08602b87d29aebDRC        throw new Exception("Inconsistency between pixel format and pixel size in BufferedImage");
3054f1580cc0e7c33385e88bca7fe08602b87d29aebDRC      int pitch = sm.getScanlineStride();
3064f1580cc0e7c33385e88bca7fe08602b87d29aebDRC      DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
307f7f3ea404cc8618305efc059c34d881566206ed9DRC      byte[] buf = db.getData();
308fac3bea8dae8664110951427434d94bcd139d17bDRC      if (srcX >= 0 && srcY >= 0)
309fac3bea8dae8664110951427434d94bcd139d17bDRC        compressedSize = compress(buf, srcX, srcY, width, pitch, height,
310fac3bea8dae8664110951427434d94bcd139d17bDRC          pixelFormat, dstBuf, subsamp, jpegQuality, flags);
311fac3bea8dae8664110951427434d94bcd139d17bDRC      else
312fac3bea8dae8664110951427434d94bcd139d17bDRC        compressedSize = compress(buf, width, pitch, height, pixelFormat,
313fac3bea8dae8664110951427434d94bcd139d17bDRC          dstBuf, subsamp, jpegQuality, flags);
3144f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    }
3154f1580cc0e7c33385e88bca7fe08602b87d29aebDRC  }
3164f1580cc0e7c33385e88bca7fe08602b87d29aebDRC
31792549de2c2b139070294aec12ec39b7c86a56b52DRC  /**
31892549de2c2b139070294aec12ec39b7c86a56b52DRC   * Compress the uncompressed source image stored in <code>srcImage</code>
31992549de2c2b139070294aec12ec39b7c86a56b52DRC   * and return a buffer containing a JPEG image.
32092549de2c2b139070294aec12ec39b7c86a56b52DRC   *
32192549de2c2b139070294aec12ec39b7c86a56b52DRC   * @param srcImage a <code>BufferedImage</code> instance containing RGB or
32292549de2c2b139070294aec12ec39b7c86a56b52DRC   * grayscale pixels to be compressed
32392549de2c2b139070294aec12ec39b7c86a56b52DRC   *
3242c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
32592549de2c2b139070294aec12ec39b7c86a56b52DRC   *
32692549de2c2b139070294aec12ec39b7c86a56b52DRC   * @return a buffer containing a JPEG image.  The length of this buffer will
32792549de2c2b139070294aec12ec39b7c86a56b52DRC   * not be equal to the size of the JPEG image.  Use {@link
32892549de2c2b139070294aec12ec39b7c86a56b52DRC   * #getCompressedSize} to obtain the size of the JPEG image.
32992549de2c2b139070294aec12ec39b7c86a56b52DRC   */
330f7f3ea404cc8618305efc059c34d881566206ed9DRC  public byte[] compress(BufferedImage srcImage, int flags) throws Exception {
3314f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    int width = srcImage.getWidth();
3324f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    int height = srcImage.getHeight();
3339b49f0e4c77c727648c6d3a4915eefdf5436de4aDRC    byte[] buf = new byte[TJ.bufSize(width, height, subsamp)];
3344f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    compress(srcImage, buf, flags);
3354f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    return buf;
3364f1580cc0e7c33385e88bca7fe08602b87d29aebDRC  }
3374f1580cc0e7c33385e88bca7fe08602b87d29aebDRC
33892549de2c2b139070294aec12ec39b7c86a56b52DRC  /**
33992549de2c2b139070294aec12ec39b7c86a56b52DRC   * Encode the uncompressed source image associated with this compressor
34092549de2c2b139070294aec12ec39b7c86a56b52DRC   * instance and output a YUV planar image to the given destination buffer.
3412c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * This method uses the accelerated color conversion routines in
34292549de2c2b139070294aec12ec39b7c86a56b52DRC   * TurboJPEG's underlying codec to produce a planar YUV image that is
34392549de2c2b139070294aec12ec39b7c86a56b52DRC   * suitable for direct video display.  Specifically, if the chrominance
34492549de2c2b139070294aec12ec39b7c86a56b52DRC   * components are subsampled along the horizontal dimension, then the width
34592549de2c2b139070294aec12ec39b7c86a56b52DRC   * of the luminance plane is padded to 2 in the output image (same goes for
34692549de2c2b139070294aec12ec39b7c86a56b52DRC   * the height of the luminance plane, if the chrominance components are
34792549de2c2b139070294aec12ec39b7c86a56b52DRC   * subsampled along the vertical dimension.)  Also, each line of each plane
34892549de2c2b139070294aec12ec39b7c86a56b52DRC   * in the output image is padded to 4 bytes.  Although this will work with
34992549de2c2b139070294aec12ec39b7c86a56b52DRC   * any subsampling option, it is really only useful in combination with
35092549de2c2b139070294aec12ec39b7c86a56b52DRC   * {@link TJ#SAMP_420}, which produces an image compatible with the I420 (AKA
35192549de2c2b139070294aec12ec39b7c86a56b52DRC   * "YUV420P") format.
35292549de2c2b139070294aec12ec39b7c86a56b52DRC   *
35380803ae5fe6ca228d0783b1921e7e800c9a28964DRC   * @param dstBuf buffer that will receive the YUV planar image.  Use
35492549de2c2b139070294aec12ec39b7c86a56b52DRC   * {@link TJ#bufSizeYUV} to determine the appropriate size for this buffer
35592549de2c2b139070294aec12ec39b7c86a56b52DRC   * based on the image width, height, and level of chrominance subsampling.
35692549de2c2b139070294aec12ec39b7c86a56b52DRC   *
3572c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
35892549de2c2b139070294aec12ec39b7c86a56b52DRC   */
359f7f3ea404cc8618305efc059c34d881566206ed9DRC  public void encodeYUV(byte[] dstBuf, int flags) throws Exception {
3604f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    if(dstBuf == null || flags < 0)
3614f1580cc0e7c33385e88bca7fe08602b87d29aebDRC      throw new Exception("Invalid argument in compress()");
3622c74e5124d25112809bdc26cbc36aa764e8870c3DRC    if(srcBuf == null) throw new Exception(NO_ASSOC_ERROR);
3634f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    if(subsamp < 0) throw new Exception("Subsampling level not set");
3642c74e5124d25112809bdc26cbc36aa764e8870c3DRC    encodeYUV(srcBuf, srcWidth, srcPitch, srcHeight,
3652c74e5124d25112809bdc26cbc36aa764e8870c3DRC      srcPixelFormat, dstBuf, subsamp, flags);
3662c74e5124d25112809bdc26cbc36aa764e8870c3DRC    compressedSize = TJ.bufSizeYUV(srcWidth, srcHeight, subsamp);
3674f1580cc0e7c33385e88bca7fe08602b87d29aebDRC  }
3684f1580cc0e7c33385e88bca7fe08602b87d29aebDRC
36992549de2c2b139070294aec12ec39b7c86a56b52DRC  /**
37092549de2c2b139070294aec12ec39b7c86a56b52DRC   * Encode the uncompressed source image associated with this compressor
37192549de2c2b139070294aec12ec39b7c86a56b52DRC   * instance and return a buffer containing a YUV planar image.  See
37292549de2c2b139070294aec12ec39b7c86a56b52DRC   * {@link #encodeYUV(byte[], int)} for more detail.
37392549de2c2b139070294aec12ec39b7c86a56b52DRC   *
3742c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
37592549de2c2b139070294aec12ec39b7c86a56b52DRC   *
37692549de2c2b139070294aec12ec39b7c86a56b52DRC   * @return a buffer containing a YUV planar image
37792549de2c2b139070294aec12ec39b7c86a56b52DRC   */
378f7f3ea404cc8618305efc059c34d881566206ed9DRC  public byte[] encodeYUV(int flags) throws Exception {
3792c74e5124d25112809bdc26cbc36aa764e8870c3DRC    if(srcWidth < 1 || srcHeight < 1)
3802c74e5124d25112809bdc26cbc36aa764e8870c3DRC      throw new Exception(NO_ASSOC_ERROR);
3814f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    if(subsamp < 0) throw new Exception("Subsampling level not set");
3822c74e5124d25112809bdc26cbc36aa764e8870c3DRC    byte[] buf = new byte[TJ.bufSizeYUV(srcWidth, srcHeight, subsamp)];
3834f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    encodeYUV(buf, flags);
3844f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    return buf;
3854f1580cc0e7c33385e88bca7fe08602b87d29aebDRC  }
3864f1580cc0e7c33385e88bca7fe08602b87d29aebDRC
38792549de2c2b139070294aec12ec39b7c86a56b52DRC  /**
38892549de2c2b139070294aec12ec39b7c86a56b52DRC   * Encode the uncompressed source image stored in <code>srcImage</code>
38992549de2c2b139070294aec12ec39b7c86a56b52DRC   * and output a YUV planar image to the given destination buffer.  See
39092549de2c2b139070294aec12ec39b7c86a56b52DRC   * {@link #encodeYUV(byte[], int)} for more detail.
39192549de2c2b139070294aec12ec39b7c86a56b52DRC   *
39292549de2c2b139070294aec12ec39b7c86a56b52DRC   * @param srcImage a <code>BufferedImage</code> instance containing RGB or
39392549de2c2b139070294aec12ec39b7c86a56b52DRC   * grayscale pixels to be encoded
39492549de2c2b139070294aec12ec39b7c86a56b52DRC   *
39580803ae5fe6ca228d0783b1921e7e800c9a28964DRC   * @param dstBuf buffer that will receive the YUV planar image.  Use
39692549de2c2b139070294aec12ec39b7c86a56b52DRC   * {@link TJ#bufSizeYUV} to determine the appropriate size for this buffer
39792549de2c2b139070294aec12ec39b7c86a56b52DRC   * based on the image width, height, and level of chrominance subsampling.
39892549de2c2b139070294aec12ec39b7c86a56b52DRC   *
3992c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
40092549de2c2b139070294aec12ec39b7c86a56b52DRC   */
401f7f3ea404cc8618305efc059c34d881566206ed9DRC  public void encodeYUV(BufferedImage srcImage, byte[] dstBuf, int flags)
4024f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    throws Exception {
4034f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    if(srcImage == null || dstBuf == null || flags < 0)
4044f1580cc0e7c33385e88bca7fe08602b87d29aebDRC      throw new Exception("Invalid argument in encodeYUV()");
40584a1bcca6fd0f21091a84f04b820b29012c60857DRC    int width = srcImage.getWidth();
40684a1bcca6fd0f21091a84f04b820b29012c60857DRC    int height = srcImage.getHeight();
407f7f3ea404cc8618305efc059c34d881566206ed9DRC    int pixelFormat;  boolean intPixels = false;
4081f014c32e66e00f4e6934f31beefae57ab51a477DRC    if(byteOrder == null)
4091f014c32e66e00f4e6934f31beefae57ab51a477DRC      byteOrder = ByteOrder.nativeOrder();
41084a1bcca6fd0f21091a84f04b820b29012c60857DRC    switch(srcImage.getType()) {
41184a1bcca6fd0f21091a84f04b820b29012c60857DRC      case BufferedImage.TYPE_3BYTE_BGR:
412f7f3ea404cc8618305efc059c34d881566206ed9DRC        pixelFormat = TJ.PF_BGR;  break;
413c08e8c15bc73e7931ac5b87b992b17bbbda7f332DRC      case BufferedImage.TYPE_4BYTE_ABGR:
414c08e8c15bc73e7931ac5b87b992b17bbbda7f332DRC      case BufferedImage.TYPE_4BYTE_ABGR_PRE:
415c08e8c15bc73e7931ac5b87b992b17bbbda7f332DRC        pixelFormat = TJ.PF_XBGR;  break;
41684a1bcca6fd0f21091a84f04b820b29012c60857DRC      case BufferedImage.TYPE_BYTE_GRAY:
417f7f3ea404cc8618305efc059c34d881566206ed9DRC        pixelFormat = TJ.PF_GRAY;  break;
41884a1bcca6fd0f21091a84f04b820b29012c60857DRC      case BufferedImage.TYPE_INT_BGR:
4191f014c32e66e00f4e6934f31beefae57ab51a477DRC        if(byteOrder == ByteOrder.BIG_ENDIAN)
4201f014c32e66e00f4e6934f31beefae57ab51a477DRC          pixelFormat = TJ.PF_XBGR;
4211f014c32e66e00f4e6934f31beefae57ab51a477DRC        else
4221f014c32e66e00f4e6934f31beefae57ab51a477DRC          pixelFormat = TJ.PF_RGBX;
4231f014c32e66e00f4e6934f31beefae57ab51a477DRC        intPixels = true;  break;
42484a1bcca6fd0f21091a84f04b820b29012c60857DRC      case BufferedImage.TYPE_INT_RGB:
425c08e8c15bc73e7931ac5b87b992b17bbbda7f332DRC      case BufferedImage.TYPE_INT_ARGB:
426c08e8c15bc73e7931ac5b87b992b17bbbda7f332DRC      case BufferedImage.TYPE_INT_ARGB_PRE:
4271f014c32e66e00f4e6934f31beefae57ab51a477DRC        if(byteOrder == ByteOrder.BIG_ENDIAN)
4281f014c32e66e00f4e6934f31beefae57ab51a477DRC          pixelFormat = TJ.PF_XRGB;
4291f014c32e66e00f4e6934f31beefae57ab51a477DRC        else
4301f014c32e66e00f4e6934f31beefae57ab51a477DRC          pixelFormat = TJ.PF_BGRX;
4311f014c32e66e00f4e6934f31beefae57ab51a477DRC        intPixels = true;  break;
43284a1bcca6fd0f21091a84f04b820b29012c60857DRC      default:
43384a1bcca6fd0f21091a84f04b820b29012c60857DRC        throw new Exception("Unsupported BufferedImage format");
43484a1bcca6fd0f21091a84f04b820b29012c60857DRC    }
43584a1bcca6fd0f21091a84f04b820b29012c60857DRC    WritableRaster wr = srcImage.getRaster();
4364f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    if(subsamp < 0) throw new Exception("Subsampling level not set");
43784a1bcca6fd0f21091a84f04b820b29012c60857DRC    if(intPixels) {
43884a1bcca6fd0f21091a84f04b820b29012c60857DRC      SinglePixelPackedSampleModel sm =
43984a1bcca6fd0f21091a84f04b820b29012c60857DRC        (SinglePixelPackedSampleModel)srcImage.getSampleModel();
44084a1bcca6fd0f21091a84f04b820b29012c60857DRC      int pitch = sm.getScanlineStride();
44184a1bcca6fd0f21091a84f04b820b29012c60857DRC      DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
442f7f3ea404cc8618305efc059c34d881566206ed9DRC      int[] buf = db.getData();
4434f1580cc0e7c33385e88bca7fe08602b87d29aebDRC      encodeYUV(buf, width, pitch, height, pixelFormat, dstBuf, subsamp,
4444f1580cc0e7c33385e88bca7fe08602b87d29aebDRC        flags);
44584a1bcca6fd0f21091a84f04b820b29012c60857DRC    }
44684a1bcca6fd0f21091a84f04b820b29012c60857DRC    else {
44784a1bcca6fd0f21091a84f04b820b29012c60857DRC      ComponentSampleModel sm =
44884a1bcca6fd0f21091a84f04b820b29012c60857DRC        (ComponentSampleModel)srcImage.getSampleModel();
44984a1bcca6fd0f21091a84f04b820b29012c60857DRC      int pixelSize = sm.getPixelStride();
4504f1580cc0e7c33385e88bca7fe08602b87d29aebDRC      if(pixelSize != TJ.getPixelSize(pixelFormat))
45184a1bcca6fd0f21091a84f04b820b29012c60857DRC        throw new Exception("Inconsistency between pixel format and pixel size in BufferedImage");
45284a1bcca6fd0f21091a84f04b820b29012c60857DRC      int pitch = sm.getScanlineStride();
45384a1bcca6fd0f21091a84f04b820b29012c60857DRC      DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
454f7f3ea404cc8618305efc059c34d881566206ed9DRC      byte[] buf = db.getData();
4554f1580cc0e7c33385e88bca7fe08602b87d29aebDRC      encodeYUV(buf, width, pitch, height, pixelFormat, dstBuf, subsamp,
4564f1580cc0e7c33385e88bca7fe08602b87d29aebDRC        flags);
45784a1bcca6fd0f21091a84f04b820b29012c60857DRC    }
4584f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    compressedSize = TJ.bufSizeYUV(width, height, subsamp);
4594f1580cc0e7c33385e88bca7fe08602b87d29aebDRC  }
4604f1580cc0e7c33385e88bca7fe08602b87d29aebDRC
46192549de2c2b139070294aec12ec39b7c86a56b52DRC  /**
46292549de2c2b139070294aec12ec39b7c86a56b52DRC   * Encode the uncompressed source image stored in <code>srcImage</code>
46392549de2c2b139070294aec12ec39b7c86a56b52DRC   * and return a buffer containing a YUV planar image.  See
46492549de2c2b139070294aec12ec39b7c86a56b52DRC   * {@link #encodeYUV(byte[], int)} for more detail.
46592549de2c2b139070294aec12ec39b7c86a56b52DRC   *
46692549de2c2b139070294aec12ec39b7c86a56b52DRC   * @param srcImage a <code>BufferedImage</code> instance containing RGB or
46792549de2c2b139070294aec12ec39b7c86a56b52DRC   * grayscale pixels to be encoded
46892549de2c2b139070294aec12ec39b7c86a56b52DRC   *
4692c74e5124d25112809bdc26cbc36aa764e8870c3DRC   * @param flags the bitwise OR of one or more of {@link TJ TJ.FLAG_*}
47092549de2c2b139070294aec12ec39b7c86a56b52DRC   *
47192549de2c2b139070294aec12ec39b7c86a56b52DRC   * @return a buffer containing a YUV planar image
47292549de2c2b139070294aec12ec39b7c86a56b52DRC   */
473f7f3ea404cc8618305efc059c34d881566206ed9DRC  public byte[] encodeYUV(BufferedImage srcImage, int flags)
4744f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    throws Exception {
4754f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    if(subsamp < 0) throw new Exception("Subsampling level not set");
4764f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    int width = srcImage.getWidth();
4774f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    int height = srcImage.getHeight();
478f7f3ea404cc8618305efc059c34d881566206ed9DRC    byte[] buf = new byte[TJ.bufSizeYUV(width, height, subsamp)];
4794f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    encodeYUV(srcImage, buf, flags);
4804f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    return buf;
4814f1580cc0e7c33385e88bca7fe08602b87d29aebDRC  }
4824f1580cc0e7c33385e88bca7fe08602b87d29aebDRC
48392549de2c2b139070294aec12ec39b7c86a56b52DRC  /**
48492549de2c2b139070294aec12ec39b7c86a56b52DRC   * Returns the size of the image (in bytes) generated by the most recent
48592549de2c2b139070294aec12ec39b7c86a56b52DRC   * compress/encode operation.
48692549de2c2b139070294aec12ec39b7c86a56b52DRC   *
48792549de2c2b139070294aec12ec39b7c86a56b52DRC   * @return the size of the image (in bytes) generated by the most recent
48892549de2c2b139070294aec12ec39b7c86a56b52DRC   * compress/encode operation
48992549de2c2b139070294aec12ec39b7c86a56b52DRC   */
4904f1580cc0e7c33385e88bca7fe08602b87d29aebDRC  public int getCompressedSize() {
4914f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    return compressedSize;
49284a1bcca6fd0f21091a84f04b820b29012c60857DRC  }
49384a1bcca6fd0f21091a84f04b820b29012c60857DRC
49492549de2c2b139070294aec12ec39b7c86a56b52DRC  /**
49592549de2c2b139070294aec12ec39b7c86a56b52DRC   * Free the native structures associated with this compressor instance.
49692549de2c2b139070294aec12ec39b7c86a56b52DRC   */
497c5a419970eb91c85844002901210484b29e25fb1DRC  public void close() throws Exception {
498c5a419970eb91c85844002901210484b29e25fb1DRC    destroy();
499c5a419970eb91c85844002901210484b29e25fb1DRC  }
500c5a419970eb91c85844002901210484b29e25fb1DRC
501c5a419970eb91c85844002901210484b29e25fb1DRC  protected void finalize() throws Throwable {
502c5a419970eb91c85844002901210484b29e25fb1DRC    try {
503c5a419970eb91c85844002901210484b29e25fb1DRC      close();
504c5a419970eb91c85844002901210484b29e25fb1DRC    }
505f7f3ea404cc8618305efc059c34d881566206ed9DRC    catch(Exception e) {}
506c5a419970eb91c85844002901210484b29e25fb1DRC    finally {
507c5a419970eb91c85844002901210484b29e25fb1DRC      super.finalize();
508c5a419970eb91c85844002901210484b29e25fb1DRC    }
509c5a419970eb91c85844002901210484b29e25fb1DRC  };
510c5a419970eb91c85844002901210484b29e25fb1DRC
511c5a419970eb91c85844002901210484b29e25fb1DRC  private native void init() throws Exception;
512c5a419970eb91c85844002901210484b29e25fb1DRC
513c5a419970eb91c85844002901210484b29e25fb1DRC  private native void destroy() throws Exception;
514c5a419970eb91c85844002901210484b29e25fb1DRC
515c5a419970eb91c85844002901210484b29e25fb1DRC  // JPEG size in bytes is returned
516f7f3ea404cc8618305efc059c34d881566206ed9DRC  private native int compress(byte[] srcBuf, int width, int pitch,
517fac3bea8dae8664110951427434d94bcd139d17bDRC    int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp, int jpegQual,
518c5a419970eb91c85844002901210484b29e25fb1DRC    int flags) throws Exception;
519c5a419970eb91c85844002901210484b29e25fb1DRC
520fac3bea8dae8664110951427434d94bcd139d17bDRC  private native int compress(byte[] srcBuf, int x, int y, int width,
521fac3bea8dae8664110951427434d94bcd139d17bDRC    int pitch, int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp,
522fac3bea8dae8664110951427434d94bcd139d17bDRC    int jpegQual, int flags) throws Exception;
523fac3bea8dae8664110951427434d94bcd139d17bDRC
524fac3bea8dae8664110951427434d94bcd139d17bDRC  private native int compress(int[] srcBuf, int width, int stride,
525fac3bea8dae8664110951427434d94bcd139d17bDRC    int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp, int jpegQual,
5264f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    int flags) throws Exception;
5274f1580cc0e7c33385e88bca7fe08602b87d29aebDRC
528fac3bea8dae8664110951427434d94bcd139d17bDRC  private native int compress(int[] srcBuf, int x, int y, int width,
529fac3bea8dae8664110951427434d94bcd139d17bDRC    int stride, int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp,
530fac3bea8dae8664110951427434d94bcd139d17bDRC    int jpegQual, int flags) throws Exception;
531fac3bea8dae8664110951427434d94bcd139d17bDRC
532f7f3ea404cc8618305efc059c34d881566206ed9DRC  private native void encodeYUV(byte[] srcBuf, int width, int pitch,
533fac3bea8dae8664110951427434d94bcd139d17bDRC    int height, int pixelFormat, byte[] dstBuf, int subsamp, int flags)
5344f1580cc0e7c33385e88bca7fe08602b87d29aebDRC    throws Exception;
5354f1580cc0e7c33385e88bca7fe08602b87d29aebDRC
536f7f3ea404cc8618305efc059c34d881566206ed9DRC  private native void encodeYUV(int[] srcBuf, int width, int pitch,
537fac3bea8dae8664110951427434d94bcd139d17bDRC    int height, int pixelFormat, byte[] dstBuf, int subsamp, int flags)
53884a1bcca6fd0f21091a84f04b820b29012c60857DRC    throws Exception;
53984a1bcca6fd0f21091a84f04b820b29012c60857DRC
540c5a419970eb91c85844002901210484b29e25fb1DRC  static {
541b2f9415a6365b8eb412a5b6159be3cc0f875325fDRC    TJLoader.load();
542c5a419970eb91c85844002901210484b29e25fb1DRC  }
543c5a419970eb91c85844002901210484b29e25fb1DRC
544c5a419970eb91c85844002901210484b29e25fb1DRC  private long handle = 0;
5452c74e5124d25112809bdc26cbc36aa764e8870c3DRC  private byte[] srcBuf = null;
5462c74e5124d25112809bdc26cbc36aa764e8870c3DRC  private int srcWidth = 0;
5472c74e5124d25112809bdc26cbc36aa764e8870c3DRC  private int srcHeight = 0;
548fac3bea8dae8664110951427434d94bcd139d17bDRC  private int srcX = -1;
549fac3bea8dae8664110951427434d94bcd139d17bDRC  private int srcY = -1;
5502c74e5124d25112809bdc26cbc36aa764e8870c3DRC  private int srcPitch = 0;
5512c74e5124d25112809bdc26cbc36aa764e8870c3DRC  private int srcPixelFormat = -1;
5524f1580cc0e7c33385e88bca7fe08602b87d29aebDRC  private int subsamp = -1;
5534f1580cc0e7c33385e88bca7fe08602b87d29aebDRC  private int jpegQuality = -1;
5544f1580cc0e7c33385e88bca7fe08602b87d29aebDRC  private int compressedSize = 0;
5551f014c32e66e00f4e6934f31beefae57ab51a477DRC  private ByteOrder byteOrder = null;
556c5a419970eb91c85844002901210484b29e25fb1DRC};
557