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

Side by Side Diff: src/pdf/SkPDFBitmap.cpp

Issue 950633003: PDF: remove last use of SkPDFImage (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: 2015-02-21 (Saturday) 10:55:02 EST Created 5 years, 10 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 unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkColorPriv.h" 8 #include "SkColorPriv.h"
9 #include "SkDeflateWStream.h" 9 #include "SkDeflateWStream.h"
10 #include "SkPDFBitmap.h" 10 #include "SkPDFBitmap.h"
11 #include "SkPDFCanon.h" 11 #include "SkPDFCanon.h"
12 #include "SkPDFCatalog.h" 12 #include "SkPDFCatalog.h"
13 #include "SkPDFDocument.h" 13 #include "SkPDFDocument.h"
14 #include "SkStream.h" 14 #include "SkStream.h"
15 #include "SkUnPreMultiply.h" 15 #include "SkUnPreMultiply.h"
16 16
17 //////////////////////////////////////////////////////////////////////////////// 17 ////////////////////////////////////////////////////////////////////////////////
18 18
19 static void pdf_stream_begin(SkWStream* stream) { 19 static void pdf_stream_begin(SkWStream* stream) {
20 static const char streamBegin[] = " stream\n"; 20 static const char streamBegin[] = " stream\n";
21 stream->write(streamBegin, strlen(streamBegin)); 21 stream->write(streamBegin, strlen(streamBegin));
22 } 22 }
23 23
24 static void pdf_stream_end(SkWStream* stream) { 24 static void pdf_stream_end(SkWStream* stream) {
25 static const char streamEnd[] = "\nendstream"; 25 static const char streamEnd[] = "\nendstream";
26 stream->write(streamEnd, strlen(streamEnd)); 26 stream->write(streamEnd, strlen(streamEnd));
27 } 27 }
28 28
29 static size_t pixel_count(const SkBitmap& bm) { 29 ////////////////////////////////////////////////////////////////////////////////
30 return SkToSizeT(bm.width()) * SkToSizeT(bm.height());
31 }
32 30
33 // write a single byte to a stream n times. 31 // write a single byte to a stream n times.
34 static void fill_stream(SkWStream* out, char value, size_t n) { 32 static void fill_stream(SkWStream* out, char value, size_t n) {
35 char buffer[4096]; 33 char buffer[4096];
36 memset(buffer, value, sizeof(buffer)); 34 memset(buffer, value, sizeof(buffer));
37 while (n) { 35 while (n) {
38 size_t k = SkTMin(n, sizeof(buffer)); 36 size_t k = SkTMin(n, sizeof(buffer));
39 out->write(buffer, k); 37 out->write(buffer, k);
40 n -= k; 38 n -= k;
41 } 39 }
42 } 40 }
43 41
44 static SkPMColor get_pmcolor_neighbor_avg_color(const SkBitmap& bitmap, 42 static void to_rgb24(SkPMColor color, U8CPU alpha, uint8_t* rgb) {
mtklein 2015/02/23 14:26:52 This seems weird. Why do we pass alpha twice? It
hal.canary 2015/03/20 01:09:45 I didn't want to recalculate it, but that was too
45 int xOrig, 43 uint32_t s = SkUnPreMultiply::GetScale(alpha);
46 int yOrig) { 44 rgb[0] = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(color));
47 SkASSERT(kN32_SkColorType == bitmap.colorType()); 45 rgb[1] = SkUnPreMultiply::ApplyScale(s, SkGetPackedG32(color));
48 SkASSERT(bitmap.getPixels()); 46 rgb[2] = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(color));
49 uint8_t count = 0; 47 }
50 unsigned r = 0; 48
51 unsigned g = 0; 49 static void to_rgb24(SkPMColor color, uint8_t* rgb) {
mtklein 2015/02/23 14:26:52 This is for the alpha == 0xFF case? Let's at leas
hal.canary 2015/03/20 01:09:45 this is removed.
52 unsigned b = 0; 50 rgb[0] = SkGetPackedR32(color);
53 for (int y = yOrig - 1; y <= yOrig + 1; ++y) { 51 rgb[1] = SkGetPackedG32(color);
54 if (y < 0 || y >= bitmap.height()) { 52 rgb[2] = SkGetPackedB32(color);
55 continue; 53 }
56 } 54
57 uint32_t* src = bitmap.getAddr32(0, y); 55 static SkPMColor get_pmcolor(const SkBitmap& bm, int x, int y) {
58 for (int x = xOrig - 1; x <= xOrig + 1; ++x) { 56 switch (bm.colorType()) {
59 if (x < 0 || x >= bitmap.width()) { 57 case kARGB_4444_SkColorType:
60 continue; 58 return SkPixel4444ToPixel32(*(bm.getAddr16(x, y)));
61 } 59 case kN32_SkColorType:
62 SkPMColor pmColor = src[x]; 60 return *(bm.getAddr32(x, y));
61 default:
62 SkASSERT(false);
mtklein 2015/02/23 14:26:52 // We only use this to sample around transparent p
hal.canary 2015/03/20 01:09:46 Done.
63 return 0;
64 }
65 }
66
67 /* It is necessary to average the color component of transparent
68 pixels with their surrounding neighbors since the PDF renderer may
69 separately re-sample the alpha and color channels when the image is
70 not displayed at its native resolution. Since an alpha of zero
71 gives no information about the color component, the pathological
72 case is a white image with sharp transparency bounds - the color
73 channel goes to black, and the should-be-transparent pixels are
74 rendered as grey because of the separate soft mask and color
75 resizing. e.g.: gm/bitmappremul.cpp */
76 static SkPMColor get_neighbor_avg_color(const SkBitmap& bm,
77 int xOrig,
78 int yOrig) {
79 SkASSERT(kARGB_4444_SkColorType == bm.colorType() ||
80 kN32_SkColorType == bm.colorType());
81 uint8_t n = 0;
mtklein 2015/02/23 14:26:53 This seems... unnecessarily precise? unsigned see
hal.canary 2015/03/20 01:09:45 Done.
82 unsigned r = 0, g = 0, b = 0;
83 int yrange[2] = {SkTMax(yOrig - 1, 0), SkTMin(bm.height(), yOrig + 2)};
mtklein 2015/02/23 14:26:53 Might want to swap the orders of the arguments to
hal.canary 2015/03/20 01:09:45 <= is unexpected in C.
84 int xrange[2] = {SkTMax(xOrig - 1, 0), SkTMin(bm.width(), xOrig + 2)};
85 for (int y = yrange[0]; y < yrange[1]; ++y) {
86 for (int x = xrange[0]; x < xrange[1]; ++x) {
mtklein 2015/02/23 14:26:53 Seems like when there are a lot of transparent pix
hal.canary 2015/03/20 01:09:45 I thinks so. I tried to think of how to do this i
87 SkPMColor pmColor = get_pmcolor(bm, x, y);
63 U8CPU alpha = SkGetPackedA32(pmColor); 88 U8CPU alpha = SkGetPackedA32(pmColor);
64 if (alpha != SK_AlphaTRANSPARENT) { 89 if (alpha != SK_AlphaTRANSPARENT) {
65 uint32_t s = SkUnPreMultiply::GetScale(alpha); 90 uint8_t rgb[3];
66 r += SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(pmColor)); 91 to_rgb24(pmColor, alpha, rgb);
67 g += SkUnPreMultiply::ApplyScale(s, SkGetPackedG32(pmColor)); 92 r += rgb[0];
68 b += SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(pmColor)); 93 g += rgb[1];
69 ++count; 94 b += rgb[2];
70 } 95 ++n;
71 } 96 }
72 } 97 }
73 if (count == 0) { 98 }
74 return SkPackARGB32NoCheck(SK_AlphaOPAQUE, 0, 0, 0); 99 return (n > 0) ? SkPackARGB32NoCheck(SK_AlphaOPAQUE, r / n, g / n, b / n)
100 : SkPackARGB32NoCheck(SK_AlphaOPAQUE, 0, 0, 0);
101 }
102
103 static void convert_pixel(
104 const SkBitmap& bm, int x, int y, SkPMColor color, uint8_t* dst) {
105 U8CPU alpha = SkGetPackedA32(color);
106 if (alpha != SK_AlphaTRANSPARENT) {
107 to_rgb24(color, alpha, dst);
75 } else { 108 } else {
76 return SkPackARGB32NoCheck( 109 to_rgb24(get_neighbor_avg_color(bm, x, y), dst);
77 SK_AlphaOPAQUE, r / count, g / count, b / count); 110 }
78 } 111 }
79 } 112
80 113 static void convert_scanline(const SkBitmap& bm, int y, uint8_t* dst) {
81 static void pmcolor_to_rgb24(const SkBitmap& bm, SkWStream* out) { 114 switch (bm.colorType()) {
82 SkASSERT(kN32_SkColorType == bm.colorType()); 115 case kARGB_4444_SkColorType: {
116 const uint16_t* src = bm.getAddr16(0, y);
117 for (int x = 0; x < bm.width(); ++x) {
118 convert_pixel(bm, x, y, SkPixel4444ToPixel32(*src++), dst);
119 dst += 3;
120 }
121 return;
122 }
123 case kN32_SkColorType: {
124 const SkPMColor* src = bm.getAddr32(0, y);
125 for (int x = 0; x < bm.width(); ++x) {
126 convert_pixel(bm, x, y, *src++, dst);
127 dst += 3;
128 }
129 return;
130 }
131 case kRGB_565_SkColorType: {
132 const uint16_t* src = bm.getAddr16(0, y);
133 for (int x = 0; x < bm.width(); ++x) {
134 U16CPU color565 = *src++;
135 *dst++ = SkPacked16ToR32(color565);
136 *dst++ = SkPacked16ToG32(color565);
137 *dst++ = SkPacked16ToB32(color565);
138 }
139 return;
140 }
141 default:
142 SkASSERT(false);
143 }
144 }
145
146 static size_t pixel_count(const SkBitmap& bm) {
147 return SkToSizeT(bm.width()) * SkToSizeT(bm.height());
148 }
149
150 static void bitmap_to_rgb24(const SkBitmap& bm, SkWStream* out) {
83 if (!bm.getPixels()) { 151 if (!bm.getPixels()) {
84 fill_stream(out, '\xFF', 3 * pixel_count(bm)); 152 fill_stream(out, '\xFF', 3 * pixel_count(bm));
85 return; 153 return;
86 } 154 }
87 size_t scanlineLength = 3 * bm.width(); 155 switch (bm.colorType()) {
88 SkAutoTMalloc<uint8_t> scanline(scanlineLength); 156 case kN32_SkColorType:
157 case kARGB_4444_SkColorType:
158 case kRGB_565_SkColorType: {
159 SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
160 for (int y = 0; y < bm.height(); ++y) {
161 convert_scanline(bm, y, scanline.get());
162 out->write(scanline.get(), 3 * bm.width());
163 }
164 return;
165 }
166 case kAlpha_8_SkColorType:
167 fill_stream(out, '\x00', 3 * pixel_count(bm));
168 return;
169 case kIndex_8_SkColorType:
170 for (int y = 0; y < bm.height(); ++y) {
171 out->write(bm.getAddr8(0, y), bm.width());
172 } // not actually rgb24 format.
mtklein 2015/02/23 14:26:53 Let's explain what it is rather than what it's not
hal.canary 2015/03/20 01:09:45 Done.
173 return;
174 case kUnknown_SkColorType:
175 default:
176 SkASSERT(false);
177 return;
178 }
179 }
180
181 ////////////////////////////////////////////////////////////////////////////////
182
183 static void convert_scanline_alpha(const SkBitmap& bm, int y, uint8_t* dst) {
184 switch (bm.colorType()) {
185 case kARGB_4444_SkColorType: {
186 const uint16_t* src = bm.getAddr16(0, y);
187 for (int x = 0; x < bm.width(); ++x) {
188 *dst++ = SkPacked4444ToA32(*src++);
189 }
190 return;
191 }
192 case kN32_SkColorType: {
193 const SkPMColor* src = bm.getAddr32(0, y);
194 for (int x = 0; x < bm.width(); ++x) {
195 *dst++ = SkGetPackedA32(*src++);
196 }
197 return;
198 }
199 default:
200 SkASSERT(false);
201 }
202 }
203
204 static void index8_alpha_to_a8(const SkBitmap& bm, SkWStream* out) {
205 SkASSERT(kIndex_8_SkColorType == bm.colorType());
206 SkColorTable* ct = bm.getColorTable();
207 if (!ct) {
208 fill_stream(out, '\x00', pixel_count(bm));
mtklein 2015/02/23 14:26:53 It seems like it's worth promoting this up to an a
hal.canary 2015/03/20 01:09:45 Done.
209 return;
210 }
211 SkAutoTMalloc<uint8_t> scanline(bm.width());
89 for (int y = 0; y < bm.height(); ++y) { 212 for (int y = 0; y < bm.height(); ++y) {
90 uint8_t* dst = scanline.get(); 213 uint8_t* dst = scanline.get();
91 const SkPMColor* src = bm.getAddr32(0, y); 214 const uint8_t* src = bm.getAddr8(0, y);
92 for (int x = 0; x < bm.width(); ++x) { 215 for (int x = 0; x < bm.width(); ++x) {
93 SkPMColor color = *src++; 216 *dst++ = SkGetPackedA32((*ct)[*src++]);
94 U8CPU alpha = SkGetPackedA32(color); 217 }
95 if (alpha != SK_AlphaTRANSPARENT) { 218 out->write(scanline.get(), bm.width());
96 uint32_t s = SkUnPreMultiply::GetScale(alpha); 219 }
97 *dst++ = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(color)); 220 }
98 *dst++ = SkUnPreMultiply::ApplyScale(s, SkGetPackedG32(color)); 221
99 *dst++ = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(color)); 222 static void bitmap_alpha_to_a8(const SkBitmap& bm, SkWStream* out) {
100 } else {
101 /* It is necessary to average the color component of
102 transparent pixels with their surrounding neighbors
103 since the PDF renderer may separately re-sample the
104 alpha and color channels when the image is not
105 displayed at its native resolution. Since an alpha
106 of zero gives no information about the color
107 component, the pathological case is a white image
108 with sharp transparency bounds - the color channel
109 goes to black, and the should-be-transparent pixels
110 are rendered as grey because of the separate soft
111 mask and color resizing. e.g.: gm/bitmappremul.cpp */
112 color = get_pmcolor_neighbor_avg_color(bm, x, y);
113 *dst++ = SkGetPackedR32(color);
114 *dst++ = SkGetPackedG32(color);
115 *dst++ = SkGetPackedB32(color);
116 }
117 }
118 out->write(scanline.get(), scanlineLength);
119 }
120 }
121
122 static void pmcolor_alpha_to_a8(const SkBitmap& bm, SkWStream* out) {
123 SkASSERT(kN32_SkColorType == bm.colorType());
124 if (!bm.getPixels()) { 223 if (!bm.getPixels()) {
125 fill_stream(out, '\xFF', pixel_count(bm)); 224 fill_stream(out, '\xFF', pixel_count(bm));
126 return; 225 return;
127 } 226 }
128 size_t scanlineLength = bm.width(); 227 switch (bm.colorType()) {
129 SkAutoTMalloc<uint8_t> scanline(scanlineLength); 228 case kN32_SkColorType:
130 for (int y = 0; y < bm.height(); ++y) { 229 case kARGB_4444_SkColorType: {
131 uint8_t* dst = scanline.get(); 230 SkAutoTMalloc<uint8_t> scanline(bm.width());
132 const SkPMColor* src = bm.getAddr32(0, y); 231 for (int y = 0; y < bm.height(); ++y) {
133 for (int x = 0; x < bm.width(); ++x) { 232 convert_scanline_alpha(bm, y, scanline.get());
134 *dst++ = SkGetPackedA32(*src++); 233 out->write(scanline.get(), bm.width());
135 } 234 }
136 out->write(scanline.get(), scanlineLength); 235 return;
137 } 236 }
138 } 237 case kAlpha_8_SkColorType:
139 238 for (int y = 0; y < bm.height(); ++y) {
239 out->write(bm.getAddr8(0, y), bm.width());
240 }
241 return;
242 case kIndex_8_SkColorType:
243 index8_alpha_to_a8(bm, out);
244 return;
245 case kRGB_565_SkColorType:
246 case kUnknown_SkColorType:
247 default:
248 SkASSERT(false);
249 return;
250 }
251 }
252
140 //////////////////////////////////////////////////////////////////////////////// 253 ////////////////////////////////////////////////////////////////////////////////
141 254
142 namespace { 255 namespace {
143 // This SkPDFObject only outputs the alpha layer of the given bitmap. 256 // This SkPDFObject only outputs the alpha layer of the given bitmap.
144 class PDFAlphaBitmap : public SkPDFObject { 257 class PDFAlphaBitmap : public SkPDFObject {
145 public: 258 public:
146 PDFAlphaBitmap(const SkBitmap& bm) : fBitmap(bm) {} 259 PDFAlphaBitmap(const SkBitmap& bm) : fBitmap(bm) {}
147 ~PDFAlphaBitmap() {} 260 ~PDFAlphaBitmap() {}
148 void emitObject(SkWStream*, SkPDFCatalog*) SK_OVERRIDE; 261 void emitObject(SkWStream*, SkPDFCatalog*) SK_OVERRIDE;
149 void addResources(SkTSet<SkPDFObject*>*, SkPDFCatalog*) const SK_OVERRIDE {} 262 void addResources(SkTSet<SkPDFObject*>*, SkPDFCatalog*) const SK_OVERRIDE {}
150 263
151 private: 264 private:
152 const SkBitmap fBitmap; 265 const SkBitmap fBitmap;
153 void emitDict(SkWStream*, SkPDFCatalog*, size_t, bool) const; 266 void emitDict(SkWStream*, SkPDFCatalog*, size_t, bool) const;
154 }; 267 };
155 268
156 void PDFAlphaBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) { 269 void PDFAlphaBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
157 SkAutoLockPixels autoLockPixels(fBitmap); 270 SkAutoLockPixels autoLockPixels(fBitmap);
158 271
159 #ifndef SK_NO_FLATE 272 #ifndef SK_NO_FLATE
160 // Write to a temporary buffer to get the compressed length. 273 // Write to a temporary buffer to get the compressed length.
161 SkDynamicMemoryWStream buffer; 274 SkDynamicMemoryWStream buffer;
162 SkDeflateWStream deflateWStream(&buffer); 275 SkDeflateWStream deflateWStream(&buffer);
163 pmcolor_alpha_to_a8(fBitmap, &deflateWStream); 276 bitmap_alpha_to_a8(fBitmap, &deflateWStream);
164 deflateWStream.finalize(); // call before detachAsStream(). 277 deflateWStream.finalize(); // call before detachAsStream().
165 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); 278 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
166 279
167 this->emitDict(stream, catalog, asset->getLength(), /*deflate=*/true); 280 this->emitDict(stream, catalog, asset->getLength(), /*deflate=*/true);
168 pdf_stream_begin(stream); 281 pdf_stream_begin(stream);
169 stream->writeStream(asset.get(), asset->getLength()); 282 stream->writeStream(asset.get(), asset->getLength());
170 pdf_stream_end(stream); 283 pdf_stream_end(stream);
171 #else 284 #else
172 this->emitDict(stream, catalog, pixel_count(fBitmap), /*deflate=*/false); 285 this->emitDict(stream, catalog, pixel_count(fBitmap), /*deflate=*/false);
173 pdf_stream_begin(stream); 286 pdf_stream_begin(stream);
174 pmcolor_alpha_to_a8(fBitmap, stream); 287 bitmap_alpha_to_a8(fBitmap, stream);
175 pdf_stream_end(stream); 288 pdf_stream_end(stream);
176 #endif // SK_NO_FLATE 289 #endif // SK_NO_FLATE
177 } 290 }
178 291
179 void PDFAlphaBitmap::emitDict(SkWStream* stream, 292 void PDFAlphaBitmap::emitDict(SkWStream* stream,
180 SkPDFCatalog* catalog, 293 SkPDFCatalog* catalog,
181 size_t length, 294 size_t length,
182 bool deflate) const { 295 bool deflate) const {
183 SkPDFDict pdfDict("XObject"); 296 SkPDFDict pdfDict("XObject");
184 pdfDict.insertName("Subtype", "Image"); 297 pdfDict.insertName("Subtype", "Image");
(...skipping 18 matching lines...) Expand all
203 } 316 }
204 } 317 }
205 318
206 void SkPDFBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) { 319 void SkPDFBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
207 SkAutoLockPixels autoLockPixels(fBitmap); 320 SkAutoLockPixels autoLockPixels(fBitmap);
208 321
209 #ifndef SK_NO_FLATE 322 #ifndef SK_NO_FLATE
210 // Write to a temporary buffer to get the compressed length. 323 // Write to a temporary buffer to get the compressed length.
211 SkDynamicMemoryWStream buffer; 324 SkDynamicMemoryWStream buffer;
212 SkDeflateWStream deflateWStream(&buffer); 325 SkDeflateWStream deflateWStream(&buffer);
213 pmcolor_to_rgb24(fBitmap, &deflateWStream); 326 bitmap_to_rgb24(fBitmap, &deflateWStream);
214 deflateWStream.finalize(); // call before detachAsStream(). 327 deflateWStream.finalize(); // call before detachAsStream().
215 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); 328 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
216 329
217 this->emitDict(stream, catalog, asset->getLength(), /*deflate=*/true); 330 this->emitDict(stream, catalog, asset->getLength(), /*deflate=*/true);
218 pdf_stream_begin(stream); 331 pdf_stream_begin(stream);
219 stream->writeStream(asset.get(), asset->getLength()); 332 stream->writeStream(asset.get(), asset->getLength());
220 pdf_stream_end(stream); 333 pdf_stream_end(stream);
221 #else 334 #else
222 this->emitDict(stream, catalog, 3 * pixel_count(fBitmap), /*deflate=*/false) ; 335 this->emitDict(stream, catalog, 3 * pixel_count(fBitmap), /*deflate=*/false) ;
223 pdf_stream_begin(stream); 336 pdf_stream_begin(stream);
224 pmcolor_to_rgb24(fBitmap, stream); 337 bitmap_to_rgb24(fBitmap, stream);
225 pdf_stream_end(stream); 338 pdf_stream_end(stream);
226 return; 339 return;
227 #endif // SK_NO_FLATE 340 #endif // SK_NO_FLATE
228 } 341 }
229 342
343 static SkPDFArray* make_indexed_color_space(const SkColorTable* table) {
344 SkPDFArray* result = SkNEW(SkPDFArray);
345 result->reserve(4);
346 result->appendName("Indexed");
347 result->appendName("DeviceRGB");
348 SkASSERT(table);
349 result->appendInt(table->count() - 1);
350
351 // Potentially, this could be represented in fewer bytes with a stream.
352 // Max size as a string is 1.5k.
mtklein 2015/02/23 14:26:53 Some sort of assert here then?
hal.canary 2015/03/20 01:09:45 Done.
353 SkString index;
354 for (int i = 0; i < table->count(); i++) {
355 SkPMColor color = (*table)[i];
356 U8CPU alpha = SkGetPackedA32(color);
357 uint8_t rgb[3];
358 to_rgb24(color, alpha, rgb);
359 index.append((char*)rgb, 3);
360 }
361 result->append(new SkPDFString(index))->unref();
362 return result;
363 }
364
230 void SkPDFBitmap::emitDict(SkWStream* stream, 365 void SkPDFBitmap::emitDict(SkWStream* stream,
231 SkPDFCatalog* catalog, 366 SkPDFCatalog* catalog,
232 size_t length, 367 size_t length,
233 bool deflate) const { 368 bool deflate) const {
234 SkPDFDict pdfDict("XObject"); 369 SkPDFDict pdfDict("XObject");
235 pdfDict.insertName("Subtype", "Image"); 370 pdfDict.insertName("Subtype", "Image");
236 pdfDict.insertInt("Width", fBitmap.width()); 371 pdfDict.insertInt("Width", fBitmap.width());
237 pdfDict.insertInt("Height", fBitmap.height()); 372 pdfDict.insertInt("Height", fBitmap.height());
238 pdfDict.insertName("ColorSpace", "DeviceRGB"); 373 if (fBitmap.colorType() != kIndex_8_SkColorType) {
374 pdfDict.insertName("ColorSpace", "DeviceRGB");
375 } else {
376 pdfDict.insert("ColorSpace", make_indexed_color_space(
377 fBitmap.getColorTable()))->unref();
378 }
239 pdfDict.insertInt("BitsPerComponent", 8); 379 pdfDict.insertInt("BitsPerComponent", 8);
240 if (fSMask) { 380 if (fSMask) {
241 pdfDict.insert("SMask", new SkPDFObjRef(fSMask))->unref(); 381 pdfDict.insert("SMask", new SkPDFObjRef(fSMask))->unref();
242 } 382 }
243 if (deflate) { 383 if (deflate) {
244 pdfDict.insertName("Filter", "FlateDecode"); 384 pdfDict.insertName("Filter", "FlateDecode");
245 } 385 }
246 pdfDict.insertInt("Length", length); 386 pdfDict.insertInt("Length", length);
247 pdfDict.emitObject(stream, catalog); 387 pdfDict.emitObject(stream, catalog);
248 } 388 }
249 389
250 SkPDFBitmap::SkPDFBitmap(SkPDFCanon* canon, 390 SkPDFBitmap::SkPDFBitmap(SkPDFCanon* canon,
251 const SkBitmap& bm, 391 const SkBitmap& bm,
252 SkPDFObject* smask) 392 SkPDFObject* smask)
253 : fCanon(canon), fBitmap(bm), fSMask(smask) {} 393 : fCanon(canon), fBitmap(bm), fSMask(smask) {}
254 394
255 SkPDFBitmap::~SkPDFBitmap() { fCanon->removeBitmap(this); } 395 SkPDFBitmap::~SkPDFBitmap() { fCanon->removeBitmap(this); }
256 396
257 //////////////////////////////////////////////////////////////////////////////// 397 ////////////////////////////////////////////////////////////////////////////////
258 static bool is_transparent(const SkBitmap& bm) { 398
259 SkAutoLockPixels autoLockPixels(bm); 399 static bool is_transparent_pixels(const SkBitmap& bm) {
mtklein 2015/02/23 14:26:52 pixels_are_transparent?
hal.canary 2015/03/20 01:09:45 I've stoped this check. Why lock the bitmap unnec
260 if (NULL == bm.getPixels()) {
261 return true;
262 }
263 SkASSERT(kN32_SkColorType == bm.colorType());
264 for (int y = 0; y < bm.height(); ++y) { 400 for (int y = 0; y < bm.height(); ++y) {
265 U8CPU alpha = 0; 401 U8CPU alpha = 0;
266 const SkPMColor* src = bm.getAddr32(0, y); 402 switch (bm.colorType()) {
267 for (int x = 0; x < bm.width(); ++x) { 403 case kN32_SkColorType: {
268 alpha |= SkGetPackedA32(*src++); 404 const SkPMColor* src = bm.getAddr32(0, y);
405 for (int x = 0; x < bm.width(); ++x) {
406 alpha |= SkGetPackedA32(*src++);
mtklein 2015/02/23 14:26:53 Why don't we just bail out the first time we see a
hal.canary 2015/03/20 01:09:45 Acknowledged.
407 }
408 break;
409 }
410 case kARGB_4444_SkColorType: {
411 const uint16_t* src = bm.getAddr16(0, y);
412 for (int x = 0; x < bm.width(); ++x) {
413 alpha |= SkPacked4444ToA32(*src++);
414 }
415 break;
416 }
417 case kAlpha_8_SkColorType: {
418 const uint8_t* src = bm.getAddr8(0, y);
419 for (int x = 0; x < bm.width(); ++x) {
420 alpha |= *src++;
421 }
422 break;
423 }
424 default:
425 SkASSERT(false);
269 } 426 }
270 if (alpha) { 427 if (alpha) {
271 return false; 428 return false;
272 } 429 }
273 } 430 }
274 return true; 431 return true;
275 } 432 }
276 433
434 static bool is_transparent(const SkBitmap& bm) {
435 SkAutoLockPixels autoLockPixels(bm);
436 if (NULL == bm.getPixels()) {
437 return true;
438 }
439 switch (bm.colorType()) {
440 case kN32_SkColorType:
441 case kARGB_4444_SkColorType:
442 case kAlpha_8_SkColorType:
443 return is_transparent_pixels(bm);
444 case kIndex_8_SkColorType: {
445 const SkColorTable* ct = bm.getColorTable();
446 if (!ct) {
447 return true;
448 }
449 for (int y = 0; y < bm.height(); ++y) {
450 U8CPU alpha = 0;
451 const uint8_t* src = bm.getAddr8(0, y);
452 for (int x = 0; x < bm.width(); ++x) {
453 alpha |= SkGetPackedA32((*ct)[*src++]);
mtklein 2015/02/23 14:26:52 Same question?
hal.canary 2015/03/20 01:09:45 Acknowledged.
454 }
455 if (alpha) {
456 return false;
457 }
458 }
459 return true;
460 }
461 default:
462 SkASSERT(false);
463 return false;
464 }
465 }
466
277 SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon, 467 SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon,
278 const SkBitmap& bitmap, 468 const SkBitmap& bitmap,
279 const SkIRect& subset) { 469 const SkIRect& subset) {
280 SkASSERT(canon); 470 SkASSERT(canon);
281 if (kN32_SkColorType != bitmap.colorType()) { 471 switch (bitmap.colorType()) {
282 // TODO(halcanary): support other colortypes. 472 case kN32_SkColorType:
283 return NULL; 473 case kRGB_565_SkColorType:
474 case kARGB_4444_SkColorType:
475 case kAlpha_8_SkColorType:
476 case kIndex_8_SkColorType:
477 break;
478 case kUnknown_SkColorType:
479 default:
480 return NULL;
284 } 481 }
285 SkBitmap bm; 482 SkBitmap bm;
286 // Should extractSubset be done by the SkPDFDevice? 483 // Should extractSubset be done by the SkPDFDevice?
287 if (!bitmap.extractSubset(&bm, subset)) { 484 if (!bitmap.extractSubset(&bm, subset)) {
288 return NULL; 485 return NULL;
289 } 486 }
290 if (bm.drawsNothing()) { 487 if (bm.drawsNothing()) {
291 return NULL; 488 return NULL;
292 } 489 }
293 if (!bm.isImmutable()) { 490 if (!bm.isImmutable()) {
294 SkBitmap copy; 491 SkBitmap copy;
295 if (!bm.copyTo(&copy)) { 492 if (!bm.copyTo(&copy)) {
296 return NULL; 493 return NULL;
297 } 494 }
298 copy.setImmutable(); 495 copy.setImmutable();
299 bm = copy; 496 bm = copy;
300 } 497 }
301 498
302 SkPDFBitmap* pdfBitmap = canon->findBitmap(bm); 499 SkPDFBitmap* pdfBitmap = canon->findBitmap(bm);
303 if (pdfBitmap) { 500 if (pdfBitmap) {
304 return SkRef(pdfBitmap); 501 return SkRef(pdfBitmap);
305 } 502 }
306 SkPDFObject* smask = NULL; 503 SkPDFObject* smask = NULL;
307 if (!bm.isOpaque() && !SkBitmap::ComputeIsOpaque(bm)) { 504 if (!bm.isOpaque() && !SkBitmap::ComputeIsOpaque(bm)) {
308 if (is_transparent(bm)) { 505 if (is_transparent(bm)) {
mtklein 2015/02/23 14:26:53 Just curious, do we really see fully transparent b
hal.canary 2015/03/20 01:09:46 Done.
309 return NULL; 506 return NULL;
310 } 507 }
311 // PDFAlphaBitmaps do not get directly canonicalized (they 508 // PDFAlphaBitmaps do not get directly canonicalized (they
312 // are refed by the SkPDFBitmap). 509 // are refed by the SkPDFBitmap).
313 smask = SkNEW_ARGS(PDFAlphaBitmap, (bm)); 510 smask = SkNEW_ARGS(PDFAlphaBitmap, (bm));
314 } 511 }
315 pdfBitmap = SkNEW_ARGS(SkPDFBitmap, (canon, bm, smask)); 512 pdfBitmap = SkNEW_ARGS(SkPDFBitmap, (canon, bm, smask));
316 canon->addBitmap(pdfBitmap); 513 canon->addBitmap(pdfBitmap);
317 return pdfBitmap; 514 return pdfBitmap;
318 } 515 }
OLDNEW
« gm/all_bitmap_configs.cpp ('K') | « gyp/pdf.gypi ('k') | src/pdf/SkPDFDevice.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698