OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2010 The Android Open Source Project | 2 * Copyright 2010 The Android Open Source Project |
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 "SkPDFImage.h" | 8 #include "SkPDFImage.h" |
9 | 9 |
10 #include "SkBitmap.h" | 10 #include "SkBitmap.h" |
11 #include "SkColor.h" | 11 #include "SkColor.h" |
12 #include "SkColorPriv.h" | 12 #include "SkColorPriv.h" |
13 #include "SkData.h" | |
14 #include "SkFlate.h" | |
13 #include "SkPDFCatalog.h" | 15 #include "SkPDFCatalog.h" |
14 #include "SkRect.h" | 16 #include "SkRect.h" |
15 #include "SkStream.h" | 17 #include "SkStream.h" |
16 #include "SkString.h" | 18 #include "SkString.h" |
17 #include "SkUnPreMultiply.h" | 19 #include "SkUnPreMultiply.h" |
18 | 20 |
19 namespace { | 21 namespace { |
vandebo (ex-Chrome)
2013/08/21 22:37:17
Looks like you can probably remove the anonymous n
ducky
2013/08/22 03:48:06
Done.
| |
20 | 22 |
21 void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect, | 23 #define kNoColorTransform 0 |
vandebo (ex-Chrome)
2013/08/21 22:37:17
const int kNoColorTransform = 0;
ducky
2013/08/22 03:48:06
Done.
| |
22 SkStream** imageData, SkStream** alphaData) { | |
vandebo (ex-Chrome)
2013/08/21 22:37:17
We talked about the different cases the other day:
ducky
2013/08/22 03:48:06
Done. I think the merged one is less elegant, but
| |
23 SkMemoryStream* image = NULL; | |
24 SkMemoryStream* alpha = NULL; | |
25 bool hasAlpha = false; | |
26 bool isTransparent = false; | |
27 | 24 |
25 static bool skip_compression(SkPDFCatalog* catalog) { | |
26 return SkToBool(catalog->getDocumentFlags() & | |
27 SkPDFDocument::kFavorSpeedOverSize_Flags); | |
28 } | |
29 | |
30 static size_t get_row_bytes(const SkBitmap& bitmap, | |
31 const SkIRect& srcRect) { | |
32 switch (bitmap.getConfig()) { | |
33 case SkBitmap::kIndex8_Config: | |
34 return srcRect.width(); | |
35 case SkBitmap::kARGB_4444_Config: | |
36 return (srcRect.width() * 3 + 1) / 2; | |
37 case SkBitmap::kRGB_565_Config: | |
38 return srcRect.width() * 3; | |
39 case SkBitmap::kARGB_8888_Config: | |
40 return srcRect.width() * 3; | |
41 case SkBitmap::kA1_Config: | |
42 case SkBitmap::kA8_Config: | |
43 return 1; | |
44 default: | |
45 SkASSERT(false); | |
46 return 0; | |
47 } | |
48 } | |
49 | |
50 static size_t get_uncompressed_size(const SkBitmap& bitmap, | |
51 const SkIRect& srcRect) { | |
52 switch (bitmap.getConfig()) { | |
53 case SkBitmap::kIndex8_Config: | |
54 case SkBitmap::kARGB_4444_Config: | |
55 case SkBitmap::kRGB_565_Config: | |
56 case SkBitmap::kARGB_8888_Config: | |
57 return get_row_bytes(bitmap, srcRect) * srcRect.height(); | |
58 case SkBitmap::kA1_Config: | |
59 case SkBitmap::kA8_Config: | |
60 return 1; | |
61 default: | |
62 SkASSERT(false); | |
63 return 0; | |
64 } | |
65 } | |
66 | |
67 static SkStream* extract_image_data(const SkBitmap& bitmap, | |
68 const SkIRect& srcRect) { | |
69 const int rowBytes = get_row_bytes(bitmap, srcRect); | |
70 SkMemoryStream* image = new SkMemoryStream(get_uncompressed_size(bitmap, | |
71 srcRect)); | |
28 bitmap.lockPixels(); | 72 bitmap.lockPixels(); |
29 switch (bitmap.getConfig()) { | 73 switch (bitmap.getConfig()) { |
30 case SkBitmap::kIndex8_Config: { | 74 case SkBitmap::kIndex8_Config: { |
31 const int rowBytes = srcRect.width(); | |
32 image = new SkMemoryStream(rowBytes * srcRect.height()); | |
33 uint8_t* dst = (uint8_t*)image->getMemoryBase(); | 75 uint8_t* dst = (uint8_t*)image->getMemoryBase(); |
34 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { | 76 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { |
35 memcpy(dst, bitmap.getAddr8(srcRect.fLeft, y), rowBytes); | 77 memcpy(dst, bitmap.getAddr8(srcRect.fLeft, y), rowBytes); |
36 dst += rowBytes; | 78 dst += rowBytes; |
37 } | 79 } |
38 break; | 80 break; |
39 } | 81 } |
40 case SkBitmap::kARGB_4444_Config: { | 82 case SkBitmap::kARGB_4444_Config: { |
41 isTransparent = true; | |
42 const int rowBytes = (srcRect.width() * 3 + 1) / 2; | |
43 const int alphaRowBytes = (srcRect.width() + 1) / 2; | |
44 image = new SkMemoryStream(rowBytes * srcRect.height()); | |
45 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height()); | |
46 uint8_t* dst = (uint8_t*)image->getMemoryBase(); | 83 uint8_t* dst = (uint8_t*)image->getMemoryBase(); |
47 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase(); | |
48 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { | 84 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { |
49 uint16_t* src = bitmap.getAddr16(0, y); | 85 uint16_t* src = bitmap.getAddr16(0, y); |
50 int x; | 86 int x; |
51 for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) { | 87 for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) { |
52 dst[0] = (SkGetPackedR4444(src[x]) << 4) | | 88 dst[0] = (SkGetPackedR4444(src[x]) << 4) | |
vandebo (ex-Chrome)
2013/08/21 22:37:17
UnPreMultiply?
ducky
2013/08/22 03:48:06
I'm going to do unpremul on the bitmap instead of
| |
53 SkGetPackedG4444(src[x]); | 89 SkGetPackedG4444(src[x]); |
54 dst[1] = (SkGetPackedB4444(src[x]) << 4) | | 90 dst[1] = (SkGetPackedB4444(src[x]) << 4) | |
55 SkGetPackedR4444(src[x + 1]); | 91 SkGetPackedR4444(src[x + 1]); |
56 dst[2] = (SkGetPackedG4444(src[x + 1]) << 4) | | 92 dst[2] = (SkGetPackedG4444(src[x + 1]) << 4) | |
57 SkGetPackedB4444(src[x + 1]); | 93 SkGetPackedB4444(src[x + 1]); |
58 dst += 3; | 94 dst += 3; |
59 alphaDst[0] = (SkGetPackedA4444(src[x]) << 4) | | |
60 SkGetPackedA4444(src[x + 1]); | |
61 if (alphaDst[0] != 0xFF) { | |
62 hasAlpha = true; | |
63 } | |
64 if (alphaDst[0]) { | |
65 isTransparent = false; | |
66 } | |
67 alphaDst++; | |
68 } | 95 } |
69 if (srcRect.width() & 1) { | 96 if (srcRect.width() & 1) { |
70 dst[0] = (SkGetPackedR4444(src[x]) << 4) | | 97 dst[0] = (SkGetPackedR4444(src[x]) << 4) | |
71 SkGetPackedG4444(src[x]); | 98 SkGetPackedG4444(src[x]); |
72 dst[1] = (SkGetPackedB4444(src[x]) << 4); | 99 dst[1] = (SkGetPackedB4444(src[x]) << 4); |
73 dst += 2; | 100 dst += 2; |
74 alphaDst[0] = (SkGetPackedA4444(src[x]) << 4); | |
75 if (alphaDst[0] != 0xF0) { | |
76 hasAlpha = true; | |
77 } | |
78 if (alphaDst[0] & 0xF0) { | |
79 isTransparent = false; | |
80 } | |
81 alphaDst++; | |
82 } | 101 } |
83 } | 102 } |
84 break; | 103 break; |
85 } | 104 } |
86 case SkBitmap::kRGB_565_Config: { | 105 case SkBitmap::kRGB_565_Config: { |
87 const int rowBytes = srcRect.width() * 3; | |
88 image = new SkMemoryStream(rowBytes * srcRect.height()); | |
89 uint8_t* dst = (uint8_t*)image->getMemoryBase(); | 106 uint8_t* dst = (uint8_t*)image->getMemoryBase(); |
90 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { | 107 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { |
91 uint16_t* src = bitmap.getAddr16(0, y); | 108 uint16_t* src = bitmap.getAddr16(0, y); |
92 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { | 109 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { |
93 dst[0] = SkGetPackedR16(src[x]); | 110 dst[0] = SkGetPackedR16(src[x]); |
94 dst[1] = SkGetPackedG16(src[x]); | 111 dst[1] = SkGetPackedG16(src[x]); |
95 dst[2] = SkGetPackedB16(src[x]); | 112 dst[2] = SkGetPackedB16(src[x]); |
96 dst += 3; | 113 dst += 3; |
97 } | 114 } |
98 } | 115 } |
99 break; | 116 break; |
100 } | 117 } |
101 case SkBitmap::kARGB_8888_Config: { | 118 case SkBitmap::kARGB_8888_Config: { |
102 isTransparent = true; | |
103 const int rowBytes = srcRect.width() * 3; | |
104 image = new SkMemoryStream(rowBytes * srcRect.height()); | |
105 alpha = new SkMemoryStream(srcRect.width() * srcRect.height()); | |
106 uint8_t* dst = (uint8_t*)image->getMemoryBase(); | 119 uint8_t* dst = (uint8_t*)image->getMemoryBase(); |
107 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase(); | |
108 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { | 120 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { |
109 uint32_t* src = bitmap.getAddr32(0, y); | 121 uint32_t* src = bitmap.getAddr32(0, y); |
110 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { | 122 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { |
111 dst[0] = SkGetPackedR32(src[x]); | 123 dst[0] = SkGetPackedR32(src[x]); |
112 dst[1] = SkGetPackedG32(src[x]); | 124 dst[1] = SkGetPackedG32(src[x]); |
113 dst[2] = SkGetPackedB32(src[x]); | 125 dst[2] = SkGetPackedB32(src[x]); |
114 dst += 3; | 126 dst += 3; |
115 alphaDst[0] = SkGetPackedA32(src[x]); | 127 } |
116 if (alphaDst[0] != 0xFF) { | 128 } |
129 break; | |
130 } | |
131 case SkBitmap::kA1_Config: | |
132 case SkBitmap::kA8_Config: { | |
133 ((uint8_t*)image->getMemoryBase())[0] = 0; | |
vandebo (ex-Chrome)
2013/08/21 22:37:17
Sk_ColorBLACK?
ducky
2013/08/22 03:48:06
No can do... SK_ColorBLACK is a 4-byte value conta
| |
134 break; | |
135 } | |
136 default: | |
137 SkASSERT(false); | |
138 } | |
139 bitmap.unlockPixels(); | |
140 | |
141 return image; | |
142 } | |
143 | |
144 // Extract the alpha data from a SkBitmap and output it in a SkStream. | |
145 // alphaData may be NULL if there was no alpha data to extract (image | |
146 // completely opaque). | |
147 // isTransparent outputs true if the alpha is completely transparent. | |
148 static SkStream* extract_alpha_data(const SkBitmap& bitmap, | |
149 const SkIRect& srcRect, | |
150 bool* isTransparent) { | |
151 SkMemoryStream* alpha = NULL; | |
152 bool hasAlpha = false; | |
153 *isTransparent = true; | |
154 | |
155 bitmap.lockPixels(); | |
156 switch (bitmap.getConfig()) { | |
157 case SkBitmap::kARGB_4444_Config: { | |
158 const int alphaRowBytes = (srcRect.width() + 1) / 2; | |
159 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height()); | |
160 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase(); | |
161 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { | |
162 uint16_t* src = bitmap.getAddr16(0, y); | |
163 int x; | |
164 for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) { | |
165 alphaDst[0] = (SkGetPackedA4444(src[x]) << 4) | | |
166 SkGetPackedA4444(src[x + 1]); | |
167 if (alphaDst[0] != SK_AlphaOPAQUE) { | |
117 hasAlpha = true; | 168 hasAlpha = true; |
118 } | 169 } |
119 if (alphaDst[0]) { | 170 if (alphaDst[0] != SK_AlphaTRANSPARENT) { |
120 isTransparent = false; | 171 *isTransparent = false; |
121 } | 172 } |
122 alphaDst++; | 173 alphaDst++; |
123 } | 174 } |
175 if (srcRect.width() & 1) { | |
176 alphaDst[0] = (SkGetPackedA4444(src[x]) << 4); | |
177 if (alphaDst[0] != (SK_AlphaOPAQUE & 0xF0)) { | |
178 hasAlpha = true; | |
179 } | |
180 if (alphaDst[0] != (SK_AlphaTRANSPARENT & 0xF0)) { | |
181 *isTransparent = false; | |
182 } | |
183 alphaDst++; | |
184 } | |
185 } | |
186 break; | |
187 } | |
188 case SkBitmap::kARGB_8888_Config: { | |
189 alpha = new SkMemoryStream(srcRect.width() * srcRect.height()); | |
190 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase(); | |
191 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { | |
192 uint32_t* src = bitmap.getAddr32(0, y); | |
193 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { | |
194 alphaDst[0] = SkGetPackedA32(src[x]); | |
195 if (alphaDst[0] != SK_AlphaOPAQUE) { | |
196 hasAlpha = true; | |
197 } | |
198 if (alphaDst[0] != SK_AlphaTRANSPARENT) { | |
199 *isTransparent = false; | |
200 } | |
201 alphaDst++; | |
202 } | |
124 } | 203 } |
125 break; | 204 break; |
126 } | 205 } |
127 case SkBitmap::kA1_Config: { | 206 case SkBitmap::kA1_Config: { |
128 isTransparent = true; | |
129 image = new SkMemoryStream(1); | |
130 ((uint8_t*)image->getMemoryBase())[0] = 0; | |
131 | |
132 const int alphaRowBytes = (srcRect.width() + 7) / 8; | 207 const int alphaRowBytes = (srcRect.width() + 7) / 8; |
133 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height()); | 208 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height()); |
134 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase(); | 209 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase(); |
135 int offset1 = srcRect.fLeft % 8; | 210 int offset1 = srcRect.fLeft % 8; |
136 int offset2 = 8 - offset1; | 211 int offset2 = 8 - offset1; |
137 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { | 212 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { |
138 uint8_t* src = bitmap.getAddr1(0, y); | 213 uint8_t* src = bitmap.getAddr1(0, y); |
139 // This may read up to one byte after src, but the potentially | 214 // This may read up to one byte after src, but the potentially |
140 // invalid bits are never used for computation. | 215 // invalid bits are never used for computation. |
141 for (int x = srcRect.fLeft; x < srcRect.fRight; x += 8) { | 216 for (int x = srcRect.fLeft; x < srcRect.fRight; x += 8) { |
142 if (offset1) { | 217 if (offset1) { |
143 alphaDst[0] = src[x / 8] << offset1 | | 218 alphaDst[0] = src[x / 8] << offset1 | |
144 src[x / 8 + 1] >> offset2; | 219 src[x / 8 + 1] >> offset2; |
145 } else { | 220 } else { |
146 alphaDst[0] = src[x / 8]; | 221 alphaDst[0] = src[x / 8]; |
147 } | 222 } |
148 if (x + 7 < srcRect.fRight && alphaDst[0] != 0xFF) { | 223 if (x + 7 < srcRect.fRight && |
224 alphaDst[0] != SK_AlphaOPAQUE) { | |
149 hasAlpha = true; | 225 hasAlpha = true; |
150 } | 226 } |
151 if (x + 7 < srcRect.fRight && alphaDst[0]) { | 227 if (x + 7 < srcRect.fRight && |
152 isTransparent = false; | 228 alphaDst[0] != SK_AlphaTRANSPARENT) { |
229 *isTransparent = false; | |
153 } | 230 } |
154 alphaDst++; | 231 alphaDst++; |
155 } | 232 } |
156 // Calculate the mask of bits we're interested in within the | 233 // Calculate the mask of bits we're interested in within the |
157 // last byte of alphaDst. | 234 // last byte of alphaDst. |
158 // width mod 8 == 1 -> 0x80 ... width mod 8 == 7 -> 0xFE | 235 // width mod 8 == 1 -> 0x80 ... width mod 8 == 7 -> 0xFE |
159 uint8_t mask = ~((1 << (8 - (srcRect.width() % 8))) - 1); | 236 uint8_t mask = ~((1 << (8 - (srcRect.width() % 8))) - 1); |
160 if (srcRect.width() % 8 && (alphaDst[-1] & mask) != mask) { | 237 if (srcRect.width() % 8 && |
238 ((alphaDst[-1] & mask) != (SK_AlphaOPAQUE & mask))) { | |
161 hasAlpha = true; | 239 hasAlpha = true; |
162 } | 240 } |
163 if (srcRect.width() % 8 && (alphaDst[-1] & mask)) { | 241 if (srcRect.width() % 8 && |
164 isTransparent = false; | 242 ((alphaDst[-1] & mask) != (SK_AlphaTRANSPARENT & mask))) { |
243 *isTransparent = false; | |
165 } | 244 } |
166 } | 245 } |
167 break; | 246 break; |
168 } | 247 } |
169 case SkBitmap::kA8_Config: { | 248 case SkBitmap::kA8_Config: { |
170 isTransparent = true; | |
171 image = new SkMemoryStream(1); | |
172 ((uint8_t*)image->getMemoryBase())[0] = 0; | |
173 | |
174 const int alphaRowBytes = srcRect.width(); | 249 const int alphaRowBytes = srcRect.width(); |
175 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height()); | 250 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height()); |
176 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase(); | 251 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase(); |
177 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { | 252 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { |
178 uint8_t* src = bitmap.getAddr8(0, y); | 253 uint8_t* src = bitmap.getAddr8(0, y); |
179 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { | 254 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { |
180 alphaDst[0] = src[x]; | 255 alphaDst[0] = src[x]; |
181 if (alphaDst[0] != 0xFF) { | 256 if (alphaDst[0] != SK_AlphaOPAQUE) { |
182 hasAlpha = true; | 257 hasAlpha = true; |
183 } | 258 } |
184 if (alphaDst[0]) { | 259 if (alphaDst[0] != SK_AlphaTRANSPARENT) { |
185 isTransparent = false; | 260 *isTransparent = false; |
186 } | 261 } |
187 alphaDst++; | 262 alphaDst++; |
188 } | 263 } |
189 } | 264 } |
190 break; | 265 break; |
191 } | 266 } |
267 case SkBitmap::kRGB_565_Config: | |
268 case SkBitmap::kIndex8_Config: { | |
269 *isTransparent = false; | |
270 break; | |
271 } | |
192 default: | 272 default: |
193 SkASSERT(false); | 273 SkASSERT(false); |
194 } | 274 } |
195 bitmap.unlockPixels(); | 275 bitmap.unlockPixels(); |
196 | 276 |
197 if (isTransparent) { | 277 if (!hasAlpha || *isTransparent) { |
198 SkSafeUnref(image); | 278 SkSafeUnref(alpha); |
279 return NULL; | |
199 } else { | 280 } else { |
200 *imageData = image; | 281 return alpha; |
201 } | |
202 | |
203 if (isTransparent || !hasAlpha) { | |
204 SkSafeUnref(alpha); | |
205 } else { | |
206 *alphaData = alpha; | |
207 } | 282 } |
208 } | 283 } |
209 | 284 |
210 SkPDFArray* makeIndexedColorSpace(SkColorTable* table) { | 285 SkPDFArray* makeIndexedColorSpace(SkColorTable* table) { |
211 SkPDFArray* result = new SkPDFArray(); | 286 SkPDFArray* result = new SkPDFArray(); |
212 result->reserve(4); | 287 result->reserve(4); |
213 result->appendName("Indexed"); | 288 result->appendName("Indexed"); |
214 result->appendName("DeviceRGB"); | 289 result->appendName("DeviceRGB"); |
215 result->appendInt(table->count() - 1); | 290 result->appendInt(table->count() - 1); |
216 | 291 |
(...skipping 14 matching lines...) Expand all Loading... | |
231 | 306 |
232 }; // namespace | 307 }; // namespace |
233 | 308 |
234 // static | 309 // static |
235 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap, | 310 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap, |
236 const SkIRect& srcRect, | 311 const SkIRect& srcRect, |
237 EncodeToDCTStream encoder) { | 312 EncodeToDCTStream encoder) { |
238 if (bitmap.getConfig() == SkBitmap::kNo_Config) { | 313 if (bitmap.getConfig() == SkBitmap::kNo_Config) { |
239 return NULL; | 314 return NULL; |
240 } | 315 } |
316 SkPDFImage* image = SkNEW_ARGS(SkPDFImage, (bitmap, srcRect, encoder)); | |
241 | 317 |
242 SkStream* imageData = NULL; | 318 if (image->isEmpty()) { |
vandebo (ex-Chrome)
2013/08/21 22:37:17
isEmpty just checks srcRect. 1) I think that's a
ducky
2013/08/22 03:48:06
Good point, it probably does change behavior.
What
| |
243 SkStream* alphaData = NULL; | 319 image->unref(); |
244 extractImageData(bitmap, srcRect, &imageData, &alphaData); | |
245 SkAutoUnref unrefImageData(imageData); | |
246 SkAutoUnref unrefAlphaData(alphaData); | |
247 if (!imageData) { | |
248 SkASSERT(!alphaData); | |
249 return NULL; | 320 return NULL; |
321 } else { | |
322 return image; | |
250 } | 323 } |
251 | |
252 SkPDFImage* image = | |
253 SkNEW_ARGS(SkPDFImage, (imageData, bitmap, srcRect, false, encoder)); | |
254 | |
255 if (alphaData != NULL) { | |
256 // Don't try to use DCT compression with alpha because alpha is small | |
257 // anyway and it could lead to artifacts. | |
258 image->addSMask(SkNEW_ARGS(SkPDFImage, (alphaData, bitmap, srcRect, true , NULL)))->unref(); | |
259 } | |
260 return image; | |
261 } | 324 } |
262 | 325 |
263 SkPDFImage::~SkPDFImage() { | 326 SkPDFImage::~SkPDFImage() { |
264 fResources.unrefAll(); | 327 fResources.unrefAll(); |
265 } | 328 } |
266 | 329 |
267 SkPDFImage* SkPDFImage::addSMask(SkPDFImage* mask) { | 330 SkPDFImage* SkPDFImage::addSMask(SkPDFImage* mask) { |
268 fResources.push(mask); | 331 fResources.push(mask); |
269 mask->ref(); | 332 mask->ref(); |
270 insert("SMask", new SkPDFObjRef(mask))->unref(); | 333 insert("SMask", new SkPDFObjRef(mask))->unref(); |
271 return mask; | 334 return mask; |
272 } | 335 } |
273 | 336 |
274 void SkPDFImage::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, | 337 void SkPDFImage::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, |
275 SkTSet<SkPDFObject*>* newResourceObjects) { | 338 SkTSet<SkPDFObject*>* newResourceObjects) { |
276 GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects); | 339 GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects); |
277 } | 340 } |
278 | 341 |
279 SkPDFImage::SkPDFImage(SkStream* imageData, | 342 SkPDFImage::SkPDFImage(const SkBitmap& bitmap, |
280 const SkBitmap& bitmap, | |
281 const SkIRect& srcRect, | 343 const SkIRect& srcRect, |
282 bool doingAlpha, | |
283 EncodeToDCTStream encoder) | 344 EncodeToDCTStream encoder) |
284 : SkPDFImageStream(imageData, bitmap, srcRect, encoder) { | 345 : fBitmap(bitmap), |
285 SkBitmap::Config config = bitmap.getConfig(); | 346 fSrcRect(srcRect), |
286 bool alphaOnly = (config == SkBitmap::kA1_Config || | 347 fEncoder(encoder) { |
287 config == SkBitmap::kA8_Config); | 348 bool isTransparent; |
349 SkAutoTUnref<SkStream> alphaData(extract_alpha_data(bitmap, srcRect, | |
350 &isTransparent)); | |
351 if (isTransparent) { | |
352 fSrcRect = SkIRect::MakeEmpty(); | |
353 return; | |
354 } | |
355 if (alphaData.get() != NULL) { | |
356 addSMask(SkNEW_ARGS(SkPDFImage, | |
357 (alphaData.get(), bitmap, srcRect)))->unref(); | |
358 } | |
359 | |
360 initImageParams(false); | |
361 } | |
362 | |
363 SkPDFImage::SkPDFImage(SkStream* stream, const SkBitmap& bitmap, | |
364 const SkIRect& srcRect) | |
365 : fBitmap(bitmap), | |
366 fSrcRect(srcRect), | |
367 fEncoder(NULL) { | |
368 setData(stream); | |
369 insertInt("Length", getData()->getLength()); | |
370 setState(kNoCompression_State); | |
371 | |
372 initImageParams(true); | |
373 } | |
374 | |
375 SkPDFImage::SkPDFImage(SkPDFImage& pdfImage) | |
376 : SkPDFStream(pdfImage), | |
377 fBitmap(pdfImage.fBitmap), | |
378 fSrcRect(pdfImage.fSrcRect), | |
379 fEncoder(pdfImage.fEncoder){ | |
380 // Nothing to do here - the image params are already copied in SkPDFStream's | |
vandebo (ex-Chrome)
2013/08/21 22:37:17
Remove comment.
ducky
2013/08/22 03:48:06
I think the comment about SkPDFStream is helpful -
| |
381 // constructor, and the bitmap will be regenerated and re-encoded in | |
382 // populate. | |
383 } | |
384 | |
385 void SkPDFImage::initImageParams(bool isAlpha) { | |
386 SkBitmap::Config config = fBitmap.getConfig(); | |
288 | 387 |
289 insertName("Type", "XObject"); | 388 insertName("Type", "XObject"); |
290 insertName("Subtype", "Image"); | 389 insertName("Subtype", "Image"); |
291 | 390 |
292 if (!doingAlpha && alphaOnly) { | 391 bool alphaOnly = (config == SkBitmap::kA1_Config || |
392 config == SkBitmap::kA8_Config); | |
393 | |
394 if (!isAlpha && alphaOnly) { | |
293 // For alpha only images, we stretch a single pixel of black for | 395 // For alpha only images, we stretch a single pixel of black for |
294 // the color/shape part. | 396 // the color/shape part. |
295 SkAutoTUnref<SkPDFInt> one(new SkPDFInt(1)); | 397 SkAutoTUnref<SkPDFInt> one(new SkPDFInt(1)); |
296 insert("Width", one.get()); | 398 insert("Width", one.get()); |
297 insert("Height", one.get()); | 399 insert("Height", one.get()); |
298 } else { | 400 } else { |
299 insertInt("Width", srcRect.width()); | 401 insertInt("Width", fSrcRect.width()); |
300 insertInt("Height", srcRect.height()); | 402 insertInt("Height", fSrcRect.height()); |
301 } | 403 } |
302 | 404 |
303 // if (!image mask) { | 405 if (isAlpha || alphaOnly) { |
304 if (doingAlpha || alphaOnly) { | |
305 insertName("ColorSpace", "DeviceGray"); | 406 insertName("ColorSpace", "DeviceGray"); |
306 } else if (config == SkBitmap::kIndex8_Config) { | 407 } else if (config == SkBitmap::kIndex8_Config) { |
307 SkAutoLockPixels alp(bitmap); | 408 SkAutoLockPixels alp(fBitmap); |
308 insert("ColorSpace", | 409 insert("ColorSpace", |
309 makeIndexedColorSpace(bitmap.getColorTable()))->unref(); | 410 makeIndexedColorSpace(fBitmap.getColorTable()))->unref(); |
310 } else { | 411 } else { |
311 insertName("ColorSpace", "DeviceRGB"); | 412 insertName("ColorSpace", "DeviceRGB"); |
312 } | 413 } |
313 // } | |
314 | 414 |
315 int bitsPerComp = 8; | 415 int bitsPerComp = 8; |
316 if (config == SkBitmap::kARGB_4444_Config) { | 416 if (config == SkBitmap::kARGB_4444_Config) { |
317 bitsPerComp = 4; | 417 bitsPerComp = 4; |
318 } else if (doingAlpha && config == SkBitmap::kA1_Config) { | 418 } else if (isAlpha && config == SkBitmap::kA1_Config) { |
319 bitsPerComp = 1; | 419 bitsPerComp = 1; |
320 } | 420 } |
321 insertInt("BitsPerComponent", bitsPerComp); | 421 insertInt("BitsPerComponent", bitsPerComp); |
322 | 422 |
323 if (config == SkBitmap::kRGB_565_Config) { | 423 if (config == SkBitmap::kRGB_565_Config) { |
424 SkASSERT(!isAlpha); | |
324 SkAutoTUnref<SkPDFInt> zeroVal(new SkPDFInt(0)); | 425 SkAutoTUnref<SkPDFInt> zeroVal(new SkPDFInt(0)); |
325 SkAutoTUnref<SkPDFScalar> scale5Val( | 426 SkAutoTUnref<SkPDFScalar> scale5Val( |
326 new SkPDFScalar(SkFloatToScalar(8.2258f))); // 255/2^5-1 | 427 new SkPDFScalar(SkFloatToScalar(8.2258f))); // 255/2^5-1 |
327 SkAutoTUnref<SkPDFScalar> scale6Val( | 428 SkAutoTUnref<SkPDFScalar> scale6Val( |
328 new SkPDFScalar(SkFloatToScalar(4.0476f))); // 255/2^6-1 | 429 new SkPDFScalar(SkFloatToScalar(4.0476f))); // 255/2^6-1 |
329 SkAutoTUnref<SkPDFArray> decodeValue(new SkPDFArray()); | 430 SkAutoTUnref<SkPDFArray> decodeValue(new SkPDFArray()); |
330 decodeValue->reserve(6); | 431 decodeValue->reserve(6); |
331 decodeValue->append(zeroVal.get()); | 432 decodeValue->append(zeroVal.get()); |
332 decodeValue->append(scale5Val.get()); | 433 decodeValue->append(scale5Val.get()); |
333 decodeValue->append(zeroVal.get()); | 434 decodeValue->append(zeroVal.get()); |
334 decodeValue->append(scale6Val.get()); | 435 decodeValue->append(scale6Val.get()); |
335 decodeValue->append(zeroVal.get()); | 436 decodeValue->append(zeroVal.get()); |
336 decodeValue->append(scale5Val.get()); | 437 decodeValue->append(scale5Val.get()); |
337 insert("Decode", decodeValue.get()); | 438 insert("Decode", decodeValue.get()); |
338 } | 439 } |
339 } | 440 } |
441 | |
442 SkStream* SkPDFImage::getCompressedStream() { | |
443 SkDynamicMemoryWStream dctCompressedWStream; | |
444 if (fEncoder && fEncoder(&dctCompressedWStream, fBitmap, fSrcRect)) { | |
vandebo (ex-Chrome)
2013/08/21 22:37:17
This doesn't handle the case where the image has a
ducky
2013/08/22 03:48:06
Yeah, this regressed a quite a few tests... fixed.
| |
445 // Ensure compressed version is smaller than the uncompressed version | |
446 if (dctCompressedWStream.getOffset() < | |
447 get_uncompressed_size(fBitmap, fSrcRect)) { | |
vandebo (ex-Chrome)
2013/08/21 22:37:17
if get_uncompressed_size is 1, you probably should
ducky
2013/08/22 03:48:06
Done.
| |
448 SkData* data = dctCompressedWStream.copyToData(); | |
449 SkMemoryStream* stream = SkNEW_ARGS(SkMemoryStream, (data)); | |
450 data->unref(); | |
451 return stream; | |
452 } | |
453 } | |
454 return NULL; | |
455 } | |
456 | |
457 bool SkPDFImage::populate(SkPDFCatalog* catalog) { | |
458 if (getState() == kUnused_State) { | |
459 // Initializing image data for the first time. | |
460 if (!skip_compression(catalog)) { | |
461 SkAutoTUnref<SkStream> stream(getCompressedStream()); | |
462 if (stream.get() != NULL) { | |
463 setData(stream.get()); | |
464 insertName("Filter", "DCTDecode"); | |
465 insertInt("ColorTransform", kNoColorTransform); | |
466 insertInt("Length", getData()->getLength()); | |
467 setState(kCompressed_State); | |
468 } | |
469 } | |
470 | |
471 // Fallback if it doesn't work. | |
472 if (getState() == kUnused_State) { | |
473 SkAutoTUnref<SkStream> stream(extract_image_data(fBitmap, | |
474 fSrcRect)); | |
475 setData(stream.get()); | |
476 return INHERITED::populate(catalog); | |
477 } | |
478 } else if (getState() == kNoCompression_State && | |
479 !skip_compression(catalog) && | |
480 (SkFlate::HaveFlate() || fEncoder)) { | |
481 // Compression has not been requested when the stream was first created. | |
482 // But a new Catalog would want it compressed. | |
vandebo (ex-Chrome)
2013/08/21 22:37:17
...created, but the new catalog wants it compresse
ducky
2013/08/22 03:48:06
Done.
| |
483 if (!getSubstitute()) { | |
484 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this)); | |
485 setSubstitute(substitute); | |
486 catalog->setSubstitute(this, substitute); | |
487 } | |
488 return false; | |
489 } | |
490 return true; | |
491 } | |
OLD | NEW |