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

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

Issue 22889020: Refactor SkPDFImage (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Further style improvements Created 7 years, 4 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 | Annotate | Revision Log
OLDNEW
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 static const int kNoColorTransform = 0;
20 22
21 void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect, 23 static bool skip_compression(SkPDFCatalog* catalog) {
22 SkStream** imageData, SkStream** alphaData) { 24 return SkToBool(catalog->getDocumentFlags() &
23 SkMemoryStream* image = NULL; 25 SkPDFDocument::kFavorSpeedOverSize_Flags);
24 SkMemoryStream* alpha = NULL; 26 }
25 bool hasAlpha = false; 27
26 bool isTransparent = false; 28 static size_t get_uncompressed_size(const SkBitmap& bitmap,
29 const SkIRect& srcRect) {
30 switch (bitmap.getConfig()) {
31 case SkBitmap::kIndex8_Config:
32 return srcRect.width() * srcRect.height();
33 case SkBitmap::kARGB_4444_Config:
34 return ((srcRect.width() * 3 + 1) / 2) * srcRect.height();
35 case SkBitmap::kRGB_565_Config:
36 return srcRect.width() * 3 * srcRect.height();
37 case SkBitmap::kARGB_8888_Config:
38 return srcRect.width() * 3 * srcRect.height();
39 case SkBitmap::kA1_Config:
40 case SkBitmap::kA8_Config:
41 return 1;
42 default:
43 SkASSERT(false);
44 return 0;
45 }
46 }
47
48 static SkStream* extract_index8_image(const SkBitmap& bitmap,
49 const SkIRect& srcRect) {
50 const int rowBytes = srcRect.width();
51 SkStream* stream = SkNEW_ARGS(SkMemoryStream,
52 (get_uncompressed_size(bitmap, srcRect)));
53 uint8_t* dst = (uint8_t*)stream->getMemoryBase();
54
55 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
56 memcpy(dst, bitmap.getAddr8(srcRect.fLeft, y), rowBytes);
57 dst += rowBytes;
58 }
59 return stream;
60 }
61
62 static SkStream* extract_argb4444_data(const SkBitmap& bitmap,
63 const SkIRect& srcRect,
64 bool extractAlpha,
65 bool* isOpaque,
66 bool* isTransparent) {
67 SkStream* stream;
68 uint8_t* dst = NULL;
69 if (extractAlpha) {
70 const int alphaRowBytes = (srcRect.width() + 1) / 2;
71 stream = SkNEW_ARGS(SkMemoryStream,
72 (alphaRowBytes * srcRect.height()));
73 } else {
74 stream = SkNEW_ARGS(SkMemoryStream,
75 (get_uncompressed_size(bitmap, srcRect)));
76 }
77 dst = (uint8_t*)stream->getMemoryBase();
78
79 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
80 uint16_t* src = bitmap.getAddr16(0, y);
81 int x;
82 for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) {
83 if (extractAlpha) {
84 dst[0] = (SkGetPackedA4444(src[x]) << 4) |
85 SkGetPackedA4444(src[x + 1]);
86 *isOpaque &= dst[0] == SK_AlphaOPAQUE;
vandebo (ex-Chrome) 2013/08/23 15:45:36 Has I mentioned, this function should tolerate NUL
ducky 2013/08/23 17:59:50 Done. Added at a higher level to avoid duplication
87 *isTransparent &= dst[0] == SK_AlphaTRANSPARENT;
88 dst++;
89 } else {
90 dst[0] = (SkGetPackedR4444(src[x]) << 4) |
91 SkGetPackedG4444(src[x]);
92 dst[1] = (SkGetPackedB4444(src[x]) << 4) |
93 SkGetPackedR4444(src[x + 1]);
94 dst[2] = (SkGetPackedG4444(src[x + 1]) << 4) |
95 SkGetPackedB4444(src[x + 1]);
96 dst += 3;
97 }
98 }
99 if (srcRect.width() & 1) {
100 if (extractAlpha) {
101 dst[0] = (SkGetPackedA4444(src[x]) << 4);
102 *isOpaque &= dst[0] == (SK_AlphaOPAQUE & 0xF0);
103 *isTransparent &= dst[0] == (SK_AlphaTRANSPARENT & 0xF0);
104 dst++;
105
106 } else {
107 dst[0] = (SkGetPackedR4444(src[x]) << 4) |
108 SkGetPackedG4444(src[x]);
109 dst[1] = (SkGetPackedB4444(src[x]) << 4);
110 dst += 2;
111 }
112 }
113 }
114 return stream;
115 }
116
117 static SkStream* extract_rgb565_image(const SkBitmap& bitmap,
118 const SkIRect& srcRect) {
119 SkStream* stream = SkNEW_ARGS(SkMemoryStream,
120 (get_uncompressed_size(bitmap,
121 srcRect)));
122 uint8_t* dst = (uint8_t*)stream->getMemoryBase();
123 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
124 uint16_t* src = bitmap.getAddr16(0, y);
125 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
126 dst[0] = SkGetPackedR16(src[x]);
127 dst[1] = SkGetPackedG16(src[x]);
128 dst[2] = SkGetPackedB16(src[x]);
129 dst += 3;
130 }
131 }
132 return stream;
133 }
134
135 static SkStream* extract_argb8888_data(const SkBitmap& bitmap,
136 const SkIRect& srcRect,
137 bool extractAlpha,
138 bool* isOpaque,
139 bool* isTransparent) {
140 SkStream* stream;
141 if (extractAlpha) {
142 stream = SkNEW_ARGS(SkMemoryStream,
143 (srcRect.width() * srcRect.height()));
144 } else {
145 stream = SkNEW_ARGS(SkMemoryStream,
146 (get_uncompressed_size(bitmap, srcRect)));
147 }
148 uint8_t* dst = (uint8_t*)stream->getMemoryBase();
149
150 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
151 uint32_t* src = bitmap.getAddr32(0, y);
152 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
153 if (extractAlpha) {
154 dst[0] = SkGetPackedA32(src[x]);
155 *isOpaque &= dst[0] == SK_AlphaOPAQUE;
156 *isTransparent &= dst[0] == SK_AlphaTRANSPARENT;
157 dst++;
158 } else {
159 dst[0] = SkGetPackedR32(src[x]);
160 dst[1] = SkGetPackedG32(src[x]);
161 dst[2] = SkGetPackedB32(src[x]);
162 dst += 3;
163 }
164 }
165 }
166 return stream;
167 }
168
169 static SkStream* extract_a1_alpha(const SkBitmap& bitmap,
170 const SkIRect& srcRect,
171 bool* isOpaque,
172 bool* isTransparent) {
173 const int alphaRowBytes = (srcRect.width() + 7) / 8;
174 SkStream* stream = SkNEW_ARGS(SkMemoryStream,
175 (alphaRowBytes * srcRect.height()));
176 uint8_t* alphaDst = (uint8_t*)stream->getMemoryBase();
177
178 int offset1 = srcRect.fLeft % 8;
179 int offset2 = 8 - offset1;
180
181 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
182 uint8_t* src = bitmap.getAddr1(0, y);
183 // This may read up to one byte after src, but the
184 // potentially invalid bits are never used for computation.
185 for (int x = srcRect.fLeft; x < srcRect.fRight; x += 8) {
186 if (offset1) {
187 alphaDst[0] = src[x / 8] << offset1 |
188 src[x / 8 + 1] >> offset2;
189 } else {
190 alphaDst[0] = src[x / 8];
191 }
192 if (x + 7 < srcRect.fRight) {
193 *isOpaque &= alphaDst[0] == SK_AlphaOPAQUE;
194 }
195 if (x + 7 < srcRect.fRight) {
vandebo (ex-Chrome) 2013/08/23 15:45:36 This is the same condition, put the two bodies tog
ducky 2013/08/23 17:59:50 D'oh.
196 *isTransparent &= alphaDst[0] == SK_AlphaTRANSPARENT;
197 }
198 alphaDst++;
199 }
200 // Calculate the mask of bits we're interested in within the
201 // last byte of alphaDst.
202 // width mod 8 == 1 -> 0x80 ... width mod 8 == 7 -> 0xFE
203 uint8_t mask = ~((1 << (8 - (srcRect.width() % 8))) - 1);
204 if (srcRect.width() % 8) {
205 *isOpaque &= (alphaDst[-1] & mask) == (SK_AlphaOPAQUE & mask);
206 }
207 if (srcRect.width() % 8) {
vandebo (ex-Chrome) 2013/08/23 15:45:36 Same here
ducky 2013/08/23 17:59:50 Done.
208 *isTransparent &=
209 (alphaDst[-1] & mask) == (SK_AlphaTRANSPARENT & mask);
210 }
211 }
212 return stream;
213 }
214
215 static SkStream* extract_a8_alpha(const SkBitmap& bitmap,
216 const SkIRect& srcRect,
217 bool* isOpaque,
218 bool* isTransparent) {
219 const int alphaRowBytes = srcRect.width();
220 SkStream* stream = SkNEW_ARGS(SkMemoryStream,
221 (alphaRowBytes * srcRect.height()));
222 uint8_t* alphaDst = (uint8_t*)stream->getMemoryBase();
223
224 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
225 uint8_t* src = bitmap.getAddr8(0, y);
226 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
227 alphaDst[0] = src[x];
228 *isOpaque &= alphaDst[0] == SK_AlphaOPAQUE;
229 *isTransparent &= alphaDst[0] == SK_AlphaTRANSPARENT;
230 alphaDst++;
231 }
232 }
233 return stream;
234 }
235
236 static SkStream* create_black_image() {
237 SkStream* stream = SkNEW_ARGS(SkMemoryStream, (1));
238 ((uint8_t*)stream->getMemoryBase())[0] = 0;
239 return stream;
240 }
241
242 /**
243 * Extract either the color or image data from a SkBitmap into a SkStream.
244 * @param bitmap Bitmap to extract data from.
245 * @param srcRect Region in the bitmap to extract.
246 * @param extractAlpha Set to true to extract the alpha data or false to
247 * extract the color data.
248 * @param isTransparent Pointer to a bool to output whether the alpha is
249 * completely transparent. Only valid when
250 * extractAlpha == true. May be NULL when
251 * extractAlpha == false.
252 * @return Unencoded image data, or NULL if either data was not
253 * available or alpha data was requested but the image was
254 * entirely transparent or opaque.
255 */
256 static SkStream* extract_image_data(const SkBitmap& bitmap,
257 const SkIRect& srcRect,
258 bool extractAlpha, bool* isTransparent) {
259 SkStream* stream = NULL;
260 bool isOpaque = true;
261 if (extractAlpha) {
262 *isTransparent = true;
263 }
27 264
28 bitmap.lockPixels(); 265 bitmap.lockPixels();
29 switch (bitmap.getConfig()) { 266 switch (bitmap.getConfig()) {
30 case SkBitmap::kIndex8_Config: { 267 case SkBitmap::kIndex8_Config:
31 const int rowBytes = srcRect.width(); 268 if (!extractAlpha) {
32 image = new SkMemoryStream(rowBytes * srcRect.height()); 269 stream = extract_index8_image(bitmap, srcRect);
33 uint8_t* dst = (uint8_t*)image->getMemoryBase(); 270 } else {
34 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 271 *isTransparent = false;
35 memcpy(dst, bitmap.getAddr8(srcRect.fLeft, y), rowBytes); 272 }
36 dst += rowBytes; 273 break;
37 } 274 case SkBitmap::kARGB_4444_Config:
38 break; 275 stream = extract_argb4444_data(bitmap, srcRect, extractAlpha,
39 } 276 &isOpaque, isTransparent);
40 case SkBitmap::kARGB_4444_Config: { 277 break;
41 isTransparent = true; 278 case SkBitmap::kRGB_565_Config:
42 const int rowBytes = (srcRect.width() * 3 + 1) / 2; 279 if (!extractAlpha) {
43 const int alphaRowBytes = (srcRect.width() + 1) / 2; 280 stream = extract_rgb565_image(bitmap, srcRect);
44 image = new SkMemoryStream(rowBytes * srcRect.height()); 281 } else {
45 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height()); 282 *isTransparent = false;
46 uint8_t* dst = (uint8_t*)image->getMemoryBase(); 283 }
47 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase(); 284 break;
48 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 285 case SkBitmap::kARGB_8888_Config:
49 uint16_t* src = bitmap.getAddr16(0, y); 286 stream = extract_argb8888_data(bitmap, srcRect, extractAlpha,
50 int x; 287 &isOpaque, isTransparent);
51 for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) { 288 break;
52 dst[0] = (SkGetPackedR4444(src[x]) << 4) | 289 case SkBitmap::kA1_Config:
53 SkGetPackedG4444(src[x]); 290 if (!extractAlpha) {
54 dst[1] = (SkGetPackedB4444(src[x]) << 4) | 291 stream = create_black_image();
55 SkGetPackedR4444(src[x + 1]); 292 } else {
56 dst[2] = (SkGetPackedG4444(src[x + 1]) << 4) | 293 stream = extract_a1_alpha(bitmap, srcRect,
57 SkGetPackedB4444(src[x + 1]); 294 &isOpaque, isTransparent);
58 dst += 3; 295 }
59 alphaDst[0] = (SkGetPackedA4444(src[x]) << 4) | 296 break;
60 SkGetPackedA4444(src[x + 1]); 297 case SkBitmap::kA8_Config:
61 if (alphaDst[0] != 0xFF) { 298 if (!extractAlpha) {
62 hasAlpha = true; 299 stream = create_black_image();
63 } 300 } else {
64 if (alphaDst[0]) { 301 stream = extract_a8_alpha(bitmap, srcRect,
65 isTransparent = false; 302 &isOpaque, isTransparent);
66 } 303 }
67 alphaDst++; 304 break;
68 }
69 if (srcRect.width() & 1) {
70 dst[0] = (SkGetPackedR4444(src[x]) << 4) |
71 SkGetPackedG4444(src[x]);
72 dst[1] = (SkGetPackedB4444(src[x]) << 4);
73 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 }
83 }
84 break;
85 }
86 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();
90 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
91 uint16_t* src = bitmap.getAddr16(0, y);
92 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
93 dst[0] = SkGetPackedR16(src[x]);
94 dst[1] = SkGetPackedG16(src[x]);
95 dst[2] = SkGetPackedB16(src[x]);
96 dst += 3;
97 }
98 }
99 break;
100 }
101 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();
107 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase();
108 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
109 uint32_t* src = bitmap.getAddr32(0, y);
110 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
111 dst[0] = SkGetPackedR32(src[x]);
112 dst[1] = SkGetPackedG32(src[x]);
113 dst[2] = SkGetPackedB32(src[x]);
114 dst += 3;
115 alphaDst[0] = SkGetPackedA32(src[x]);
116 if (alphaDst[0] != 0xFF) {
117 hasAlpha = true;
118 }
119 if (alphaDst[0]) {
120 isTransparent = false;
121 }
122 alphaDst++;
123 }
124 }
125 break;
126 }
127 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;
133 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height());
134 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase();
135 int offset1 = srcRect.fLeft % 8;
136 int offset2 = 8 - offset1;
137 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
138 uint8_t* src = bitmap.getAddr1(0, y);
139 // This may read up to one byte after src, but the potentially
140 // invalid bits are never used for computation.
141 for (int x = srcRect.fLeft; x < srcRect.fRight; x += 8) {
142 if (offset1) {
143 alphaDst[0] = src[x / 8] << offset1 |
144 src[x / 8 + 1] >> offset2;
145 } else {
146 alphaDst[0] = src[x / 8];
147 }
148 if (x + 7 < srcRect.fRight && alphaDst[0] != 0xFF) {
149 hasAlpha = true;
150 }
151 if (x + 7 < srcRect.fRight && alphaDst[0]) {
152 isTransparent = false;
153 }
154 alphaDst++;
155 }
156 // Calculate the mask of bits we're interested in within the
157 // last byte of alphaDst.
158 // width mod 8 == 1 -> 0x80 ... width mod 8 == 7 -> 0xFE
159 uint8_t mask = ~((1 << (8 - (srcRect.width() % 8))) - 1);
160 if (srcRect.width() % 8 && (alphaDst[-1] & mask) != mask) {
161 hasAlpha = true;
162 }
163 if (srcRect.width() % 8 && (alphaDst[-1] & mask)) {
164 isTransparent = false;
165 }
166 }
167 break;
168 }
169 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();
175 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height());
176 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase();
177 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
178 uint8_t* src = bitmap.getAddr8(0, y);
179 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
180 alphaDst[0] = src[x];
181 if (alphaDst[0] != 0xFF) {
182 hasAlpha = true;
183 }
184 if (alphaDst[0]) {
185 isTransparent = false;
186 }
187 alphaDst++;
188 }
189 }
190 break;
191 }
192 default: 305 default:
193 SkASSERT(false); 306 SkASSERT(false);
194 } 307 }
195 bitmap.unlockPixels(); 308 bitmap.unlockPixels();
196 309
197 if (isTransparent) { 310 if (extractAlpha && (*isTransparent || isOpaque)) {
198 SkSafeUnref(image); 311 SkSafeUnref(stream);
199 } else { 312 return NULL;
200 *imageData = image; 313 }
201 } 314 return stream;
202 315 }
203 if (isTransparent || !hasAlpha) { 316
204 SkSafeUnref(alpha); 317 static SkPDFArray* make_indexed_color_space(SkColorTable* table) {
205 } else {
206 *alphaData = alpha;
207 }
208 }
209
210 SkPDFArray* makeIndexedColorSpace(SkColorTable* table) {
211 SkPDFArray* result = new SkPDFArray(); 318 SkPDFArray* result = new SkPDFArray();
212 result->reserve(4); 319 result->reserve(4);
213 result->appendName("Indexed"); 320 result->appendName("Indexed");
214 result->appendName("DeviceRGB"); 321 result->appendName("DeviceRGB");
215 result->appendInt(table->count() - 1); 322 result->appendInt(table->count() - 1);
216 323
217 // Potentially, this could be represented in fewer bytes with a stream. 324 // Potentially, this could be represented in fewer bytes with a stream.
218 // Max size as a string is 1.5k. 325 // Max size as a string is 1.5k.
219 SkString index; 326 SkString index;
220 for (int i = 0; i < table->count(); i++) { 327 for (int i = 0; i < table->count(); i++) {
221 char buf[3]; 328 char buf[3];
222 SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]); 329 SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]);
223 buf[0] = SkGetPackedR32(color); 330 buf[0] = SkGetPackedR32(color);
224 buf[1] = SkGetPackedG32(color); 331 buf[1] = SkGetPackedG32(color);
225 buf[2] = SkGetPackedB32(color); 332 buf[2] = SkGetPackedB32(color);
226 index.append(buf, 3); 333 index.append(buf, 3);
227 } 334 }
228 result->append(new SkPDFString(index))->unref(); 335 result->append(new SkPDFString(index))->unref();
229 return result; 336 return result;
230 } 337 }
231 338
232 }; // namespace
233
234 // static 339 // static
235 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap, 340 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap,
236 const SkIRect& srcRect, 341 const SkIRect& srcRect,
237 EncodeToDCTStream encoder) { 342 EncodeToDCTStream encoder) {
238 if (bitmap.getConfig() == SkBitmap::kNo_Config) { 343 if (bitmap.getConfig() == SkBitmap::kNo_Config) {
239 return NULL; 344 return NULL;
240 } 345 }
241 346
242 SkStream* imageData = NULL; 347 bool isTransparent = false;
243 SkStream* alphaData = NULL; 348 SkAutoTUnref<SkStream> alphaData;
244 extractImageData(bitmap, srcRect, &imageData, &alphaData); 349 if (!bitmap.isOpaque()) {
245 SkAutoUnref unrefImageData(imageData); 350 // Note that isOpaque is not guaranteed to return false for bitmaps
246 SkAutoUnref unrefAlphaData(alphaData); 351 // with alpha support but a completely opaque alpha channel,
247 if (!imageData) { 352 // so alphaData may still be NULL if we have a completely opaque
248 SkASSERT(!alphaData); 353 // (or transparent) bitmap.
354 alphaData.reset(
355 extract_image_data(bitmap, srcRect, true, &isTransparent));
356 }
357 if (isTransparent) {
249 return NULL; 358 return NULL;
250 } 359 }
251 360
252 SkPDFImage* image = 361 SkPDFImage* image = SkNEW_ARGS(SkPDFImage, (NULL, bitmap,
253 SkNEW_ARGS(SkPDFImage, (imageData, bitmap, srcRect, false, encoder)); 362 false, srcRect, encoder));
363 if (alphaData.get() != NULL) {
364 SkAutoTUnref<SkPDFImage> mask(
365 SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap,
366 true, srcRect, NULL)));
367 image->addSMask(mask);
368 }
254 369
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; 370 return image;
261 } 371 }
262 372
263 SkPDFImage::~SkPDFImage() { 373 SkPDFImage::~SkPDFImage() {
264 fResources.unrefAll(); 374 fResources.unrefAll();
265 } 375 }
266 376
267 SkPDFImage* SkPDFImage::addSMask(SkPDFImage* mask) { 377 SkPDFImage* SkPDFImage::addSMask(SkPDFImage* mask) {
268 fResources.push(mask); 378 fResources.push(mask);
269 mask->ref(); 379 mask->ref();
270 insert("SMask", new SkPDFObjRef(mask))->unref(); 380 insert("SMask", new SkPDFObjRef(mask))->unref();
271 return mask; 381 return mask;
272 } 382 }
273 383
274 void SkPDFImage::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, 384 void SkPDFImage::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
275 SkTSet<SkPDFObject*>* newResourceObjects) { 385 SkTSet<SkPDFObject*>* newResourceObjects) {
276 GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects); 386 GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects);
277 } 387 }
278 388
279 SkPDFImage::SkPDFImage(SkStream* imageData, 389 SkPDFImage::SkPDFImage(SkStream* stream,
280 const SkBitmap& bitmap, 390 const SkBitmap& bitmap,
391 bool isAlpha,
281 const SkIRect& srcRect, 392 const SkIRect& srcRect,
282 bool doingAlpha,
283 EncodeToDCTStream encoder) 393 EncodeToDCTStream encoder)
284 : SkPDFImageStream(imageData, bitmap, srcRect, encoder) { 394 : fBitmap(bitmap),
285 SkBitmap::Config config = bitmap.getConfig(); 395 fSrcRect(srcRect),
286 bool alphaOnly = (config == SkBitmap::kA1_Config || 396 fEncoder(encoder) {
287 config == SkBitmap::kA8_Config); 397
398 if (stream != NULL) {
399 setData(stream);
400 fStreamValid = true;
401 } else {
402 fStreamValid = false;
403 }
404
405 SkBitmap::Config config = fBitmap.getConfig();
288 406
289 insertName("Type", "XObject"); 407 insertName("Type", "XObject");
290 insertName("Subtype", "Image"); 408 insertName("Subtype", "Image");
291 409
292 if (!doingAlpha && alphaOnly) { 410 bool alphaOnly = (config == SkBitmap::kA1_Config ||
411 config == SkBitmap::kA8_Config);
412
413 if (!isAlpha && alphaOnly) {
293 // For alpha only images, we stretch a single pixel of black for 414 // For alpha only images, we stretch a single pixel of black for
294 // the color/shape part. 415 // the color/shape part.
295 SkAutoTUnref<SkPDFInt> one(new SkPDFInt(1)); 416 SkAutoTUnref<SkPDFInt> one(new SkPDFInt(1));
296 insert("Width", one.get()); 417 insert("Width", one.get());
297 insert("Height", one.get()); 418 insert("Height", one.get());
298 } else { 419 } else {
299 insertInt("Width", srcRect.width()); 420 insertInt("Width", fSrcRect.width());
300 insertInt("Height", srcRect.height()); 421 insertInt("Height", fSrcRect.height());
301 } 422 }
302 423
303 // if (!image mask) { 424 if (isAlpha || alphaOnly) {
304 if (doingAlpha || alphaOnly) {
305 insertName("ColorSpace", "DeviceGray"); 425 insertName("ColorSpace", "DeviceGray");
306 } else if (config == SkBitmap::kIndex8_Config) { 426 } else if (config == SkBitmap::kIndex8_Config) {
307 SkAutoLockPixels alp(bitmap); 427 SkAutoLockPixels alp(fBitmap);
308 insert("ColorSpace", 428 insert("ColorSpace",
309 makeIndexedColorSpace(bitmap.getColorTable()))->unref(); 429 make_indexed_color_space(fBitmap.getColorTable()))->unref();
310 } else { 430 } else {
311 insertName("ColorSpace", "DeviceRGB"); 431 insertName("ColorSpace", "DeviceRGB");
312 } 432 }
313 // }
314 433
315 int bitsPerComp = 8; 434 int bitsPerComp = 8;
316 if (config == SkBitmap::kARGB_4444_Config) { 435 if (config == SkBitmap::kARGB_4444_Config) {
317 bitsPerComp = 4; 436 bitsPerComp = 4;
318 } else if (doingAlpha && config == SkBitmap::kA1_Config) { 437 } else if (isAlpha && config == SkBitmap::kA1_Config) {
319 bitsPerComp = 1; 438 bitsPerComp = 1;
320 } 439 }
321 insertInt("BitsPerComponent", bitsPerComp); 440 insertInt("BitsPerComponent", bitsPerComp);
322 441
323 if (config == SkBitmap::kRGB_565_Config) { 442 if (config == SkBitmap::kRGB_565_Config) {
443 SkASSERT(!isAlpha);
324 SkAutoTUnref<SkPDFInt> zeroVal(new SkPDFInt(0)); 444 SkAutoTUnref<SkPDFInt> zeroVal(new SkPDFInt(0));
325 SkAutoTUnref<SkPDFScalar> scale5Val( 445 SkAutoTUnref<SkPDFScalar> scale5Val(
326 new SkPDFScalar(SkFloatToScalar(8.2258f))); // 255/2^5-1 446 new SkPDFScalar(SkFloatToScalar(8.2258f))); // 255/2^5-1
327 SkAutoTUnref<SkPDFScalar> scale6Val( 447 SkAutoTUnref<SkPDFScalar> scale6Val(
328 new SkPDFScalar(SkFloatToScalar(4.0476f))); // 255/2^6-1 448 new SkPDFScalar(SkFloatToScalar(4.0476f))); // 255/2^6-1
329 SkAutoTUnref<SkPDFArray> decodeValue(new SkPDFArray()); 449 SkAutoTUnref<SkPDFArray> decodeValue(new SkPDFArray());
330 decodeValue->reserve(6); 450 decodeValue->reserve(6);
331 decodeValue->append(zeroVal.get()); 451 decodeValue->append(zeroVal.get());
332 decodeValue->append(scale5Val.get()); 452 decodeValue->append(scale5Val.get());
333 decodeValue->append(zeroVal.get()); 453 decodeValue->append(zeroVal.get());
334 decodeValue->append(scale6Val.get()); 454 decodeValue->append(scale6Val.get());
335 decodeValue->append(zeroVal.get()); 455 decodeValue->append(zeroVal.get());
336 decodeValue->append(scale5Val.get()); 456 decodeValue->append(scale5Val.get());
337 insert("Decode", decodeValue.get()); 457 insert("Decode", decodeValue.get());
338 } 458 }
339 } 459 }
460
461 SkPDFImage::SkPDFImage(SkPDFImage& pdfImage)
462 : SkPDFStream(pdfImage),
463 fBitmap(pdfImage.fBitmap),
464 fSrcRect(pdfImage.fSrcRect),
465 fEncoder(pdfImage.fEncoder),
466 fStreamValid(pdfImage.fStreamValid) {
467 // Nothing to do here - the image params are already copied in SkPDFStream's
468 // constructor, and the bitmap will be regenerated and encoded in
469 // populate.
470 }
471
472 bool SkPDFImage::populate(SkPDFCatalog* catalog) {
473 if (getState() == kUnused_State) {
474 // Initializing image data for the first time.
475 SkDynamicMemoryWStream dctCompressedWStream;
476 if (!skip_compression(catalog) && fEncoder &&
477 get_uncompressed_size(fBitmap, fSrcRect) > 1 &&
478 fEncoder(&dctCompressedWStream, fBitmap, fSrcRect) &&
479 dctCompressedWStream.getOffset() <
480 get_uncompressed_size(fBitmap, fSrcRect)) {
481 SkAutoTUnref<SkData> data(dctCompressedWStream.copyToData());
482 SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream, (data)));
483 setData(stream.get());
484
485 insertName("Filter", "DCTDecode");
486 insertInt("ColorTransform", kNoColorTransform);
487 insertInt("Length", getData()->getLength());
488 setState(kCompressed_State);
489 return true;
490 }
491 // Fallback method
492 if (!fStreamValid) {
493 SkAutoTUnref<SkStream> stream(
494 extract_image_data(fBitmap, fSrcRect, false, NULL));
vandebo (ex-Chrome) 2013/08/23 15:45:36 If we use isAlpha from the constructor here instea
ducky 2013/08/23 17:59:50 Good point. Done. On 2013/08/23 15:45:36, vandeb
495 setData(stream);
496 fStreamValid = true;
497 }
498 return INHERITED::populate(catalog);
499 } else if (getState() == kNoCompression_State &&
500 !skip_compression(catalog) &&
501 (SkFlate::HaveFlate() || fEncoder)) {
502 // Compression has not been requested when the stream was first created,
503 // but the new catalog wants it compressed.
504 if (!getSubstitute()) {
505 SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this));
506 setSubstitute(substitute);
507 catalog->setSubstitute(this, substitute);
508 }
509 return false;
510 }
511 return true;
512 }
OLDNEW
« src/pdf/SkPDFImage.h ('K') | « src/pdf/SkPDFImage.h ('k') | src/pdf/SkPDFImageStream.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698