Chromium Code Reviews| 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; |
| +} |