OLD | NEW |
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 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
329 SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]); | 329 SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]); |
330 buf[0] = SkGetPackedR32(color); | 330 buf[0] = SkGetPackedR32(color); |
331 buf[1] = SkGetPackedG32(color); | 331 buf[1] = SkGetPackedG32(color); |
332 buf[2] = SkGetPackedB32(color); | 332 buf[2] = SkGetPackedB32(color); |
333 index.append(buf, 3); | 333 index.append(buf, 3); |
334 } | 334 } |
335 result->append(new SkPDFString(index))->unref(); | 335 result->append(new SkPDFString(index))->unref(); |
336 return result; | 336 return result; |
337 } | 337 } |
338 | 338 |
| 339 /** |
| 340 * Removes the alpha component of an ARGB color (including unpremultiply) while |
| 341 * keeping the output in the same format as the input. |
| 342 */ |
| 343 static uint32_t remove_alpha_argb8888(uint32_t pmColor) { |
| 344 SkColor color = SkUnPreMultiply::PMColorToColor(pmColor); |
| 345 return SkPackARGB32NoCheck(SK_AlphaOPAQUE, |
| 346 SkColorGetR(color), |
| 347 SkColorGetG(color), |
| 348 SkColorGetB(color)); |
| 349 } |
| 350 |
| 351 static uint16_t remove_alpha_argb4444(uint16_t pmColor) { |
| 352 return SkPixel32ToPixel4444( |
| 353 remove_alpha_argb8888(SkPixel4444ToPixel32(pmColor))); |
| 354 } |
| 355 |
| 356 static uint32_t get_argb8888_neighbor_avg_color(const SkBitmap& bitmap, |
| 357 int xOrig, int yOrig) { |
| 358 uint8_t count = 0; |
| 359 uint16_t r = 0; |
| 360 uint16_t g = 0; |
| 361 uint16_t b = 0; |
| 362 |
| 363 for (int y = yOrig - 1; y <= yOrig + 1; y++) { |
| 364 if (y < 0 || y >= bitmap.height()) { |
| 365 continue; |
| 366 } |
| 367 uint32_t* src = bitmap.getAddr32(0, y); |
| 368 for (int x = xOrig - 1; x <= xOrig + 1; x++) { |
| 369 if (x < 0 || x >= bitmap.width()) { |
| 370 continue; |
| 371 } |
| 372 if (SkGetPackedA32(src[x]) != SK_AlphaTRANSPARENT) { |
| 373 uint32_t color = remove_alpha_argb8888(src[x]); |
| 374 r += SkGetPackedR32(color); |
| 375 g += SkGetPackedG32(color); |
| 376 b += SkGetPackedB32(color); |
| 377 count++; |
| 378 } |
| 379 } |
| 380 } |
| 381 |
| 382 if (count == 0) { |
| 383 return SkPackARGB32NoCheck(SK_AlphaOPAQUE, 0, 0, 0); |
| 384 } else { |
| 385 return SkPackARGB32NoCheck(SK_AlphaOPAQUE, |
| 386 r / count, g / count, b / count); |
| 387 } |
| 388 } |
| 389 |
| 390 static uint16_t get_argb4444_neighbor_avg_color(const SkBitmap& bitmap, |
| 391 int xOrig, int yOrig) { |
| 392 uint8_t count = 0; |
| 393 uint8_t r = 0; |
| 394 uint8_t g = 0; |
| 395 uint8_t b = 0; |
| 396 |
| 397 for (int y = yOrig - 1; y <= yOrig + 1; y++) { |
| 398 if (y < 0 || y >= bitmap.height()) { |
| 399 continue; |
| 400 } |
| 401 uint16_t* src = bitmap.getAddr16(0, y); |
| 402 for (int x = xOrig - 1; x <= xOrig + 1; x++) { |
| 403 if (x < 0 || x >= bitmap.width()) { |
| 404 continue; |
| 405 } |
| 406 if ((SkGetPackedA4444(src[x]) & 0x0F) != SK_AlphaTRANSPARENT) { |
| 407 uint16_t color = remove_alpha_argb4444(src[x]); |
| 408 r += SkGetPackedR4444(color); |
| 409 g += SkGetPackedG4444(color); |
| 410 b += SkGetPackedB4444(color); |
| 411 count++; |
| 412 } |
| 413 } |
| 414 } |
| 415 |
| 416 if (count == 0) { |
| 417 return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F, 0, 0, 0); |
| 418 } else { |
| 419 return SkPackARGB4444(SK_AlphaOPAQUE & 0x0F, |
| 420 r / count, g / count, b / count); |
| 421 } |
| 422 } |
| 423 |
| 424 static SkBitmap unpremultiply_bitmap(const SkBitmap& bitmap, |
| 425 const SkIRect& srcRect) { |
| 426 SkBitmap outBitmap; |
| 427 outBitmap.setConfig(bitmap.config(), srcRect.width(), srcRect.height()); |
| 428 outBitmap.allocPixels(); |
| 429 size_t dstRow = 0; |
| 430 |
| 431 outBitmap.lockPixels(); |
| 432 bitmap.lockPixels(); |
| 433 switch (bitmap.config()) { |
| 434 case SkBitmap::kARGB_4444_Config: { |
| 435 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { |
| 436 uint16_t* dst = outBitmap.getAddr16(0, dstRow); |
| 437 uint16_t* src = bitmap.getAddr16(0, y); |
| 438 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { |
| 439 uint8_t a = SkGetPackedA4444(src[x]); |
| 440 // It is necessary to average the color component of |
| 441 // transparent pixels with their surrounding neighbors |
| 442 // since the PDF renderer may separately re-sample the |
| 443 // alpha and color channels when the image is not |
| 444 // displayed at its native resolution. Since an alpha of |
| 445 // zero gives no information about the color component, |
| 446 // the pathological case is a white image with sharp |
| 447 // transparency bounds - the color channel goes to black, |
| 448 // and the should-be-transparent pixels are rendered |
| 449 // as grey because of the separate soft mask and color |
| 450 // resizing. |
| 451 if (a == (SK_AlphaTRANSPARENT & 0x0F)) { |
| 452 *dst = get_argb4444_neighbor_avg_color(bitmap, x, y); |
| 453 } else { |
| 454 *dst = remove_alpha_argb4444(src[x]); |
| 455 } |
| 456 dst++; |
| 457 } |
| 458 dstRow++; |
| 459 } |
| 460 break; |
| 461 } |
| 462 case SkBitmap::kARGB_8888_Config: { |
| 463 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { |
| 464 uint32_t* dst = outBitmap.getAddr32(0, dstRow); |
| 465 uint32_t* src = bitmap.getAddr32(0, y); |
| 466 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { |
| 467 uint8_t a = SkGetPackedA32(src[x]); |
| 468 if (a == SK_AlphaTRANSPARENT) { |
| 469 *dst = get_argb8888_neighbor_avg_color(bitmap, x, y); |
| 470 } else { |
| 471 *dst = remove_alpha_argb8888(src[x]); |
| 472 } |
| 473 dst++; |
| 474 } |
| 475 dstRow++; |
| 476 } |
| 477 break; |
| 478 } |
| 479 default: |
| 480 SkASSERT(false); |
| 481 } |
| 482 bitmap.unlockPixels(); |
| 483 outBitmap.unlockPixels(); |
| 484 |
| 485 outBitmap.setImmutable(); |
| 486 |
| 487 return outBitmap; |
| 488 } |
| 489 |
339 // static | 490 // static |
340 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap, | 491 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap, |
341 const SkIRect& srcRect, | 492 const SkIRect& srcRect, |
342 SkPicture::EncodeBitmap encoder) { | 493 SkPicture::EncodeBitmap encoder) { |
343 if (bitmap.getConfig() == SkBitmap::kNo_Config) { | 494 if (bitmap.getConfig() == SkBitmap::kNo_Config) { |
344 return NULL; | 495 return NULL; |
345 } | 496 } |
346 | 497 |
347 bool isTransparent = false; | 498 bool isTransparent = false; |
348 SkAutoTUnref<SkStream> alphaData; | 499 SkAutoTUnref<SkStream> alphaData; |
349 if (!bitmap.isOpaque()) { | 500 if (!bitmap.isOpaque()) { |
350 // Note that isOpaque is not guaranteed to return false for bitmaps | 501 // Note that isOpaque is not guaranteed to return false for bitmaps |
351 // with alpha support but a completely opaque alpha channel, | 502 // with alpha support but a completely opaque alpha channel, |
352 // so alphaData may still be NULL if we have a completely opaque | 503 // so alphaData may still be NULL if we have a completely opaque |
353 // (or transparent) bitmap. | 504 // (or transparent) bitmap. |
354 alphaData.reset( | 505 alphaData.reset( |
355 extract_image_data(bitmap, srcRect, true, &isTransparent)); | 506 extract_image_data(bitmap, srcRect, true, &isTransparent)); |
356 } | 507 } |
357 if (isTransparent) { | 508 if (isTransparent) { |
358 return NULL; | 509 return NULL; |
359 } | 510 } |
360 | 511 |
361 SkPDFImage* image = SkNEW_ARGS(SkPDFImage, (NULL, bitmap, | 512 SkPDFImage* image; |
362 false, srcRect, encoder)); | 513 SkBitmap::Config config = bitmap.config(); |
| 514 if (alphaData.get() != NULL && (config == SkBitmap::kARGB_8888_Config || |
| 515 config == SkBitmap::kARGB_4444_Config)) { |
| 516 SkBitmap unpremulBitmap = unpremultiply_bitmap(bitmap, srcRect); |
| 517 image = SkNEW_ARGS(SkPDFImage, (NULL, unpremulBitmap, false, |
| 518 SkIRect::MakeWH(srcRect.width(), srcRect.height()), |
| 519 encoder)); |
| 520 } else { |
| 521 image = SkNEW_ARGS(SkPDFImage, (NULL, bitmap, false, srcRect, encoder)); |
| 522 } |
363 if (alphaData.get() != NULL) { | 523 if (alphaData.get() != NULL) { |
364 SkAutoTUnref<SkPDFImage> mask( | 524 SkAutoTUnref<SkPDFImage> mask( |
365 SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap, | 525 SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap, |
366 true, srcRect, NULL))); | 526 true, srcRect, NULL))); |
367 image->addSMask(mask); | 527 image->addSMask(mask); |
368 } | 528 } |
369 | 529 |
370 return image; | 530 return image; |
371 } | 531 } |
372 | 532 |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
520 // but the new catalog wants it compressed. | 680 // but the new catalog wants it compressed. |
521 if (!getSubstitute()) { | 681 if (!getSubstitute()) { |
522 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this)); | 682 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this)); |
523 setSubstitute(substitute); | 683 setSubstitute(substitute); |
524 catalog->setSubstitute(this, substitute); | 684 catalog->setSubstitute(this, substitute); |
525 } | 685 } |
526 return false; | 686 return false; |
527 } | 687 } |
528 return true; | 688 return true; |
529 } | 689 } |
OLD | NEW |