Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(637)

Unified Diff: src/pdf/SkPDFBitmap.cpp

Issue 918813002: PDF: Add (low-memory) SkPDFBitmap class (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: 2015-02-11 (Wednesday) 18:49:13 EST Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/pdf/SkPDFBitmap.cpp
diff --git a/src/pdf/SkPDFBitmap.cpp b/src/pdf/SkPDFBitmap.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5f0dcec27cb7c492b103e359a57f57b0205c58e3
--- /dev/null
+++ b/src/pdf/SkPDFBitmap.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkPDFBitmap.h"
+#include "SkPDFCanon.h"
+#include "SkUnPreMultiply.h"
+#include "SkColorPriv.h"
+#include "SkStream.h"
+#include "SkDeflateWStream.h"
+#include "SkFlate.h"
+
+static void emit_pdf_bitmap_dict(SkWStream* stream,
+ SkPDFCatalog* catalog,
+ SkISize dimensions,
+ int32_t length,
+ SkPDFObject* smask,
+ bool deflate,
+ const char colorSpace[]) {
+ SkPDFDict pdfDict("Xobject");
+ pdfDict.insertName("Subtype", "Image");
+ pdfDict.insertInt("Width", dimensions.width());
+ pdfDict.insertInt("Height", dimensions.height());
+ pdfDict.insertName("ColorSpace", colorSpace);
+ pdfDict.insertInt("BitsPerComponent", 8);
+ if (smask) {
+ pdfDict.insert("SMask", new SkPDFObjRef(smask))->unref();
+ }
+ pdfDict.insertInt("Length", length);
+ if (deflate) {
+ pdfDict.insertName("Filter", "FlateDecode");
+ }
+ pdfDict.emitObject(stream, catalog);
+}
+
+static void pmcolor_scanline_to_rgb24(const SkPMColor* src,
mtklein 2015/02/12 00:21:46 This is just a suggestion. I've grown to like (ds
hal.canary 2015/02/12 21:28:03 Refactored out.
+ uint8_t* dst, int width) {
+ for (int x = 0; x < width; ++x) {
+ const SkPMColor pmColor = *src++;
+ const uint32_t s = SkUnPreMultiply::GetScale(SkGetPackedA32(pmColor));
+ *dst++ = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(pmColor));
+ *dst++ = SkUnPreMultiply::ApplyScale(s, SkGetPackedG32(pmColor));
+ *dst++ = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(pmColor));
+ }
+}
+
+static void pmcolor_alpha_scanline_to_a8(const SkPMColor* src,
+ uint8_t* dst, int width) {
+ for (int x = 0; x < width; ++x) {
+ *dst++ = SkGetPackedA32(*src++);
+ }
+}
+
+SkPDFBitmap::~SkPDFBitmap() {
+ if (!fIsAlpha) {
mtklein 2015/02/12 00:21:46 It'd be nice to explain fIsAlpha and why we track
hal.canary 2015/02/12 21:28:03 Done.
+ SkAutoMutexAcquire autoMutexAcquire(SkPDFCanon::GetBitmapMutex());
+ SkPDFCanon::GetCanon().removeBitmap(this);
+ }
+}
+
+void SkPDFBitmap::addResources(SkTSet<SkPDFObject*>* resourceSet,
+ SkPDFCatalog* catalog) const {
+ if (fSMask.get()) {
+ resourceSet->add(fSMask.get());
+ }
+}
+
+void SkPDFBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
+ SkASSERT(kN32_SkColorType == fBitmap.colorType());
+ SkAutoLockPixels autoLockPixels(fBitmap);
+ SkASSERT(fBitmap.getPixels());
+
+ if (SkFlate::HaveFlate()) {
+ SkDynamicMemoryWStream buffer;
+ size_t scanlineLength = fIsAlpha ? fBitmap.width()
+ : 3 * fBitmap.width();
+ SkAutoTMalloc<uint8_t> scanline(scanlineLength);
+ if (fIsAlpha) {
+ SkDeflateWStream deflateWStream(&buffer);
+ for (int y = 0; y < fBitmap.height(); ++y) {
+ pmcolor_alpha_scanline_to_a8(fBitmap.getAddr32(0, y),
+ scanline.get(),
+ fBitmap.width());
+ deflateWStream.write(scanline.get(), scanlineLength);
+ }
+ // deflateWStream is deleted.
mtklein 2015/02/12 00:21:46 Is this salient here but not in the rgb case?
hal.canary 2015/02/12 21:28:03 refactored out
+ } else {
+ SkDeflateWStream deflateWStream(&buffer);
+ for (int y = 0; y < fBitmap.height(); ++y) {
+ pmcolor_scanline_to_rgb24(fBitmap.getAddr32(0, y),
+ scanline.get(),
+ fBitmap.width());
+ deflateWStream.write(scanline.get(), scanlineLength);
+ }
+ }
+ SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
+ emit_pdf_bitmap_dict(stream,
+ catalog,
+ fBitmap.dimensions(),
+ asset->getLength(),
+ fSMask,
+ true,
mtklein 2015/02/12 00:21:46 Is this /* using DEFLATE */ and false /* not compr
+ fIsAlpha ? "DeviceGray" : "DeviceRGB");
+ stream->writeText(" stream\n");
+ stream->writeStream(asset.get(), asset->getLength());
+ stream->writeText("\nendstream");
+ return;
+ } else { // !SkFlate::HaveFlate()
+ size_t scanlineLength = fIsAlpha ? fBitmap.width()
mtklein 2015/02/12 00:21:46 Seems like an awful lot of code duplicated between
+ : 3 * fBitmap.width();
+ emit_pdf_bitmap_dict(stream,
+ catalog,
+ fBitmap.dimensions(),
+ fBitmap.height() * scanlineLength,
+ fSMask,
+ false,
+ fIsAlpha ? "DeviceGray" : "DeviceRGB");
+ stream->writeText(" stream\n");
+
+ SkAutoTMalloc<uint8_t> scanline(scanlineLength);
+
+ if (fIsAlpha) {
+ for (int y = 0; y < fBitmap.height(); ++y) {
+ pmcolor_alpha_scanline_to_a8(fBitmap.getAddr32(0, y),
+ scanline.get(),
+ fBitmap.width());
+ stream->write(scanline.get(), scanlineLength);
+ }
+ } else {
+ for (int y = 0; y < fBitmap.height(); ++y) {
+ pmcolor_scanline_to_rgb24(fBitmap.getAddr32(0, y),
+ scanline.get(),
+ fBitmap.width());
+ stream->write(scanline.get(), scanlineLength);
+ }
+ }
+ stream->writeText("\nendstream");
+ return;
+ }
+}
+
+SkPDFBitmap::SkPDFBitmap(const SkBitmap& bm, bool isAlpha, SkPDFBitmap* smask)
+ : fBitmap(bm), fSMask(smask), fIsAlpha(isAlpha) {}
+
+SkPDFBitmap* SkPDFBitmap::Create(const SkBitmap& bitmap,
+ const SkIRect& subset) {
+ if (kN32_SkColorType != bitmap.colorType()) {
+ return NULL;
+ }
+ SkBitmap bm;
+ if (!bitmap.extractSubset(&bm, subset)) {
+ return NULL;
+ }
+ if (bm.drawsNothing()) {
+ return NULL;
mtklein 2015/02/12 00:21:46 Is this really an error?
hal.canary 2015/02/12 21:28:03 Just a shortcut.
+ }
+ SkAutoMutexAcquire autoMutexAcquire(SkPDFCanon::GetBitmapMutex());
+ SkPDFCanon& canon = SkPDFCanon::GetCanon();
+ SkPDFBitmap* pdfBitmap = canon.findBitmap(bm);
+ if (pdfBitmap) {
+ return SkRef(pdfBitmap);
+ } // src/pdf/SkPDFBitmap.cpp
+ SkPDFBitmap* smask = NULL;
+ if (!bitmap.isOpaque() && !SkBitmap::ComputeIsOpaque(bitmap)) {
+ smask = SkNEW_ARGS(SkPDFBitmap, (bm, true, NULL));
mtklein 2015/02/12 00:21:46 Are the smasks always alpha-only and the main SkPD
hal.canary 2015/02/12 21:28:03 Okay, done. Seems like more code this way.
+ }
+ pdfBitmap = SkNEW_ARGS(SkPDFBitmap, (bm, false, smask));
+ canon.addBitmap(pdfBitmap);
+ return pdfBitmap;
+}

Powered by Google App Engine
This is Rietveld 408576698