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

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: Update DEPS with libjpeg-turbo fix 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
« no previous file with comments | « platform_tools/android/gyp/dependencies.gypi ('k') | src/codec/SkJpegDecoderMgr.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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& srcInfo, SkJpegCodec* codec) 392 SkJpegScanlineDecoder(const SkImageInfo& srcInfo, SkJpegCodec* codec)
(...skipping 20 matching lines...) Expand all
413 if (!fCodec->setOutputColorSpace(dstInfo)) { 413 if (!fCodec->setOutputColorSpace(dstInfo)) {
414 return SkCodec::kInvalidConversion; 414 return SkCodec::kInvalidConversion;
415 } 415 }
416 416
417 // Perform the necessary scaling 417 // Perform the necessary scaling
418 if (!fCodec->scaleToDimensions(dstInfo.width(), dstInfo.height())) { 418 if (!fCodec->scaleToDimensions(dstInfo.width(), dstInfo.height())) {
419 return SkCodec::kInvalidScale; 419 return SkCodec::kInvalidScale;
420 } 420 }
421 421
422 // Now, given valid output dimensions, we can start the decompress 422 // Now, given valid output dimensions, we can start the decompress
423 if (!turbo_jpeg_start_decompress(fCodec->fDecoderMgr->dinfo())) { 423 if (!chromium_jpeg_start_decompress(fCodec->fDecoderMgr->dinfo())) {
424 SkCodecPrintf("start decompress failed\n"); 424 SkCodecPrintf("start decompress failed\n");
425 return SkCodec::kInvalidInput; 425 return SkCodec::kInvalidInput;
426 } 426 }
427 427
428 fOpts = options; 428 fOpts = options;
429 429
430 return SkCodec::kSuccess; 430 return SkCodec::kSuccess;
431 } 431 }
432 432
433 virtual ~SkJpegScanlineDecoder() { 433 virtual ~SkJpegScanlineDecoder() {
434 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { 434 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) {
435 SkCodecPrintf("setjmp: Error in libjpeg finish_decompress\n"); 435 SkCodecPrintf("setjmp: Error in libjpeg finish_decompress\n");
436 return; 436 return;
437 } 437 }
438 438
439 // We may not have decoded the entire image. Prevent libjpeg-turbo from failing on a 439 // We may not have decoded the entire image. Prevent libjpeg-turbo from failing on a
440 // partial decode. 440 // partial decode.
441 fCodec->fDecoderMgr->dinfo()->output_scanline = fCodec->getInfo().height (); 441 fCodec->fDecoderMgr->dinfo()->output_scanline = fCodec->getInfo().height ();
442 turbo_jpeg_finish_decompress(fCodec->fDecoderMgr->dinfo()); 442 chromium_jpeg_finish_decompress(fCodec->fDecoderMgr->dinfo());
443 } 443 }
444 444
445 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de { 445 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de {
446 // Set the jump location for libjpeg errors 446 // Set the jump location for libjpeg errors
447 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { 447 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) {
448 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali dInput); 448 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali dInput);
449 } 449 }
450 450
451 // Read rows one at a time 451 // Read rows one at a time
452 JSAMPLE* dstRow = (JSAMPLE*) dst; 452 JSAMPLE* dstRow = (JSAMPLE*) dst;
453 for (int y = 0; y < count; y++) { 453 for (int y = 0; y < count; y++) {
454 // Read row of the image 454 // Read row of the image
455 uint32_t rowsDecoded = 455 uint32_t rowsDecoded =
456 turbo_jpeg_read_scanlines(fCodec->fDecoderMgr->dinfo(), &dst Row, 1); 456 chromium_jpeg_read_scanlines(fCodec->fDecoderMgr->dinfo(), & dstRow, 1);
457 if (rowsDecoded != 1) { 457 if (rowsDecoded != 1) {
458 if (SkCodec::kNo_ZeroInitialized == fOpts.fZeroInitialized || 458 if (SkCodec::kNo_ZeroInitialized == fOpts.fZeroInitialized ||
459 kN32_SkColorType == this->dstInfo().colorType()) { 459 kN32_SkColorType == this->dstInfo().colorType()) {
460 SkSwizzler::Fill(dstRow, this->dstInfo(), rowBytes, 460 SkSwizzler::Fill(dstRow, this->dstInfo(), rowBytes,
461 count - y, SK_ColorBLACK, NULL); 461 count - y, SK_ColorBLACK, NULL);
462 } 462 }
463 fCodec->fDecoderMgr->dinfo()->output_scanline = this->dstInfo(). height(); 463 fCodec->fDecoderMgr->dinfo()->output_scanline = this->dstInfo(). height();
464 return SkCodec::kIncompleteInput; 464 return SkCodec::kIncompleteInput;
465 } 465 }
466 466
467 // Convert to RGBA if necessary 467 // Convert to RGBA if necessary
468 if (JCS_CMYK == fCodec->fDecoderMgr->dinfo()->out_color_space) { 468 if (JCS_CMYK == fCodec->fDecoderMgr->dinfo()->out_color_space) {
469 convert_CMYK_to_RGBA(dstRow, this->dstInfo().width()); 469 convert_CMYK_to_RGBA(dstRow, this->dstInfo().width());
470 } 470 }
471 471
472 // Move to the next row 472 // Move to the next row
473 dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes); 473 dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes);
474 } 474 }
475 475
476 return SkCodec::kSuccess; 476 return SkCodec::kSuccess;
477 } 477 }
478 478
479 #ifndef TURBO_HAS_SKIP 479 #ifndef TURBO_HAS_SKIP
480 #define turbo_jpeg_skip_scanlines(dinfo, count) \ 480 // TODO (msarett): Make this a member function and avoid reallocating the
481 // memory buffer on each call to skip.
482 #define chromium_jpeg_skip_scanlines(dinfo, count) \
481 SkAutoMalloc storage(dinfo->output_width * dinfo->out_color_components); \ 483 SkAutoMalloc storage(dinfo->output_width * dinfo->out_color_components); \
482 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); \ 484 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); \
483 for (int y = 0; y < count; y++) { \ 485 for (int y = 0; y < count; y++) { \
484 turbo_jpeg_read_scanlines(dinfo, &storagePtr, 1); \ 486 chromium_jpeg_read_scanlines(dinfo, &storagePtr, 1); \
485 } 487 }
486 #endif 488 #endif
487 489
488 SkCodec::Result onSkipScanlines(int count) override { 490 SkCodec::Result onSkipScanlines(int count) override {
489 // Set the jump location for libjpeg errors 491 // Set the jump location for libjpeg errors
490 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { 492 if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) {
491 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali dInput); 493 return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvali dInput);
492 } 494 }
493 495
494 turbo_jpeg_skip_scanlines(fCodec->fDecoderMgr->dinfo(), count); 496 chromium_jpeg_skip_scanlines(fCodec->fDecoderMgr->dinfo(), count);
495 497
496 return SkCodec::kSuccess; 498 return SkCodec::kSuccess;
497 } 499 }
498 500
501 #ifndef TURBO_HAS_SKIP
502 #undef chromium_jpeg_skip_scanlines
503 #endif
504
499 private: 505 private:
500 SkAutoTDelete<SkJpegCodec> fCodec; 506 SkAutoTDelete<SkJpegCodec> fCodec;
501 SkCodec::Options fOpts; 507 SkCodec::Options fOpts;
502 508
503 typedef SkScanlineDecoder INHERITED; 509 typedef SkScanlineDecoder INHERITED;
504 }; 510 };
505 511
506 SkScanlineDecoder* SkJpegCodec::NewSDFromStream(SkStream* stream) { 512 SkScanlineDecoder* SkJpegCodec::NewSDFromStream(SkStream* stream) {
507 SkAutoTDelete<SkJpegCodec> codec(static_cast<SkJpegCodec*>(SkJpegCodec::NewF romStream(stream))); 513 SkAutoTDelete<SkJpegCodec> codec(static_cast<SkJpegCodec*>(SkJpegCodec::NewF romStream(stream)));
508 if (!codec) { 514 if (!codec) {
509 return NULL; 515 return NULL;
510 } 516 }
511 517
512 const SkImageInfo& srcInfo = codec->getInfo(); 518 const SkImageInfo& srcInfo = codec->getInfo();
513 // Return the new scanline decoder 519 // Return the new scanline decoder
514 return SkNEW_ARGS(SkJpegScanlineDecoder, (srcInfo, codec.detach())); 520 return SkNEW_ARGS(SkJpegScanlineDecoder, (srcInfo, codec.detach()));
515 } 521 }
OLDNEW
« no previous file with comments | « platform_tools/android/gyp/dependencies.gypi ('k') | src/codec/SkJpegDecoderMgr.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698