| Index: src/pdf/SkPDFBitmap.cpp
|
| diff --git a/src/pdf/SkPDFBitmap.cpp b/src/pdf/SkPDFBitmap.cpp
|
| index 4e49db518d802896ed069a75fe4f3f66d9bd0bb2..88f273763ac697a03255bac1020c6d91c6316751 100644
|
| --- a/src/pdf/SkPDFBitmap.cpp
|
| +++ b/src/pdf/SkPDFBitmap.cpp
|
| @@ -14,6 +14,7 @@
|
| #include "SkPDFCanon.h"
|
| #include "SkStream.h"
|
| #include "SkUnPreMultiply.h"
|
| +#include "SkPngPredictors.h"
|
|
|
| void image_get_ro_pixels(const SkImage* image, SkBitmap* dst) {
|
| if(as_IB(image)->getROPixels(dst)
|
| @@ -172,12 +173,40 @@ static size_t pdf_color_component_count(SkColorType ct) {
|
| }
|
| }
|
|
|
| -static void bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) {
|
| +namespace {
|
| +template<int COMPONENT_COUNT, void(*FN)(int, const uint8_t*, const uint8_t*, uint8_t*)>
|
| +class PngPredictor {
|
| +public:
|
| + PngPredictor(int widthInPixels)
|
| + : fBuffer(2 * (COMPONENT_COUNT * widthInPixels + 1))
|
| + , fWidth(widthInPixels)
|
| + , fFirstline(true) {
|
| + fScanline = fBuffer.get();
|
| + fPrevScanline = &fScanline[COMPONENT_COUNT * widthInPixels + 1];
|
| + }
|
| + uint8_t* scanline() { return &fScanline[1]; }
|
| + void write(SkWStream* out) {
|
| + fPrevScanline[0] = 4;
|
| + FN(fWidth, fFirstline ? nullptr : &fPrevScanline[1], &fScanline[1], &fPrevScanline[1]);
|
| + out->write(fPrevScanline, COMPONENT_COUNT * fWidth + 1);
|
| + SkTSwap(fScanline, fPrevScanline);
|
| + fFirstline = false;
|
| + }
|
| +private:
|
| + SkAutoTMalloc<uint8_t> fBuffer;
|
| + uint8_t* fScanline;
|
| + uint8_t* fPrevScanline;
|
| + int fWidth;
|
| + bool fFirstline;
|
| +};
|
| +} // namespace
|
| +
|
| +static bool bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) {
|
| if (!bitmap.getPixels()) {
|
| size_t size = pixel_count(bitmap) *
|
| pdf_color_component_count(bitmap.colorType());
|
| fill_stream(out, '\x00', size);
|
| - return;
|
| + return false;
|
| }
|
| SkBitmap copy;
|
| const SkBitmap& bm = not4444(bitmap, ©);
|
| @@ -187,10 +216,10 @@ static void bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) {
|
| case kRGBA_8888_SkColorType:
|
| case kBGRA_8888_SkColorType: {
|
| SkASSERT(3 == pdf_color_component_count(colorType));
|
| - SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
|
| + PngPredictor<3, SkPaethEncode3> paether(bm.width());
|
| for (int y = 0; y < bm.height(); ++y) {
|
| const uint32_t* src = bm.getAddr32(0, y);
|
| - uint8_t* dst = scanline.get();
|
| + uint8_t* dst = paether.scanline();
|
| for (int x = 0; x < bm.width(); ++x) {
|
| uint32_t color = *src++;
|
| U8CPU alpha = SkGetA32Component(color, colorType);
|
| @@ -201,30 +230,30 @@ static void bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) {
|
| }
|
| dst += 3;
|
| }
|
| - out->write(scanline.get(), 3 * bm.width());
|
| + paether.write(out);
|
| }
|
| - return;
|
| + return true;
|
| }
|
| case kRGB_565_SkColorType: {
|
| SkASSERT(3 == pdf_color_component_count(colorType));
|
| - SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
|
| + PngPredictor<3, SkPaethEncode3> paether(bm.width());
|
| for (int y = 0; y < bm.height(); ++y) {
|
| const uint16_t* src = bm.getAddr16(0, y);
|
| - uint8_t* dst = scanline.get();
|
| + uint8_t* dst = paether.scanline();
|
| for (int x = 0; x < bm.width(); ++x) {
|
| U16CPU color565 = *src++;
|
| *dst++ = SkPacked16ToR32(color565);
|
| *dst++ = SkPacked16ToG32(color565);
|
| *dst++ = SkPacked16ToB32(color565);
|
| }
|
| - out->write(scanline.get(), 3 * bm.width());
|
| + paether.write(out);
|
| }
|
| - return;
|
| + return true;
|
| }
|
| case kAlpha_8_SkColorType:
|
| SkASSERT(1 == pdf_color_component_count(colorType));
|
| fill_stream(out, '\x00', pixel_count(bm));
|
| - return;
|
| + return false;
|
| case kGray_8_SkColorType:
|
| case kIndex_8_SkColorType:
|
| SkASSERT(1 == pdf_color_component_count(colorType));
|
| @@ -232,20 +261,21 @@ static void bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) {
|
| for (int y = 0; y < bm.height(); ++y) {
|
| out->write(bm.getAddr8(0, y), bm.width());
|
| }
|
| - return;
|
| + return false;
|
| case kUnknown_SkColorType:
|
| case kARGB_4444_SkColorType:
|
| default:
|
| SkDEBUGFAIL("unexpected color type");
|
| + return false;
|
| }
|
| }
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
|
|
| -static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) {
|
| +static bool bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) {
|
| if (!bitmap.getPixels()) {
|
| fill_stream(out, '\xFF', pixel_count(bitmap));
|
| - return;
|
| + return false;
|
| }
|
| SkBitmap copy;
|
| const SkBitmap& bm = not4444(bitmap, ©);
|
| @@ -254,22 +284,22 @@ static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) {
|
| switch (colorType) {
|
| case kRGBA_8888_SkColorType:
|
| case kBGRA_8888_SkColorType: {
|
| - SkAutoTMalloc<uint8_t> scanline(bm.width());
|
| + PngPredictor<1, SkPaethEncode1> paether(bm.width());
|
| for (int y = 0; y < bm.height(); ++y) {
|
| - uint8_t* dst = scanline.get();
|
| + uint8_t* dst = paether.scanline();
|
| const SkPMColor* src = bm.getAddr32(0, y);
|
| for (int x = 0; x < bm.width(); ++x) {
|
| *dst++ = SkGetA32Component(*src++, colorType);
|
| }
|
| - out->write(scanline.get(), bm.width());
|
| + paether.write(out);
|
| }
|
| - return;
|
| + return true;
|
| }
|
| case kAlpha_8_SkColorType:
|
| for (int y = 0; y < bm.height(); ++y) {
|
| out->write(bm.getAddr8(0, y), bm.width());
|
| }
|
| - return;
|
| + return false;
|
| case kIndex_8_SkColorType: {
|
| SkColorTable* ct = bm.getColorTable();
|
| SkASSERT(ct);
|
| @@ -282,18 +312,19 @@ static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) {
|
| }
|
| out->write(scanline.get(), bm.width());
|
| }
|
| - return;
|
| + return false;
|
| }
|
| case kRGB_565_SkColorType:
|
| case kGray_8_SkColorType:
|
| SkDEBUGFAIL("color type has no alpha");
|
| - return;
|
| + return false;
|
| case kARGB_4444_SkColorType:
|
| SkDEBUGFAIL("4444 color type should have been converted to N32");
|
| - return;
|
| + return false;
|
| case kUnknown_SkColorType:
|
| default:
|
| SkDEBUGFAIL("unexpected color type");
|
| + return false;
|
| }
|
| }
|
|
|
| @@ -340,10 +371,11 @@ static void emit_image_xobject(SkWStream* stream,
|
| // Write to a temporary buffer to get the compressed length.
|
| SkDynamicMemoryWStream buffer;
|
| SkDeflateWStream deflateWStream(&buffer);
|
| + bool paethPredictor = false;
|
| if (alpha) {
|
| - bitmap_alpha_to_a8(bitmap, &deflateWStream);
|
| + paethPredictor = bitmap_alpha_to_a8(bitmap, &deflateWStream);
|
| } else {
|
| - bitmap_to_pdf_pixels(bitmap, &deflateWStream);
|
| + paethPredictor = bitmap_to_pdf_pixels(bitmap, &deflateWStream);
|
| }
|
| deflateWStream.finalize(); // call before detachAsStream().
|
| SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
|
| @@ -368,6 +400,14 @@ static void emit_image_xobject(SkWStream* stream,
|
| }
|
| pdfDict.insertInt("BitsPerComponent", 8);
|
| pdfDict.insertName("Filter", "FlateDecode");
|
| + if (paethPredictor) {
|
| + SkAutoTUnref<SkPDFDict> params(new SkPDFDict);
|
| + params->insertInt("BitsPerComponent", 8);
|
| + params->insertInt("Predictor", 15);
|
| + params->insertInt("Colors", alpha ? 1 : 3);
|
| + params->insertInt("Columns", bitmap.width());
|
| + pdfDict.insertObject("DecodeParms", params.detach());
|
| + }
|
| pdfDict.insertInt("Length", asset->getLength());
|
| pdfDict.emitObject(stream, objNumMap, substitutes);
|
|
|
|
|