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

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

Issue 1411083009: Use SkSwizzler to convert from CMYK (Closed) Base URL: https://skia.googlesource.com/skia.git@NewFromData
Patch Set: Add missing break statement Created 5 years, 1 month 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 | « no previous file | src/codec/SkSwizzler.h » ('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"
11 #include "SkJpegUtility_codec.h" 11 #include "SkJpegUtility_codec.h"
12 #include "SkCodecPriv.h" 12 #include "SkCodecPriv.h"
13 #include "SkColorPriv.h" 13 #include "SkColorPriv.h"
14 #include "SkStream.h" 14 #include "SkStream.h"
15 #include "SkTemplates.h" 15 #include "SkTemplates.h"
16 #include "SkTypes.h" 16 #include "SkTypes.h"
17 17
18 // stdio is needed for libjpeg-turbo 18 // stdio is needed for libjpeg-turbo
19 #include <stdio.h> 19 #include <stdio.h>
20 20
21 extern "C" { 21 extern "C" {
22 #include "jerror.h" 22 #include "jerror.h"
23 #include "jpeglib.h" 23 #include "jpeglib.h"
24 } 24 }
25 25
26 /*
27 * Convert a row of CMYK samples to RGBA in place.
28 * Note that this method moves the row pointer.
29 * @param width the number of pixels in the row that is being converted
30 * CMYK is stored as four bytes per pixel
31 */
32 static void convert_CMYK_to_RGBA(uint8_t* row, uint32_t width) {
33 // We will implement a crude conversion from CMYK -> RGB using formulas
34 // from easyrgb.com.
35 //
36 // CMYK -> CMY
37 // C = C * (1 - K) + K
38 // M = M * (1 - K) + K
39 // Y = Y * (1 - K) + K
40 //
41 // libjpeg actually gives us inverted CMYK, so we must subtract the
42 // original terms from 1.
43 // CMYK -> CMY
44 // C = (1 - C) * (1 - (1 - K)) + (1 - K)
45 // M = (1 - M) * (1 - (1 - K)) + (1 - K)
46 // Y = (1 - Y) * (1 - (1 - K)) + (1 - K)
47 //
48 // Simplifying the above expression.
49 // CMYK -> CMY
50 // C = 1 - CK
51 // M = 1 - MK
52 // Y = 1 - YK
53 //
54 // CMY -> RGB
55 // R = (1 - C) * 255
56 // G = (1 - M) * 255
57 // B = (1 - Y) * 255
58 //
59 // Therefore the full conversion is below. This can be verified at
60 // www.rapidtables.com (assuming inverted CMYK).
61 // CMYK -> RGB
62 // R = C * K * 255
63 // G = M * K * 255
64 // B = Y * K * 255
65 //
66 // As a final note, we have treated the CMYK values as if they were on
67 // a scale from 0-1, when in fact they are 8-bit ints scaling from 0-255.
68 // We must divide each CMYK component by 255 to obtain the true conversion
69 // we should perform.
70 // CMYK -> RGB
71 // R = C * K / 255
72 // G = M * K / 255
73 // B = Y * K / 255
74 for (uint32_t x = 0; x < width; x++, row += 4) {
75 #if defined(SK_PMCOLOR_IS_RGBA)
76 row[0] = SkMulDiv255Round(row[0], row[3]);
77 row[1] = SkMulDiv255Round(row[1], row[3]);
78 row[2] = SkMulDiv255Round(row[2], row[3]);
79 #else
80 uint8_t tmp = row[0];
81 row[0] = SkMulDiv255Round(row[2], row[3]);
82 row[1] = SkMulDiv255Round(row[1], row[3]);
83 row[2] = SkMulDiv255Round(tmp, row[3]);
84 #endif
85 row[3] = 0xFF;
86 }
87 }
88
89 bool SkJpegCodec::IsJpeg(SkStream* stream) { 26 bool SkJpegCodec::IsJpeg(SkStream* stream) {
90 static const uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF }; 27 static const uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF };
91 char buffer[sizeof(jpegSig)]; 28 char buffer[sizeof(jpegSig)];
92 return stream->read(buffer, sizeof(jpegSig)) == sizeof(jpegSig) && 29 return stream->read(buffer, sizeof(jpegSig)) == sizeof(jpegSig) &&
93 !memcmp(buffer, jpegSig, sizeof(jpegSig)); 30 !memcmp(buffer, jpegSig, sizeof(jpegSig));
94 } 31 }
95 32
96 bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, 33 bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
97 JpegDecoderMgr** decoderMgrOut) { 34 JpegDecoderMgr** decoderMgrOut) {
98 35
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 #if defined(SK_PMCOLOR_IS_RGBA) 193 #if defined(SK_PMCOLOR_IS_RGBA)
257 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA; 194 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
258 #else 195 #else
259 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA; 196 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA;
260 #endif 197 #endif
261 #endif 198 #endif
262 } 199 }
263 return true; 200 return true;
264 case kRGB_565_SkColorType: 201 case kRGB_565_SkColorType:
265 if (isCMYK) { 202 if (isCMYK) {
266 // FIXME (msarett): We need to support 565 here. It's not hard to do, considering 203 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
267 // we already convert CMYK to RGBA, I just need to do it. I thi nk it might be
268 // best to do this in SkSwizzler and also move convert_CMYK_to_R GBA into SkSwizzler.
269 return false;
270 } else { 204 } else {
271 #if defined(GOOGLE3) 205 #if defined(GOOGLE3)
272 return false; 206 return false;
273 #else 207 #else
274 fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE; 208 fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE;
275 fDecoderMgr->dinfo()->out_color_space = JCS_RGB565; 209 fDecoderMgr->dinfo()->out_color_space = JCS_RGB565;
276 #endif 210 #endif
277 } 211 }
278 return true; 212 return true;
279 case kGray_8_SkColorType: 213 case kGray_8_SkColorType:
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
358 292
359 // Now, given valid output dimensions, we can start the decompress 293 // Now, given valid output dimensions, we can start the decompress
360 if (!jpeg_start_decompress(dinfo)) { 294 if (!jpeg_start_decompress(dinfo)) {
361 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); 295 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
362 } 296 }
363 297
364 // The recommended output buffer height should always be 1 in high quality m odes. 298 // The recommended output buffer height should always be 1 in high quality m odes.
365 // If it's not, we want to know because it means our strategy is not optimal . 299 // If it's not, we want to know because it means our strategy is not optimal .
366 SkASSERT(1 == dinfo->rec_outbuf_height); 300 SkASSERT(1 == dinfo->rec_outbuf_height);
367 301
302 if (JCS_CMYK == dinfo->out_color_space) {
303 this->initializeSwizzler(dstInfo, options);
304 }
305
368 // Perform the decode a single row at a time 306 // Perform the decode a single row at a time
369 uint32_t dstHeight = dstInfo.height(); 307 uint32_t dstHeight = dstInfo.height();
370 JSAMPLE* dstRow = (JSAMPLE*) dst; 308
309 JSAMPLE* dstRow;
310 if (fSwizzler) {
311 // write data to storage row, then sample using swizzler
312 dstRow = fSrcRow;
313 } else {
314 // write data directly to dst
315 dstRow = (JSAMPLE*) dst;
316 }
317
371 for (uint32_t y = 0; y < dstHeight; y++) { 318 for (uint32_t y = 0; y < dstHeight; y++) {
372 // Read rows of the image 319 // Read rows of the image
373 uint32_t lines = jpeg_read_scanlines(dinfo, &dstRow, 1); 320 uint32_t lines = jpeg_read_scanlines(dinfo, &dstRow, 1);
374 321
375 // If we cannot read enough rows, assume the input is incomplete 322 // If we cannot read enough rows, assume the input is incomplete
376 if (lines != 1) { 323 if (lines != 1) {
377 *rowsDecoded = y; 324 *rowsDecoded = y;
378 325
379 return fDecoderMgr->returnFailure("Incomplete image data", kIncomple teInput); 326 return fDecoderMgr->returnFailure("Incomplete image data", kIncomple teInput);
380 } 327 }
381 328
382 // Convert to RGBA if necessary 329 if (fSwizzler) {
383 if (JCS_CMYK == dinfo->out_color_space) { 330 // use swizzler to sample row
384 convert_CMYK_to_RGBA(dstRow, dstInfo.width()); 331 fSwizzler->swizzle(dst, dstRow);
332 dst = SkTAddOffset<JSAMPLE>(dst, dstRowBytes);
333 } else {
334 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes);
385 } 335 }
386
387 // Move to the next row
388 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes);
389 } 336 }
390 337
391 return kSuccess; 338 return kSuccess;
392 } 339 }
393 340
394 void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) { 341 void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) {
395 SkSwizzler::SrcConfig srcConfig = SkSwizzler::kUnknown; 342 SkSwizzler::SrcConfig srcConfig = SkSwizzler::kUnknown;
396 switch (dstInfo.colorType()) { 343 if (JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) {
397 case kGray_8_SkColorType: 344 srcConfig = SkSwizzler::kCMYK;
398 srcConfig = SkSwizzler::kGray; 345 } else {
399 break; 346 switch (dstInfo.colorType()) {
400 case kRGBA_8888_SkColorType: 347 case kGray_8_SkColorType:
401 srcConfig = SkSwizzler::kRGBX; 348 srcConfig = SkSwizzler::kGray;
402 break; 349 break;
403 case kBGRA_8888_SkColorType: 350 case kRGBA_8888_SkColorType:
404 srcConfig = SkSwizzler::kBGRX; 351 srcConfig = SkSwizzler::kRGBX;
405 break; 352 break;
406 case kRGB_565_SkColorType: 353 case kBGRA_8888_SkColorType:
407 srcConfig = SkSwizzler::kRGB_565; 354 srcConfig = SkSwizzler::kBGRX;
408 break; 355 break;
409 default: 356 case kRGB_565_SkColorType:
410 // This function should only be called if the colorType is supported by jpeg 357 srcConfig = SkSwizzler::kRGB_565;
358 break;
359 default:
360 // This function should only be called if the colorType is suppo rted by jpeg
411 #if defined(GOOGLE3) 361 #if defined(GOOGLE3)
412 SK_CRASH(); 362 SK_CRASH();
413 #else 363 #else
414 SkASSERT(false); 364 SkASSERT(false);
415 #endif 365 #endif
366 }
416 } 367 }
417 368
418 fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, dstInfo, opti ons)); 369 fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, dstInfo, opti ons));
419 fStorage.reset(get_row_bytes(fDecoderMgr->dinfo())); 370 fStorage.reset(get_row_bytes(fDecoderMgr->dinfo()));
420 fSrcRow = static_cast<uint8_t*>(fStorage.get()); 371 fSrcRow = static_cast<uint8_t*>(fStorage.get());
421 } 372 }
422 373
423 SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) { 374 SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) {
424 if (!createIfNecessary || fSwizzler) { 375 if (!createIfNecessary || fSwizzler) {
425 SkASSERT(!fSwizzler || (fSrcRow && static_cast<uint8_t*>(fStorage.get()) == fSrcRow)); 376 SkASSERT(!fSwizzler || (fSrcRow && static_cast<uint8_t*>(fStorage.get()) == fSrcRow));
(...skipping 21 matching lines...) Expand all
447 fSwizzler.reset(nullptr); 398 fSwizzler.reset(nullptr);
448 fSrcRow = nullptr; 399 fSrcRow = nullptr;
449 fStorage.free(); 400 fStorage.free();
450 401
451 // Now, given valid output dimensions, we can start the decompress 402 // Now, given valid output dimensions, we can start the decompress
452 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) { 403 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) {
453 SkCodecPrintf("start decompress failed\n"); 404 SkCodecPrintf("start decompress failed\n");
454 return kInvalidInput; 405 return kInvalidInput;
455 } 406 }
456 407
457 // We will need a swizzler if we are performing a subset decode 408 // We will need a swizzler if we are performing a subset decode or
458 if (options.fSubset) { 409 // converting from CMYK.
410 if (options.fSubset || JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) {
459 this->initializeSwizzler(dstInfo, options); 411 this->initializeSwizzler(dstInfo, options);
460 } 412 }
461 413
462 return kSuccess; 414 return kSuccess;
463 } 415 }
464 416
465 int SkJpegCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { 417 int SkJpegCodec::onGetScanlines(void* dst, int count, size_t rowBytes) {
466 // Set the jump location for libjpeg errors 418 // Set the jump location for libjpeg errors
467 if (setjmp(fDecoderMgr->getJmpBuf())) { 419 if (setjmp(fDecoderMgr->getJmpBuf())) {
468 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); 420 return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
469 } 421 }
470 // Read rows one at a time 422 // Read rows one at a time
471 JSAMPLE* dstRow; 423 JSAMPLE* dstRow;
472 if (fSwizzler) { 424 if (fSwizzler) {
473 // write data to storage row, then sample using swizzler 425 // write data to storage row, then sample using swizzler
474 dstRow = fSrcRow; 426 dstRow = fSrcRow;
475 } else { 427 } else {
476 // write data directly to dst 428 // write data directly to dst
477 dstRow = (JSAMPLE*) dst; 429 dstRow = (JSAMPLE*) dst;
478 } 430 }
479 431
480 for (int y = 0; y < count; y++) { 432 for (int y = 0; y < count; y++) {
481 // Read row of the image 433 // Read row of the image
482 uint32_t rowsDecoded = jpeg_read_scanlines(fDecoderMgr->dinfo(), &dstRow , 1); 434 uint32_t rowsDecoded = jpeg_read_scanlines(fDecoderMgr->dinfo(), &dstRow , 1);
483 if (rowsDecoded != 1) { 435 if (rowsDecoded != 1) {
484 fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height(); 436 fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height();
485 return y; 437 return y;
486 } 438 }
487 439
488 // Convert to RGBA if necessary 440 if (fSwizzler) {
489 if (JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) {
490 convert_CMYK_to_RGBA(dstRow, fDecoderMgr->dinfo()->output_width);
491 }
492
493 if(fSwizzler) {
494 // use swizzler to sample row 441 // use swizzler to sample row
495 fSwizzler->swizzle(dst, dstRow); 442 fSwizzler->swizzle(dst, dstRow);
496 dst = SkTAddOffset<JSAMPLE>(dst, rowBytes); 443 dst = SkTAddOffset<JSAMPLE>(dst, rowBytes);
497 } else { 444 } else {
498 dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes); 445 dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes);
499 } 446 }
500 } 447 }
501 return count; 448 return count;
502 } 449 }
503 450
(...skipping 12 matching lines...) Expand all
516 #endif 463 #endif
517 464
518 bool SkJpegCodec::onSkipScanlines(int count) { 465 bool SkJpegCodec::onSkipScanlines(int count) {
519 // Set the jump location for libjpeg errors 466 // Set the jump location for libjpeg errors
520 if (setjmp(fDecoderMgr->getJmpBuf())) { 467 if (setjmp(fDecoderMgr->getJmpBuf())) {
521 return fDecoderMgr->returnFalse("setjmp"); 468 return fDecoderMgr->returnFalse("setjmp");
522 } 469 }
523 470
524 return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count); 471 return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count);
525 } 472 }
OLDNEW
« no previous file with comments | « no previous file | src/codec/SkSwizzler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698