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); |