blob: 35052334dbb1338bfb09a16401176a09df4cc81e [file] [log] [blame]
halcanary1b5c6042015-02-18 11:29:56 -08001/*
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 "SkColorPriv.h"
halcanarya8448bc2015-04-17 13:27:24 -07009#include "SkData.h"
halcanaryd9e57152015-08-12 11:24:40 -070010#include "SkDeflate.h"
halcanarya8448bc2015-04-17 13:27:24 -070011#include "SkImageGenerator.h"
halcanary96287f72015-05-07 11:46:59 -070012#include "SkJpegInfo.h"
halcanary1b5c6042015-02-18 11:29:56 -080013#include "SkPDFBitmap.h"
14#include "SkPDFCanon.h"
halcanarya8448bc2015-04-17 13:27:24 -070015#include "SkPixelRef.h"
halcanary1b5c6042015-02-18 11:29:56 -080016#include "SkStream.h"
17#include "SkUnPreMultiply.h"
18
19////////////////////////////////////////////////////////////////////////////////
20
21static void pdf_stream_begin(SkWStream* stream) {
22 static const char streamBegin[] = " stream\n";
23 stream->write(streamBegin, strlen(streamBegin));
24}
25
26static void pdf_stream_end(SkWStream* stream) {
27 static const char streamEnd[] = "\nendstream";
28 stream->write(streamEnd, strlen(streamEnd));
29}
30
halcanarydb0dcc72015-03-20 12:31:52 -070031////////////////////////////////////////////////////////////////////////////////
halcanary1b5c6042015-02-18 11:29:56 -080032
halcanary1b5c6042015-02-18 11:29:56 -080033// write a single byte to a stream n times.
34static void fill_stream(SkWStream* out, char value, size_t n) {
35 char buffer[4096];
36 memset(buffer, value, sizeof(buffer));
halcanarydb0dcc72015-03-20 12:31:52 -070037 for (size_t i = 0; i < n / sizeof(buffer); ++i) {
38 out->write(buffer, sizeof(buffer));
halcanary1b5c6042015-02-18 11:29:56 -080039 }
halcanarydb0dcc72015-03-20 12:31:52 -070040 out->write(buffer, n % sizeof(buffer));
halcanary1b5c6042015-02-18 11:29:56 -080041}
42
halcanarydb0dcc72015-03-20 12:31:52 -070043// unpremultiply and extract R, G, B components.
44static void pmcolor_to_rgb24(SkPMColor pmColor, uint8_t* rgb) {
45 uint32_t s = SkUnPreMultiply::GetScale(SkGetPackedA32(pmColor));
46 rgb[0] = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(pmColor));
47 rgb[1] = SkUnPreMultiply::ApplyScale(s, SkGetPackedG32(pmColor));
48 rgb[2] = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(pmColor));
49}
50
51/* It is necessary to average the color component of transparent
52 pixels with their surrounding neighbors since the PDF renderer may
53 separately re-sample the alpha and color channels when the image is
54 not displayed at its native resolution. Since an alpha of zero
55 gives no information about the color component, the pathological
56 case is a white image with sharp transparency bounds - the color
57 channel goes to black, and the should-be-transparent pixels are
58 rendered as grey because of the separate soft mask and color
59 resizing. e.g.: gm/bitmappremul.cpp */
60static void get_neighbor_avg_color(const SkBitmap& bm,
61 int xOrig,
62 int yOrig,
63 uint8_t rgb[3]) {
64 SkASSERT(kN32_SkColorType == bm.colorType());
65 unsigned a = 0, r = 0, g = 0, b = 0;
66 // Clamp the range to the edge of the bitmap.
67 int ymin = SkTMax(0, yOrig - 1);
68 int ymax = SkTMin(yOrig + 1, bm.height() - 1);
69 int xmin = SkTMax(0, xOrig - 1);
70 int xmax = SkTMin(xOrig + 1, bm.width() - 1);
71 for (int y = ymin; y <= ymax; ++y) {
72 SkPMColor* scanline = bm.getAddr32(0, y);
73 for (int x = xmin; x <= xmax; ++x) {
74 SkPMColor pmColor = scanline[x];
75 a += SkGetPackedA32(pmColor);
76 r += SkGetPackedR32(pmColor);
77 g += SkGetPackedG32(pmColor);
78 b += SkGetPackedB32(pmColor);
halcanary1b5c6042015-02-18 11:29:56 -080079 }
80 }
halcanarydb0dcc72015-03-20 12:31:52 -070081 if (a > 0) {
82 rgb[0] = SkToU8(255 * r / a);
83 rgb[1] = SkToU8(255 * g / a);
84 rgb[2] = SkToU8(255 * b / a);
halcanary1b5c6042015-02-18 11:29:56 -080085 } else {
halcanarydb0dcc72015-03-20 12:31:52 -070086 rgb[0] = rgb[1] = rgb[2] = 0;
halcanary1b5c6042015-02-18 11:29:56 -080087 }
88}
89
halcanarydb0dcc72015-03-20 12:31:52 -070090static size_t pixel_count(const SkBitmap& bm) {
91 return SkToSizeT(bm.width()) * SkToSizeT(bm.height());
92}
93
94static const SkBitmap& not4444(const SkBitmap& input, SkBitmap* copy) {
95 if (input.colorType() != kARGB_4444_SkColorType) {
96 return input;
97 }
98 // ARGB_4444 is rarely used, so we can do a wasteful tmp copy.
99 SkAssertResult(input.copyTo(copy, kN32_SkColorType));
100 copy->setImmutable();
101 return *copy;
102}
103
104static size_t pdf_color_component_count(SkColorType ct) {
105 switch (ct) {
106 case kN32_SkColorType:
107 case kRGB_565_SkColorType:
108 case kARGB_4444_SkColorType:
109 return 3;
110 case kAlpha_8_SkColorType:
111 case kIndex_8_SkColorType:
112 case kGray_8_SkColorType:
113 return 1;
114 case kUnknown_SkColorType:
115 default:
116 SkDEBUGFAIL("unexpected color type");
117 return 0;
118 }
119}
120
121static void bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) {
122 if (!bitmap.getPixels()) {
123 size_t size = pixel_count(bitmap) *
124 pdf_color_component_count(bitmap.colorType());
125 fill_stream(out, '\x00', size);
halcanary1b5c6042015-02-18 11:29:56 -0800126 return;
127 }
halcanarydb0dcc72015-03-20 12:31:52 -0700128 SkBitmap copy;
129 const SkBitmap& bm = not4444(bitmap, &copy);
130 SkAutoLockPixels autoLockPixels(bm);
131 switch (bm.colorType()) {
132 case kN32_SkColorType: {
133 SkASSERT(3 == pdf_color_component_count(bitmap.colorType()));
134 SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
135 for (int y = 0; y < bm.height(); ++y) {
136 const SkPMColor* src = bm.getAddr32(0, y);
137 uint8_t* dst = scanline.get();
138 for (int x = 0; x < bm.width(); ++x) {
139 SkPMColor color = *src++;
140 U8CPU alpha = SkGetPackedA32(color);
141 if (alpha != SK_AlphaTRANSPARENT) {
142 pmcolor_to_rgb24(color, dst);
143 } else {
144 get_neighbor_avg_color(bm, x, y, dst);
145 }
146 dst += 3;
147 }
148 out->write(scanline.get(), 3 * bm.width());
halcanary1b5c6042015-02-18 11:29:56 -0800149 }
halcanarydb0dcc72015-03-20 12:31:52 -0700150 return;
halcanary1b5c6042015-02-18 11:29:56 -0800151 }
halcanarydb0dcc72015-03-20 12:31:52 -0700152 case kRGB_565_SkColorType: {
153 SkASSERT(3 == pdf_color_component_count(bitmap.colorType()));
154 SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
155 for (int y = 0; y < bm.height(); ++y) {
156 const uint16_t* src = bm.getAddr16(0, y);
157 uint8_t* dst = scanline.get();
158 for (int x = 0; x < bm.width(); ++x) {
159 U16CPU color565 = *src++;
160 *dst++ = SkPacked16ToR32(color565);
161 *dst++ = SkPacked16ToG32(color565);
162 *dst++ = SkPacked16ToB32(color565);
163 }
164 out->write(scanline.get(), 3 * bm.width());
165 }
166 return;
167 }
168 case kAlpha_8_SkColorType:
169 SkASSERT(1 == pdf_color_component_count(bitmap.colorType()));
170 fill_stream(out, '\x00', pixel_count(bm));
171 return;
172 case kGray_8_SkColorType:
173 case kIndex_8_SkColorType:
174 SkASSERT(1 == pdf_color_component_count(bitmap.colorType()));
175 // these two formats need no transformation to serialize.
176 for (int y = 0; y < bm.height(); ++y) {
177 out->write(bm.getAddr8(0, y), bm.width());
178 }
179 return;
180 case kUnknown_SkColorType:
181 case kARGB_4444_SkColorType:
182 default:
183 SkDEBUGFAIL("unexpected color type");
halcanary1b5c6042015-02-18 11:29:56 -0800184 }
185}
186
halcanarydb0dcc72015-03-20 12:31:52 -0700187////////////////////////////////////////////////////////////////////////////////
188
189static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) {
190 if (!bitmap.getPixels()) {
191 fill_stream(out, '\xFF', pixel_count(bitmap));
halcanary1b5c6042015-02-18 11:29:56 -0800192 return;
193 }
halcanarydb0dcc72015-03-20 12:31:52 -0700194 SkBitmap copy;
195 const SkBitmap& bm = not4444(bitmap, &copy);
196 SkAutoLockPixels autoLockPixels(bm);
197 switch (bm.colorType()) {
198 case kN32_SkColorType: {
199 SkAutoTMalloc<uint8_t> scanline(bm.width());
200 for (int y = 0; y < bm.height(); ++y) {
201 uint8_t* dst = scanline.get();
202 const SkPMColor* src = bm.getAddr32(0, y);
203 for (int x = 0; x < bm.width(); ++x) {
204 *dst++ = SkGetPackedA32(*src++);
205 }
206 out->write(scanline.get(), bm.width());
207 }
208 return;
halcanary1b5c6042015-02-18 11:29:56 -0800209 }
halcanarydb0dcc72015-03-20 12:31:52 -0700210 case kAlpha_8_SkColorType:
211 for (int y = 0; y < bm.height(); ++y) {
212 out->write(bm.getAddr8(0, y), bm.width());
213 }
214 return;
215 case kIndex_8_SkColorType: {
216 SkColorTable* ct = bm.getColorTable();
217 SkASSERT(ct);
218 SkAutoTMalloc<uint8_t> scanline(bm.width());
219 for (int y = 0; y < bm.height(); ++y) {
220 uint8_t* dst = scanline.get();
221 const uint8_t* src = bm.getAddr8(0, y);
222 for (int x = 0; x < bm.width(); ++x) {
223 *dst++ = SkGetPackedA32((*ct)[*src++]);
224 }
225 out->write(scanline.get(), bm.width());
226 }
227 return;
228 }
229 case kRGB_565_SkColorType:
230 case kGray_8_SkColorType:
231 SkDEBUGFAIL("color type has no alpha");
232 return;
233 case kARGB_4444_SkColorType:
234 SkDEBUGFAIL("4444 color type should have been converted to N32");
235 return;
236 case kUnknown_SkColorType:
237 default:
238 SkDEBUGFAIL("unexpected color type");
halcanary1b5c6042015-02-18 11:29:56 -0800239 }
240}
241
242////////////////////////////////////////////////////////////////////////////////
243
244namespace {
245// This SkPDFObject only outputs the alpha layer of the given bitmap.
246class PDFAlphaBitmap : public SkPDFObject {
247public:
248 PDFAlphaBitmap(const SkBitmap& bm) : fBitmap(bm) {}
249 ~PDFAlphaBitmap() {}
halcanary37c46ca2015-03-31 12:30:20 -0700250 void emitObject(SkWStream*,
251 const SkPDFObjNumMap&,
halcanarya060eba2015-08-19 12:26:46 -0700252 const SkPDFSubstituteMap&) const override;
halcanary1b5c6042015-02-18 11:29:56 -0800253
254private:
255 const SkBitmap fBitmap;
halcanary1b5c6042015-02-18 11:29:56 -0800256};
257
halcanary37c46ca2015-03-31 12:30:20 -0700258void PDFAlphaBitmap::emitObject(SkWStream* stream,
259 const SkPDFObjNumMap& objNumMap,
halcanarya060eba2015-08-19 12:26:46 -0700260 const SkPDFSubstituteMap& substitutes) const {
halcanary1b5c6042015-02-18 11:29:56 -0800261 SkAutoLockPixels autoLockPixels(fBitmap);
halcanarydb0dcc72015-03-20 12:31:52 -0700262 SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType ||
263 fBitmap.getColorTable());
halcanary1b5c6042015-02-18 11:29:56 -0800264
halcanary1b5c6042015-02-18 11:29:56 -0800265 // Write to a temporary buffer to get the compressed length.
266 SkDynamicMemoryWStream buffer;
267 SkDeflateWStream deflateWStream(&buffer);
halcanarydb0dcc72015-03-20 12:31:52 -0700268 bitmap_alpha_to_a8(fBitmap, &deflateWStream);
halcanary1b5c6042015-02-18 11:29:56 -0800269 deflateWStream.finalize(); // call before detachAsStream().
270 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
271
halcanary1b5c6042015-02-18 11:29:56 -0800272 SkPDFDict pdfDict("XObject");
273 pdfDict.insertName("Subtype", "Image");
274 pdfDict.insertInt("Width", fBitmap.width());
275 pdfDict.insertInt("Height", fBitmap.height());
276 pdfDict.insertName("ColorSpace", "DeviceGray");
277 pdfDict.insertInt("BitsPerComponent", 8);
halcanarydb0dcc72015-03-20 12:31:52 -0700278 pdfDict.insertName("Filter", "FlateDecode");
halcanary37c46ca2015-03-31 12:30:20 -0700279 pdfDict.insertInt("Length", asset->getLength());
280 pdfDict.emitObject(stream, objNumMap, substitutes);
281
282 pdf_stream_begin(stream);
283 stream->writeStream(asset.get(), asset->getLength());
284 pdf_stream_end(stream);
halcanary1b5c6042015-02-18 11:29:56 -0800285}
286} // namespace
287
288////////////////////////////////////////////////////////////////////////////////
289
halcanarya8448bc2015-04-17 13:27:24 -0700290namespace {
291class PDFDefaultBitmap : public SkPDFBitmap {
292public:
293 const SkAutoTUnref<SkPDFObject> fSMask;
294 void emitObject(SkWStream*,
295 const SkPDFObjNumMap&,
halcanarya060eba2015-08-19 12:26:46 -0700296 const SkPDFSubstituteMap&) const override;
halcanarya8448bc2015-04-17 13:27:24 -0700297 void addResources(SkPDFObjNumMap*,
298 const SkPDFSubstituteMap&) const override;
299 PDFDefaultBitmap(const SkBitmap& bm, SkPDFObject* smask)
300 : SkPDFBitmap(bm), fSMask(smask) {}
301};
302} // namespace
303
304void PDFDefaultBitmap::addResources(
305 SkPDFObjNumMap* catalog,
306 const SkPDFSubstituteMap& substitutes) const {
halcanary1b5c6042015-02-18 11:29:56 -0800307 if (fSMask.get()) {
halcanary37c46ca2015-03-31 12:30:20 -0700308 SkPDFObject* obj = substitutes.getSubstitute(fSMask.get());
309 SkASSERT(obj);
310 if (catalog->addObject(obj)) {
311 obj->addResources(catalog, substitutes);
halcanarydb0dcc72015-03-20 12:31:52 -0700312 }
halcanary1b5c6042015-02-18 11:29:56 -0800313 }
314}
315
halcanarydb0dcc72015-03-20 12:31:52 -0700316static SkPDFArray* make_indexed_color_space(const SkColorTable* table) {
halcanary385fe4d2015-08-26 13:07:48 -0700317 SkPDFArray* result = new SkPDFArray;
halcanarydb0dcc72015-03-20 12:31:52 -0700318 result->reserve(4);
319 result->appendName("Indexed");
320 result->appendName("DeviceRGB");
321 SkASSERT(table);
322 if (table->count() < 1) {
323 result->appendInt(0);
324 char shortTableArray[3] = {0, 0, 0};
325 SkString tableString(shortTableArray, SK_ARRAY_COUNT(shortTableArray));
halcanarya25b3372015-04-27 14:00:09 -0700326 result->appendString(tableString);
halcanarydb0dcc72015-03-20 12:31:52 -0700327 return result;
328 }
329 result->appendInt(table->count() - 1); // maximum color index.
330
331 // Potentially, this could be represented in fewer bytes with a stream.
332 // Max size as a string is 1.5k.
333 char tableArray[256 * 3];
334 SkASSERT(3u * table->count() <= SK_ARRAY_COUNT(tableArray));
335 uint8_t* tablePtr = reinterpret_cast<uint8_t*>(tableArray);
336 const SkPMColor* colors = table->readColors();
337 for (int i = 0; i < table->count(); i++) {
338 pmcolor_to_rgb24(colors[i], tablePtr);
339 tablePtr += 3;
340 }
341 SkString tableString(tableArray, 3 * table->count());
halcanarya25b3372015-04-27 14:00:09 -0700342 result->appendString(tableString);
halcanarydb0dcc72015-03-20 12:31:52 -0700343 return result;
halcanary1b5c6042015-02-18 11:29:56 -0800344}
345
halcanarya8448bc2015-04-17 13:27:24 -0700346void PDFDefaultBitmap::emitObject(SkWStream* stream,
347 const SkPDFObjNumMap& objNumMap,
halcanarya060eba2015-08-19 12:26:46 -0700348 const SkPDFSubstituteMap& substitutes) const {
halcanary37c46ca2015-03-31 12:30:20 -0700349 SkAutoLockPixels autoLockPixels(fBitmap);
350 SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType ||
351 fBitmap.getColorTable());
352
353 // Write to a temporary buffer to get the compressed length.
354 SkDynamicMemoryWStream buffer;
355 SkDeflateWStream deflateWStream(&buffer);
356 bitmap_to_pdf_pixels(fBitmap, &deflateWStream);
357 deflateWStream.finalize(); // call before detachAsStream().
358 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
359
halcanary1b5c6042015-02-18 11:29:56 -0800360 SkPDFDict pdfDict("XObject");
361 pdfDict.insertName("Subtype", "Image");
362 pdfDict.insertInt("Width", fBitmap.width());
363 pdfDict.insertInt("Height", fBitmap.height());
halcanarydb0dcc72015-03-20 12:31:52 -0700364 if (fBitmap.colorType() == kIndex_8_SkColorType) {
365 SkASSERT(1 == pdf_color_component_count(fBitmap.colorType()));
halcanarya25b3372015-04-27 14:00:09 -0700366 pdfDict.insertObject("ColorSpace",
367 make_indexed_color_space(fBitmap.getColorTable()));
halcanarydb0dcc72015-03-20 12:31:52 -0700368 } else if (1 == pdf_color_component_count(fBitmap.colorType())) {
369 pdfDict.insertName("ColorSpace", "DeviceGray");
370 } else {
371 pdfDict.insertName("ColorSpace", "DeviceRGB");
372 }
halcanary1b5c6042015-02-18 11:29:56 -0800373 pdfDict.insertInt("BitsPerComponent", 8);
374 if (fSMask) {
halcanarya25b3372015-04-27 14:00:09 -0700375 pdfDict.insertObjRef("SMask", SkRef(fSMask.get()));
halcanary1b5c6042015-02-18 11:29:56 -0800376 }
halcanarydb0dcc72015-03-20 12:31:52 -0700377 pdfDict.insertName("Filter", "FlateDecode");
halcanary37c46ca2015-03-31 12:30:20 -0700378 pdfDict.insertInt("Length", asset->getLength());
halcanarya8448bc2015-04-17 13:27:24 -0700379 pdfDict.emitObject(stream, objNumMap, substitutes);
halcanary37c46ca2015-03-31 12:30:20 -0700380
381 pdf_stream_begin(stream);
382 stream->writeStream(asset.get(), asset->getLength());
383 pdf_stream_end(stream);
halcanary1b5c6042015-02-18 11:29:56 -0800384}
385
halcanary1b5c6042015-02-18 11:29:56 -0800386////////////////////////////////////////////////////////////////////////////////
halcanarydb0dcc72015-03-20 12:31:52 -0700387
388static const SkBitmap& immutable_bitmap(const SkBitmap& bm, SkBitmap* copy) {
389 if (bm.isImmutable()) {
390 return bm;
halcanary1b5c6042015-02-18 11:29:56 -0800391 }
halcanarydb0dcc72015-03-20 12:31:52 -0700392 bm.copyTo(copy);
393 copy->setImmutable();
394 return *copy;
halcanary1b5c6042015-02-18 11:29:56 -0800395}
396
halcanarya8448bc2015-04-17 13:27:24 -0700397namespace {
398/**
399 * This PDFObject assumes that its constructor was handed YUV JFIF
400 * Jpeg-encoded data that can be directly embedded into a PDF.
401 */
402class PDFJpegBitmap : public SkPDFBitmap {
403public:
404 SkAutoTUnref<SkData> fData;
halcanary96287f72015-05-07 11:46:59 -0700405 bool fIsYUV;
406 PDFJpegBitmap(const SkBitmap& bm, SkData* data, bool isYUV)
407 : SkPDFBitmap(bm), fData(SkRef(data)), fIsYUV(isYUV) {}
halcanarya8448bc2015-04-17 13:27:24 -0700408 void emitObject(SkWStream*,
409 const SkPDFObjNumMap&,
halcanarya060eba2015-08-19 12:26:46 -0700410 const SkPDFSubstituteMap&) const override;
halcanarya8448bc2015-04-17 13:27:24 -0700411};
412
413void PDFJpegBitmap::emitObject(SkWStream* stream,
414 const SkPDFObjNumMap& objNumMap,
halcanarya060eba2015-08-19 12:26:46 -0700415 const SkPDFSubstituteMap& substituteMap) const {
halcanarya8448bc2015-04-17 13:27:24 -0700416 SkPDFDict pdfDict("XObject");
417 pdfDict.insertName("Subtype", "Image");
418 pdfDict.insertInt("Width", fBitmap.width());
419 pdfDict.insertInt("Height", fBitmap.height());
halcanary96287f72015-05-07 11:46:59 -0700420 if (fIsYUV) {
421 pdfDict.insertName("ColorSpace", "DeviceRGB");
422 } else {
423 pdfDict.insertName("ColorSpace", "DeviceGray");
424 }
halcanarya8448bc2015-04-17 13:27:24 -0700425 pdfDict.insertInt("BitsPerComponent", 8);
426 pdfDict.insertName("Filter", "DCTDecode");
427 pdfDict.insertInt("ColorTransform", 0);
428 pdfDict.insertInt("Length", SkToInt(fData->size()));
429 pdfDict.emitObject(stream, objNumMap, substituteMap);
430 pdf_stream_begin(stream);
431 stream->write(fData->data(), fData->size());
432 pdf_stream_end(stream);
433}
434} // namespace
435
436////////////////////////////////////////////////////////////////////////////////
437
halcanarydb0dcc72015-03-20 12:31:52 -0700438SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon, const SkBitmap& bitmap) {
halcanary792c80f2015-02-20 07:21:05 -0800439 SkASSERT(canon);
halcanarydb0dcc72015-03-20 12:31:52 -0700440 if (!SkColorTypeIsValid(bitmap.colorType()) ||
441 kUnknown_SkColorType == bitmap.colorType()) {
halcanary1b5c6042015-02-18 11:29:56 -0800442 return NULL;
443 }
halcanarydb0dcc72015-03-20 12:31:52 -0700444 SkBitmap copy;
445 const SkBitmap& bm = immutable_bitmap(bitmap, &copy);
halcanary1b5c6042015-02-18 11:29:56 -0800446 if (bm.drawsNothing()) {
447 return NULL;
448 }
halcanarydb0dcc72015-03-20 12:31:52 -0700449 if (SkPDFBitmap* canonBitmap = canon->findBitmap(bm)) {
450 return SkRef(canonBitmap);
halcanary1b5c6042015-02-18 11:29:56 -0800451 }
halcanarya8448bc2015-04-17 13:27:24 -0700452
453 if (bm.pixelRef() && bm.pixelRefOrigin().isZero() &&
454 bm.dimensions() == bm.pixelRef()->info().dimensions()) {
455 // Requires the bitmap to be backed by lazy pixels.
456 SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData());
halcanary96287f72015-05-07 11:46:59 -0700457 SkJFIFInfo info;
458 if (data && SkIsJFIF(data, &info)) {
459 bool yuv = info.fType == SkJFIFInfo::kYCbCr;
halcanary385fe4d2015-08-26 13:07:48 -0700460 SkPDFBitmap* pdfBitmap = new PDFJpegBitmap(bm, data, yuv);
halcanarya8448bc2015-04-17 13:27:24 -0700461 canon->addBitmap(pdfBitmap);
462 return pdfBitmap;
463 }
464 }
465
halcanary1b5c6042015-02-18 11:29:56 -0800466 SkPDFObject* smask = NULL;
467 if (!bm.isOpaque() && !SkBitmap::ComputeIsOpaque(bm)) {
halcanary385fe4d2015-08-26 13:07:48 -0700468 smask = new PDFAlphaBitmap(bm);
halcanary1b5c6042015-02-18 11:29:56 -0800469 }
halcanary385fe4d2015-08-26 13:07:48 -0700470 SkPDFBitmap* pdfBitmap = new PDFDefaultBitmap(bm, smask);
halcanary792c80f2015-02-20 07:21:05 -0800471 canon->addBitmap(pdfBitmap);
halcanary1b5c6042015-02-18 11:29:56 -0800472 return pdfBitmap;
473}