1/*
2 * Copyright (C)2011, 2013-2015 D. R. Commander.  All Rights Reserved.
3 * Copyright (C)2015 Viktor Szathmáry.  All Rights Reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice,
9 *   this list of conditions and the following disclaimer.
10 * - Redistributions in binary form must reproduce the above copyright notice,
11 *   this list of conditions and the following disclaimer in the documentation
12 *   and/or other materials provided with the distribution.
13 * - Neither the name of the libjpeg-turbo Project nor the names of its
14 *   contributors may be used to endorse or promote products derived from this
15 *   software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30package org.libjpegturbo.turbojpeg;
31
32/**
33 * TurboJPEG lossless transformer
34 */
35public class TJTransformer extends TJDecompressor {
36
37  /**
38   * Create a TurboJPEG lossless transformer instance.
39   */
40  public TJTransformer() throws TJException {
41    init();
42  }
43
44  /**
45   * Create a TurboJPEG lossless transformer instance and associate the JPEG
46   * image stored in <code>jpegImage</code> with the newly created instance.
47   *
48   * @param jpegImage JPEG image buffer (size of the JPEG image is assumed to
49   * be the length of the array.)  This buffer is not modified.
50   */
51  public TJTransformer(byte[] jpegImage) throws TJException {
52    init();
53    setSourceImage(jpegImage, jpegImage.length);
54  }
55
56  /**
57   * Create a TurboJPEG lossless transformer instance and associate the JPEG
58   * image of length <code>imageSize</code> bytes stored in
59   * <code>jpegImage</code> with the newly created instance.
60   *
61   * @param jpegImage JPEG image buffer.  This buffer is not modified.
62   *
63   * @param imageSize size of the JPEG image (in bytes)
64   */
65  public TJTransformer(byte[] jpegImage, int imageSize) throws TJException {
66    init();
67    setSourceImage(jpegImage, imageSize);
68  }
69
70  /**
71   * Losslessly transform the JPEG image associated with this transformer
72   * instance into one or more JPEG images stored in the given destination
73   * buffers.  Lossless transforms work by moving the raw coefficients from one
74   * JPEG image structure to another without altering the values of the
75   * coefficients.  While this is typically faster than decompressing the
76   * image, transforming it, and re-compressing it, lossless transforms are not
77   * free.  Each lossless transform requires reading and performing Huffman
78   * decoding on all of the coefficients in the source image, regardless of the
79   * size of the destination image.  Thus, this method provides a means of
80   * generating multiple transformed images from the same source or of applying
81   * multiple transformations simultaneously, in order to eliminate the need to
82   * read the source coefficients multiple times.
83   *
84   * @param dstBufs an array of image buffers.  <code>dstbufs[i]</code> will
85   * receive a JPEG image that has been transformed using the parameters in
86   * <code>transforms[i]</code>.  Use {@link TJ#bufSize} to determine the
87   * maximum size for each buffer based on the transformed or cropped width and
88   * height and the level of subsampling used in the source image.
89   *
90   * @param transforms an array of {@link TJTransform} instances, each of
91   * which specifies the transform parameters and/or cropping region for the
92   * corresponding transformed output image
93   *
94   * @param flags the bitwise OR of one or more of
95   * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
96   */
97  public void transform(byte[][] dstBufs, TJTransform[] transforms,
98                        int flags) throws TJException {
99    if (jpegBuf == null)
100      throw new IllegalStateException("JPEG buffer not initialized");
101    transformedSizes = transform(jpegBuf, jpegBufSize, dstBufs, transforms,
102                                 flags);
103  }
104
105  /**
106   * Losslessly transform the JPEG image associated with this transformer
107   * instance and return an array of {@link TJDecompressor} instances, each of
108   * which has a transformed JPEG image associated with it.
109   *
110   * @param transforms an array of {@link TJTransform} instances, each of
111   * which specifies the transform parameters and/or cropping region for the
112   * corresponding transformed output image
113   *
114   * @return an array of {@link TJDecompressor} instances, each of
115   * which has a transformed JPEG image associated with it.
116   *
117   * @param flags the bitwise OR of one or more of
118   * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
119   */
120  public TJDecompressor[] transform(TJTransform[] transforms, int flags)
121                                    throws TJException {
122    byte[][] dstBufs = new byte[transforms.length][];
123    if (jpegWidth < 1 || jpegHeight < 1)
124      throw new IllegalStateException("JPEG buffer not initialized");
125    for (int i = 0; i < transforms.length; i++) {
126      int w = jpegWidth, h = jpegHeight;
127      if ((transforms[i].options & TJTransform.OPT_CROP) != 0) {
128        if (transforms[i].width != 0) w = transforms[i].width;
129        if (transforms[i].height != 0) h = transforms[i].height;
130      }
131      dstBufs[i] = new byte[TJ.bufSize(w, h, jpegSubsamp)];
132    }
133    TJDecompressor[] tjd = new TJDecompressor[transforms.length];
134    transform(dstBufs, transforms, flags);
135    for (int i = 0; i < transforms.length; i++)
136      tjd[i] = new TJDecompressor(dstBufs[i], transformedSizes[i]);
137    return tjd;
138  }
139
140  /**
141   * Returns an array containing the sizes of the transformed JPEG images
142   * generated by the most recent transform operation.
143   *
144   * @return an array containing the sizes of the transformed JPEG images
145   * generated by the most recent transform operation.
146   */
147  public int[] getTransformedSizes() {
148    if (transformedSizes == null)
149      throw new IllegalStateException("No image has been transformed yet");
150    return transformedSizes;
151  }
152
153  private native void init() throws TJException;
154
155  private native int[] transform(byte[] srcBuf, int srcSize, byte[][] dstBufs,
156    TJTransform[] transforms, int flags) throws TJException;
157
158  static {
159    TJLoader.load();
160  }
161
162  private int[] transformedSizes = null;
163}
164