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

Side by Side Diff: src/pdf/SkPDFImage.cpp

Issue 22831039: Add unpremultiply support and GM (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Fix 8888 case Created 7 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 | Annotate | Revision Log
« gm/bitmappremul.cpp ('K') | « src/pdf/SkPDFImage.h ('k') | no next file » | 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 2010 The Android Open Source Project 2 * Copyright 2010 The Android Open Source Project
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 "SkPDFImage.h" 8 #include "SkPDFImage.h"
9 9
10 #include "SkBitmap.h" 10 #include "SkBitmap.h"
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after
360 SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]); 360 SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]);
361 buf[0] = SkGetPackedR32(color); 361 buf[0] = SkGetPackedR32(color);
362 buf[1] = SkGetPackedG32(color); 362 buf[1] = SkGetPackedG32(color);
363 buf[2] = SkGetPackedB32(color); 363 buf[2] = SkGetPackedB32(color);
364 index.append(buf, 3); 364 index.append(buf, 3);
365 } 365 }
366 result->append(new SkPDFString(index))->unref(); 366 result->append(new SkPDFString(index))->unref();
367 return result; 367 return result;
368 } 368 }
369 369
370 /**
371 * Unpremultiply an ARGB color, keeping the output in the same format
372 * as the input.
373 */
374 static uint32_t unpremultiply_argb8888(uint32_t src) {
vandebo (ex-Chrome) 2013/08/23 06:16:11 nit: src -> pm_color
ducky 2013/08/23 08:06:11 Done.
375 uint8_t a = SkGetPackedA32(src);
376 SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(a);
377 return SkPackARGB32NoCheck(
378 SK_AlphaOPAQUE,
379 SkUnPreMultiply::ApplyScale(scale, SkGetPackedR32(src)),
vandebo (ex-Chrome) 2013/08/23 06:16:11 I think it's nicer to hide the scale stuff, so on
ducky 2013/08/23 08:06:11 Done.
380 SkUnPreMultiply::ApplyScale(scale, SkGetPackedG32(src)),
381 SkUnPreMultiply::ApplyScale(scale, SkGetPackedB32(src)));
382 }
383
384 static uint16_t unpremultiply_argb4444(uint16_t src) {
385 // Unpack and transform the alpha values from 4 bits to 8 bits.
386 // This is necessary since the unpremultiply functions expect to work in
387 // 8-bit space, but we are passing in 4-bit values. Since we scale up
388 // the alpha, we scale down the amount the value is increased by, so that
389 // the results are correct for 4-bit color components.
390 uint8_t alpha = SkGetPackedA4444(src);
vandebo (ex-Chrome) 2013/08/23 06:16:11 While it might be a bit wasteful, the simplest thi
ducky 2013/08/23 08:06:11 Ehhhhhh - it would make more sense if the code had
vandebo (ex-Chrome) 2013/08/23 16:09:17 Just because it's already written is not a good re
ducky 2013/08/23 18:49:17 Done. Though for performance overhead, it could al
391 alpha = (alpha << 4) | alpha;
392 SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(alpha);
393 return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F,
394 SkUnPreMultiply::ApplyScale(scale, SkGetPackedR4444(src)),
395 SkUnPreMultiply::ApplyScale(scale, SkGetPackedG4444(src)),
396 SkUnPreMultiply::ApplyScale(scale, SkGetPackedB4444(src)));
397 }
398
399 static void argb8888_pixel_sum(uint32_t pixel, uint8_t* count,
vandebo (ex-Chrome) 2013/08/23 06:16:11 Since this is only used in one place, I think it'l
ducky 2013/08/23 08:06:11 Ok. Though the nested loops doesn't that look nice
400 uint16_t* r, uint16_t* g, uint16_t* b) {
401 if (SkGetPackedA32(pixel) != SK_AlphaTRANSPARENT) {
402 uint32_t color = unpremultiply_argb8888(pixel);
403 *r += SkGetPackedR32(color);
404 *g += SkGetPackedG32(color);
405 *b += SkGetPackedB32(color);
406 (*count)++;
407 }
408 }
409
410 static void argb4444_pixel_sum(uint16_t pixel, uint8_t* count,
411 uint8_t* r, uint8_t* g, uint8_t* b) {
412 if ((SkGetPackedA4444(pixel) & 0x0F) != SK_AlphaTRANSPARENT) {
413 uint16_t color = unpremultiply_argb4444(pixel);
414 *r += SkGetPackedR4444(color);
415 *g += SkGetPackedG4444(color);
416 *b += SkGetPackedB4444(color);
417 (*count)++;
418 }
419 }
420
421 static uint32_t get_argb8888_neighbor_color(const SkBitmap& bitmap,
422 int xOrig, int yOrig) {
423 uint8_t count = 0;
424 uint16_t r = 0;
425 uint16_t g = 0;
426 uint16_t b = 0;
427
428 for (int y = yOrig - 1; y <= yOrig + 1; y++) {
429 if (y < 0 || y >= bitmap.height()) {
430 continue;
431 }
432 uint32_t* src = bitmap.getAddr32(0, y);
433 for (int x = xOrig - 1; x <= xOrig + 1; x++) {
434 if (x < 0 || x >= bitmap.width()) {
435 continue;
436 }
437 argb8888_pixel_sum(src[x], &count, &r, &g, &b);
438 }
439 }
440
441 if (count == 0) {
442 return SkPackARGB32NoCheck(SK_AlphaOPAQUE, 0, 0, 0);
vandebo (ex-Chrome) 2013/08/23 06:16:11 return SK_ColorBLACK
ducky 2013/08/23 08:06:11 SkColor packing doesn't necessarily match ARGB8888
443 } else {
444 return SkPackARGB32NoCheck(SK_AlphaOPAQUE,
445 r / count, g / count, b / count);
446 }
447 }
448
449 static uint16_t get_argb4444_neighbor_color(const SkBitmap& bitmap,
vandebo (ex-Chrome) 2013/08/23 06:16:11 nit: ...neighbor_color_avg
ducky 2013/08/23 08:06:11 Done.
450 int xOrig, int yOrig) {
451 uint8_t count = 0;
452 uint8_t r = 0;
453 uint8_t g = 0;
454 uint8_t b = 0;
455
456 for (int y = yOrig - 1; y <= yOrig + 1; y++) {
457 if (y < 0 || y >= bitmap.height()) {
458 continue;
459 }
460 uint16_t* src = bitmap.getAddr16(0, y);
461 for (int x = xOrig - 1; x <= xOrig + 1; x++) {
462 if (x < 0 || x >= bitmap.width()) {
463 continue;
464 }
465 argb4444_pixel_sum(src[x], &count, &r, &g, &b);
466 }
467 }
468
469 if (count == 0) {
470 return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F, 0, 0, 0);
471 } else {
472 return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F,
473 r / count, g / count, b / count);
474 }
475 }
476
477 static SkBitmap unpremultiply_bitmap(const SkBitmap& bitmap,
478 const SkIRect& srcRect) {
479 SkBitmap outBitmap;
480 outBitmap.setConfig(bitmap.config(), srcRect.width(), srcRect.height());
481 SkASSERT(outBitmap.allocPixels());
482 size_t dstRow = 0;
483
484 outBitmap.lockPixels();
485 bitmap.lockPixels();
486 switch (bitmap.config()) {
487 case SkBitmap::kARGB_4444_Config: {
488 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
vandebo (ex-Chrome) 2013/08/23 06:16:11 y++, dstRow++ ?
ducky 2013/08/23 08:06:11 It's kind of nice to keep the loop self-contained
489 uint16_t* dst = outBitmap.getAddr16(0, dstRow);
490 uint16_t* src = bitmap.getAddr16(0, y);
491 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
vandebo (ex-Chrome) 2013/08/23 06:16:11 x++, dst++
ducky 2013/08/23 08:06:11 Same as above.
492 uint8_t a = SkGetPackedA4444(src[x]);
493 if ((a & 0x0F) == SK_AlphaTRANSPARENT) {
vandebo (ex-Chrome) 2013/08/23 06:16:11 if (a == (SK_AlphaTRANSPARENT & 0x0F))
vandebo (ex-Chrome) 2013/08/23 06:16:11 A big comment here about why we need to do this wo
ducky 2013/08/23 08:06:11 Done.
ducky 2013/08/23 08:06:11 Done.
vandebo (ex-Chrome) 2013/08/23 16:09:17 Sorry, I didn't mean a comment about masking the b
ducky 2013/08/23 18:49:17 Done.
494 *dst = get_argb4444_neighbor_color(bitmap, x, y);
495 } else {
496 *dst = unpremultiply_argb4444(src[x]);
497 }
498 dst++;
499 }
500 dstRow++;
501 }
502 } break;
vandebo (ex-Chrome) 2013/08/23 06:16:11 Put the break inside the braces.
ducky 2013/08/23 08:06:11 Done.
503 case SkBitmap::kARGB_8888_Config: {
504 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
505 uint32_t* dst = outBitmap.getAddr32(0, dstRow);
506 uint32_t* src = bitmap.getAddr32(0, y);
507 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
508 uint8_t a = SkGetPackedA32(src[x]);
509 if (a == SK_AlphaTRANSPARENT) {
510 *dst = get_argb8888_neighbor_color(bitmap, x, y);
511 } else {
512 *dst = unpremultiply_argb8888(src[x]);
513 }
514 dst++;
515 }
516 dstRow++;
517 }
518 } break;
519 default:
520 SkASSERT(false);
521 }
522 bitmap.unlockPixels();
523 outBitmap.unlockPixels();
524
525 outBitmap.setImmutable();
526
527 return outBitmap;
528 }
529
370 // static 530 // static
371 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap, 531 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap,
372 const SkIRect& srcRect, 532 const SkIRect& srcRect,
373 EncodeToDCTStream encoder) { 533 EncodeToDCTStream encoder) {
374 if (bitmap.getConfig() == SkBitmap::kNo_Config) { 534 if (bitmap.getConfig() == SkBitmap::kNo_Config) {
375 return NULL; 535 return NULL;
376 } 536 }
377 537
378 bool isTransparent; 538 bool isTransparent;
379 SkAutoTUnref<SkStream> alphaData( 539 SkAutoTUnref<SkStream> alphaData(
380 extract_image_data(bitmap, srcRect, true, &isTransparent)); 540 extract_image_data(bitmap, srcRect, true, &isTransparent));
381 if (isTransparent) { 541 if (isTransparent) {
382 return NULL; 542 return NULL;
383 } 543 }
384 544
385 SkPDFImage* image = SkNEW_ARGS(SkPDFImage, (bitmap, srcRect, encoder)); 545 SkPDFImage* image;
546 SkBitmap::Config config = bitmap.config();
547 if (alphaData.get() != NULL && (config == SkBitmap::kARGB_8888_Config ||
548 config == SkBitmap::kARGB_4444_Config)) {
549 SkBitmap unpremulBitmap = unpremultiply_bitmap(bitmap, srcRect);
550 SkIRect newSrcRect = srcRect;
551 newSrcRect.offset(-srcRect.left(), -srcRect.top());
552 image = SkNEW_ARGS(SkPDFImage, (unpremulBitmap, srcRect, encoder));
vandebo (ex-Chrome) 2013/08/23 06:16:11 You need to use newSrcRect here.
ducky 2013/08/23 08:06:11 Done.
553 } else {
554 image = SkNEW_ARGS(SkPDFImage, (bitmap, srcRect, encoder));
555 }
386 if (alphaData.get() != NULL) { 556 if (alphaData.get() != NULL) {
387 SkAutoTUnref<SkPDFImage> mask( 557 SkAutoTUnref<SkPDFImage> mask(
388 SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap, srcRect))); 558 SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap, srcRect)));
389 image->addSMask(mask); 559 image->addSMask(mask);
390 } 560 }
391 561
392 return image; 562 return image;
393 } 563 }
394 564
395 SkPDFImage::~SkPDFImage() { 565 SkPDFImage::~SkPDFImage() {
396 fResources.unrefAll(); 566 fResources.unrefAll();
397 } 567 }
398 568
399 SkPDFImage* SkPDFImage::addSMask(SkPDFImage* mask) { 569 SkPDFImage* SkPDFImage::addSMask(SkPDFImage* mask) {
400 fResources.push(mask); 570 fResources.push(mask);
401 mask->ref(); 571 mask->ref();
402 insert("SMask", new SkPDFObjRef(mask))->unref(); 572 insert("SMask", new SkPDFObjRef(mask))->unref();
403 return mask; 573 return mask;
404 } 574 }
405 575
406 void SkPDFImage::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, 576 void SkPDFImage::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
407 SkTSet<SkPDFObject*>* newResourceObjects) { 577 SkTSet<SkPDFObject*>* newResourceObjects) {
408 GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects); 578 GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects);
409 } 579 }
410 580
411 SkPDFImage::SkPDFImage(const SkBitmap& bitmap, 581 SkPDFImage::SkPDFImage(const SkBitmap& bitmap,
412 const SkIRect& srcRect, 582 const SkIRect& srcRect,
413 EncodeToDCTStream encoder) 583 EncodeToDCTStream encoder)
414 : fBitmap(bitmap), 584 : fSrcRect(srcRect),
415 fSrcRect(srcRect),
416 fEncoder(encoder), 585 fEncoder(encoder),
417 fStreamValid(false) { 586 fStreamValid(false) {
587 initBitmap(bitmap);
418 initImageParams(false); 588 initImageParams(false);
419 } 589 }
420 590
421 SkPDFImage::SkPDFImage(SkStream* stream, const SkBitmap& bitmap, 591 SkPDFImage::SkPDFImage(SkStream* stream, const SkBitmap& bitmap,
422 const SkIRect& srcRect) 592 const SkIRect& srcRect)
423 : fBitmap(bitmap), 593 : fSrcRect(srcRect),
424 fSrcRect(srcRect),
425 fEncoder(NULL), 594 fEncoder(NULL),
426 fStreamValid(true) { 595 fStreamValid(true) {
427 setData(stream); 596 setData(stream);
597 initBitmap(bitmap);
428 initImageParams(true); 598 initImageParams(true);
429 } 599 }
430 600
431 SkPDFImage::SkPDFImage(SkPDFImage& pdfImage) 601 SkPDFImage::SkPDFImage(SkPDFImage& pdfImage)
432 : SkPDFStream(pdfImage), 602 : SkPDFStream(pdfImage),
433 fBitmap(pdfImage.fBitmap), 603 fBitmap(pdfImage.fBitmap),
434 fSrcRect(pdfImage.fSrcRect), 604 fSrcRect(pdfImage.fSrcRect),
435 fEncoder(pdfImage.fEncoder), 605 fEncoder(pdfImage.fEncoder),
436 fStreamValid(pdfImage.fStreamValid) { 606 fStreamValid(pdfImage.fStreamValid) {
437 // Nothing to do here - the image params are already copied in SkPDFStream's 607 // Nothing to do here - the image params are already copied in SkPDFStream's
438 // constructor, and the bitmap will be regenerated and re-encoded in 608 // constructor, and the bitmap will be regenerated and re-encoded in
439 // populate. 609 // populate. It is assumed that the source bitmap is immutable.
610 }
611
612 void SkPDFImage::initBitmap(const SkBitmap& bitmap) {
613 if (bitmap.isImmutable()) {
614 fBitmap = bitmap;
615 } else {
616 bitmap.deepCopyTo(&fBitmap, bitmap.config());
617 fBitmap.setImmutable();
618 }
440 } 619 }
441 620
442 void SkPDFImage::initImageParams(bool isAlpha) { 621 void SkPDFImage::initImageParams(bool isAlpha) {
443 SkBitmap::Config config = fBitmap.getConfig(); 622 SkBitmap::Config config = fBitmap.getConfig();
444 623
445 insertName("Type", "XObject"); 624 insertName("Type", "XObject");
446 insertName("Subtype", "Image"); 625 insertName("Subtype", "Image");
447 626
448 bool alphaOnly = (config == SkBitmap::kA1_Config || 627 bool alphaOnly = (config == SkBitmap::kA1_Config ||
449 config == SkBitmap::kA8_Config); 628 config == SkBitmap::kA8_Config);
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
531 // but the new catalog wants it compressed. 710 // but the new catalog wants it compressed.
532 if (!getSubstitute()) { 711 if (!getSubstitute()) {
533 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this)); 712 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this));
534 setSubstitute(substitute); 713 setSubstitute(substitute);
535 catalog->setSubstitute(this, substitute); 714 catalog->setSubstitute(this, substitute);
536 } 715 }
537 return false; 716 return false;
538 } 717 }
539 return true; 718 return true;
540 } 719 }
OLDNEW
« gm/bitmappremul.cpp ('K') | « src/pdf/SkPDFImage.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698