Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(408)

Side by Side Diff: src/codec/SkJpegCodec.cpp

Issue 1275773004: Switching Skia to chromium's libjpeg-turbo (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkCodec.h" 8 #include "SkCodec.h"
9 #include "SkJpegCodec.h" 9 #include "SkJpegCodec.h"
10 #include "SkJpegDecoderMgr.h" 10 #include "SkJpegDecoderMgr.h"
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 104
105 // libjpeg errors will be caught and reported here 105 // libjpeg errors will be caught and reported here
106 if (setjmp(decoderMgr->getJmpBuf())) { 106 if (setjmp(decoderMgr->getJmpBuf())) {
107 return decoderMgr->returnFalse("setjmp"); 107 return decoderMgr->returnFalse("setjmp");
108 } 108 }
109 109
110 // Initialize the decompress info and the source manager 110 // Initialize the decompress info and the source manager
111 decoderMgr->init(); 111 decoderMgr->init();
112 112
113 // Read the jpeg header 113 // Read the jpeg header
114 if (JPEG_HEADER_OK != turbo_jpeg_read_header(decoderMgr->dinfo(), true)) { 114 if (JPEG_HEADER_OK != chromium_jpeg_read_header(decoderMgr->dinfo(), true)) {
115 return decoderMgr->returnFalse("read_header"); 115 return decoderMgr->returnFalse("read_header");
116 } 116 }
117 117
118 if (NULL != codecOut) { 118 if (NULL != codecOut) {
119 // Recommend the color type to decode to 119 // Recommend the color type to decode to
120 const SkColorType colorType = decoderMgr->getColorType(); 120 const SkColorType colorType = decoderMgr->getColorType();
121 121
122 // Create image info object and the codec 122 // Create image info object and the codec
123 const SkImageInfo& imageInfo = SkImageInfo::Make(decoderMgr->dinfo()->im age_width, 123 const SkImageInfo& imageInfo = SkImageInfo::Make(decoderMgr->dinfo()->im age_width,
124 decoderMgr->dinfo()->image_height, colorType, kOpaque_SkAlphaTyp e); 124 decoderMgr->dinfo()->image_height, colorType, kOpaque_SkAlphaTyp e);
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
176 176
177 // Set up a fake decompress struct in order to use libjpeg to calculate outp ut dimensions 177 // Set up a fake decompress struct in order to use libjpeg to calculate outp ut dimensions
178 jpeg_decompress_struct dinfo; 178 jpeg_decompress_struct dinfo;
179 sk_bzero(&dinfo, sizeof(dinfo)); 179 sk_bzero(&dinfo, sizeof(dinfo));
180 dinfo.image_width = this->getInfo().width(); 180 dinfo.image_width = this->getInfo().width();
181 dinfo.image_height = this->getInfo().height(); 181 dinfo.image_height = this->getInfo().height();
182 dinfo.global_state = DSTATE_READY; 182 dinfo.global_state = DSTATE_READY;
183 dinfo.num_components = 0; 183 dinfo.num_components = 0;
184 dinfo.scale_num = num; 184 dinfo.scale_num = num;
185 dinfo.scale_denom = denom; 185 dinfo.scale_denom = denom;
186 turbo_jpeg_calc_output_dimensions(&dinfo); 186 chromium_jpeg_calc_output_dimensions(&dinfo);
187 187
188 // Return the calculated output dimensions for the given scale 188 // Return the calculated output dimensions for the given scale
189 return SkISize::Make(dinfo.output_width, dinfo.output_height); 189 return SkISize::Make(dinfo.output_width, dinfo.output_height);
190 } 190 }
191 191
192 /* 192 /*
193 * Handles rewinding the input stream if it is necessary 193 * Handles rewinding the input stream if it is necessary
194 */ 194 */
195 bool SkJpegCodec::handleRewind() { 195 bool SkJpegCodec::handleRewind() {
196 switch(this->rewindIfNeeded()) { 196 switch(this->rewindIfNeeded()) {
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
272 } 272 }
273 273
274 /* 274 /*
275 * Checks if we can scale to the requested dimensions and scales the dimensions 275 * Checks if we can scale to the requested dimensions and scales the dimensions
276 * if possible 276 * if possible
277 */ 277 */
278 bool SkJpegCodec::scaleToDimensions(uint32_t dstWidth, uint32_t dstHeight) { 278 bool SkJpegCodec::scaleToDimensions(uint32_t dstWidth, uint32_t dstHeight) {
279 // libjpeg-turbo can scale to 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, and 1/1 279 // libjpeg-turbo can scale to 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, and 1/1
280 fDecoderMgr->dinfo()->scale_denom = 8; 280 fDecoderMgr->dinfo()->scale_denom = 8;
281 fDecoderMgr->dinfo()->scale_num = 8; 281 fDecoderMgr->dinfo()->scale_num = 8;
282 turbo_jpeg_calc_output_dimensions(fDecoderMgr->dinfo()); 282 chromium_jpeg_calc_output_dimensions(fDecoderMgr->dinfo());
283 while (fDecoderMgr->dinfo()->output_width != dstWidth || 283 while (fDecoderMgr->dinfo()->output_width != dstWidth ||
284 fDecoderMgr->dinfo()->output_height != dstHeight) { 284 fDecoderMgr->dinfo()->output_height != dstHeight) {
285 285
286 // Return a failure if we have tried all of the possible scales 286 // Return a failure if we have tried all of the possible scales
287 if (1 == fDecoderMgr->dinfo()->scale_num || 287 if (1 == fDecoderMgr->dinfo()->scale_num ||
288 dstWidth > fDecoderMgr->dinfo()->output_width || 288 dstWidth > fDecoderMgr->dinfo()->output_width ||
289 dstHeight > fDecoderMgr->dinfo()->output_height) { 289 dstHeight > fDecoderMgr->dinfo()->output_height) {
290 return fDecoderMgr->returnFalse("could not scale to requested dimens ions"); 290 return fDecoderMgr->returnFalse("could not scale to requested dimens ions");
291 } 291 }
292 292
293 // Try the next scale 293 // Try the next scale
294 fDecoderMgr->dinfo()->scale_num -= 1; 294 fDecoderMgr->dinfo()->scale_num -= 1;
295 turbo_jpeg_calc_output_dimensions(fDecoderMgr->dinfo()); 295 chromium_jpeg_calc_output_dimensions(fDecoderMgr->dinfo());
296 } 296 }
297 return true; 297 return true;
298 } 298 }
299 299
300 /* 300 /*
301 * Performs the jpeg decode 301 * Performs the jpeg decode
302 */ 302 */
303 SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo, 303 SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
304 void* dst, size_t dstRowBytes, 304 void* dst, size_t dstRowBytes,
305 const Options& options, SkPMColor*, int *) { 305 const Options& options, SkPMColor*, int *) {
(...skipping 19 matching lines...) Expand all
325 if (!this->setOutputColorSpace(dstInfo)) { 325 if (!this->setOutputColorSpace(dstInfo)) {
326 return fDecoderMgr->returnFailure("conversion_possible", kInvalidConvers ion); 326 return fDecoderMgr->returnFailure("conversion_possible", kInvalidConvers ion);
327 } 327 }
328 328
329 // Perform the necessary scaling 329 // Perform the necessary scaling
330 if (!this->scaleToDimensions(dstInfo.width(), dstInfo.height())) { 330 if (!this->scaleToDimensions(dstInfo.width(), dstInfo.height())) {
331 return fDecoderMgr->returnFailure("cannot scale to requested dims", kInv alidScale); 331 return fDecoderMgr->returnFailure("cannot scale to requested dims", kInv alidScale);
332 } 332 }
333 333
334 // Now, given valid output dimensions, we can start the decompress 334 // Now, given valid output dimensions, we can start the decompress
335 if (!turbo_jpeg_start_decompress(dinfo)) { 335 if (!chromium_jpeg_start_decompress(dinfo)) {
336 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); 336 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
337 } 337 }
338 338
339 // The recommended output buffer height should always be 1 in high quality m odes. 339 // The recommended output buffer height should always be 1 in high quality m odes.
340 // If it's not, we want to know because it means our strategy is not optimal . 340 // If it's not, we want to know because it means our strategy is not optimal .
341 SkASSERT(1 == dinfo->rec_outbuf_height); 341 SkASSERT(1 == dinfo->rec_outbuf_height);
342 342
343 // Perform the decode a single row at a time 343 // Perform the decode a single row at a time
344 uint32_t dstHeight = dstInfo.height(); 344 uint32_t dstHeight = dstInfo.height();
345 JSAMPLE* dstRow = (JSAMPLE*) dst; 345 JSAMPLE* dstRow = (JSAMPLE*) dst;
346 for (uint32_t y = 0; y < dstHeight; y++) { 346 for (uint32_t y = 0; y < dstHeight; y++) {
347 // Read rows of the image 347 // Read rows of the image
348 uint32_t rowsDecoded = turbo_jpeg_read_scanlines(dinfo, &dstRow, 1); 348 uint32_t rowsDecoded = chromium_jpeg_read_scanlines(dinfo, &dstRow, 1);
349 349
350 // If we cannot read enough rows, assume the input is incomplete 350 // If we cannot read enough rows, assume the input is incomplete
351 if (rowsDecoded != 1) { 351 if (rowsDecoded != 1) {
352 // Fill the remainder of the image with black. This error handling 352 // Fill the remainder of the image with black. This error handling
353 // behavior is unspecified but SkCodec consistently uses black as 353 // behavior is unspecified but SkCodec consistently uses black as
354 // the fill color for opaque images. If the destination is kGray, 354 // the fill color for opaque images. If the destination is kGray,
355 // the low 8 bits of SK_ColorBLACK will be used. Conveniently, 355 // the low 8 bits of SK_ColorBLACK will be used. Conveniently,
356 // these are zeros, which is the representation for black in kGray. 356 // these are zeros, which is the representation for black in kGray.
357 // If the destination is kRGB_565, the low 16 bits of SK_ColorBLACK 357 // If the destination is kRGB_565, the low 16 bits of SK_ColorBLACK
358 // will be used. Conveniently, these are zeros, which is the 358 // will be used. Conveniently, these are zeros, which is the
359 // representation for black in kRGB_565. 359 // representation for black in kRGB_565.
360 if (kNo_ZeroInitialized == options.fZeroInitialized || 360 if (kNo_ZeroInitialized == options.fZeroInitialized ||
361 kN32_SkColorType == dstInfo.colorType()) { 361 kN32_SkColorType == dstInfo.colorType()) {
362 SkSwizzler::Fill(dstRow, dstInfo, dstRowBytes, dstHeight - y, 362 SkSwizzler::Fill(dstRow, dstInfo, dstRowBytes, dstHeight - y,
363 SK_ColorBLACK, NULL); 363 SK_ColorBLACK, NULL);
364 } 364 }
365 365
366 // Prevent libjpeg from failing on incomplete decode 366 // Prevent libjpeg from failing on incomplete decode
367 dinfo->output_scanline = dstHeight; 367 dinfo->output_scanline = dstHeight;
368 368
369 // Finish the decode and indicate that the input was incomplete. 369 // Finish the decode and indicate that the input was incomplete.
370 turbo_jpeg_finish_decompress(dinfo); 370 chromium_jpeg_finish_decompress(dinfo);
371 return fDecoderMgr->returnFailure("Incomplete image data", kIncomple teInput); 371 return fDecoderMgr->returnFailure("Incomplete image data", kIncomple teInput);
372 } 372 }
373 373
374 // Convert to RGBA if necessary 374 // Convert to RGBA if necessary
375 if (JCS_CMYK == dinfo->out_color_space) { 375 if (JCS_CMYK == dinfo->out_color_space) {
376 convert_CMYK_to_RGBA(dstRow, dstInfo.width()); 376 convert_CMYK_to_RGBA(dstRow, dstInfo.width());
377 } 377 }
378 378
379 // Move to the next row 379 // Move to the next row
380 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes); 380 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes);
381 } 381 }
382 turbo_jpeg_finish_decompress(dinfo); 382 chromium_jpeg_finish_decompress(dinfo);
383 383
384 return kSuccess; 384 return kSuccess;
385 } 385 }
386 386
387 /* 387 /*
388 * Enable scanline decoding for jpegs 388 * Enable scanline decoding for jpegs
389 */ 389 */
390 class SkJpegScanlineDecoder : public SkScanlineDecoder { 390 class SkJpegScanlineDecoder : public SkScanlineDecoder {
391 public: 391 public:
392 SkJpegScanlineDecoder(const SkImageInfo& dstInfo, SkJpegCodec* codec, 392 SkJpegScanlineDecoder(const SkImageInfo& dstInfo, SkJpegCodec* codec,
393 const SkCodec::Options& opts) 393 const SkCodec::Options& opts)
394 : INHERITED(dstInfo) 394 : INHERITED(dstInfo)
395 , fCodec(codec) 395 , fCodec(codec)
396 , fOpts(opts) 396 , fOpts(opts)
397 {} 397 {}
398 398
399 virtual ~SkJpegScanlineDecoder() { 399 virtual ~SkJpegScanlineDecoder() {
400 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { 400 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) {
401 SkCodecPrintf("setjmp: Error in libjpeg finish_decompress\n"); 401 SkCodecPrintf("setjmp: Error in libjpeg finish_decompress\n");
402 return; 402 return;
403 } 403 }
404 404
405 // We may not have decoded the entire image. Prevent libjpeg-turbo from failing on a 405 // We may not have decoded the entire image. Prevent libjpeg-turbo from failing on a
406 // partial decode. 406 // partial decode.
407 fCodec->fDecoderMgr->dinfo()->output_scanline = fCodec->getInfo().height (); 407 fCodec->fDecoderMgr->dinfo()->output_scanline = fCodec->getInfo().height ();
408 turbo_jpeg_finish_decompress(fCodec->fDecoderMgr->dinfo()); 408 chromium_jpeg_finish_decompress(fCodec->fDecoderMgr->dinfo());
409 } 409 }
410 410
411 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de { 411 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de {
412 // Set the jump location for libjpeg errors 412 // Set the jump location for libjpeg errors
413 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { 413 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) {
414 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali dInput); 414 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali dInput);
415 } 415 }
416 416
417 // Read rows one at a time 417 // Read rows one at a time
418 JSAMPLE* dstRow = (JSAMPLE*) dst; 418 JSAMPLE* dstRow = (JSAMPLE*) dst;
419 for (int y = 0; y < count; y++) { 419 for (int y = 0; y < count; y++) {
420 // Read row of the image 420 // Read row of the image
421 uint32_t rowsDecoded = 421 uint32_t rowsDecoded =
422 turbo_jpeg_read_scanlines(fCodec->fDecoderMgr->dinfo(), &dst Row, 1); 422 chromium_jpeg_read_scanlines(fCodec->fDecoderMgr->dinfo(), & dstRow, 1);
423 if (rowsDecoded != 1) { 423 if (rowsDecoded != 1) {
424 if (SkCodec::kNo_ZeroInitialized == fOpts.fZeroInitialized || 424 if (SkCodec::kNo_ZeroInitialized == fOpts.fZeroInitialized ||
425 kN32_SkColorType == this->dstInfo().colorType()) { 425 kN32_SkColorType == this->dstInfo().colorType()) {
426 SkSwizzler::Fill(dstRow, this->dstInfo(), rowBytes, 426 SkSwizzler::Fill(dstRow, this->dstInfo(), rowBytes,
427 count - y, SK_ColorBLACK, NULL); 427 count - y, SK_ColorBLACK, NULL);
428 } 428 }
429 fCodec->fDecoderMgr->dinfo()->output_scanline = this->dstInfo(). height(); 429 fCodec->fDecoderMgr->dinfo()->output_scanline = this->dstInfo(). height();
430 return SkCodec::kIncompleteInput; 430 return SkCodec::kIncompleteInput;
431 } 431 }
432 432
433 // Convert to RGBA if necessary 433 // Convert to RGBA if necessary
434 if (JCS_CMYK == fCodec->fDecoderMgr->dinfo()->out_color_space) { 434 if (JCS_CMYK == fCodec->fDecoderMgr->dinfo()->out_color_space) {
435 convert_CMYK_to_RGBA(dstRow, this->dstInfo().width()); 435 convert_CMYK_to_RGBA(dstRow, this->dstInfo().width());
436 } 436 }
437 437
438 // Move to the next row 438 // Move to the next row
439 dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes); 439 dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes);
440 } 440 }
441 441
442 return SkCodec::kSuccess; 442 return SkCodec::kSuccess;
443 } 443 }
444 444
445 #ifndef TURBO_HAS_SKIP 445 #ifndef chromium_HAS_SKIP
446 #define turbo_jpeg_skip_scanlines(dinfo, count) \ 446 #define chromium_jpeg_skip_scanlines(dinfo, count) \
447 SkAutoMalloc storage(dinfo->output_width * dinfo->out_color_components); \ 447 SkAutoMalloc storage(dinfo->output_width * dinfo->out_color_components); \
448 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); \ 448 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); \
449 for (int y = 0; y < count; y++) { \ 449 for (int y = 0; y < count; y++) { \
450 turbo_jpeg_read_scanlines(dinfo, &storagePtr, 1); \ 450 chromium_jpeg_read_scanlines(dinfo, &storagePtr, 1); \
451 } 451 }
452 #endif 452 #endif
453 453
454 SkCodec::Result onSkipScanlines(int count) override { 454 SkCodec::Result onSkipScanlines(int count) override {
455 // Set the jump location for libjpeg errors 455 // Set the jump location for libjpeg errors
456 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { 456 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) {
457 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali dInput); 457 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali dInput);
458 } 458 }
459 459
460 turbo_jpeg_skip_scanlines(fCodec->fDecoderMgr->dinfo(), count); 460 chromium_jpeg_skip_scanlines(fCodec->fDecoderMgr->dinfo(), count);
461 461
462 return SkCodec::kSuccess; 462 return SkCodec::kSuccess;
463 } 463 }
464 464
465 private: 465 private:
466 SkAutoTDelete<SkJpegCodec> fCodec; 466 SkAutoTDelete<SkJpegCodec> fCodec;
467 const SkCodec::Options& fOpts; 467 const SkCodec::Options& fOpts;
468 468
469 typedef SkScanlineDecoder INHERITED; 469 typedef SkScanlineDecoder INHERITED;
470 }; 470 };
471 471
472 SkScanlineDecoder* SkJpegCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, 472 SkScanlineDecoder* SkJpegCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo,
473 const Options& options, SkPMColor ctable[], int* ctableCount) { 473 const Options& options, SkPMColor ctable[], int* ctableCount) {
474 474
475 // Rewind the stream if needed 475 // Rewind the stream if needed
476 if (!this->handleRewind()) { 476 if (!this->handleRewind()) {
477 SkCodecPrintf("Could not rewind\n"); 477 SkCodecPrintf("Could not rewind\n");
478 return NULL; 478 return NULL;
479 } 479 }
480 480
481 // Set the jump location for libjpeg errors
482 if (setjmp(fDecoderMgr->getJmpBuf())) {
483 SkCodecPrintf("setjmp: Error from libjpeg\n");
484 return NULL;
485 }
486
487 SkStream* stream = this->stream()->duplicate(); 481 SkStream* stream = this->stream()->duplicate();
488 if (!stream) { 482 if (!stream) {
489 return NULL; 483 return NULL;
490 } 484 }
491 SkAutoTDelete<SkJpegCodec> codec(static_cast<SkJpegCodec*>(SkJpegCodec::NewF romStream(stream))); 485 SkAutoTDelete<SkJpegCodec> codec(static_cast<SkJpegCodec*>(SkJpegCodec::NewF romStream(stream)));
492 if (!codec) { 486 if (!codec) {
493 return NULL; 487 return NULL;
494 } 488 }
495 489
490 // Set the jump location for libjpeg errors
msarett 2015/08/10 17:28:21 Scanline decoder setjmp bug fix that is loosely re
491 if (setjmp(codec->fDecoderMgr->getJmpBuf())) {
492 SkCodecPrintf("setjmp: Error from libjpeg\n");
493 return NULL;
494 }
495
496 // Check if we can decode to the requested destination and set the output co lor space 496 // Check if we can decode to the requested destination and set the output co lor space
497 if (!codec->setOutputColorSpace(dstInfo)) { 497 if (!codec->setOutputColorSpace(dstInfo)) {
498 SkCodecPrintf("Cannot convert to output type\n"); 498 SkCodecPrintf("Cannot convert to output type\n");
499 return NULL; 499 return NULL;
500 } 500 }
501 501
502 // Perform the necessary scaling 502 // Perform the necessary scaling
503 if (!codec->scaleToDimensions(dstInfo.width(), dstInfo.height())) { 503 if (!codec->scaleToDimensions(dstInfo.width(), dstInfo.height())) {
504 SkCodecPrintf("Cannot scale to output dimensions\n"); 504 SkCodecPrintf("Cannot scale to output dimensions\n");
505 return NULL; 505 return NULL;
506 } 506 }
507 507
508 // Now, given valid output dimensions, we can start the decompress 508 // Now, given valid output dimensions, we can start the decompress
509 if (!turbo_jpeg_start_decompress(codec->fDecoderMgr->dinfo())) { 509 if (!chromium_jpeg_start_decompress(codec->fDecoderMgr->dinfo())) {
510 SkCodecPrintf("start decompress failed\n"); 510 SkCodecPrintf("start decompress failed\n");
511 return NULL; 511 return NULL;
512 } 512 }
513 513
514 // Return the new scanline decoder 514 // Return the new scanline decoder
515 return SkNEW_ARGS(SkJpegScanlineDecoder, (dstInfo, codec.detach(), options)) ; 515 return SkNEW_ARGS(SkJpegScanlineDecoder, (dstInfo, codec.detach(), options)) ;
516 } 516 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698