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

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

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

Powered by Google App Engine
This is Rietveld 408576698