765016dcf2d0d06f05b25cca2747649513ad0ef5
[platform/upstream/libSkiaSharp.git] / src / pdf / SkPDFBitmap.cpp
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 "SkColorPriv.h"
9 #include "SkFlate.h"
10 #include "SkPDFBitmap.h"
11 #include "SkPDFCanon.h"
12 #include "SkPDFCatalog.h"
13 #include "SkStream.h"
14 #include "SkUnPreMultiply.h"
15
16 ////////////////////////////////////////////////////////////////////////////////
17
18 static void pdf_stream_begin(SkWStream* stream) {
19     static const char streamBegin[] = " stream\n";
20     stream->write(streamBegin, strlen(streamBegin));
21 }
22
23 static void pdf_stream_end(SkWStream* stream) {
24     static const char streamEnd[] = "\nendstream";
25     stream->write(streamEnd, strlen(streamEnd));
26 }
27
28 ////////////////////////////////////////////////////////////////////////////////
29
30 // write a single byte to a stream n times.
31 static void fill_stream(SkWStream* out, char value, size_t n) {
32     char buffer[4096];
33     memset(buffer, value, sizeof(buffer));
34     for (size_t i = 0; i < n / sizeof(buffer); ++i) {
35         out->write(buffer, sizeof(buffer));
36     }
37     out->write(buffer, n % sizeof(buffer));
38 }
39
40 // unpremultiply and extract R, G, B components.
41 static void pmcolor_to_rgb24(SkPMColor pmColor, uint8_t* rgb) {
42     uint32_t s = SkUnPreMultiply::GetScale(SkGetPackedA32(pmColor));
43     rgb[0] = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(pmColor));
44     rgb[1] = SkUnPreMultiply::ApplyScale(s, SkGetPackedG32(pmColor));
45     rgb[2] = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(pmColor));
46 }
47
48 /* It is necessary to average the color component of transparent
49    pixels with their surrounding neighbors since the PDF renderer may
50    separately re-sample the alpha and color channels when the image is
51    not displayed at its native resolution. Since an alpha of zero
52    gives no information about the color component, the pathological
53    case is a white image with sharp transparency bounds - the color
54    channel goes to black, and the should-be-transparent pixels are
55    rendered as grey because of the separate soft mask and color
56    resizing. e.g.: gm/bitmappremul.cpp */
57 static void get_neighbor_avg_color(const SkBitmap& bm,
58                                    int xOrig,
59                                    int yOrig,
60                                    uint8_t rgb[3]) {
61     SkASSERT(kN32_SkColorType == bm.colorType());
62     unsigned a = 0, r = 0, g = 0, b = 0;
63     // Clamp the range to the edge of the bitmap.
64     int ymin = SkTMax(0, yOrig - 1);
65     int ymax = SkTMin(yOrig + 1, bm.height() - 1);
66     int xmin = SkTMax(0, xOrig - 1);
67     int xmax = SkTMin(xOrig + 1, bm.width() - 1);
68     for (int y = ymin; y <= ymax; ++y) {
69         SkPMColor* scanline = bm.getAddr32(0, y);
70         for (int x = xmin; x <= xmax; ++x) {
71             SkPMColor pmColor = scanline[x];
72             a += SkGetPackedA32(pmColor);
73             r += SkGetPackedR32(pmColor);
74             g += SkGetPackedG32(pmColor);
75             b += SkGetPackedB32(pmColor);
76         }
77     }
78     if (a > 0) {
79         rgb[0] = SkToU8(255 * r / a);
80         rgb[1] = SkToU8(255 * g / a);
81         rgb[2] = SkToU8(255 * b / a);
82     } else {
83         rgb[0] = rgb[1] = rgb[2] = 0;
84     }
85 }
86
87 static size_t pixel_count(const SkBitmap& bm) {
88     return SkToSizeT(bm.width()) * SkToSizeT(bm.height());
89 }
90
91 static const SkBitmap& not4444(const SkBitmap& input, SkBitmap* copy) {
92     if (input.colorType() != kARGB_4444_SkColorType) {
93         return input;
94     }
95     // ARGB_4444 is rarely used, so we can do a wasteful tmp copy.
96     SkAssertResult(input.copyTo(copy, kN32_SkColorType));
97     copy->setImmutable();
98     return *copy;
99 }
100
101 static size_t pdf_color_component_count(SkColorType ct) {
102     switch (ct) {
103         case kN32_SkColorType:
104         case kRGB_565_SkColorType:
105         case kARGB_4444_SkColorType:
106             return 3;
107         case kAlpha_8_SkColorType:
108         case kIndex_8_SkColorType:
109         case kGray_8_SkColorType:
110             return 1;
111         case kUnknown_SkColorType:
112         default:
113             SkDEBUGFAIL("unexpected color type");
114             return 0;
115     }
116 }
117
118 static void bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) {
119     if (!bitmap.getPixels()) {
120         size_t size = pixel_count(bitmap) *
121                       pdf_color_component_count(bitmap.colorType());
122         fill_stream(out, '\x00', size);
123         return;
124     }
125     SkBitmap copy;
126     const SkBitmap& bm = not4444(bitmap, &copy);
127     SkAutoLockPixels autoLockPixels(bm);
128     switch (bm.colorType()) {
129         case kN32_SkColorType: {
130             SkASSERT(3 == pdf_color_component_count(bitmap.colorType()));
131             SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
132             for (int y = 0; y < bm.height(); ++y) {
133                 const SkPMColor* src = bm.getAddr32(0, y);
134                 uint8_t* dst = scanline.get();
135                 for (int x = 0; x < bm.width(); ++x) {
136                     SkPMColor color = *src++;
137                     U8CPU alpha = SkGetPackedA32(color);
138                     if (alpha != SK_AlphaTRANSPARENT) {
139                         pmcolor_to_rgb24(color, dst);
140                     } else {
141                         get_neighbor_avg_color(bm, x, y, dst);
142                     }
143                     dst += 3;
144                 }
145                 out->write(scanline.get(), 3 * bm.width());
146             }
147             return;
148         }
149         case kRGB_565_SkColorType: {
150             SkASSERT(3 == pdf_color_component_count(bitmap.colorType()));
151             SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
152             for (int y = 0; y < bm.height(); ++y) {
153                 const uint16_t* src = bm.getAddr16(0, y);
154                 uint8_t* dst = scanline.get();
155                 for (int x = 0; x < bm.width(); ++x) {
156                     U16CPU color565 = *src++;
157                     *dst++ = SkPacked16ToR32(color565);
158                     *dst++ = SkPacked16ToG32(color565);
159                     *dst++ = SkPacked16ToB32(color565);
160                 }
161                 out->write(scanline.get(), 3 * bm.width());
162             }
163             return;
164         }
165         case kAlpha_8_SkColorType:
166             SkASSERT(1 == pdf_color_component_count(bitmap.colorType()));
167             fill_stream(out, '\x00', pixel_count(bm));
168             return;
169         case kGray_8_SkColorType:
170         case kIndex_8_SkColorType:
171             SkASSERT(1 == pdf_color_component_count(bitmap.colorType()));
172             // these two formats need no transformation to serialize.
173             for (int y = 0; y < bm.height(); ++y) {
174                 out->write(bm.getAddr8(0, y), bm.width());
175             }
176             return;
177         case kUnknown_SkColorType:
178         case kARGB_4444_SkColorType:
179         default:
180             SkDEBUGFAIL("unexpected color type");
181     }
182 }
183
184 ////////////////////////////////////////////////////////////////////////////////
185
186 static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) {
187     if (!bitmap.getPixels()) {
188         fill_stream(out, '\xFF', pixel_count(bitmap));
189         return;
190     }
191     SkBitmap copy;
192     const SkBitmap& bm = not4444(bitmap, &copy);
193     SkAutoLockPixels autoLockPixels(bm);
194     switch (bm.colorType()) {
195         case kN32_SkColorType: {
196             SkAutoTMalloc<uint8_t> scanline(bm.width());
197             for (int y = 0; y < bm.height(); ++y) {
198                 uint8_t* dst = scanline.get();
199                 const SkPMColor* src = bm.getAddr32(0, y);
200                 for (int x = 0; x < bm.width(); ++x) {
201                     *dst++ = SkGetPackedA32(*src++);
202                 }
203                 out->write(scanline.get(), bm.width());
204             }
205             return;
206         }
207         case kAlpha_8_SkColorType:
208             for (int y = 0; y < bm.height(); ++y) {
209                 out->write(bm.getAddr8(0, y), bm.width());
210             }
211             return;
212         case kIndex_8_SkColorType: {
213             SkColorTable* ct = bm.getColorTable();
214             SkASSERT(ct);
215             SkAutoTMalloc<uint8_t> scanline(bm.width());
216             for (int y = 0; y < bm.height(); ++y) {
217                 uint8_t* dst = scanline.get();
218                 const uint8_t* src = bm.getAddr8(0, y);
219                 for (int x = 0; x < bm.width(); ++x) {
220                     *dst++ = SkGetPackedA32((*ct)[*src++]);
221                 }
222                 out->write(scanline.get(), bm.width());
223             }
224             return;
225         }
226         case kRGB_565_SkColorType:
227         case kGray_8_SkColorType:
228             SkDEBUGFAIL("color type has no alpha");
229             return;
230         case kARGB_4444_SkColorType:
231             SkDEBUGFAIL("4444 color type should have been converted to N32");
232             return;
233         case kUnknown_SkColorType:
234         default:
235             SkDEBUGFAIL("unexpected color type");
236     }
237 }
238
239 ////////////////////////////////////////////////////////////////////////////////
240
241 namespace {
242 // This SkPDFObject only outputs the alpha layer of the given bitmap.
243 class PDFAlphaBitmap : public SkPDFObject {
244 public:
245     PDFAlphaBitmap(const SkBitmap& bm) : fBitmap(bm) {}
246     ~PDFAlphaBitmap() {}
247     void emitObject(SkWStream*, SkPDFCatalog*) SK_OVERRIDE;
248
249 private:
250     const SkBitmap fBitmap;
251     void emitDict(SkWStream*, SkPDFCatalog*, size_t) const;
252 };
253
254 void PDFAlphaBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
255     SkAutoLockPixels autoLockPixels(fBitmap);
256     SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType ||
257              fBitmap.getColorTable());
258
259     // Write to a temporary buffer to get the compressed length.
260     SkDynamicMemoryWStream buffer;
261     SkDeflateWStream deflateWStream(&buffer);
262     bitmap_alpha_to_a8(fBitmap, &deflateWStream);
263     deflateWStream.finalize();  // call before detachAsStream().
264     SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
265
266     this->emitDict(stream, catalog, asset->getLength());
267     pdf_stream_begin(stream);
268     stream->writeStream(asset.get(), asset->getLength());
269     pdf_stream_end(stream);
270 }
271
272 void PDFAlphaBitmap::emitDict(SkWStream* stream,
273                               SkPDFCatalog* catalog,
274                               size_t length) const {
275     SkPDFDict pdfDict("XObject");
276     pdfDict.insertName("Subtype", "Image");
277     pdfDict.insertInt("Width", fBitmap.width());
278     pdfDict.insertInt("Height", fBitmap.height());
279     pdfDict.insertName("ColorSpace", "DeviceGray");
280     pdfDict.insertInt("BitsPerComponent", 8);
281     pdfDict.insertName("Filter", "FlateDecode");
282     pdfDict.insertInt("Length", length);
283     pdfDict.emitObject(stream, catalog);
284 }
285 }  // namespace
286
287 ////////////////////////////////////////////////////////////////////////////////
288
289 void SkPDFBitmap::addResources(SkPDFCatalog* catalog) const {
290     if (fSMask.get()) {
291         if (catalog->addObject(fSMask.get())) {
292             fSMask->addResources(catalog);
293         }
294     }
295 }
296
297 void SkPDFBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
298     SkAutoLockPixels autoLockPixels(fBitmap);
299     SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType ||
300              fBitmap.getColorTable());
301
302     // Write to a temporary buffer to get the compressed length.
303     SkDynamicMemoryWStream buffer;
304     SkDeflateWStream deflateWStream(&buffer);
305     bitmap_to_pdf_pixels(fBitmap, &deflateWStream);
306     deflateWStream.finalize();  // call before detachAsStream().
307     SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
308
309     this->emitDict(stream, catalog, asset->getLength());
310     pdf_stream_begin(stream);
311     stream->writeStream(asset.get(), asset->getLength());
312     pdf_stream_end(stream);
313 }
314
315 static 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;
343 }
344
345 void SkPDFBitmap::emitDict(SkWStream* stream,
346                            SkPDFCatalog* catalog,
347                            size_t length) const {
348     SkPDFDict pdfDict("XObject");
349     pdfDict.insertName("Subtype", "Image");
350     pdfDict.insertInt("Width", fBitmap.width());
351     pdfDict.insertInt("Height", fBitmap.height());
352     if (fBitmap.colorType() == kIndex_8_SkColorType) {
353         SkASSERT(1 == pdf_color_component_count(fBitmap.colorType()));
354         pdfDict.insert("ColorSpace", make_indexed_color_space(
355                                              fBitmap.getColorTable()))->unref();
356     } else if (1 == pdf_color_component_count(fBitmap.colorType())) {
357         pdfDict.insertName("ColorSpace", "DeviceGray");
358     } else {
359         pdfDict.insertName("ColorSpace", "DeviceRGB");
360     }
361     pdfDict.insertInt("BitsPerComponent", 8);
362     if (fSMask) {
363         pdfDict.insert("SMask", new SkPDFObjRef(fSMask))->unref();
364     }
365     pdfDict.insertName("Filter", "FlateDecode");
366     pdfDict.insertInt("Length", length);
367     pdfDict.emitObject(stream, catalog);
368 }
369
370 SkPDFBitmap::SkPDFBitmap(const SkBitmap& bm,
371                          SkPDFObject* smask)
372     : fBitmap(bm), fSMask(smask) {}
373
374 SkPDFBitmap::~SkPDFBitmap() {}
375
376 ////////////////////////////////////////////////////////////////////////////////
377
378 static const SkBitmap& immutable_bitmap(const SkBitmap& bm, SkBitmap* copy) {
379     if (bm.isImmutable()) {
380         return bm;
381     }
382     bm.copyTo(copy);
383     copy->setImmutable();
384     return *copy;
385 }
386
387 SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon, const SkBitmap& bitmap) {
388     SkASSERT(canon);
389     if (!SkColorTypeIsValid(bitmap.colorType()) ||
390         kUnknown_SkColorType == bitmap.colorType()) {
391         return NULL;
392     }
393     SkBitmap copy;
394     const SkBitmap& bm = immutable_bitmap(bitmap, &copy);
395     if (bm.drawsNothing()) {
396         return NULL;
397     }
398     if (SkPDFBitmap* canonBitmap = canon->findBitmap(bm)) {
399         return SkRef(canonBitmap);
400     }
401     SkPDFObject* smask = NULL;
402     if (!bm.isOpaque() && !SkBitmap::ComputeIsOpaque(bm)) {
403         smask = SkNEW_ARGS(PDFAlphaBitmap, (bm));
404     }
405     SkPDFBitmap* pdfBitmap = SkNEW_ARGS(SkPDFBitmap, (bm, smask));
406     canon->addBitmap(pdfBitmap);
407     return pdfBitmap;
408 }