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