1 /*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/pdf/SkPDFBitmap.h"
9
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkData.h"
12 #include "include/core/SkExecutor.h"
13 #include "include/core/SkImage.h"
14 #include "include/core/SkStream.h"
15 #include "include/private/SkColorData.h"
16 #include "include/private/SkImageInfoPriv.h"
17 #include "include/private/SkTo.h"
18 #include "src/pdf/SkDeflate.h"
19 #include "src/pdf/SkJpegInfo.h"
20 #include "src/pdf/SkPDFDocumentPriv.h"
21 #include "src/pdf/SkPDFTypes.h"
22 #include "src/pdf/SkPDFUtils.h"
23
24 ////////////////////////////////////////////////////////////////////////////////
25
26 // write a single byte to a stream n times.
fill_stream(SkWStream * out,char value,size_t n)27 static void fill_stream(SkWStream* out, char value, size_t n) {
28 char buffer[4096];
29 memset(buffer, value, sizeof(buffer));
30 for (size_t i = 0; i < n / sizeof(buffer); ++i) {
31 out->write(buffer, sizeof(buffer));
32 }
33 out->write(buffer, n % sizeof(buffer));
34 }
35
36 /* It is necessary to average the color component of transparent
37 pixels with their surrounding neighbors since the PDF renderer may
38 separately re-sample the alpha and color channels when the image is
39 not displayed at its native resolution. Since an alpha of zero
40 gives no information about the color component, the pathological
41 case is a white image with sharp transparency bounds - the color
42 channel goes to black, and the should-be-transparent pixels are
43 rendered as grey because of the separate soft mask and color
44 resizing. e.g.: gm/bitmappremul.cpp */
get_neighbor_avg_color(const SkPixmap & bm,int xOrig,int yOrig)45 static SkColor get_neighbor_avg_color(const SkPixmap& bm, int xOrig, int yOrig) {
46 SkASSERT(kBGRA_8888_SkColorType == bm.colorType());
47 unsigned r = 0, g = 0, b = 0, n = 0;
48 // Clamp the range to the edge of the bitmap.
49 int ymin = std::max(0, yOrig - 1);
50 int ymax = std::min(yOrig + 1, bm.height() - 1);
51 int xmin = std::max(0, xOrig - 1);
52 int xmax = std::min(xOrig + 1, bm.width() - 1);
53 for (int y = ymin; y <= ymax; ++y) {
54 const SkColor* scanline = bm.addr32(0, y);
55 for (int x = xmin; x <= xmax; ++x) {
56 SkColor color = scanline[x];
57 if (color != SK_ColorTRANSPARENT) {
58 r += SkColorGetR(color);
59 g += SkColorGetG(color);
60 b += SkColorGetB(color);
61 n++;
62 }
63 }
64 }
65 return n > 0 ? SkColorSetRGB(SkToU8(r / n), SkToU8(g / n), SkToU8(b / n))
66 : SK_ColorTRANSPARENT;
67 }
68
69 template <typename T>
emit_image_stream(SkPDFDocument * doc,SkPDFIndirectReference ref,T writeStream,SkISize size,const char * colorSpace,SkPDFIndirectReference sMask,int length,bool isJpeg)70 static void emit_image_stream(SkPDFDocument* doc,
71 SkPDFIndirectReference ref,
72 T writeStream,
73 SkISize size,
74 const char* colorSpace,
75 SkPDFIndirectReference sMask,
76 int length,
77 bool isJpeg) {
78 SkPDFDict pdfDict("XObject");
79 pdfDict.insertName("Subtype", "Image");
80 pdfDict.insertInt("Width", size.width());
81 pdfDict.insertInt("Height", size.height());
82 pdfDict.insertName("ColorSpace", colorSpace);
83 if (sMask) {
84 pdfDict.insertRef("SMask", sMask);
85 }
86 pdfDict.insertInt("BitsPerComponent", 8);
87 #ifdef SK_PDF_BASE85_BINARY
88 auto filters = SkPDFMakeArray();
89 filters->appendName("ASCII85Decode");
90 filters->appendName(isJpeg ? "DCTDecode" : "FlateDecode");
91 pdfDict.insertObject("Filter", std::move(filters));
92 #else
93 pdfDict.insertName("Filter", isJpeg ? "DCTDecode" : "FlateDecode");
94 #endif
95 if (isJpeg) {
96 pdfDict.insertInt("ColorTransform", 0);
97 }
98 pdfDict.insertInt("Length", length);
99 doc->emitStream(pdfDict, std::move(writeStream), ref);
100 }
101
do_deflated_alpha(const SkPixmap & pm,SkPDFDocument * doc,SkPDFIndirectReference ref)102 static void do_deflated_alpha(const SkPixmap& pm, SkPDFDocument* doc, SkPDFIndirectReference ref) {
103 SkDynamicMemoryWStream buffer;
104 SkDeflateWStream deflateWStream(&buffer);
105 if (kAlpha_8_SkColorType == pm.colorType()) {
106 SkASSERT(pm.rowBytes() == (size_t)pm.width());
107 buffer.write(pm.addr8(), pm.width() * pm.height());
108 } else {
109 SkASSERT(pm.alphaType() == kUnpremul_SkAlphaType);
110 SkASSERT(pm.colorType() == kBGRA_8888_SkColorType);
111 SkASSERT(pm.rowBytes() == (size_t)pm.width() * 4);
112 const uint32_t* ptr = pm.addr32();
113 const uint32_t* stop = ptr + pm.height() * pm.width();
114
115 uint8_t byteBuffer[4092];
116 uint8_t* bufferStop = byteBuffer + SK_ARRAY_COUNT(byteBuffer);
117 uint8_t* dst = byteBuffer;
118 while (ptr != stop) {
119 *dst++ = 0xFF & ((*ptr++) >> SK_BGRA_A32_SHIFT);
120 if (dst == bufferStop) {
121 deflateWStream.write(byteBuffer, sizeof(byteBuffer));
122 dst = byteBuffer;
123 }
124 }
125 deflateWStream.write(byteBuffer, dst - byteBuffer);
126 }
127 deflateWStream.finalize();
128
129 #ifdef SK_PDF_BASE85_BINARY
130 SkPDFUtils::Base85Encode(buffer.detachAsStream(), &buffer);
131 #endif
132 int length = SkToInt(buffer.bytesWritten());
133 emit_image_stream(doc, ref, [&buffer](SkWStream* stream) { buffer.writeToAndReset(stream); },
134 pm.info().dimensions(), "DeviceGray", SkPDFIndirectReference(),
135 length, false);
136 }
137
do_deflated_image(const SkPixmap & pm,SkPDFDocument * doc,bool isOpaque,SkPDFIndirectReference ref)138 static void do_deflated_image(const SkPixmap& pm,
139 SkPDFDocument* doc,
140 bool isOpaque,
141 SkPDFIndirectReference ref) {
142 SkPDFIndirectReference sMask;
143 if (!isOpaque) {
144 sMask = doc->reserveRef();
145 }
146 SkDynamicMemoryWStream buffer;
147 SkDeflateWStream deflateWStream(&buffer);
148 const char* colorSpace = "DeviceGray";
149 switch (pm.colorType()) {
150 case kAlpha_8_SkColorType:
151 fill_stream(&deflateWStream, '\x00', pm.width() * pm.height());
152 break;
153 case kGray_8_SkColorType:
154 SkASSERT(sMask.fValue = -1);
155 SkASSERT(pm.rowBytes() == (size_t)pm.width());
156 deflateWStream.write(pm.addr8(), pm.width() * pm.height());
157 break;
158 default:
159 colorSpace = "DeviceRGB";
160 SkASSERT(pm.alphaType() == kUnpremul_SkAlphaType);
161 SkASSERT(pm.colorType() == kBGRA_8888_SkColorType);
162 SkASSERT(pm.rowBytes() == (size_t)pm.width() * 4);
163 uint8_t byteBuffer[3072];
164 static_assert(SK_ARRAY_COUNT(byteBuffer) % 3 == 0, "");
165 uint8_t* bufferStop = byteBuffer + SK_ARRAY_COUNT(byteBuffer);
166 uint8_t* dst = byteBuffer;
167 for (int y = 0; y < pm.height(); ++y) {
168 const SkColor* src = pm.addr32(0, y);
169 for (int x = 0; x < pm.width(); ++x) {
170 SkColor color = *src++;
171 if (SkColorGetA(color) == SK_AlphaTRANSPARENT) {
172 color = get_neighbor_avg_color(pm, x, y);
173 }
174 *dst++ = SkColorGetR(color);
175 *dst++ = SkColorGetG(color);
176 *dst++ = SkColorGetB(color);
177 if (dst == bufferStop) {
178 deflateWStream.write(byteBuffer, sizeof(byteBuffer));
179 dst = byteBuffer;
180 }
181 }
182 }
183 deflateWStream.write(byteBuffer, dst - byteBuffer);
184 }
185 deflateWStream.finalize();
186 #ifdef SK_PDF_BASE85_BINARY
187 SkPDFUtils::Base85Encode(buffer.detachAsStream(), &buffer);
188 #endif
189 int length = SkToInt(buffer.bytesWritten());
190 emit_image_stream(doc, ref, [&buffer](SkWStream* stream) { buffer.writeToAndReset(stream); },
191 pm.info().dimensions(), colorSpace, sMask, length, false);
192 if (!isOpaque) {
193 do_deflated_alpha(pm, doc, sMask);
194 }
195 }
196
do_jpeg(sk_sp<SkData> data,SkPDFDocument * doc,SkISize size,SkPDFIndirectReference ref)197 static bool do_jpeg(sk_sp<SkData> data, SkPDFDocument* doc, SkISize size,
198 SkPDFIndirectReference ref) {
199 SkISize jpegSize;
200 SkEncodedInfo::Color jpegColorType;
201 SkEncodedOrigin exifOrientation;
202 if (!SkGetJpegInfo(data->data(), data->size(), &jpegSize,
203 &jpegColorType, &exifOrientation)) {
204 return false;
205 }
206 bool yuv = jpegColorType == SkEncodedInfo::kYUV_Color;
207 bool goodColorType = yuv || jpegColorType == SkEncodedInfo::kGray_Color;
208 if (jpegSize != size // Safety check.
209 || !goodColorType
210 || kTopLeft_SkEncodedOrigin != exifOrientation) {
211 return false;
212 }
213 #ifdef SK_PDF_BASE85_BINARY
214 SkDynamicMemoryWStream buffer;
215 SkPDFUtils::Base85Encode(SkMemoryStream::MakeDirect(data->data(), data->size()), &buffer);
216 data = buffer.detachAsData();
217 #endif
218
219 emit_image_stream(doc, ref,
220 [&data](SkWStream* dst) { dst->write(data->data(), data->size()); },
221 jpegSize, yuv ? "DeviceRGB" : "DeviceGray",
222 SkPDFIndirectReference(), SkToInt(data->size()), true);
223 return true;
224 }
225
to_pixels(const SkImage * image)226 static SkBitmap to_pixels(const SkImage* image) {
227 SkBitmap bm;
228 int w = image->width(),
229 h = image->height();
230 switch (image->colorType()) {
231 case kAlpha_8_SkColorType:
232 bm.allocPixels(SkImageInfo::MakeA8(w, h));
233 break;
234 case kGray_8_SkColorType:
235 bm.allocPixels(SkImageInfo::Make(w, h, kGray_8_SkColorType, kOpaque_SkAlphaType));
236 break;
237 default: {
238 // TODO: makeColorSpace(sRGB) or actually tag the images
239 SkAlphaType at = bm.isOpaque() ? kOpaque_SkAlphaType : kUnpremul_SkAlphaType;
240 bm.allocPixels(SkImageInfo::Make(w, h, kBGRA_8888_SkColorType, at));
241 }
242 }
243 // TODO: support GPU images in PDFs
244 if (!image->readPixels(nullptr, bm.pixmap(), 0, 0)) {
245 bm.eraseColor(SkColorSetARGB(0xFF, 0, 0, 0));
246 }
247 return bm;
248 }
249
serialize_image(const SkImage * img,int encodingQuality,SkPDFDocument * doc,SkPDFIndirectReference ref)250 void serialize_image(const SkImage* img,
251 int encodingQuality,
252 SkPDFDocument* doc,
253 SkPDFIndirectReference ref) {
254 SkASSERT(img);
255 SkASSERT(doc);
256 SkASSERT(encodingQuality >= 0);
257 SkISize dimensions = img->dimensions();
258 if (sk_sp<SkData> data = img->refEncodedData()) {
259 if (do_jpeg(std::move(data), doc, dimensions, ref)) {
260 return;
261 }
262 }
263 SkBitmap bm = to_pixels(img);
264 const SkPixmap& pm = bm.pixmap();
265 bool isOpaque = pm.isOpaque() || pm.computeIsOpaque();
266 if (encodingQuality <= 100 && isOpaque) {
267 if (sk_sp<SkData> data = img->encodeToData(SkEncodedImageFormat::kJPEG, encodingQuality)) {
268 if (do_jpeg(std::move(data), doc, dimensions, ref)) {
269 return;
270 }
271 }
272 }
273 do_deflated_image(pm, doc, isOpaque, ref);
274 }
275
SkPDFSerializeImage(const SkImage * img,SkPDFDocument * doc,int encodingQuality)276 SkPDFIndirectReference SkPDFSerializeImage(const SkImage* img,
277 SkPDFDocument* doc,
278 int encodingQuality) {
279 SkASSERT(img);
280 SkASSERT(doc);
281 SkPDFIndirectReference ref = doc->reserveRef();
282 if (SkExecutor* executor = doc->executor()) {
283 SkRef(img);
284 doc->incrementJobCount();
285 executor->add([img, encodingQuality, doc, ref]() {
286 serialize_image(img, encodingQuality, doc, ref);
287 SkSafeUnref(img);
288 doc->signalJobComplete();
289 });
290 return ref;
291 }
292 serialize_image(img, encodingQuality, doc, ref);
293 return ref;
294 }
295