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 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 35 JpegReader::~JpegReader() { 36 if (reset() != J_SUCCESS) { 37 LOGE("Failed to destroy compress object, JpegReader may leak memory."); 38 } 39 } 40 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 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 174 void JpegReader::updateEnv(JNIEnv *env) { 175 UpdateSrcEnv(&mInfo, env); 176 } 177 178 // Does in-place pixel formatting 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 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