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

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-03-19 (Thursday) 21:02:14 EDT 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 yrange[2] = {SkTMax(0, yOrig - 1), SkTMin(yOrig + 2, bm.height())};
65 int xrange[2] = {SkTMax(0, xOrig - 1), SkTMin(xOrig + 2, bm.width())};
66 for (int y = yrange[0]; y < yrange[1]; ++y) {
reed1 2015/03/20 12:42:04 range[0], range[1]... pretty hard to read. Why not
hal.canary 2015/03/20 13:49:50 Done.
67 SkPMColor* scanline = bm.getAddr32(0, y);
68 for (int x = xrange[0]; x < xrange[1]; ++x) {
69 SkPMColor pmColor = scanline[x];
70 a += SkGetPackedA32(pmColor);
71 r += SkGetPackedR32(pmColor);
72 g += SkGetPackedG32(pmColor);
73 b += SkGetPackedB32(pmColor);
74 }
75 }
76 if (a > 0) {
77 rgb[0] = 255 * r / a;
reed1 2015/03/20 12:42:03 SkToU8(...) -- this guy asserts in debug that we'r
hal.canary 2015/03/20 13:49:50 Done.
78 rgb[1] = 255 * g / a;
79 rgb[2] = 255 * b / a;
80 } else {
81 rgb[0] = rgb[1] = rgb[2] = 0;
82 }
83 }
84
28 static size_t pixel_count(const SkBitmap& bm) { 85 static size_t pixel_count(const SkBitmap& bm) {
29 return SkToSizeT(bm.width()) * SkToSizeT(bm.height()); 86 return SkToSizeT(bm.width()) * SkToSizeT(bm.height());
30 } 87 }
31 88
32 // write a single byte to a stream n times. 89 static const SkBitmap& not4444(const SkBitmap& input, SkBitmap* copy) {
33 static void fill_stream(SkWStream* out, char value, size_t n) { 90 if (input.colorType() != kARGB_4444_SkColorType) {
34 char buffer[4096]; 91 return input;
35 memset(buffer, value, sizeof(buffer)); 92 }
36 while (n) { 93 // ARGB_4444 is rarely used, so we can do a wasteful tmp copy.
37 size_t k = SkTMin(n, sizeof(buffer)); 94 SkAssertResult(input.copyTo(copy, kN32_SkColorType));
38 out->write(buffer, k); 95 copy->setImmutable();
39 n -= k; 96 return *copy;
97 }
98
99 static void bitmap_to_rgb24(const SkBitmap& bitmap, SkWStream* out) {
reed1 2015/03/20 12:42:03 Since this sometimes writes index8 or gray8, perha
hal.canary 2015/03/20 13:49:50 Done.
100 if (!bitmap.getPixels()) {
101 if (kIndex_8_SkColorType == bitmap.colorType()) {
102 fill_stream(out, '\x00', pixel_count(bitmap));
103 } else {
104 fill_stream(out, '\xFF', 3 * pixel_count(bitmap));
105 }
106 return;
107 }
108 SkBitmap copy;
109 const SkBitmap& bm = not4444(bitmap, &copy);
110 SkAutoLockPixels autoLockPixels(bm);
111 switch (bm.colorType()) {
112 case kN32_SkColorType: {
113 SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
114 for (int y = 0; y < bm.height(); ++y) {
115 const SkPMColor* src = bm.getAddr32(0, y);
116 uint8_t* dst = scanline.get();
117 for (int x = 0; x < bm.width(); ++x) {
118 SkPMColor color = *src++;
119 U8CPU alpha = SkGetPackedA32(color);
120 if (alpha != SK_AlphaTRANSPARENT) {
121 pmcolor_to_rgb24(color, dst);
122 } else {
123 get_neighbor_avg_color(bm, x, y, dst);
124 }
125 dst += 3;
126 }
127 out->write(scanline.get(), 3 * bm.width());
128 }
129 return;
130 }
131 case kRGB_565_SkColorType: {
132 SkAutoTMalloc<uint8_t> scanline(3 * bm.width());
133 for (int y = 0; y < bm.height(); ++y) {
134 const uint16_t* src = bm.getAddr16(0, y);
135 uint8_t* dst = scanline.get();
136 for (int x = 0; x < bm.width(); ++x) {
137 U16CPU color565 = *src++;
138 *dst++ = SkPacked16ToR32(color565);
139 *dst++ = SkPacked16ToG32(color565);
140 *dst++ = SkPacked16ToB32(color565);
141 }
142 out->write(scanline.get(), 3 * bm.width());
143 }
144 return;
145 }
146 case kAlpha_8_SkColorType:
147 fill_stream(out, '\x00', 3 * pixel_count(bm));
148 return;
149 case kGray_8_SkColorType: // grayscale8, not actually rgb24 format.
150 case kIndex_8_SkColorType: // indexed8, not actually rgb24 format.
151 // these two formats need no transformation to serialize.
152 for (int y = 0; y < bm.height(); ++y) {
153 out->write(bm.getAddr8(0, y), bm.width());
154 }
155 return;
156 case kUnknown_SkColorType:
157 case kARGB_4444_SkColorType:
158 default:
159 SkASSERT(false);
40 } 160 }
41 } 161 }
42 162
43 static SkPMColor get_pmcolor_neighbor_avg_color(const SkBitmap& bitmap, 163 ////////////////////////////////////////////////////////////////////////////////
44 int xOrig, 164
45 int yOrig) { 165 static void bitmap_alpha_to_a8(const SkBitmap& bitmap, SkWStream* out) {
46 SkASSERT(kN32_SkColorType == bitmap.colorType()); 166 if (!bitmap.getPixels()) {
47 SkASSERT(bitmap.getPixels()); 167 fill_stream(out, '\xFF', pixel_count(bitmap));
48 uint8_t count = 0; 168 return;
49 unsigned r = 0; 169 }
50 unsigned g = 0; 170 SkBitmap copy;
51 unsigned b = 0; 171 const SkBitmap& bm = not4444(bitmap, &copy);
52 for (int y = yOrig - 1; y <= yOrig + 1; ++y) { 172 SkAutoLockPixels autoLockPixels(bm);
53 if (y < 0 || y >= bitmap.height()) { 173 switch (bm.colorType()) {
54 continue; 174 case kN32_SkColorType: {
175 SkAutoTMalloc<uint8_t> scanline(bm.width());
176 for (int y = 0; y < bm.height(); ++y) {
177 uint8_t* dst = scanline.get();
178 const SkPMColor* src = bm.getAddr32(0, y);
179 for (int x = 0; x < bm.width(); ++x) {
180 *dst++ = SkGetPackedA32(*src++);
181 }
182 out->write(scanline.get(), bm.width());
183 }
184 return;
55 } 185 }
56 uint32_t* src = bitmap.getAddr32(0, y); 186 case kAlpha_8_SkColorType:
57 for (int x = xOrig - 1; x <= xOrig + 1; ++x) { 187 for (int y = 0; y < bm.height(); ++y) {
58 if (x < 0 || x >= bitmap.width()) { 188 out->write(bm.getAddr8(0, y), bm.width());
59 continue;
60 } 189 }
61 SkPMColor pmColor = src[x]; 190 return;
62 U8CPU alpha = SkGetPackedA32(pmColor); 191 case kIndex_8_SkColorType: {
63 if (alpha != SK_AlphaTRANSPARENT) { 192 SkColorTable* ct = bm.getColorTable();
64 uint32_t s = SkUnPreMultiply::GetScale(alpha); 193 SkASSERT(ct);
65 r += SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(pmColor)); 194 SkAutoTMalloc<uint8_t> scanline(bm.width());
66 g += SkUnPreMultiply::ApplyScale(s, SkGetPackedG32(pmColor)); 195 for (int y = 0; y < bm.height(); ++y) {
67 b += SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(pmColor)); 196 uint8_t* dst = scanline.get();
68 ++count; 197 const uint8_t* src = bm.getAddr8(0, y);
198 for (int x = 0; x < bm.width(); ++x) {
199 *dst++ = SkGetPackedA32((*ct)[*src++]);
200 }
201 out->write(scanline.get(), bm.width());
69 } 202 }
203 return;
70 } 204 }
71 } 205 case kRGB_565_SkColorType: // no alpha
72 if (count == 0) { 206 case kARGB_4444_SkColorType: // converted to N32
reed1 2015/03/20 12:42:03 what does "converted to N32" mean? Does it mean we
hal.canary 2015/03/20 13:49:50 That's why I skassert(false).
73 return SkPackARGB32NoCheck(SK_AlphaOPAQUE, 0, 0, 0); 207 case kGray_8_SkColorType: // no alpha
74 } else { 208 case kUnknown_SkColorType: // unsupported
75 return SkPackARGB32NoCheck( 209 default:
76 SK_AlphaOPAQUE, r / count, g / count, b / count); 210 SkASSERT(false);
77 } 211 }
78 } 212 }
79 213
80 static void pmcolor_to_rgb24(const SkBitmap& bm, SkWStream* out) {
81 SkASSERT(kN32_SkColorType == bm.colorType());
82 if (!bm.getPixels()) {
83 fill_stream(out, '\xFF', 3 * pixel_count(bm));
84 return;
85 }
86 size_t scanlineLength = 3 * bm.width();
87 SkAutoTMalloc<uint8_t> scanline(scanlineLength);
88 for (int y = 0; y < bm.height(); ++y) {
89 uint8_t* dst = scanline.get();
90 const SkPMColor* src = bm.getAddr32(0, y);
91 for (int x = 0; x < bm.width(); ++x) {
92 SkPMColor color = *src++;
93 U8CPU alpha = SkGetPackedA32(color);
94 if (alpha != SK_AlphaTRANSPARENT) {
95 uint32_t s = SkUnPreMultiply::GetScale(alpha);
96 *dst++ = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(color));
97 *dst++ = SkUnPreMultiply::ApplyScale(s, SkGetPackedG32(color));
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);
115 }
116 }
117 out->write(scanline.get(), scanlineLength);
118 }
119 }
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
139 //////////////////////////////////////////////////////////////////////////////// 214 ////////////////////////////////////////////////////////////////////////////////
140 215
141 namespace { 216 namespace {
142 // This SkPDFObject only outputs the alpha layer of the given bitmap. 217 // This SkPDFObject only outputs the alpha layer of the given bitmap.
143 class PDFAlphaBitmap : public SkPDFObject { 218 class PDFAlphaBitmap : public SkPDFObject {
144 public: 219 public:
145 PDFAlphaBitmap(const SkBitmap& bm) : fBitmap(bm) {} 220 PDFAlphaBitmap(const SkBitmap& bm) : fBitmap(bm) {}
146 ~PDFAlphaBitmap() {} 221 ~PDFAlphaBitmap() {}
147 void emitObject(SkWStream*, SkPDFCatalog*) SK_OVERRIDE; 222 void emitObject(SkWStream*, SkPDFCatalog*) SK_OVERRIDE;
148 void addResources(SkTSet<SkPDFObject*>*, SkPDFCatalog*) const SK_OVERRIDE {}
149 223
150 private: 224 private:
151 const SkBitmap fBitmap; 225 const SkBitmap fBitmap;
152 void emitDict(SkWStream*, SkPDFCatalog*, size_t, bool) const; 226 void emitDict(SkWStream*, SkPDFCatalog*, size_t) const;
153 }; 227 };
154 228
155 void PDFAlphaBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) { 229 void PDFAlphaBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
156 SkAutoLockPixels autoLockPixels(fBitmap); 230 SkAutoLockPixels autoLockPixels(fBitmap);
231 SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType ||
232 fBitmap.getColorTable());
157 233
158 #ifndef SK_NO_FLATE
159 // Write to a temporary buffer to get the compressed length. 234 // Write to a temporary buffer to get the compressed length.
160 SkDynamicMemoryWStream buffer; 235 SkDynamicMemoryWStream buffer;
161 SkDeflateWStream deflateWStream(&buffer); 236 SkDeflateWStream deflateWStream(&buffer);
162 pmcolor_alpha_to_a8(fBitmap, &deflateWStream); 237 bitmap_alpha_to_a8(fBitmap, &deflateWStream);
163 deflateWStream.finalize(); // call before detachAsStream(). 238 deflateWStream.finalize(); // call before detachAsStream().
164 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); 239 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
165 240
166 this->emitDict(stream, catalog, asset->getLength(), /*deflate=*/true); 241 this->emitDict(stream, catalog, asset->getLength());
167 pdf_stream_begin(stream); 242 pdf_stream_begin(stream);
168 stream->writeStream(asset.get(), asset->getLength()); 243 stream->writeStream(asset.get(), asset->getLength());
169 pdf_stream_end(stream); 244 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
176 } 245 }
177 246
178 void PDFAlphaBitmap::emitDict(SkWStream* stream, 247 void PDFAlphaBitmap::emitDict(SkWStream* stream,
179 SkPDFCatalog* catalog, 248 SkPDFCatalog* catalog,
180 size_t length, 249 size_t length) const {
181 bool deflate) const {
182 SkPDFDict pdfDict("XObject"); 250 SkPDFDict pdfDict("XObject");
183 pdfDict.insertName("Subtype", "Image"); 251 pdfDict.insertName("Subtype", "Image");
184 pdfDict.insertInt("Width", fBitmap.width()); 252 pdfDict.insertInt("Width", fBitmap.width());
185 pdfDict.insertInt("Height", fBitmap.height()); 253 pdfDict.insertInt("Height", fBitmap.height());
186 pdfDict.insertName("ColorSpace", "DeviceGray"); 254 pdfDict.insertName("ColorSpace", "DeviceGray");
187 pdfDict.insertInt("BitsPerComponent", 8); 255 pdfDict.insertInt("BitsPerComponent", 8);
188 if (deflate) { 256 pdfDict.insertName("Filter", "FlateDecode");
189 pdfDict.insertName("Filter", "FlateDecode");
190 }
191 pdfDict.insertInt("Length", length); 257 pdfDict.insertInt("Length", length);
192 pdfDict.emitObject(stream, catalog); 258 pdfDict.emitObject(stream, catalog);
193 } 259 }
194 } // namespace 260 } // namespace
195 261
196 //////////////////////////////////////////////////////////////////////////////// 262 ////////////////////////////////////////////////////////////////////////////////
197 263
198 void SkPDFBitmap::addResources(SkTSet<SkPDFObject*>* resourceSet, 264 void SkPDFBitmap::addResources(SkTSet<SkPDFObject*>* resourceSet,
199 SkPDFCatalog* catalog) const { 265 SkPDFCatalog* catalog) const {
200 if (fSMask.get()) { 266 if (fSMask.get()) {
201 resourceSet->add(fSMask.get()); 267 if (resourceSet->add(fSMask.get())) {
268 fSMask->addResources(resourceSet, catalog);
269 }
202 } 270 }
203 } 271 }
204 272
205 void SkPDFBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) { 273 void SkPDFBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
206 SkAutoLockPixels autoLockPixels(fBitmap); 274 SkAutoLockPixels autoLockPixels(fBitmap);
275 SkASSERT(fBitmap.colorType() != kIndex_8_SkColorType ||
276 fBitmap.getColorTable());
207 277
208 #ifndef SK_NO_FLATE
209 // Write to a temporary buffer to get the compressed length. 278 // Write to a temporary buffer to get the compressed length.
210 SkDynamicMemoryWStream buffer; 279 SkDynamicMemoryWStream buffer;
211 SkDeflateWStream deflateWStream(&buffer); 280 SkDeflateWStream deflateWStream(&buffer);
212 pmcolor_to_rgb24(fBitmap, &deflateWStream); 281 bitmap_to_rgb24(fBitmap, &deflateWStream);
213 deflateWStream.finalize(); // call before detachAsStream(). 282 deflateWStream.finalize(); // call before detachAsStream().
214 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream()); 283 SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
215 284
216 this->emitDict(stream, catalog, asset->getLength(), /*deflate=*/true); 285 this->emitDict(stream, catalog, asset->getLength());
217 pdf_stream_begin(stream); 286 pdf_stream_begin(stream);
218 stream->writeStream(asset.get(), asset->getLength()); 287 stream->writeStream(asset.get(), asset->getLength());
219 pdf_stream_end(stream); 288 pdf_stream_end(stream);
220 #else 289 }
221 this->emitDict(stream, catalog, 3 * pixel_count(fBitmap), /*deflate=*/false) ; 290
222 pdf_stream_begin(stream); 291 static SkPDFArray* make_indexed_color_space(const SkColorTable* table) {
223 pmcolor_to_rgb24(fBitmap, stream); 292 SkPDFArray* result = SkNEW(SkPDFArray);
224 pdf_stream_end(stream); 293 result->reserve(4);
225 return; 294 result->appendName("Indexed");
226 #endif // SK_NO_FLATE 295 result->appendName("DeviceRGB");
296 SkASSERT(table);
297 result->appendInt(table->count() - 1);
298
299 // Potentially, this could be represented in fewer bytes with a stream.
300 // Max size as a string is 1.5k.
301 char tableArray[768];
302 SkASSERT(3u * table->count() <= sizeof(tableArray));
303 uint8_t* tablePtr = reinterpret_cast<uint8_t*>(tableArray);
304 const SkPMColor* colors = table->readColors();
305 for (int i = 0; i < table->count(); i++) {
306 pmcolor_to_rgb24(colors[i], tablePtr);
307 tablePtr += 3;
308 }
309 SkString tableString(tableArray, 3 * table->count());
310 result->append(new SkPDFString(tableString))->unref();
311 return result;
227 } 312 }
228 313
229 void SkPDFBitmap::emitDict(SkWStream* stream, 314 void SkPDFBitmap::emitDict(SkWStream* stream,
230 SkPDFCatalog* catalog, 315 SkPDFCatalog* catalog,
231 size_t length, 316 size_t length) const {
232 bool deflate) const {
233 SkPDFDict pdfDict("XObject"); 317 SkPDFDict pdfDict("XObject");
234 pdfDict.insertName("Subtype", "Image"); 318 pdfDict.insertName("Subtype", "Image");
235 pdfDict.insertInt("Width", fBitmap.width()); 319 pdfDict.insertInt("Width", fBitmap.width());
236 pdfDict.insertInt("Height", fBitmap.height()); 320 pdfDict.insertInt("Height", fBitmap.height());
237 pdfDict.insertName("ColorSpace", "DeviceRGB"); 321 if (fBitmap.colorType() == kGray_8_SkColorType) {
322 pdfDict.insertName("ColorSpace", "DeviceGray");
323 } else if (fBitmap.colorType() == kIndex_8_SkColorType) {
324 pdfDict.insert("ColorSpace", make_indexed_color_space(
325 fBitmap.getColorTable()))->unref();
326 } else {
327 pdfDict.insertName("ColorSpace", "DeviceRGB");
328 }
238 pdfDict.insertInt("BitsPerComponent", 8); 329 pdfDict.insertInt("BitsPerComponent", 8);
239 if (fSMask) { 330 if (fSMask) {
240 pdfDict.insert("SMask", new SkPDFObjRef(fSMask))->unref(); 331 pdfDict.insert("SMask", new SkPDFObjRef(fSMask))->unref();
241 } 332 }
242 if (deflate) { 333 pdfDict.insertName("Filter", "FlateDecode");
243 pdfDict.insertName("Filter", "FlateDecode");
244 }
245 pdfDict.insertInt("Length", length); 334 pdfDict.insertInt("Length", length);
246 pdfDict.emitObject(stream, catalog); 335 pdfDict.emitObject(stream, catalog);
247 } 336 }
248 337
249 SkPDFBitmap::SkPDFBitmap(const SkBitmap& bm, 338 SkPDFBitmap::SkPDFBitmap(const SkBitmap& bm,
250 SkPDFObject* smask) 339 SkPDFObject* smask)
251 : fBitmap(bm), fSMask(smask) {} 340 : fBitmap(bm), fSMask(smask) {}
252 341
253 SkPDFBitmap::~SkPDFBitmap() {} 342 SkPDFBitmap::~SkPDFBitmap() {}
254 343
255 //////////////////////////////////////////////////////////////////////////////// 344 ////////////////////////////////////////////////////////////////////////////////
256 static bool is_transparent(const SkBitmap& bm) { 345
257 SkAutoLockPixels autoLockPixels(bm); 346 static const SkBitmap& immutable_bitmap(const SkBitmap& bm, SkBitmap* copy) {
258 if (NULL == bm.getPixels()) { 347 if (bm.isImmutable()) {
259 return true; 348 return bm;
260 } 349 }
261 SkASSERT(kN32_SkColorType == bm.colorType()); 350 bm.copyTo(copy);
262 for (int y = 0; y < bm.height(); ++y) { 351 copy->setImmutable();
263 U8CPU alpha = 0; 352 return *copy;
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;
273 } 353 }
274 354
275 SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon, 355 SkPDFBitmap* SkPDFBitmap::Create(SkPDFCanon* canon, const SkBitmap& bitmap) {
276 const SkBitmap& bitmap,
277 const SkIRect& subset) {
278 SkASSERT(canon); 356 SkASSERT(canon);
279 if (kN32_SkColorType != bitmap.colorType()) { 357 if (!SkColorTypeIsValid(bitmap.colorType()) ||
280 // TODO(halcanary): support other colortypes. 358 kUnknown_SkColorType == bitmap.colorType()) {
281 return NULL; 359 return NULL;
282 } 360 }
283 SkBitmap bm; 361 SkBitmap copy;
284 // Should extractSubset be done by the SkPDFDevice? 362 const SkBitmap& bm = immutable_bitmap(bitmap, &copy);
285 if (!bitmap.extractSubset(&bm, subset)) {
286 return NULL;
287 }
288 if (bm.drawsNothing()) { 363 if (bm.drawsNothing()) {
289 return NULL; 364 return NULL;
290 } 365 }
291 if (!bm.isImmutable()) { 366 if (SkPDFBitmap* canonBitmap = canon->findBitmap(bm)) {
292 SkBitmap copy; 367 return SkRef(canonBitmap);
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);
303 } 368 }
304 SkPDFObject* smask = NULL; 369 SkPDFObject* smask = NULL;
305 if (!bm.isOpaque() && !SkBitmap::ComputeIsOpaque(bm)) { 370 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).
311 smask = SkNEW_ARGS(PDFAlphaBitmap, (bm)); 371 smask = SkNEW_ARGS(PDFAlphaBitmap, (bm));
312 } 372 }
313 pdfBitmap = SkNEW_ARGS(SkPDFBitmap, (bm, smask)); 373 SkPDFBitmap* pdfBitmap = SkNEW_ARGS(SkPDFBitmap, (bm, smask));
314 canon->addBitmap(pdfBitmap); 374 canon->addBitmap(pdfBitmap);
315 return pdfBitmap; 375 return pdfBitmap;
316 } 376 }
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