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

Unified Diff: src/pdf/SkPDFBitmap.cpp

Issue 1025773002: PDF: Correctly embed JPEG images directly into PDF output. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: 2015-04-17 (Friday) 16:19:22 EDT Created 5 years, 8 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
« no previous file with comments | « src/pdf/SkPDFBitmap.h ('k') | tests/PDFJpegEmbedTest.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/pdf/SkPDFBitmap.cpp
diff --git a/src/pdf/SkPDFBitmap.cpp b/src/pdf/SkPDFBitmap.cpp
index 2a9deb6d0bdaf433fe95951cbe5fab847a57903d..3b0d38ce26ff769e8cb19b46fede5fb5aac77c21 100644
--- a/src/pdf/SkPDFBitmap.cpp
+++ b/src/pdf/SkPDFBitmap.cpp
@@ -6,9 +6,12 @@
*/
#include "SkColorPriv.h"
+#include "SkData.h"
#include "SkFlate.h"
+#include "SkImageGenerator.h"
#include "SkPDFBitmap.h"
#include "SkPDFCanon.h"
+#include "SkPixelRef.h"
#include "SkStream.h"
#include "SkUnPreMultiply.h"
@@ -283,8 +286,23 @@ void PDFAlphaBitmap::emitObject(SkWStream* stream,
////////////////////////////////////////////////////////////////////////////////
-void SkPDFBitmap::addResources(SkPDFObjNumMap* catalog,
- const SkPDFSubstituteMap& substitutes) const {
+namespace {
+class PDFDefaultBitmap : public SkPDFBitmap {
+public:
+ const SkAutoTUnref<SkPDFObject> fSMask;
+ void emitObject(SkWStream*,
+ const SkPDFObjNumMap&,
+ const SkPDFSubstituteMap&) override;
+ void addResources(SkPDFObjNumMap*,
+ const SkPDFSubstituteMap&) const override;
+ PDFDefaultBitmap(const SkBitmap& bm, SkPDFObject* smask)
+ : SkPDFBitmap(bm), fSMask(smask) {}
+};
+} // namespace
+
+void PDFDefaultBitmap::addResources(
+ SkPDFObjNumMap* catalog,
+ const SkPDFSubstituteMap& substitutes) const {
if (fSMask.get()) {
SkPDFObject* obj = substitutes.getSubstitute(fSMask.get());
SkASSERT(obj);
@@ -324,9 +342,9 @@ static SkPDFArray* make_indexed_color_space(const SkColorTable* table) {
return result;
}
-void SkPDFBitmap::emitObject(SkWStream* stream,
- const SkPDFObjNumMap& objNumMap,
- const SkPDFSubstituteMap& substitutes) {
+void PDFDefaultBitmap::emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substitutes) {
SkAutoLockPixels autoLockPixels(fBitmap);
SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType ||
fBitmap.getColorTable());
@@ -357,19 +375,13 @@ void SkPDFBitmap::emitObject(SkWStream* stream,
}
pdfDict.insertName("Filter", "FlateDecode");
pdfDict.insertInt("Length", asset->getLength());
- pdfDict.emitObject(stream, objNumMap,substitutes);
+ pdfDict.emitObject(stream, objNumMap, substitutes);
pdf_stream_begin(stream);
stream->writeStream(asset.get(), asset->getLength());
pdf_stream_end(stream);
}
-SkPDFBitmap::SkPDFBitmap(const SkBitmap& bm,
- SkPDFObject* smask)
- : fBitmap(bm), fSMask(smask) {}
-
-SkPDFBitmap::~SkPDFBitmap() {}
-
////////////////////////////////////////////////////////////////////////////////
static const SkBitmap& immutable_bitmap(const SkBitmap& bm, SkBitmap* copy) {
@@ -381,6 +393,59 @@ static const SkBitmap& immutable_bitmap(const SkBitmap& bm, SkBitmap* copy) {
return *copy;
}
+namespace {
+/**
+ * This PDFObject assumes that its constructor was handed YUV JFIF
+ * Jpeg-encoded data that can be directly embedded into a PDF.
+ */
+class PDFJpegBitmap : public SkPDFBitmap {
+public:
+ SkAutoTUnref<SkData> fData;
+ PDFJpegBitmap(const SkBitmap& bm, SkData* data)
+ : SkPDFBitmap(bm), fData(SkRef(data)) {}
+ void emitObject(SkWStream*,
+ const SkPDFObjNumMap&,
+ const SkPDFSubstituteMap&) override;
+};
+
+void PDFJpegBitmap::emitObject(SkWStream* stream,
+ const SkPDFObjNumMap& objNumMap,
+ const SkPDFSubstituteMap& substituteMap) {
+ SkPDFDict pdfDict("XObject");
+ pdfDict.insertName("Subtype", "Image");
+ pdfDict.insertInt("Width", fBitmap.width());
+ pdfDict.insertInt("Height", fBitmap.height());
+ pdfDict.insertName("ColorSpace", "DeviceRGB");
+ pdfDict.insertInt("BitsPerComponent", 8);
+ pdfDict.insertName("Filter", "DCTDecode");
+ pdfDict.insertInt("ColorTransform", 0);
+ pdfDict.insertInt("Length", SkToInt(fData->size()));
+ pdfDict.emitObject(stream, objNumMap, substituteMap);
+ pdf_stream_begin(stream);
+ stream->write(fData->data(), fData->size());
+ pdf_stream_end(stream);
+}
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+
+static bool is_jfif_yuv_jpeg(SkData* data) {
+ const uint8_t bytesZeroToThree[] = {0xFF, 0xD8, 0xFF, 0xE0};
+ const uint8_t bytesSixToTen[] = {'J', 'F', 'I', 'F', 0};
+ // 0 1 2 3 4 5 6 7 8 9 10
+ // FF D8 FF E0 ?? ?? 'J' 'F' 'I' 'F' 00 ...
+ if (data->size() < 11 ||
+ 0 != memcmp(data->bytes(), bytesZeroToThree,
+ sizeof(bytesZeroToThree)) ||
+ 0 != memcmp(data->bytes() + 6, bytesSixToTen, sizeof(bytesSixToTen))) {
+ return false;
+ }
+ SkAutoTDelete<SkImageGenerator> gen(SkImageGenerator::NewFromData(data));
+ SkISize sizes[3];
+ // Only YUV JPEG allows access to YUV planes.
+ return gen && gen->getYUV8Planes(sizes, NULL, NULL, NULL);
+}
+
SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon, const SkBitmap& bitmap) {
SkASSERT(canon);
if (!SkColorTypeIsValid(bitmap.colorType()) ||
@@ -395,11 +460,23 @@ SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon, const SkBitmap& bitmap) {
if (SkPDFBitmap* canonBitmap = canon->findBitmap(bm)) {
return SkRef(canonBitmap);
}
+
+ if (bm.pixelRef() && bm.pixelRefOrigin().isZero() &&
+ bm.dimensions() == bm.pixelRef()->info().dimensions()) {
+ // Requires the bitmap to be backed by lazy pixels.
+ SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData());
+ if (data && is_jfif_yuv_jpeg(data)) {
+ SkPDFBitmap* pdfBitmap = SkNEW_ARGS(PDFJpegBitmap, (bm, data));
+ canon->addBitmap(pdfBitmap);
+ return pdfBitmap;
+ }
+ }
+
SkPDFObject* smask = NULL;
if (!bm.isOpaque() && !SkBitmap::ComputeIsOpaque(bm)) {
smask = SkNEW_ARGS(PDFAlphaBitmap, (bm));
}
- SkPDFBitmap* pdfBitmap = SkNEW_ARGS(SkPDFBitmap, (bm, smask));
+ SkPDFBitmap* pdfBitmap = SkNEW_ARGS(PDFDefaultBitmap, (bm, smask));
canon->addBitmap(pdfBitmap);
return pdfBitmap;
}
« no previous file with comments | « src/pdf/SkPDFBitmap.h ('k') | tests/PDFJpegEmbedTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698