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))); | |
edisonn
2013/10/17 19:52:39
would not be more optimum to & with 0x3f? (or some
vandebo (ex-Chrome)
2013/10/17 21:46:43
This doesn't strip the alpha component, it unpremu
| |
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 SkASSERT(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 SkIRect newSrcRect = srcRect; | |
518 newSrcRect.offset(-srcRect.left(), -srcRect.top()); | |
edisonn
2013/10/17 19:52:39
can you explain/comment the logic here? why -srcRe
vandebo (ex-Chrome)
2013/10/17 21:46:43
Fixed - newSrcRect isn't needed.
| |
519 image = SkNEW_ARGS(SkPDFImage, (NULL, unpremulBitmap, | |
520 false, newSrcRect, encoder)); | |
521 } else { | |
522 image = SkNEW_ARGS(SkPDFImage, (NULL, bitmap, false, srcRect, encoder)); | |
523 } | |
363 if (alphaData.get() != NULL) { | 524 if (alphaData.get() != NULL) { |
364 SkAutoTUnref<SkPDFImage> mask( | 525 SkAutoTUnref<SkPDFImage> mask( |
365 SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap, | 526 SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap, |
366 true, srcRect, NULL))); | 527 true, srcRect, NULL))); |
367 image->addSMask(mask); | 528 image->addSMask(mask); |
368 } | 529 } |
369 | 530 |
370 return image; | 531 return image; |
371 } | 532 } |
372 | 533 |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
520 // but the new catalog wants it compressed. | 681 // but the new catalog wants it compressed. |
521 if (!getSubstitute()) { | 682 if (!getSubstitute()) { |
522 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this)); | 683 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this)); |
523 setSubstitute(substitute); | 684 setSubstitute(substitute); |
524 catalog->setSubstitute(this, substitute); | 685 catalog->setSubstitute(this, substitute); |
525 } | 686 } |
526 return false; | 687 return false; |
527 } | 688 } |
528 return true; | 689 return true; |
529 } | 690 } |
OLD | NEW |