| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/gfx/codec/jpeg_codec.h" | 5 #include "ui/gfx/codec/jpeg_codec.h" |
| 6 | 6 |
| 7 #include <setjmp.h> | 7 #include <setjmp.h> |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 | 10 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 | 36 |
| 37 void ErrorExit(jpeg_common_struct* cinfo) { | 37 void ErrorExit(jpeg_common_struct* cinfo) { |
| 38 CoderErrorMgr *err = reinterpret_cast<CoderErrorMgr*>(cinfo->err); | 38 CoderErrorMgr *err = reinterpret_cast<CoderErrorMgr*>(cinfo->err); |
| 39 | 39 |
| 40 // Return control to the setjmp point. | 40 // Return control to the setjmp point. |
| 41 longjmp(err->setjmp_buffer, false); | 41 longjmp(err->setjmp_buffer, false); |
| 42 } | 42 } |
| 43 | 43 |
| 44 } // namespace | 44 } // namespace |
| 45 | 45 |
| 46 // This method helps identify at run time which library chromium is using. | |
| 47 JPEGCodec::LibraryVariant JPEGCodec::JpegLibraryVariant() { | |
| 48 #if defined(USE_SYSTEM_LIBJPEG) | |
| 49 return SYSTEM_LIBJPEG; | |
| 50 #elif defined(USE_LIBJPEG_TURBO) | |
| 51 return LIBJPEG_TURBO; | |
| 52 #else | |
| 53 return IJG_LIBJPEG; | |
| 54 #endif | |
| 55 } | |
| 56 | |
| 57 // Encoder --------------------------------------------------------------------- | 46 // Encoder --------------------------------------------------------------------- |
| 58 // | 47 // |
| 59 // This code is based on nsJPEGEncoder from Mozilla. | 48 // This code is based on nsJPEGEncoder from Mozilla. |
| 60 // Copyright 2005 Google Inc. (Brett Wilson, contributor) | 49 // Copyright 2005 Google Inc. (Brett Wilson, contributor) |
| 61 | 50 |
| 62 namespace { | 51 namespace { |
| 63 | 52 |
| 64 // Initial size for the output buffer in the JpegEncoderState below. | 53 // Initial size for the output buffer in the JpegEncoderState below. |
| 65 static const int initial_output_buffer_size = 8192; | 54 static const int initial_output_buffer_size = 8192; |
| 66 | 55 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 137 | 126 |
| 138 // update the used byte based on the next byte libjpeg would write to | 127 // update the used byte based on the next byte libjpeg would write to |
| 139 state->image_buffer_used = cinfo->dest->next_output_byte - &(*state->out)[0]; | 128 state->image_buffer_used = cinfo->dest->next_output_byte - &(*state->out)[0]; |
| 140 DCHECK(state->image_buffer_used < state->out->size()) << | 129 DCHECK(state->image_buffer_used < state->out->size()) << |
| 141 "JPEG library busted, got a bad image buffer size"; | 130 "JPEG library busted, got a bad image buffer size"; |
| 142 | 131 |
| 143 // update our buffer so that it exactly encompases the desired data | 132 // update our buffer so that it exactly encompases the desired data |
| 144 state->out->resize(state->image_buffer_used); | 133 state->out->resize(state->image_buffer_used); |
| 145 } | 134 } |
| 146 | 135 |
| 147 #if !defined(JCS_EXTENSIONS) | |
| 148 // Converts RGBA to RGB (removing the alpha values) to prepare to send data to | |
| 149 // libjpeg. This converts one row of data in rgba with the given width in | |
| 150 // pixels the the given rgb destination buffer (which should have enough space | |
| 151 // reserved for the final data). | |
| 152 void StripAlpha(const unsigned char* rgba, int pixel_width, unsigned char* rgb) | |
| 153 { | |
| 154 for (int x = 0; x < pixel_width; x++) | |
| 155 memcpy(&rgb[x * 3], &rgba[x * 4], 3); | |
| 156 } | |
| 157 | |
| 158 // Converts BGRA to RGB by reordering the color components and dropping the | |
| 159 // alpha. This converts one row of data in rgba with the given width in | |
| 160 // pixels the the given rgb destination buffer (which should have enough space | |
| 161 // reserved for the final data). | |
| 162 void BGRAtoRGB(const unsigned char* bgra, int pixel_width, unsigned char* rgb) | |
| 163 { | |
| 164 for (int x = 0; x < pixel_width; x++) { | |
| 165 const unsigned char* pixel_in = &bgra[x * 4]; | |
| 166 unsigned char* pixel_out = &rgb[x * 3]; | |
| 167 pixel_out[0] = pixel_in[2]; | |
| 168 pixel_out[1] = pixel_in[1]; | |
| 169 pixel_out[2] = pixel_in[0]; | |
| 170 } | |
| 171 } | |
| 172 #endif // !defined(JCS_EXTENSIONS) | |
| 173 | |
| 174 // This class destroys the given jpeg_compress object when it goes out of | 136 // This class destroys the given jpeg_compress object when it goes out of |
| 175 // scope. It simplifies the error handling in Encode (and even applies to the | 137 // scope. It simplifies the error handling in Encode (and even applies to the |
| 176 // success case). | 138 // success case). |
| 177 class CompressDestroyer { | 139 class CompressDestroyer { |
| 178 public: | 140 public: |
| 179 CompressDestroyer() : cinfo_(NULL) { | 141 CompressDestroyer() : cinfo_(NULL) { |
| 180 } | 142 } |
| 181 ~CompressDestroyer() { | 143 ~CompressDestroyer() { |
| 182 DestroyManagedObject(); | 144 DestroyManagedObject(); |
| 183 } | 145 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 197 | 159 |
| 198 } // namespace | 160 } // namespace |
| 199 | 161 |
| 200 bool JPEGCodec::Encode(const unsigned char* input, ColorFormat format, | 162 bool JPEGCodec::Encode(const unsigned char* input, ColorFormat format, |
| 201 int w, int h, int row_byte_width, | 163 int w, int h, int row_byte_width, |
| 202 int quality, std::vector<unsigned char>* output) { | 164 int quality, std::vector<unsigned char>* output) { |
| 203 jpeg_compress_struct cinfo; | 165 jpeg_compress_struct cinfo; |
| 204 CompressDestroyer destroyer; | 166 CompressDestroyer destroyer; |
| 205 destroyer.SetManagedObject(&cinfo); | 167 destroyer.SetManagedObject(&cinfo); |
| 206 output->clear(); | 168 output->clear(); |
| 207 #if !defined(JCS_EXTENSIONS) | |
| 208 unsigned char* row_buffer = NULL; | |
| 209 #endif | |
| 210 | 169 |
| 211 // We set up the normal JPEG error routines, then override error_exit. | 170 // We set up the normal JPEG error routines, then override error_exit. |
| 212 // This must be done before the call to create_compress. | 171 // This must be done before the call to create_compress. |
| 213 CoderErrorMgr errmgr; | 172 CoderErrorMgr errmgr; |
| 214 cinfo.err = jpeg_std_error(&errmgr.pub); | 173 cinfo.err = jpeg_std_error(&errmgr.pub); |
| 215 errmgr.pub.error_exit = ErrorExit; | 174 errmgr.pub.error_exit = ErrorExit; |
| 216 | 175 |
| 217 // Establish the setjmp return context for ErrorExit to use. | 176 // Establish the setjmp return context for ErrorExit to use. |
| 218 if (setjmp(errmgr.setjmp_buffer)) { | 177 if (setjmp(errmgr.setjmp_buffer)) { |
| 219 // If we get here, the JPEG code has signaled an error. | 178 // If we get here, the JPEG code has signaled an error. |
| 220 // MSDN notes: "if you intend your code to be portable, do not rely on | 179 // MSDN notes: "if you intend your code to be portable, do not rely on |
| 221 // correct destruction of frame-based objects when executing a nonlocal | 180 // correct destruction of frame-based objects when executing a nonlocal |
| 222 // goto using a call to longjmp." So we delete the CompressDestroyer's | 181 // goto using a call to longjmp." So we delete the CompressDestroyer's |
| 223 // object manually instead. | 182 // object manually instead. |
| 224 destroyer.DestroyManagedObject(); | 183 destroyer.DestroyManagedObject(); |
| 225 #if !defined(JCS_EXTENSIONS) | |
| 226 delete[] row_buffer; | |
| 227 #endif | |
| 228 return false; | 184 return false; |
| 229 } | 185 } |
| 230 | 186 |
| 231 // The destroyer will destroy() cinfo on exit. | 187 // The destroyer will destroy() cinfo on exit. |
| 232 jpeg_create_compress(&cinfo); | 188 jpeg_create_compress(&cinfo); |
| 233 | 189 |
| 234 cinfo.image_width = w; | 190 cinfo.image_width = w; |
| 235 cinfo.image_height = h; | 191 cinfo.image_height = h; |
| 236 cinfo.input_components = 3; | 192 cinfo.input_components = 4; |
| 237 #ifdef JCS_EXTENSIONS | |
| 238 // Choose an input colorspace and return if it is an unsupported one. Since | 193 // Choose an input colorspace and return if it is an unsupported one. Since |
| 239 // libjpeg-turbo supports all input formats used by Chromium (i.e. RGB, RGBA, | 194 // libjpeg-turbo supports all input formats used by Chromium (i.e. RGB, RGBA, |
| 240 // and BGRA), we just map the input parameters to a colorspace used by | 195 // and BGRA), we just map the input parameters to a colorspace used by |
| 241 // libjpeg-turbo. | 196 // libjpeg-turbo. |
| 242 if (format == FORMAT_RGB) { | 197 if (format == FORMAT_RGBA || |
| 243 cinfo.input_components = 3; | 198 (format == FORMAT_SkBitmap && SK_R32_SHIFT == 0)) { |
| 244 cinfo.in_color_space = JCS_RGB; | |
| 245 } else if (format == FORMAT_RGBA || | |
| 246 (format == FORMAT_SkBitmap && SK_R32_SHIFT == 0)) { | |
| 247 cinfo.input_components = 4; | |
| 248 cinfo.in_color_space = JCS_EXT_RGBX; | 199 cinfo.in_color_space = JCS_EXT_RGBX; |
| 249 } else if (format == FORMAT_BGRA || | 200 } else if (format == FORMAT_BGRA || |
| 250 (format == FORMAT_SkBitmap && SK_B32_SHIFT == 0)) { | 201 (format == FORMAT_SkBitmap && SK_B32_SHIFT == 0)) { |
| 251 cinfo.input_components = 4; | |
| 252 cinfo.in_color_space = JCS_EXT_BGRX; | 202 cinfo.in_color_space = JCS_EXT_BGRX; |
| 253 } else { | 203 } else { |
| 254 // We can exit this function without calling jpeg_destroy_compress() because | 204 // We can exit this function without calling jpeg_destroy_compress() because |
| 255 // CompressDestroyer automaticaly calls it. | 205 // CompressDestroyer automaticaly calls it. |
| 256 NOTREACHED() << "Invalid pixel format"; | 206 NOTREACHED() << "Invalid pixel format"; |
| 257 return false; | 207 return false; |
| 258 } | 208 } |
| 259 #else | |
| 260 cinfo.in_color_space = JCS_RGB; | |
| 261 #endif | |
| 262 cinfo.data_precision = 8; | 209 cinfo.data_precision = 8; |
| 263 | 210 |
| 264 jpeg_set_defaults(&cinfo); | 211 jpeg_set_defaults(&cinfo); |
| 265 jpeg_set_quality(&cinfo, quality, 1); // quality here is 0-100 | 212 jpeg_set_quality(&cinfo, quality, 1); // quality here is 0-100 |
| 266 | 213 |
| 267 // set up the destination manager | 214 // set up the destination manager |
| 268 jpeg_destination_mgr destmgr; | 215 jpeg_destination_mgr destmgr; |
| 269 destmgr.init_destination = InitDestination; | 216 destmgr.init_destination = InitDestination; |
| 270 destmgr.empty_output_buffer = EmptyOutputBuffer; | 217 destmgr.empty_output_buffer = EmptyOutputBuffer; |
| 271 destmgr.term_destination = TermDestination; | 218 destmgr.term_destination = TermDestination; |
| 272 cinfo.dest = &destmgr; | 219 cinfo.dest = &destmgr; |
| 273 | 220 |
| 274 JpegEncoderState state(output); | 221 JpegEncoderState state(output); |
| 275 cinfo.client_data = &state; | 222 cinfo.client_data = &state; |
| 276 | 223 |
| 277 jpeg_start_compress(&cinfo, 1); | 224 jpeg_start_compress(&cinfo, 1); |
| 278 | 225 |
| 279 // feed it the rows, doing necessary conversions for the color format | 226 // feed it the rows, doing necessary conversions for the color format |
| 280 #ifdef JCS_EXTENSIONS | |
| 281 // This function already returns when the input format is not supported by | 227 // This function already returns when the input format is not supported by |
| 282 // libjpeg-turbo and needs conversion. Therefore, we just encode lines without | 228 // libjpeg-turbo and needs conversion. Therefore, we just encode lines without |
| 283 // conversions. | 229 // conversions. |
| 284 while (cinfo.next_scanline < cinfo.image_height) { | 230 while (cinfo.next_scanline < cinfo.image_height) { |
| 285 const unsigned char* row = &input[cinfo.next_scanline * row_byte_width]; | 231 const unsigned char* row = &input[cinfo.next_scanline * row_byte_width]; |
| 286 jpeg_write_scanlines(&cinfo, const_cast<unsigned char**>(&row), 1); | 232 jpeg_write_scanlines(&cinfo, const_cast<unsigned char**>(&row), 1); |
| 287 } | 233 } |
| 288 #else | |
| 289 if (format == FORMAT_RGB) { | |
| 290 // no conversion necessary | |
| 291 while (cinfo.next_scanline < cinfo.image_height) { | |
| 292 const unsigned char* row = &input[cinfo.next_scanline * row_byte_width]; | |
| 293 jpeg_write_scanlines(&cinfo, const_cast<unsigned char**>(&row), 1); | |
| 294 } | |
| 295 } else { | |
| 296 // get the correct format converter | |
| 297 void (*converter)(const unsigned char* in, int w, unsigned char* rgb); | |
| 298 if (format == FORMAT_RGBA || | |
| 299 (format == FORMAT_SkBitmap && SK_R32_SHIFT == 0)) { | |
| 300 converter = StripAlpha; | |
| 301 } else if (format == FORMAT_BGRA || | |
| 302 (format == FORMAT_SkBitmap && SK_B32_SHIFT == 0)) { | |
| 303 converter = BGRAtoRGB; | |
| 304 } else { | |
| 305 NOTREACHED() << "Invalid pixel format"; | |
| 306 return false; | |
| 307 } | |
| 308 | |
| 309 // output row after converting | |
| 310 row_buffer = new unsigned char[w * 3]; | |
| 311 | |
| 312 while (cinfo.next_scanline < cinfo.image_height) { | |
| 313 converter(&input[cinfo.next_scanline * row_byte_width], w, row_buffer); | |
| 314 jpeg_write_scanlines(&cinfo, &row_buffer, 1); | |
| 315 } | |
| 316 delete[] row_buffer; | |
| 317 } | |
| 318 #endif | |
| 319 | 234 |
| 320 jpeg_finish_compress(&cinfo); | 235 jpeg_finish_compress(&cinfo); |
| 321 return true; | 236 return true; |
| 322 } | 237 } |
| 323 | 238 |
| 324 // Decoder -------------------------------------------------------------------- | 239 // Decoder -------------------------------------------------------------------- |
| 325 | 240 |
| 326 namespace { | 241 namespace { |
| 327 | 242 |
| 328 struct JpegDecoderState { | 243 struct JpegDecoderState { |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 391 | 306 |
| 392 // Our source doesn't need any cleanup, so this is a NOP. | 307 // Our source doesn't need any cleanup, so this is a NOP. |
| 393 // | 308 // |
| 394 // From the JPEG library: | 309 // From the JPEG library: |
| 395 // "Terminate source --- called by jpeg_finish_decompress() after all data has | 310 // "Terminate source --- called by jpeg_finish_decompress() after all data has |
| 396 // been read to clean up JPEG source manager. NOT called by jpeg_abort() or | 311 // been read to clean up JPEG source manager. NOT called by jpeg_abort() or |
| 397 // jpeg_destroy()." | 312 // jpeg_destroy()." |
| 398 void TermSource(j_decompress_ptr cinfo) { | 313 void TermSource(j_decompress_ptr cinfo) { |
| 399 } | 314 } |
| 400 | 315 |
| 401 #if !defined(JCS_EXTENSIONS) | |
| 402 // Converts one row of rgb data to rgba data by adding a fully-opaque alpha | |
| 403 // value. | |
| 404 void AddAlpha(const unsigned char* rgb, int pixel_width, unsigned char* rgba) { | |
| 405 for (int x = 0; x < pixel_width; x++) { | |
| 406 memcpy(&rgba[x * 4], &rgb[x * 3], 3); | |
| 407 rgba[x * 4 + 3] = 0xff; | |
| 408 } | |
| 409 } | |
| 410 | |
| 411 // Converts one row of RGB data to BGRA by reordering the color components and | |
| 412 // adding alpha values of 0xff. | |
| 413 void RGBtoBGRA(const unsigned char* bgra, int pixel_width, unsigned char* rgb) | |
| 414 { | |
| 415 for (int x = 0; x < pixel_width; x++) { | |
| 416 const unsigned char* pixel_in = &bgra[x * 3]; | |
| 417 unsigned char* pixel_out = &rgb[x * 4]; | |
| 418 pixel_out[0] = pixel_in[2]; | |
| 419 pixel_out[1] = pixel_in[1]; | |
| 420 pixel_out[2] = pixel_in[0]; | |
| 421 pixel_out[3] = 0xff; | |
| 422 } | |
| 423 } | |
| 424 #endif // !defined(JCS_EXTENSIONS) | |
| 425 | |
| 426 // This class destroys the given jpeg_decompress object when it goes out of | 316 // This class destroys the given jpeg_decompress object when it goes out of |
| 427 // scope. It simplifies the error handling in Decode (and even applies to the | 317 // scope. It simplifies the error handling in Decode (and even applies to the |
| 428 // success case). | 318 // success case). |
| 429 class DecompressDestroyer { | 319 class DecompressDestroyer { |
| 430 public: | 320 public: |
| 431 DecompressDestroyer() : cinfo_(NULL) { | 321 DecompressDestroyer() : cinfo_(NULL) { |
| 432 } | 322 } |
| 433 ~DecompressDestroyer() { | 323 ~DecompressDestroyer() { |
| 434 DestroyManagedObject(); | 324 DestroyManagedObject(); |
| 435 } | 325 } |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 489 | 379 |
| 490 // fill the file metadata into our buffer | 380 // fill the file metadata into our buffer |
| 491 if (jpeg_read_header(&cinfo, true) != JPEG_HEADER_OK) | 381 if (jpeg_read_header(&cinfo, true) != JPEG_HEADER_OK) |
| 492 return false; | 382 return false; |
| 493 | 383 |
| 494 // we want to always get RGB data out | 384 // we want to always get RGB data out |
| 495 switch (cinfo.jpeg_color_space) { | 385 switch (cinfo.jpeg_color_space) { |
| 496 case JCS_GRAYSCALE: | 386 case JCS_GRAYSCALE: |
| 497 case JCS_RGB: | 387 case JCS_RGB: |
| 498 case JCS_YCbCr: | 388 case JCS_YCbCr: |
| 499 #ifdef JCS_EXTENSIONS | |
| 500 // Choose an output colorspace and return if it is an unsupported one. | 389 // Choose an output colorspace and return if it is an unsupported one. |
| 501 // Same as JPEGCodec::Encode(), libjpeg-turbo supports all input formats | 390 // Same as JPEGCodec::Encode(), libjpeg-turbo supports all input formats |
| 502 // used by Chromium (i.e. RGB, RGBA, and BGRA) and we just map the input | 391 // used by Chromium (i.e. RGB, RGBA, and BGRA) and we just map the input |
| 503 // parameters to a colorspace. | 392 // parameters to a colorspace. |
| 504 if (format == FORMAT_RGB) { | 393 if (format == FORMAT_RGBA || |
| 505 cinfo.out_color_space = JCS_RGB; | 394 (format == FORMAT_SkBitmap && SK_R32_SHIFT == 0)) { |
| 506 cinfo.output_components = 3; | |
| 507 } else if (format == FORMAT_RGBA || | |
| 508 (format == FORMAT_SkBitmap && SK_R32_SHIFT == 0)) { | |
| 509 cinfo.out_color_space = JCS_EXT_RGBX; | 395 cinfo.out_color_space = JCS_EXT_RGBX; |
| 510 cinfo.output_components = 4; | 396 cinfo.output_components = 4; |
| 511 } else if (format == FORMAT_BGRA || | 397 } else if (format == FORMAT_BGRA || |
| 512 (format == FORMAT_SkBitmap && SK_B32_SHIFT == 0)) { | 398 (format == FORMAT_SkBitmap && SK_B32_SHIFT == 0)) { |
| 513 cinfo.out_color_space = JCS_EXT_BGRX; | 399 cinfo.out_color_space = JCS_EXT_BGRX; |
| 514 cinfo.output_components = 4; | 400 cinfo.output_components = 4; |
| 515 } else { | 401 } else { |
| 516 // We can exit this function without calling jpeg_destroy_decompress() | 402 // We can exit this function without calling jpeg_destroy_decompress() |
| 517 // because DecompressDestroyer automaticaly calls it. | 403 // because DecompressDestroyer automaticaly calls it. |
| 518 NOTREACHED() << "Invalid pixel format"; | 404 NOTREACHED() << "Invalid pixel format"; |
| 519 return false; | 405 return false; |
| 520 } | 406 } |
| 521 #else | |
| 522 cinfo.out_color_space = JCS_RGB; | |
| 523 #endif | |
| 524 break; | 407 break; |
| 525 case JCS_CMYK: | 408 case JCS_CMYK: |
| 526 case JCS_YCCK: | 409 case JCS_YCCK: |
| 527 default: | 410 default: |
| 528 // Mozilla errors out on these color spaces, so I presume that the jpeg | 411 // Mozilla errors out on these color spaces, so I presume that the jpeg |
| 529 // library can't do automatic color space conversion for them. We don't | 412 // library can't do automatic color space conversion for them. We don't |
| 530 // care about these anyway. | 413 // care about these anyway. |
| 531 return false; | 414 return false; |
| 532 } | 415 } |
| 533 #ifndef JCS_EXTENSIONS | |
| 534 cinfo.output_components = 3; | |
| 535 #endif | |
| 536 | 416 |
| 537 jpeg_calc_output_dimensions(&cinfo); | 417 jpeg_calc_output_dimensions(&cinfo); |
| 538 *w = cinfo.output_width; | 418 *w = cinfo.output_width; |
| 539 *h = cinfo.output_height; | 419 *h = cinfo.output_height; |
| 540 | 420 |
| 541 jpeg_start_decompress(&cinfo); | 421 jpeg_start_decompress(&cinfo); |
| 542 | 422 |
| 543 // FIXME(brettw) we may want to allow the capability for callers to request | 423 // FIXME(brettw) we may want to allow the capability for callers to request |
| 544 // how to align row lengths as we do for the compressor. | 424 // how to align row lengths as we do for the compressor. |
| 545 int row_read_stride = cinfo.output_width * cinfo.output_components; | 425 int row_read_stride = cinfo.output_width * cinfo.output_components; |
| 546 | 426 |
| 547 #ifdef JCS_EXTENSIONS | |
| 548 // Create memory for a decoded image and write decoded lines to the memory | 427 // Create memory for a decoded image and write decoded lines to the memory |
| 549 // without conversions same as JPEGCodec::Encode(). | 428 // without conversions same as JPEGCodec::Encode(). |
| 550 int row_write_stride = row_read_stride; | 429 int row_write_stride = row_read_stride; |
| 551 output->resize(row_write_stride * cinfo.output_height); | 430 output->resize(row_write_stride * cinfo.output_height); |
| 552 | 431 |
| 553 for (int row = 0; row < static_cast<int>(cinfo.output_height); row++) { | 432 for (int row = 0; row < static_cast<int>(cinfo.output_height); row++) { |
| 554 unsigned char* rowptr = &(*output)[row * row_write_stride]; | 433 unsigned char* rowptr = &(*output)[row * row_write_stride]; |
| 555 if (!jpeg_read_scanlines(&cinfo, &rowptr, 1)) | 434 if (!jpeg_read_scanlines(&cinfo, &rowptr, 1)) |
| 556 return false; | 435 return false; |
| 557 } | 436 } |
| 558 #else | |
| 559 if (format == FORMAT_RGB) { | |
| 560 // easy case, row needs no conversion | |
| 561 int row_write_stride = row_read_stride; | |
| 562 output->resize(row_write_stride * cinfo.output_height); | |
| 563 | |
| 564 for (int row = 0; row < static_cast<int>(cinfo.output_height); row++) { | |
| 565 unsigned char* rowptr = &(*output)[row * row_write_stride]; | |
| 566 if (!jpeg_read_scanlines(&cinfo, &rowptr, 1)) | |
| 567 return false; | |
| 568 } | |
| 569 } else { | |
| 570 // Rows need conversion to output format: read into a temporary buffer and | |
| 571 // expand to the final one. Performance: we could avoid the extra | |
| 572 // allocation by doing the expansion in-place. | |
| 573 int row_write_stride; | |
| 574 void (*converter)(const unsigned char* rgb, int w, unsigned char* out); | |
| 575 if (format == FORMAT_RGBA || | |
| 576 (format == FORMAT_SkBitmap && SK_R32_SHIFT == 0)) { | |
| 577 row_write_stride = cinfo.output_width * 4; | |
| 578 converter = AddAlpha; | |
| 579 } else if (format == FORMAT_BGRA || | |
| 580 (format == FORMAT_SkBitmap && SK_B32_SHIFT == 0)) { | |
| 581 row_write_stride = cinfo.output_width * 4; | |
| 582 converter = RGBtoBGRA; | |
| 583 } else { | |
| 584 NOTREACHED() << "Invalid pixel format"; | |
| 585 jpeg_destroy_decompress(&cinfo); | |
| 586 return false; | |
| 587 } | |
| 588 | |
| 589 output->resize(row_write_stride * cinfo.output_height); | |
| 590 | |
| 591 std::unique_ptr<unsigned char[]> row_data( | |
| 592 new unsigned char[row_read_stride]); | |
| 593 unsigned char* rowptr = row_data.get(); | |
| 594 for (int row = 0; row < static_cast<int>(cinfo.output_height); row++) { | |
| 595 if (!jpeg_read_scanlines(&cinfo, &rowptr, 1)) | |
| 596 return false; | |
| 597 converter(rowptr, *w, &(*output)[row * row_write_stride]); | |
| 598 } | |
| 599 } | |
| 600 #endif | |
| 601 | 437 |
| 602 jpeg_finish_decompress(&cinfo); | 438 jpeg_finish_decompress(&cinfo); |
| 603 jpeg_destroy_decompress(&cinfo); | 439 jpeg_destroy_decompress(&cinfo); |
| 604 return true; | 440 return true; |
| 605 } | 441 } |
| 606 | 442 |
| 607 // static | 443 // static |
| 608 std::unique_ptr<SkBitmap> JPEGCodec::Decode(const unsigned char* input, | 444 std::unique_ptr<SkBitmap> JPEGCodec::Decode(const unsigned char* input, |
| 609 size_t input_size) { | 445 size_t input_size) { |
| 610 int w, h; | 446 int w, h; |
| 611 std::vector<unsigned char> data_vector; | 447 std::vector<unsigned char> data_vector; |
| 612 if (!Decode(input, input_size, FORMAT_SkBitmap, &data_vector, &w, &h)) | 448 if (!Decode(input, input_size, FORMAT_SkBitmap, &data_vector, &w, &h)) |
| 613 return nullptr; | 449 return nullptr; |
| 614 | 450 |
| 615 // Skia only handles 32 bit images. | 451 // Skia only handles 32 bit images. |
| 616 int data_length = w * h * 4; | 452 int data_length = w * h * 4; |
| 617 | 453 |
| 618 std::unique_ptr<SkBitmap> bitmap(new SkBitmap()); | 454 std::unique_ptr<SkBitmap> bitmap(new SkBitmap()); |
| 619 bitmap->allocN32Pixels(w, h); | 455 bitmap->allocN32Pixels(w, h); |
| 620 memcpy(bitmap->getAddr32(0, 0), &data_vector[0], data_length); | 456 memcpy(bitmap->getAddr32(0, 0), &data_vector[0], data_length); |
| 621 | 457 |
| 622 return bitmap; | 458 return bitmap; |
| 623 } | 459 } |
| 624 | 460 |
| 625 } // namespace gfx | 461 } // namespace gfx |
| OLD | NEW |