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 
JpegReader()23 JpegReader::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 
~JpegReader()35 JpegReader::~JpegReader() {
36     if (reset() != J_SUCCESS) {
37         LOGE("Failed to destroy compress object, JpegReader may leak memory.");
38     }
39 }
40 
setup(JNIEnv * env,jobject in,int32_t * width,int32_t * height,Jpeg_Config::Format format)41 int32_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 
read(int8_t * bytes,int32_t offset,int32_t count)117 int32_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 
updateEnv(JNIEnv * env)174 void JpegReader::updateEnv(JNIEnv *env) {
175     UpdateSrcEnv(&mInfo, env);
176 }
177 
178 // Does in-place pixel formatting
formatPixels(uint8_t * buf,int32_t len)179 void 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         uint8_t* end = buf + len - 1;
219         for (int i = len - 1; i >= 0; i -= 4) {
220             buf[i] = 255;
221             buf[i - 1] = *--iter;
222             buf[i - 2] = *--iter;
223             buf[i - 3] = *--iter;
224         }
225     } else if (mFormat == Jpeg_Config::FORMAT_ABGR) {
226         // Reverse endianness and set alphas to 255
227         uint8_t* end = buf + len - 1;
228         int r, g, b;
229         for (int i = len - 1; i >= 0; i -= 4) {
230             b = *--iter;
231             g = *--iter;
232             r = *--iter;
233             buf[i] = r;
234             buf[i - 1] = g;
235             buf[i - 2] = b;
236             buf[i - 3] = 255;
237         }
238     }
239 }
240 
reset()241 int32_t JpegReader::reset() {
242     // Set jump address for error handling
243     if (setjmp(mErrorManager.setjmp_buf)) {
244         return J_ERROR_FATAL;
245     }
246     // Clean up global java references
247     CleanSrc(&mInfo);
248     // Wipe decompress struct, free memory pools
249     jpeg_destroy_decompress(&mInfo);
250     mFinished = false;
251     mSetup = false;
252     return J_SUCCESS;
253 }
254 
255