| Index: src/pdf/SkPDFBitmap.cpp
|
| diff --git a/src/pdf/SkPDFBitmap.cpp b/src/pdf/SkPDFBitmap.cpp
|
| index 4e49db518d802896ed069a75fe4f3f66d9bd0bb2..85874ed707658dbdcd4fcff7cd5f01f5505a7cb9 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,70 @@ static size_t pdf_color_component_count(SkColorType ct) {
|
| }
|
| }
|
|
|
| -static void bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) {
|
| +//#define SK_PDF_USE_BEST_PNG_PREDICTOR
|
| +//#define SK_PDF_USE_PAETH_PNG_PREDICTOR
|
| +namespace {
|
| +#if defined(SK_PDF_USE_BEST_PNG_PREDICTOR) || defined(SK_PDF_USE_PAETH_PNG_PREDICTOR)
|
| +template<int BPP>
|
| +class PngPredictor {
|
| +public:
|
| + PngPredictor(int widthInPixels)
|
| + : fBuffer(2 * (BPP * widthInPixels + 1))
|
| + , fWidth(widthInPixels)
|
| + , fFirstline(true) {
|
| + fScanline = fBuffer.get();
|
| + fPrevScanline = &fScanline[BPP * widthInPixels + 1];
|
| + }
|
| + bool predicts() { return true; }
|
| + uint8_t* scanline() { return &fScanline[1]; }
|
| + void write(SkWStream* out) {
|
| + static_assert(3 == BPP || 1 == BPP, "");
|
| + #if defined(SK_PDF_USE_BEST_PNG_PREDICTOR) // smaller
|
| + auto encode = (3 == BPP) ? &SkPngEncode3 : &SkPngEncode1;
|
| + #elif defined(SK_PDF_USE_PAETH_PNG_PREDICTOR) // faster
|
| + auto encode = (3 == BPP) ? &SkPaethEncode3 : &SkPaethEncode1;
|
| + #endif
|
| + fPrevScanline[0] = encode(
|
| + fWidth, fFirstline ? nullptr : &fPrevScanline[1],
|
| + &fScanline[1], &fPrevScanline[1]);
|
| + out->write(fPrevScanline, BPP * fWidth + 1);
|
| + SkTSwap(fScanline, fPrevScanline);
|
| + fFirstline = false;
|
| + }
|
| +private:
|
| + SkAutoTMalloc<uint8_t> fBuffer;
|
| + uint8_t* fScanline;
|
| + uint8_t* fPrevScanline;
|
| + uint8_t* fScratch;
|
| + int fWidth;
|
| + bool fFirstline;
|
| +};
|
| +#else
|
| +template<int BPP>
|
| +class PngPredictor {
|
| +public:
|
| + PngPredictor(int widthInPixels)
|
| + : fBuffer(BPP * widthInPixels)
|
| + , fWidthInBytes(BPP * widthInPixels) {
|
| + }
|
| + bool predicts() { return false; }
|
| + uint8_t* scanline() { return fBuffer.get(); }
|
| + void write(SkWStream* out) {
|
| + out->write(fBuffer.get(), fWidthInBytes);
|
| + }
|
| +private:
|
| + SkAutoTMalloc<uint8_t> fBuffer;
|
| + int fWidthInBytes;
|
| +};
|
| +#endif
|
| +} // 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 +246,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> pngPredictorFilter(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 = pngPredictorFilter.scanline();
|
| for (int x = 0; x < bm.width(); ++x) {
|
| uint32_t color = *src++;
|
| U8CPU alpha = SkGetA32Component(color, colorType);
|
| @@ -201,30 +260,30 @@ static void bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) {
|
| }
|
| dst += 3;
|
| }
|
| - out->write(scanline.get(), 3 * bm.width());
|
| + pngPredictorFilter.write(out);
|
| }
|
| - return;
|
| + return pngPredictorFilter.predicts();
|
| }
|
| case kRGB_565_SkColorType: {
|
| SkASSERT(3 == pdf_color_component_count(colorType));
|
| - SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
|
| + PngPredictor<3> pngPredictorFilter(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 = pngPredictorFilter.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());
|
| + pngPredictorFilter.write(out);
|
| }
|
| - return;
|
| + return pngPredictorFilter.predicts();
|
| }
|
| 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 +291,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 +314,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> pngPredictorFilter(bm.width());
|
| for (int y = 0; y < bm.height(); ++y) {
|
| - uint8_t* dst = scanline.get();
|
| + uint8_t* dst = pngPredictorFilter.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());
|
| + pngPredictorFilter.write(out);
|
| }
|
| - return;
|
| + return pngPredictorFilter.predicts();
|
| }
|
| 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 +342,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 +401,11 @@ static void emit_image_xobject(SkWStream* stream,
|
| // Write to a temporary buffer to get the compressed length.
|
| SkDynamicMemoryWStream buffer;
|
| SkDeflateWStream deflateWStream(&buffer);
|
| + bool usePngPredictor = false;
|
| if (alpha) {
|
| - bitmap_alpha_to_a8(bitmap, &deflateWStream);
|
| + usePngPredictor = bitmap_alpha_to_a8(bitmap, &deflateWStream);
|
| } else {
|
| - bitmap_to_pdf_pixels(bitmap, &deflateWStream);
|
| + usePngPredictor = bitmap_to_pdf_pixels(bitmap, &deflateWStream);
|
| }
|
| deflateWStream.finalize(); // call before detachAsStream().
|
| SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
|
| @@ -368,6 +430,14 @@ static void emit_image_xobject(SkWStream* stream,
|
| }
|
| pdfDict.insertInt("BitsPerComponent", 8);
|
| pdfDict.insertName("Filter", "FlateDecode");
|
| + if (usePngPredictor) {
|
| + 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);
|
|
|
|
|