blob: 3b0d38ce26ff769e8cb19b46fede5fb5aac77c21 [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"
mtkleine6cf9cb2015-02-26 13:25:05 -080010#include "SkFlate.h"
halcanarya8448bc2015-04-17 13:27:24 -070011#include "SkImageGenerator.h"
halcanary1b5c6042015-02-18 11:29:56 -080012#include "SkPDFBitmap.h"
13#include "SkPDFCanon.h"
halcanarya8448bc2015-04-17 13:27:24 -070014#include "SkPixelRef.h"
halcanary1b5c6042015-02-18 11:29:56 -080015#include "SkStream.h"
16#include "SkUnPreMultiply.h"
17
18////////////////////////////////////////////////////////////////////////////////
19
20static void pdf_stream_begin(SkWStream* stream) {
21 static const char streamBegin[] = " stream\n";
22 stream->write(streamBegin, strlen(streamBegin));
23}
24
25static void pdf_stream_end(SkWStream* stream) {
26 static const char streamEnd[] = "\nendstream";
27 stream->write(streamEnd, strlen(streamEnd));
28}
29
halcanarydb0dcc72015-03-20 12:31:52 -070030////////////////////////////////////////////////////////////////////////////////
halcanary1b5c6042015-02-18 11:29:56 -080031
halcanary1b5c6042015-02-18 11:29:56 -080032// write a single byte to a stream n times.
33static void fill_stream(SkWStream* out, char value, size_t n) {
34 char buffer[4096];
35 memset(buffer, value, sizeof(buffer));
halcanarydb0dcc72015-03-20 12:31:52 -070036 for (size_t i = 0; i < n / sizeof(buffer); ++i) {
37 out->write(buffer, sizeof(buffer));
halcanary1b5c6042015-02-18 11:29:56 -080038 }
halcanarydb0dcc72015-03-20 12:31:52 -070039 out->write(buffer, n % sizeof(buffer));
halcanary1b5c6042015-02-18 11:29:56 -080040}
41
halcanarydb0dcc72015-03-20 12:31:52 -070042// unpremultiply and extract R, G, B components.
43static void pmcolor_to_rgb24(SkPMColor pmColor, uint8_t* rgb) {
44 uint32_t s = SkUnPreMultiply::GetScale(SkGetPackedA32(pmColor));
45 rgb[0] = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(pmColor));
46 rgb[1] = SkUnPreMultiply::ApplyScale(s, SkGetPackedG32(pmColor));
47 rgb[2] = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(pmColor));
48}
49
50/* It is necessary to average the color component of transparent
51 pixels with their surrounding neighbors since the PDF renderer may
52 separately re-sample the alpha and color channels when the image is
53 not displayed at its native resolution. Since an alpha of zero
54 gives no information about the color component, the pathological
55 case is a white image with sharp transparency bounds - the color
56 channel goes to black, and the should-be-transparent pixels are
57 rendered as grey because of the separate soft mask and color
58 resizing. e.g.: gm/bitmappremul.cpp */
59static void get_neighbor_avg_color(const SkBitmap& bm,
60 int xOrig,
61 int yOrig,
62 uint8_t rgb[3]) {
63 SkASSERT(kN32_SkColorType == bm.colorType());
64 unsigned a = 0, r = 0, g = 0, b = 0;
65 // Clamp the range to the edge of the bitmap.
66 int ymin = SkTMax(0, yOrig - 1);
67 int ymax = SkTMin(yOrig + 1, bm.height() - 1);
68 int xmin = SkTMax(0, xOrig - 1);
69 int xmax = SkTMin(xOrig + 1, bm.width() - 1);
70 for (int y = ymin; y <= ymax; ++y) {
71 SkPMColor* scanline = bm.getAddr32(0, y);
72 for (int x = xmin; x <= xmax; ++x) {
73 SkPMColor pmColor = scanline[x];
74 a += SkGetPackedA32(pmColor);
75 r += SkGetPackedR32(pmColor);
76 g += SkGetPackedG32(pmColor);
77 b += SkGetPackedB32(pmColor);
halcanary1b5c6042015-02-18 11:29:56 -080078 }
79 }
halcanarydb0dcc72015-03-20 12:31:52 -070080 if (a > 0) {
81 rgb[0] = SkToU8(255 * r / a);
82 rgb[1] = SkToU8(255 * g / a);
83 rgb[2] = SkToU8(255 * b / a);
halcanary1b5c6042015-02-18 11:29:56 -080084 } else {
halcanarydb0dcc72015-03-20 12:31:52 -070085 rgb[0] = rgb[1] = rgb[2] = 0;
halcanary1b5c6042015-02-18 11:29:56 -080086 }
87}
88
halcanarydb0dcc72015-03-20 12:31:52 -070089static size_t pixel_count(const SkBitmap& bm) {
90 return SkToSizeT(bm.width()) * SkToSizeT(bm.height());
91}
92
93static const SkBitmap& not4444(const SkBitmap& input, SkBitmap* copy) {
94 if (input.colorType() != kARGB_4444_SkColorType) {
95 return input;
96 }
97 // ARGB_4444 is rarely used, so we can do a wasteful tmp copy.
98 SkAssertResult(input.copyTo(copy, kN32_SkColorType));
99 copy->setImmutable();
100 return *copy;
101}
102
103static size_t pdf_color_component_count(SkColorType ct) {
104 switch (ct) {
105 case kN32_SkColorType:
106 case kRGB_565_SkColorType:
107 case kARGB_4444_SkColorType:
108 return 3;
109 case kAlpha_8_SkColorType:
110 case kIndex_8_SkColorType:
111 case kGray_8_SkColorType:
112 return 1;
113 case kUnknown_SkColorType:
114 default:
115 SkDEBUGFAIL("unexpected color type");
116 return 0;
117 }
118}
119
120static void bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) {
121 if (!bitmap.getPixels()) {
122 size_t size = pixel_count(bitmap) *
123 pdf_color_component_count(bitmap.colorType());
124 fill_stream(out, '\x00', size);
halcanary1b5c6042015-02-18 11:29:56 -0800125 return;
126 }
halcanarydb0dcc72015-03-20 12:31:52 -0700127 SkBitmap copy;
128 const SkBitmap& bm = not4444(bitmap, &copy);
129 SkAutoLockPixels autoLockPixels(bm);
130 switch (bm.colorType()) {
131 case kN32_SkColorType: {
132 SkASSERT(3 == pdf_color_component_count(bitmap.colorType()));
133 SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
134 for (int y = 0; y < bm.height(); ++y) {
135 const SkPMColor* src = bm.getAddr32(0, y);
136 uint8_t* dst = scanline.get();
137 for (int x = 0; x < bm.width(); ++x) {
138 SkPMColor color = *src++;
139 U8CPU alpha = SkGetPackedA32(color);
140 if (alpha != SK_AlphaTRANSPARENT) {
141 pmcolor_to_rgb24(color, dst);
142 } else {
143 get_neighbor_avg_color(bm, x, y, dst);
144 }
145 dst += 3;
146 }
147 out->write(scanline.get(), 3 * bm.width());
halcanary1b5c6042015-02-18 11:29:56 -0800148 }
halcanarydb0dcc72015-03-20 12:31:52 -0700149 return;
halcanary1b5c6042015-02-18 11:29:56 -0800150 }
halcanarydb0dcc72015-03-20 12:31:52 -0700151 case kRGB_565_SkColorType: {
152 SkASSERT(3 == pdf_color_component_count(bitmap.colorType()));
153 SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
154 for (int y = 0; y < bm.height(); ++y) {
155 const uint16_t* src = bm.getAddr16(0, y);
156 uint8_t* dst = scanline.get();
157 for (int x = 0; x < bm.width(); ++x) {
158 U16CPU color565 = *src++;
159 *dst++ = SkPacked16ToR32(color565);
160 *dst++ = SkPacked16ToG32(color565);
161 *dst++ = SkPacked16ToB32(color565);
162 }
163 out->write(scanline.get(), 3 * bm.width());
164 }
165 return;
166 }
167 case kAlpha_8_SkColorType:
168 SkASSERT(1 == pdf_color_component_count(bitmap.colorType()));
169 fill_stream(out, '\x00', pixel_count(bm));
170 return;
171 case kGray_8_SkColorType:
172 case kIndex_8_SkColorType:
173 SkASSERT(1 == pdf_color_component_count(bitmap.colorType()));
174 // these two formats need no transformation to serialize.
175 for (int y = 0; y < bm.height(); ++y) {
176 out->write(bm.getAddr8(0, y), bm.width());
177 }
178 return;
179 case kUnknown_SkColorType:
180 case kARGB_4444_SkColorType:
181 default:
182 SkDEBUGFAIL("unexpected color type");
halcanary1b5c6042015-02-18 11:29:56 -0800183 }
184}
185
halcanarydb0dcc72015-03-20 12:31:52 -0700186////////////////////////////////////////////////////////////////////////////////
187
188static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) {
189 if (!bitmap.getPixels()) {
190 fill_stream(out, '\xFF', pixel_count(bitmap));
halcanary1b5c6042015-02-18 11:29:56 -0800191 return;
192 }
halcanarydb0dcc72015-03-20 12:31:52 -0700193 SkBitmap copy;
194 const SkBitmap& bm = not4444(bitmap, &copy);
195 SkAutoLockPixels autoLockPixels(bm);
196 switch (bm.colorType()) {
197 case kN32_SkColorType: {
198 SkAutoTMalloc<uint8_t> scanline(bm.width());
199 for (int y = 0; y < bm.height(); ++y) {
200 uint8_t* dst = scanline.get();
201 const SkPMColor* src = bm.getAddr32(0, y);
202 for (int x = 0; x < bm.width(); ++x) {
203 *dst++ = SkGetPackedA32(*src++);
204 }
205 out->write(scanline.get(), bm.width());
206 }
207 return;
halcanary1b5c6042015-02-18 11:29:56 -0800208 }
halcanarydb0dcc72015-03-20 12:31:52 -0700209 case kAlpha_8_SkColorType:
210 for (int y = 0; y < bm.height(); ++y) {
211 out->write(bm.getAddr8(0, y), bm.width());
212 }
213 return;
214 case kIndex_8_SkColorType: {
215 SkColorTable* ct = bm.getColorTable();
216 SkASSERT(ct);
217 SkAutoTMalloc<uint8_t> scanline(bm.width());
218 for (int y = 0; y < bm.height(); ++y) {
219 uint8_t* dst = scanline.get();
220 const uint8_t* src = bm.getAddr8(0, y);
221 for (int x = 0; x < bm.width(); ++x) {
222 *dst++ = SkGetPackedA32((*ct)[*src++]);
223 }
224 out->write(scanline.get(), bm.width());
225 }
226 return;
227 }
228 case kRGB_565_SkColorType:
229 case kGray_8_SkColorType:
230 SkDEBUGFAIL("color type has no alpha");
231 return;
232 case kARGB_4444_SkColorType:
233 SkDEBUGFAIL("4444 color type should have been converted to N32");
234 return;
235 case kUnknown_SkColorType:
236 default:
237 SkDEBUGFAIL("unexpected color type");
halcanary1b5c6042015-02-18 11:29:56 -0800238 }
239}
240
241////////////////////////////////////////////////////////////////////////////////
242
243namespace {
244// This SkPDFObject only outputs the alpha layer of the given bitmap.
245class PDFAlphaBitmap : public SkPDFObject {
246public:
247 PDFAlphaBitmap(const SkBitmap& bm) : fBitmap(bm) {}
248 ~PDFAlphaBitmap() {}
halcanary37c46ca2015-03-31 12:30:20 -0700249 void emitObject(SkWStream*,
250 const SkPDFObjNumMap&,
251 const SkPDFSubstituteMap&) override;
halcanary1b5c6042015-02-18 11:29:56 -0800252
253private:
254 const SkBitmap fBitmap;
halcanary1b5c6042015-02-18 11:29:56 -0800255};
256
halcanary37c46ca2015-03-31 12:30:20 -0700257void PDFAlphaBitmap::emitObject(SkWStream* stream,
258 const SkPDFObjNumMap& objNumMap,
259 const SkPDFSubstituteMap& substitutes) {
halcanary1b5c6042015-02-18 11:29:56 -0800260 SkAutoLockPixels autoLockPixels(fBitmap);
halcanarydb0dcc72015-03-20 12:31:52 -0700261 SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType ||
262 fBitmap.getColorTable());
halcanary1b5c6042015-02-18 11:29:56 -0800263
halcanary1b5c6042015-02-18 11:29:56 -0800264 // Write to a temporary buffer to get the compressed length.
265 SkDynamicMemoryWStream buffer;
266 SkDeflateWStream deflateWStream(&buffer);
halcanarydb0dcc72015-03-20 12:31:52 -0700267 bitmap_alpha_to_a8(fBitmap, &deflateWStream);
halcanary1b5c6042015-02-18 11:29:56 -0800268 deflateWStream.finalize(); // call before detachAsStream().
269 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
270
halcanary1b5c6042015-02-18 11:29:56 -0800271 SkPDFDict pdfDict("XObject");
272 pdfDict.insertName("Subtype", "Image");
273 pdfDict.insertInt("Width", fBitmap.width());
274 pdfDict.insertInt("Height", fBitmap.height());
275 pdfDict.insertName("ColorSpace", "DeviceGray");
276 pdfDict.insertInt("BitsPerComponent", 8);
halcanarydb0dcc72015-03-20 12:31:52 -0700277 pdfDict.insertName("Filter", "FlateDecode");
halcanary37c46ca2015-03-31 12:30:20 -0700278 pdfDict.insertInt("Length", asset->getLength());
279 pdfDict.emitObject(stream, objNumMap, substitutes);
280
281 pdf_stream_begin(stream);
282 stream->writeStream(asset.get(), asset->getLength());
283 pdf_stream_end(stream);
halcanary1b5c6042015-02-18 11:29:56 -0800284}
285} // namespace
286
287////////////////////////////////////////////////////////////////////////////////
288
halcanarya8448bc2015-04-17 13:27:24 -0700289namespace {
290class PDFDefaultBitmap : public SkPDFBitmap {
291public:
292 const SkAutoTUnref<SkPDFObject> fSMask;
293 void emitObject(SkWStream*,
294 const SkPDFObjNumMap&,
295 const SkPDFSubstituteMap&) override;
296 void addResources(SkPDFObjNumMap*,
297 const SkPDFSubstituteMap&) const override;
298 PDFDefaultBitmap(const SkBitmap& bm, SkPDFObject* smask)
299 : SkPDFBitmap(bm), fSMask(smask) {}
300};
301} // namespace
302
303void PDFDefaultBitmap::addResources(
304 SkPDFObjNumMap* catalog,
305 const SkPDFSubstituteMap& substitutes) const {
halcanary1b5c6042015-02-18 11:29:56 -0800306 if (fSMask.get()) {
halcanary37c46ca2015-03-31 12:30:20 -0700307 SkPDFObject* obj = substitutes.getSubstitute(fSMask.get());
308 SkASSERT(obj);
309 if (catalog->addObject(obj)) {
310 obj->addResources(catalog, substitutes);
halcanarydb0dcc72015-03-20 12:31:52 -0700311 }
halcanary1b5c6042015-02-18 11:29:56 -0800312 }
313}
314
halcanarydb0dcc72015-03-20 12:31:52 -0700315static SkPDFArray* make_indexed_color_space(const SkColorTable* table) {
316 SkPDFArray* result = SkNEW(SkPDFArray);
317 result->reserve(4);
318 result->appendName("Indexed");
319 result->appendName("DeviceRGB");
320 SkASSERT(table);
321 if (table->count() < 1) {
322 result->appendInt(0);
323 char shortTableArray[3] = {0, 0, 0};
324 SkString tableString(shortTableArray, SK_ARRAY_COUNT(shortTableArray));
325 result->append(new SkPDFString(tableString))->unref();
326 return result;
327 }
328 result->appendInt(table->count() - 1); // maximum color index.
329
330 // Potentially, this could be represented in fewer bytes with a stream.
331 // Max size as a string is 1.5k.
332 char tableArray[256 * 3];
333 SkASSERT(3u * table->count() <= SK_ARRAY_COUNT(tableArray));
334 uint8_t* tablePtr = reinterpret_cast<uint8_t*>(tableArray);
335 const SkPMColor* colors = table->readColors();
336 for (int i = 0; i < table->count(); i++) {
337 pmcolor_to_rgb24(colors[i], tablePtr);
338 tablePtr += 3;
339 }
340 SkString tableString(tableArray, 3 * table->count());
341 result->append(new SkPDFString(tableString))->unref();
342 return result;
halcanary1b5c6042015-02-18 11:29:56 -0800343}
344
halcanarya8448bc2015-04-17 13:27:24 -0700345void PDFDefaultBitmap::emitObject(SkWStream* stream,
346 const SkPDFObjNumMap& objNumMap,
347 const SkPDFSubstituteMap& substitutes) {
halcanary37c46ca2015-03-31 12:30:20 -0700348 SkAutoLockPixels autoLockPixels(fBitmap);
349 SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType ||
350 fBitmap.getColorTable());
351
352 // Write to a temporary buffer to get the compressed length.
353 SkDynamicMemoryWStream buffer;
354 SkDeflateWStream deflateWStream(&buffer);
355 bitmap_to_pdf_pixels(fBitmap, &deflateWStream);
356 deflateWStream.finalize(); // call before detachAsStream().
357 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
358
halcanary1b5c6042015-02-18 11:29:56 -0800359 SkPDFDict pdfDict("XObject");
360 pdfDict.insertName("Subtype", "Image");
361 pdfDict.insertInt("Width", fBitmap.width());
362 pdfDict.insertInt("Height", fBitmap.height());
halcanarydb0dcc72015-03-20 12:31:52 -0700363 if (fBitmap.colorType() == kIndex_8_SkColorType) {
364 SkASSERT(1 == pdf_color_component_count(fBitmap.colorType()));
365 pdfDict.insert("ColorSpace", make_indexed_color_space(
366 fBitmap.getColorTable()))->unref();
367 } else if (1 == pdf_color_component_count(fBitmap.colorType())) {
368 pdfDict.insertName("ColorSpace", "DeviceGray");
369 } else {
370 pdfDict.insertName("ColorSpace", "DeviceRGB");
371 }
halcanary1b5c6042015-02-18 11:29:56 -0800372 pdfDict.insertInt("BitsPerComponent", 8);
373 if (fSMask) {
374 pdfDict.insert("SMask", new SkPDFObjRef(fSMask))->unref();
375 }
halcanarydb0dcc72015-03-20 12:31:52 -0700376 pdfDict.insertName("Filter", "FlateDecode");
halcanary37c46ca2015-03-31 12:30:20 -0700377 pdfDict.insertInt("Length", asset->getLength());
halcanarya8448bc2015-04-17 13:27:24 -0700378 pdfDict.emitObject(stream, objNumMap, substitutes);
halcanary37c46ca2015-03-31 12:30:20 -0700379
380 pdf_stream_begin(stream);
381 stream->writeStream(asset.get(), asset->getLength());
382 pdf_stream_end(stream);
halcanary1b5c6042015-02-18 11:29:56 -0800383}
384
halcanary1b5c6042015-02-18 11:29:56 -0800385////////////////////////////////////////////////////////////////////////////////
halcanarydb0dcc72015-03-20 12:31:52 -0700386
387static const SkBitmap& immutable_bitmap(const SkBitmap& bm, SkBitmap* copy) {
388 if (bm.isImmutable()) {
389 return bm;
halcanary1b5c6042015-02-18 11:29:56 -0800390 }
halcanarydb0dcc72015-03-20 12:31:52 -0700391 bm.copyTo(copy);
392 copy->setImmutable();
393 return *copy;
halcanary1b5c6042015-02-18 11:29:56 -0800394}
395
halcanarya8448bc2015-04-17 13:27:24 -0700396namespace {
397/**
398 * This PDFObject assumes that its constructor was handed YUV JFIF
399 * Jpeg-encoded data that can be directly embedded into a PDF.
400 */
401class PDFJpegBitmap : public SkPDFBitmap {
402public:
403 SkAutoTUnref<SkData> fData;
404 PDFJpegBitmap(const SkBitmap& bm, SkData* data)
405 : SkPDFBitmap(bm), fData(SkRef(data)) {}
406 void emitObject(SkWStream*,
407 const SkPDFObjNumMap&,
408 const SkPDFSubstituteMap&) override;
409};
410
411void PDFJpegBitmap::emitObject(SkWStream* stream,
412 const SkPDFObjNumMap& objNumMap,
413 const SkPDFSubstituteMap& substituteMap) {
414 SkPDFDict pdfDict("XObject");
415 pdfDict.insertName("Subtype", "Image");
416 pdfDict.insertInt("Width", fBitmap.width());
417 pdfDict.insertInt("Height", fBitmap.height());
418 pdfDict.insertName("ColorSpace", "DeviceRGB");
419 pdfDict.insertInt("BitsPerComponent", 8);
420 pdfDict.insertName("Filter", "DCTDecode");
421 pdfDict.insertInt("ColorTransform", 0);
422 pdfDict.insertInt("Length", SkToInt(fData->size()));
423 pdfDict.emitObject(stream, objNumMap, substituteMap);
424 pdf_stream_begin(stream);
425 stream->write(fData->data(), fData->size());
426 pdf_stream_end(stream);
427}
428} // namespace
429
430////////////////////////////////////////////////////////////////////////////////
431
432static bool is_jfif_yuv_jpeg(SkData* data) {
433 const uint8_t bytesZeroToThree[] = {0xFF, 0xD8, 0xFF, 0xE0};
434 const uint8_t bytesSixToTen[] = {'J', 'F', 'I', 'F', 0};
435 // 0 1 2 3 4 5 6 7 8 9 10
436 // FF D8 FF E0 ?? ?? 'J' 'F' 'I' 'F' 00 ...
437 if (data->size() < 11 ||
438 0 != memcmp(data->bytes(), bytesZeroToThree,
439 sizeof(bytesZeroToThree)) ||
440 0 != memcmp(data->bytes() + 6, bytesSixToTen, sizeof(bytesSixToTen))) {
441 return false;
442 }
443 SkAutoTDelete<SkImageGenerator> gen(SkImageGenerator::NewFromData(data));
444 SkISize sizes[3];
445 // Only YUV JPEG allows access to YUV planes.
446 return gen && gen->getYUV8Planes(sizes, NULL, NULL, NULL);
447}
448
halcanarydb0dcc72015-03-20 12:31:52 -0700449SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon, const SkBitmap& bitmap) {
halcanary792c80f2015-02-20 07:21:05 -0800450 SkASSERT(canon);
halcanarydb0dcc72015-03-20 12:31:52 -0700451 if (!SkColorTypeIsValid(bitmap.colorType()) ||
452 kUnknown_SkColorType == bitmap.colorType()) {
halcanary1b5c6042015-02-18 11:29:56 -0800453 return NULL;
454 }
halcanarydb0dcc72015-03-20 12:31:52 -0700455 SkBitmap copy;
456 const SkBitmap& bm = immutable_bitmap(bitmap, &copy);
halcanary1b5c6042015-02-18 11:29:56 -0800457 if (bm.drawsNothing()) {
458 return NULL;
459 }
halcanarydb0dcc72015-03-20 12:31:52 -0700460 if (SkPDFBitmap* canonBitmap = canon->findBitmap(bm)) {
461 return SkRef(canonBitmap);
halcanary1b5c6042015-02-18 11:29:56 -0800462 }
halcanarya8448bc2015-04-17 13:27:24 -0700463
464 if (bm.pixelRef() && bm.pixelRefOrigin().isZero() &&
465 bm.dimensions() == bm.pixelRef()->info().dimensions()) {
466 // Requires the bitmap to be backed by lazy pixels.
467 SkAutoTUnref<SkData> data(bm.pixelRef()->refEncodedData());
468 if (data && is_jfif_yuv_jpeg(data)) {
469 SkPDFBitmap* pdfBitmap = SkNEW_ARGS(PDFJpegBitmap, (bm, data));
470 canon->addBitmap(pdfBitmap);
471 return pdfBitmap;
472 }
473 }
474
halcanary1b5c6042015-02-18 11:29:56 -0800475 SkPDFObject* smask = NULL;
476 if (!bm.isOpaque() && !SkBitmap::ComputeIsOpaque(bm)) {
halcanary1b5c6042015-02-18 11:29:56 -0800477 smask = SkNEW_ARGS(PDFAlphaBitmap, (bm));
478 }
halcanarya8448bc2015-04-17 13:27:24 -0700479 SkPDFBitmap* pdfBitmap = SkNEW_ARGS(PDFDefaultBitmap, (bm, smask));
halcanary792c80f2015-02-20 07:21:05 -0800480 canon->addBitmap(pdfBitmap);
halcanary1b5c6042015-02-18 11:29:56 -0800481 return pdfBitmap;
482}