1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "jpeg_reader.h"
18#include "error_codes.h"
19#include "jpeg_hook.h"
20
21#include <setjmp.h>
22
23JpegReader::JpegReader() :
24                mInfo(),
25                mErrorManager(),
26                mScanlineBuf(NULL),
27                mScanlineIter(NULL),
28                mScanlineBuflen(0),
29                mScanlineUnformattedBuflen(0),
30                mScanlineBytesRemaining(0),
31                mFormat(),
32                mFinished(false),
33                mSetup(false) {}
34
35JpegReader::~JpegReader() {
36    if (reset() != J_SUCCESS) {
37        LOGE("Failed to destroy compress object, JpegReader may leak memory.");
38    }
39}
40
41int32_t JpegReader::setup(JNIEnv *env, jobject in, int32_t* width, int32_t* height,
42        Jpeg_Config::Format format) {
43    if (mFinished || mSetup) {
44        return J_ERROR_FATAL;
45    }
46    if (env->ExceptionCheck()) {
47        return J_EXCEPTION;
48    }
49
50    // Setup error handler
51    SetupErrMgr(reinterpret_cast<j_common_ptr>(&mInfo), &mErrorManager);
52    // Set jump address for error handling
53    if (setjmp(mErrorManager.setjmp_buf)) {
54        return J_ERROR_FATAL;
55    }
56
57    // Call libjpeg setup
58    jpeg_create_decompress(&mInfo);
59
60    // Setup our data source object, this allocates java global references
61    int32_t flags = MakeSrc(&mInfo, env, in);
62    if (flags != J_SUCCESS) {
63        LOGE("Failed to make source with error code: %d ", flags);
64        return flags;
65    }
66
67    // Reads jpeg file header
68    jpeg_read_header(&mInfo, TRUE);
69    jpeg_calc_output_dimensions(&mInfo);
70
71    const int components = (static_cast<int>(format) & 0xff);
72
73    // Do setup for input format
74    switch (components) {
75    case 1:
76        mInfo.out_color_space = JCS_GRAYSCALE;
77        mScanlineUnformattedBuflen = mInfo.output_width;
78        break;
79    case 3:
80    case 4:
81        mScanlineUnformattedBuflen = mInfo.output_width * components;
82        if (mInfo.jpeg_color_space == JCS_CMYK
83                || mInfo.jpeg_color_space == JCS_YCCK) {
84            // Always use cmyk for output in a 4 channel jpeg.
85            // libjpeg has a builtin cmyk->rgb decoder.
86            mScanlineUnformattedBuflen = mInfo.output_width * 4;
87            mInfo.out_color_space = JCS_CMYK;
88        } else {
89            mInfo.out_color_space = JCS_RGB;
90        }
91        break;
92    default:
93        return J_ERROR_BAD_ARGS;
94    }
95
96    mScanlineBuflen = mInfo.output_width * components;
97    mScanlineBytesRemaining = mScanlineBuflen;
98    mScanlineBuf = (JSAMPLE *) (mInfo.mem->alloc_small)(
99            reinterpret_cast<j_common_ptr>(&mInfo), JPOOL_PERMANENT,
100            mScanlineUnformattedBuflen * sizeof(JSAMPLE));
101    mScanlineIter = mScanlineBuf;
102    jpeg_start_decompress(&mInfo);
103
104    // Output image dimensions
105    if (width != NULL) {
106        *width = mInfo.output_width;
107    }
108    if (height != NULL) {
109        *height = mInfo.output_height;
110    }
111
112    mFormat = format;
113    mSetup = true;
114    return J_SUCCESS;
115}
116
117int32_t JpegReader::read(int8_t* bytes, int32_t offset, int32_t count) {
118    if (!mSetup) {
119        return J_ERROR_FATAL;
120    }
121    if (mFinished) {
122        return J_DONE;
123    }
124    // Set jump address for error handling
125    if (setjmp(mErrorManager.setjmp_buf)) {
126        return J_ERROR_FATAL;
127    }
128    if (count <= 0) {
129        return J_ERROR_BAD_ARGS;
130    }
131    int32_t total_length = count;
132    while (mInfo.output_scanline < mInfo.output_height) {
133        if (count < mScanlineBytesRemaining) {
134            // read partial scanline and return
135            if (bytes != NULL) {
136                // Treat NULL bytes as a skip
137                memcpy((void*) (bytes + offset), (void*) mScanlineIter,
138                        count * sizeof(int8_t));
139            }
140            mScanlineBytesRemaining -= count;
141            mScanlineIter += count;
142            return total_length;
143        } else if (count > 0) {
144            // read full scanline
145            if (bytes != NULL) {
146                // Treat NULL bytes as a skip
147                memcpy((void*) (bytes + offset), (void*) mScanlineIter,
148                        mScanlineBytesRemaining * sizeof(int8_t));
149                bytes += mScanlineBytesRemaining;
150            }
151            count -= mScanlineBytesRemaining;
152            mScanlineBytesRemaining = 0;
153        }
154        // Scanline buffer exhausted, read next scanline
155        if (jpeg_read_scanlines(&mInfo, &mScanlineBuf, 1) != 1) {
156            // Always read full scanline, no IO suspension
157            return J_ERROR_FATAL;
158        }
159        // Do in-place pixel formatting
160        formatPixels(static_cast<uint8_t*>(mScanlineBuf),
161                mScanlineUnformattedBuflen);
162
163        // Reset iterators
164        mScanlineIter = mScanlineBuf;
165        mScanlineBytesRemaining = mScanlineBuflen;
166    }
167
168    // Read all of the scanlines
169    jpeg_finish_decompress(&mInfo);
170    mFinished = true;
171    return total_length - count;
172}
173
174void JpegReader::updateEnv(JNIEnv *env) {
175    UpdateSrcEnv(&mInfo, env);
176}
177
178// Does in-place pixel formatting
179void JpegReader::formatPixels(uint8_t* buf, int32_t len) {
180    uint8_t *iter = buf;
181
182    // Do cmyk->rgb conversion if necessary
183    switch (mInfo.out_color_space) {
184    case JCS_CMYK:
185        // Convert CMYK to RGB
186        int r, g, b, c, m, y, k;
187        for (int i = 0; i < len; i += 4) {
188            c = buf[i + 0];
189            m = buf[i + 1];
190            y = buf[i + 2];
191            k = buf[i + 3];
192            // Handle fmt for weird photoshop markers
193            if (mInfo.saw_Adobe_marker) {
194                r = (k * c) / 255;
195                g = (k * m) / 255;
196                b = (k * y) / 255;
197            } else {
198                r = (255 - k) * (255 - c) / 255;
199                g = (255 - k) * (255 - m) / 255;
200                b = (255 - k) * (255 - y) / 255;
201            }
202            *iter++ = r;
203            *iter++ = g;
204            *iter++ = b;
205        }
206        break;
207    case JCS_RGB:
208        iter += (len * 3 / 4);
209        break;
210    case JCS_GRAYSCALE:
211    default:
212        return;
213    }
214
215    // Do endianness and alpha for output format
216    if (mFormat == Jpeg_Config::FORMAT_RGBA) {
217        // Set alphas to 255
218        for (int i = len - 1; i >= 0; i -= 4) {
219            buf[i] = 255;
220            buf[i - 1] = *--iter;
221            buf[i - 2] = *--iter;
222            buf[i - 3] = *--iter;
223        }
224    } else if (mFormat == Jpeg_Config::FORMAT_ABGR) {
225        // Reverse endianness and set alphas to 255
226        int r, g, b;
227        for (int i = len - 1; i >= 0; i -= 4) {
228            b = *--iter;
229            g = *--iter;
230            r = *--iter;
231            buf[i] = r;
232            buf[i - 1] = g;
233            buf[i - 2] = b;
234            buf[i - 3] = 255;
235        }
236    }
237}
238
239int32_t JpegReader::reset() {
240    // Set jump address for error handling
241    if (setjmp(mErrorManager.setjmp_buf)) {
242        return J_ERROR_FATAL;
243    }
244    // Clean up global java references
245    CleanSrc(&mInfo);
246    // Wipe decompress struct, free memory pools
247    jpeg_destroy_decompress(&mInfo);
248    mFinished = false;
249    mSetup = false;
250    return J_SUCCESS;
251}
252
253