OLD | NEW |
| (Empty) |
1 /* libs/graphics/images/SkImageDecoder_libpng.cpp | |
2 ** | |
3 ** Copyright 2006, The Android Open Source Project | |
4 ** | |
5 ** Licensed under the Apache License, Version 2.0 (the "License"); | |
6 ** you may not use this file except in compliance with the License. | |
7 ** You may obtain a copy of the License at | |
8 ** | |
9 ** http://www.apache.org/licenses/LICENSE-2.0 | |
10 ** | |
11 ** Unless required by applicable law or agreed to in writing, software | |
12 ** distributed under the License is distributed on an "AS IS" BASIS, | |
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 ** See the License for the specific language governing permissions and | |
15 ** limitations under the License. | |
16 */ | |
17 | |
18 #include "SkImageDecoder.h" | |
19 #include "SkColor.h" | |
20 #include "SkColorPriv.h" | |
21 #include "SkDither.h" | |
22 #include "SkMath.h" | |
23 #include "SkScaledBitmapSampler.h" | |
24 #include "SkStream.h" | |
25 #include "SkTemplates.h" | |
26 #include "SkUtils.h" | |
27 | |
28 extern "C" { | |
29 #include "png.h" | |
30 } | |
31 | |
32 class SkPNGImageDecoder : public SkImageDecoder { | |
33 public: | |
34 virtual Format getFormat() const { | |
35 return kPNG_Format; | |
36 } | |
37 | |
38 protected: | |
39 virtual bool onDecode(SkStream* stream, SkBitmap* bm, | |
40 SkBitmap::Config pref, Mode); | |
41 }; | |
42 | |
43 #ifndef png_jmpbuf | |
44 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) | |
45 #endif | |
46 | |
47 #define PNG_BYTES_TO_CHECK 4 | |
48 | |
49 /* Automatically clean up after throwing an exception */ | |
50 struct PNGAutoClean { | |
51 PNGAutoClean(png_structp p, png_infop i): png_ptr(p), info_ptr(i) {} | |
52 ~PNGAutoClean() { | |
53 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); | |
54 } | |
55 private: | |
56 png_structp png_ptr; | |
57 png_infop info_ptr; | |
58 }; | |
59 | |
60 SkImageDecoder* SkImageDecoder_PNG_Factory(SkStream* stream) { | |
61 char buf[PNG_BYTES_TO_CHECK]; | |
62 if (stream->read(buf, PNG_BYTES_TO_CHECK) == PNG_BYTES_TO_CHECK && | |
63 !png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { | |
64 return SkNEW(SkPNGImageDecoder); | |
65 } | |
66 return NULL; | |
67 } | |
68 | |
69 static void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) { | |
70 SkStream* sk_stream = (SkStream*) png_ptr->io_ptr; | |
71 size_t bytes = sk_stream->read(data, length); | |
72 if (bytes != length) { | |
73 png_error(png_ptr, "Read Error!"); | |
74 } | |
75 } | |
76 | |
77 static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { | |
78 SkImageDecoder::Peeker* peeker = | |
79 (SkImageDecoder::Peeker*)png_get_user_chunk_ptr(png_ptr); | |
80 // peek() returning true means continue decoding | |
81 return peeker->peek((const char*)chunk->name, chunk->data, chunk->size) ? | |
82 1 : -1; | |
83 } | |
84 | |
85 static void sk_error_fn(png_structp png_ptr, png_const_charp msg) { | |
86 #if 0 | |
87 SkDebugf("------ png error %s\n", msg); | |
88 #endif | |
89 longjmp(png_jmpbuf(png_ptr), 1); | |
90 } | |
91 | |
92 static void skip_src_rows(png_structp png_ptr, uint8_t storage[], int count) { | |
93 for (int i = 0; i < count; i++) { | |
94 uint8_t* tmp = storage; | |
95 png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); | |
96 } | |
97 } | |
98 | |
99 static bool pos_le(int value, int max) { | |
100 return value > 0 && value <= max; | |
101 } | |
102 | |
103 static bool substituteTranspColor(SkBitmap* bm, SkPMColor match) { | |
104 SkASSERT(bm->config() == SkBitmap::kARGB_8888_Config); | |
105 | |
106 bool reallyHasAlpha = false; | |
107 | |
108 for (int y = bm->height() - 1; y >= 0; --y) { | |
109 SkPMColor* p = bm->getAddr32(0, y); | |
110 for (int x = bm->width() - 1; x >= 0; --x) { | |
111 if (match == *p) { | |
112 *p = 0; | |
113 reallyHasAlpha = true; | |
114 } | |
115 p += 1; | |
116 } | |
117 } | |
118 return reallyHasAlpha; | |
119 } | |
120 | |
121 bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap, | |
122 SkBitmap::Config prefConfig, Mode mode) { | |
123 // SkAutoTrace apr("SkPNGImageDecoder::onDecode"); | |
124 | |
125 /* Create and initialize the png_struct with the desired error handler | |
126 * functions. If you want to use the default stderr and longjump method, | |
127 * you can supply NULL for the last three parameters. We also supply the | |
128 * the compiler header file version, so that we know if the application | |
129 * was compiled with a compatible version of the library. */ | |
130 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, | |
131 NULL, sk_error_fn, NULL); | |
132 // png_voidp user_error_ptr, user_error_fn, user_warning_fn); | |
133 if (png_ptr == NULL) { | |
134 return false; | |
135 } | |
136 | |
137 /* Allocate/initialize the memory for image information. */ | |
138 png_infop info_ptr = png_create_info_struct(png_ptr); | |
139 if (info_ptr == NULL) { | |
140 png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); | |
141 return false; | |
142 } | |
143 | |
144 PNGAutoClean autoClean(png_ptr, info_ptr); | |
145 | |
146 /* Set error handling if you are using the setjmp/longjmp method (this is | |
147 * the normal method of doing things with libpng). REQUIRED unless you | |
148 * set up your own error handlers in the png_create_read_struct() earlier. | |
149 */ | |
150 if (setjmp(png_jmpbuf(png_ptr))) { | |
151 return false; | |
152 } | |
153 | |
154 /* If you are using replacement read functions, instead of calling | |
155 * png_init_io() here you would call: | |
156 */ | |
157 png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn); | |
158 /* where user_io_ptr is a structure you want available to the callbacks */ | |
159 /* If we have already read some of the signature */ | |
160 // png_set_sig_bytes(png_ptr, 0 /* sig_read */ ); | |
161 | |
162 // hookup our peeker so we can see any user-chunks the caller may be interes
ted in | |
163 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"",
0); | |
164 if (this->getPeeker()) { | |
165 png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_rea
d_user_chunk); | |
166 } | |
167 | |
168 /* The call to png_read_info() gives us all of the information from the | |
169 * PNG file before the first IDAT (image data chunk). */ | |
170 png_read_info(png_ptr, info_ptr); | |
171 png_uint_32 origWidth, origHeight; | |
172 int bit_depth, color_type, interlace_type; | |
173 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, &color_
type, | |
174 &interlace_type, int_p_NULL, int_p_NULL); | |
175 | |
176 /* tell libpng to strip 16 bit/color files down to 8 bits/color */ | |
177 if (bit_depth == 16) { | |
178 png_set_strip_16(png_ptr); | |
179 } | |
180 /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single | |
181 * byte into separate bytes (useful for paletted and grayscale images). */ | |
182 if (bit_depth < 8) { | |
183 png_set_packing(png_ptr); | |
184 } | |
185 /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ | |
186 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { | |
187 png_set_gray_1_2_4_to_8(png_ptr); | |
188 } | |
189 | |
190 /* Make a grayscale image into RGB. */ | |
191 if (color_type == PNG_COLOR_TYPE_GRAY || | |
192 color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { | |
193 png_set_gray_to_rgb(png_ptr); | |
194 } | |
195 | |
196 SkBitmap::Config config; | |
197 bool hasAlpha = false; | |
198 bool doDither = this->getDitherImage(); | |
199 SkPMColor theTranspColor = 0; // 0 tells us not to try to match | |
200 | |
201 // check for sBIT chunk data, in case we should disable dithering because | |
202 // our data is not truely 8bits per component | |
203 if (doDither) { | |
204 #if 0 | |
205 SkDebugf("----- sBIT %d %d %d %d\n", info_ptr->sig_bit.red, | |
206 info_ptr->sig_bit.green, info_ptr->sig_bit.blue, | |
207 info_ptr->sig_bit.alpha); | |
208 #endif | |
209 // 0 seems to indicate no information available | |
210 if (pos_le(info_ptr->sig_bit.red, SK_R16_BITS) && | |
211 pos_le(info_ptr->sig_bit.green, SK_G16_BITS) && | |
212 pos_le(info_ptr->sig_bit.blue, SK_B16_BITS)) { | |
213 doDither = false; | |
214 } | |
215 } | |
216 | |
217 if (color_type == PNG_COLOR_TYPE_PALETTE) { | |
218 config = SkBitmap::kIndex8_Config; // defer sniffing for hasAlpha | |
219 } else { | |
220 png_color_16p transpColor = NULL; | |
221 int numTransp = 0; | |
222 | |
223 png_get_tRNS(png_ptr, info_ptr, NULL, &numTransp, &transpColor); | |
224 | |
225 bool valid = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS); | |
226 | |
227 if (valid && numTransp == 1 && transpColor != NULL) { | |
228 /* Compute our transparent color, which we'll match against later. | |
229 We don't really handle 16bit components properly here, since we | |
230 do our compare *after* the values have been knocked down to 8bit | |
231 which means we will find more matches than we should. The real | |
232 fix seems to be to see the actual 16bit components, do the | |
233 compare, and then knock it down to 8bits ourselves. | |
234 */ | |
235 if (color_type & PNG_COLOR_MASK_COLOR) { | |
236 if (16 == bit_depth) { | |
237 theTranspColor = SkPackARGB32(0xFF, transpColor->red >> 8, | |
238 transpColor->green >> 8, transpColor->blue >> 8); | |
239 } else { | |
240 theTranspColor = SkPackARGB32(0xFF, transpColor->red, | |
241 transpColor->green, transpColor->blue); | |
242 } | |
243 } else { // gray | |
244 if (16 == bit_depth) { | |
245 theTranspColor = SkPackARGB32(0xFF, transpColor->gray >> 8, | |
246 transpColor->gray >> 8, transpColor->gray >> 8); | |
247 } else { | |
248 theTranspColor = SkPackARGB32(0xFF, transpColor->gray, | |
249 transpColor->gray, transpColor->gray); | |
250 } | |
251 } | |
252 } | |
253 | |
254 if (valid || | |
255 PNG_COLOR_TYPE_RGB_ALPHA == color_type || | |
256 PNG_COLOR_TYPE_GRAY_ALPHA == color_type) { | |
257 hasAlpha = true; | |
258 config = SkBitmap::kARGB_8888_Config; | |
259 } else { // we get to choose the config | |
260 config = prefConfig; | |
261 if (config == SkBitmap::kNo_Config) { | |
262 config = SkImageDecoder::GetDeviceConfig(); | |
263 } | |
264 if (config != SkBitmap::kRGB_565_Config && | |
265 config != SkBitmap::kARGB_4444_Config) { | |
266 config = SkBitmap::kARGB_8888_Config; | |
267 } | |
268 } | |
269 } | |
270 | |
271 if (!this->chooseFromOneChoice(config, origWidth, origHeight)) { | |
272 return false; | |
273 } | |
274 | |
275 const int sampleSize = this->getSampleSize(); | |
276 SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize); | |
277 | |
278 decodedBitmap->setConfig(config, sampler.scaledWidth(), | |
279 sampler.scaledHeight(), 0); | |
280 if (SkImageDecoder::kDecodeBounds_Mode == mode) { | |
281 return true; | |
282 } | |
283 | |
284 // from here down we are concerned with colortables and pixels | |
285 | |
286 // we track if we actually see a non-opaque pixels, since sometimes a PNG se
ts its colortype | |
287 // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We
care, since we | |
288 // draw lots faster if we can flag the bitmap has being opaque | |
289 bool reallyHasAlpha = false; | |
290 | |
291 SkColorTable* colorTable = NULL; | |
292 | |
293 if (color_type == PNG_COLOR_TYPE_PALETTE) { | |
294 int num_palette; | |
295 png_colorp palette; | |
296 png_bytep trans; | |
297 int num_trans; | |
298 | |
299 png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); | |
300 | |
301 /* BUGGY IMAGE WORKAROUND | |
302 | |
303 We hit some images (e.g. fruit_.png) who contain bytes that are == c
olortable_count | |
304 which is a problem since we use the byte as an index. To work around
this we grow | |
305 the colortable by 1 (if its < 256) and duplicate the last color into
that slot. | |
306 */ | |
307 int colorCount = num_palette + (num_palette < 256); | |
308 | |
309 colorTable = SkNEW_ARGS(SkColorTable, (colorCount)); | |
310 | |
311 SkPMColor* colorPtr = colorTable->lockColors(); | |
312 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { | |
313 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); | |
314 hasAlpha = (num_trans > 0); | |
315 } else { | |
316 num_trans = 0; | |
317 colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsA
reOpaque_Flag); | |
318 } | |
319 // check for bad images that might make us crash | |
320 if (num_trans > num_palette) { | |
321 num_trans = num_palette; | |
322 } | |
323 | |
324 int index = 0; | |
325 int transLessThanFF = 0; | |
326 | |
327 for (; index < num_trans; index++) { | |
328 transLessThanFF |= (int)*trans - 0xFF; | |
329 *colorPtr++ = SkPreMultiplyARGB(*trans++, palette->red, palette->gre
en, palette->blue); | |
330 palette++; | |
331 } | |
332 reallyHasAlpha |= (transLessThanFF < 0); | |
333 | |
334 for (; index < num_palette; index++) { | |
335 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palet
te->blue); | |
336 palette++; | |
337 } | |
338 | |
339 // see BUGGY IMAGE WORKAROUND comment above | |
340 if (num_palette < 256) { | |
341 *colorPtr = colorPtr[-1]; | |
342 } | |
343 colorTable->unlockColors(true); | |
344 } | |
345 | |
346 SkAutoUnref aur(colorTable); | |
347 | |
348 if (!this->allocPixelRef(decodedBitmap, colorTable)) { | |
349 return false; | |
350 } | |
351 | |
352 SkAutoLockPixels alp(*decodedBitmap); | |
353 | |
354 /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ | |
355 // if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) | |
356 // ; // png_set_swap_alpha(png_ptr); | |
357 | |
358 /* swap bytes of 16 bit files to least significant byte first */ | |
359 // png_set_swap(png_ptr); | |
360 | |
361 /* Add filler (or alpha) byte (before/after each RGB triplet) */ | |
362 if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) { | |
363 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); | |
364 } | |
365 | |
366 /* Turn on interlace handling. REQUIRED if you are not using | |
367 * png_read_image(). To see how to handle interlacing passes, | |
368 * see the png_read_row() method below: | |
369 */ | |
370 const int number_passes = interlace_type != PNG_INTERLACE_NONE ? | |
371 png_set_interlace_handling(png_ptr) : 1; | |
372 | |
373 /* Optional call to gamma correct and add the background to the palette | |
374 * and update info structure. REQUIRED if you are expecting libpng to | |
375 * update the palette for you (ie you selected such a transform above). | |
376 */ | |
377 png_read_update_info(png_ptr, info_ptr); | |
378 | |
379 if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) { | |
380 for (int i = 0; i < number_passes; i++) { | |
381 for (png_uint_32 y = 0; y < origHeight; y++) { | |
382 uint8_t* bmRow = decodedBitmap->getAddr8(0, y); | |
383 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); | |
384 } | |
385 } | |
386 } else { | |
387 SkScaledBitmapSampler::SrcConfig sc; | |
388 int srcBytesPerPixel = 4; | |
389 | |
390 if (SkBitmap::kIndex8_Config == config) { | |
391 sc = SkScaledBitmapSampler::kIndex; | |
392 srcBytesPerPixel = 1; | |
393 } else if (hasAlpha) { | |
394 sc = SkScaledBitmapSampler::kRGBA; | |
395 } else { | |
396 sc = SkScaledBitmapSampler::kRGBX; | |
397 } | |
398 | |
399 SkAutoMalloc storage(origWidth * srcBytesPerPixel); | |
400 const int height = decodedBitmap->height(); | |
401 | |
402 for (int i = 0; i < number_passes; i++) { | |
403 if (!sampler.begin(decodedBitmap, sc, doDither)) { | |
404 return false; | |
405 } | |
406 | |
407 uint8_t* srcRow = (uint8_t*)storage.get(); | |
408 skip_src_rows(png_ptr, srcRow, sampler.srcY0()); | |
409 | |
410 for (int y = 0; y < height; y++) { | |
411 uint8_t* tmp = srcRow; | |
412 png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); | |
413 reallyHasAlpha |= sampler.next(srcRow); | |
414 if (y < height - 1) { | |
415 skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1); | |
416 } | |
417 } | |
418 | |
419 // skip the rest of the rows (if any) | |
420 png_uint_32 read = (height - 1) * sampler.srcDY() + | |
421 sampler.srcY0() + 1; | |
422 SkASSERT(read <= origHeight); | |
423 skip_src_rows(png_ptr, srcRow, origHeight - read); | |
424 } | |
425 | |
426 if (hasAlpha && !reallyHasAlpha) { | |
427 #if 0 | |
428 SkDEBUGF(("Image doesn't really have alpha [%d %d]\n", | |
429 origWidth, origHeight)); | |
430 #endif | |
431 } | |
432 } | |
433 | |
434 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ | |
435 png_read_end(png_ptr, info_ptr); | |
436 | |
437 if (0 != theTranspColor) { | |
438 reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor); | |
439 } | |
440 decodedBitmap->setIsOpaque(!reallyHasAlpha); | |
441 return true; | |
442 } | |
443 | |
444 /////////////////////////////////////////////////////////////////////////////// | |
445 | |
446 #ifdef SK_SUPPORT_IMAGE_ENCODE | |
447 | |
448 #include "SkColorPriv.h" | |
449 #include "SkUnPreMultiply.h" | |
450 | |
451 static void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) { | |
452 SkWStream* sk_stream = (SkWStream*)png_ptr->io_ptr; | |
453 if (!sk_stream->write(data, len)) { | |
454 png_error(png_ptr, "sk_write_fn Error!"); | |
455 } | |
456 } | |
457 | |
458 typedef void (*transform_scanline_proc)(const char* SK_RESTRICT src, | |
459 int width, char* SK_RESTRICT dst); | |
460 | |
461 static void transform_scanline_565(const char* SK_RESTRICT src, int width, | |
462 char* SK_RESTRICT dst) { | |
463 const uint16_t* SK_RESTRICT srcP = (const uint16_t*)src; | |
464 for (int i = 0; i < width; i++) { | |
465 unsigned c = *srcP++; | |
466 *dst++ = SkPacked16ToR32(c); | |
467 *dst++ = SkPacked16ToG32(c); | |
468 *dst++ = SkPacked16ToB32(c); | |
469 } | |
470 } | |
471 | |
472 static void transform_scanline_888(const char* SK_RESTRICT src, int width, | |
473 char* SK_RESTRICT dst) { | |
474 const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src; | |
475 for (int i = 0; i < width; i++) { | |
476 SkPMColor c = *srcP++; | |
477 *dst++ = SkGetPackedR32(c); | |
478 *dst++ = SkGetPackedG32(c); | |
479 *dst++ = SkGetPackedB32(c); | |
480 } | |
481 } | |
482 | |
483 static void transform_scanline_444(const char* SK_RESTRICT src, int width, | |
484 char* SK_RESTRICT dst) { | |
485 const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src; | |
486 for (int i = 0; i < width; i++) { | |
487 SkPMColor16 c = *srcP++; | |
488 *dst++ = SkPacked4444ToR32(c); | |
489 *dst++ = SkPacked4444ToG32(c); | |
490 *dst++ = SkPacked4444ToB32(c); | |
491 } | |
492 } | |
493 | |
494 static void transform_scanline_8888(const char* SK_RESTRICT src, int width, | |
495 char* SK_RESTRICT dst) { | |
496 const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src; | |
497 const SkUnPreMultiply::Scale* SK_RESTRICT table = | |
498 SkUnPreMultiply::GetScaleTable(); | |
499 | |
500 for (int i = 0; i < width; i++) { | |
501 SkPMColor c = *srcP++; | |
502 unsigned a = SkGetPackedA32(c); | |
503 unsigned r = SkGetPackedR32(c); | |
504 unsigned g = SkGetPackedG32(c); | |
505 unsigned b = SkGetPackedB32(c); | |
506 | |
507 if (0 != a && 255 != a) { | |
508 SkUnPreMultiply::Scale scale = table[a]; | |
509 r = SkUnPreMultiply::ApplyScale(scale, r); | |
510 g = SkUnPreMultiply::ApplyScale(scale, g); | |
511 b = SkUnPreMultiply::ApplyScale(scale, b); | |
512 } | |
513 *dst++ = r; | |
514 *dst++ = g; | |
515 *dst++ = b; | |
516 *dst++ = a; | |
517 } | |
518 } | |
519 | |
520 static void transform_scanline_4444(const char* SK_RESTRICT src, int width, | |
521 char* SK_RESTRICT dst) { | |
522 const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src; | |
523 const SkUnPreMultiply::Scale* SK_RESTRICT table = | |
524 SkUnPreMultiply::GetScaleTable(); | |
525 | |
526 for (int i = 0; i < width; i++) { | |
527 SkPMColor16 c = *srcP++; | |
528 unsigned a = SkPacked4444ToA32(c); | |
529 unsigned r = SkPacked4444ToR32(c); | |
530 unsigned g = SkPacked4444ToG32(c); | |
531 unsigned b = SkPacked4444ToB32(c); | |
532 | |
533 if (0 != a && 255 != a) { | |
534 SkUnPreMultiply::Scale scale = table[a]; | |
535 r = SkUnPreMultiply::ApplyScale(scale, r); | |
536 g = SkUnPreMultiply::ApplyScale(scale, g); | |
537 b = SkUnPreMultiply::ApplyScale(scale, b); | |
538 } | |
539 *dst++ = r; | |
540 *dst++ = g; | |
541 *dst++ = b; | |
542 *dst++ = a; | |
543 } | |
544 } | |
545 | |
546 static void transform_scanline_index8(const char* SK_RESTRICT src, int width, | |
547 char* SK_RESTRICT dst) { | |
548 memcpy(dst, src, width); | |
549 } | |
550 | |
551 static transform_scanline_proc choose_proc(SkBitmap::Config config, | |
552 bool hasAlpha) { | |
553 // we don't care about search on alpha if we're kIndex8, since only the | |
554 // colortable packing cares about that distinction, not the pixels | |
555 if (SkBitmap::kIndex8_Config == config) { | |
556 hasAlpha = false; // we store false in the table entries for kIndex8 | |
557 } | |
558 | |
559 static const struct { | |
560 SkBitmap::Config fConfig; | |
561 bool fHasAlpha; | |
562 transform_scanline_proc fProc; | |
563 } gMap[] = { | |
564 { SkBitmap::kRGB_565_Config, false, transform_scanline_565 }, | |
565 { SkBitmap::kARGB_8888_Config, false, transform_scanline_888 }, | |
566 { SkBitmap::kARGB_8888_Config, true, transform_scanline_8888 }, | |
567 { SkBitmap::kARGB_4444_Config, false, transform_scanline_444 }, | |
568 { SkBitmap::kARGB_4444_Config, true, transform_scanline_4444 }, | |
569 { SkBitmap::kIndex8_Config, false, transform_scanline_index8 }, | |
570 }; | |
571 | |
572 for (int i = SK_ARRAY_COUNT(gMap) - 1; i >= 0; --i) { | |
573 if (gMap[i].fConfig == config && gMap[i].fHasAlpha == hasAlpha) { | |
574 return gMap[i].fProc; | |
575 } | |
576 } | |
577 sk_throw(); | |
578 return NULL; | |
579 } | |
580 | |
581 // return the minimum legal bitdepth (by png standards) for this many colortable | |
582 // entries. SkBitmap always stores in 8bits per pixel, but for colorcount <= 16, | |
583 // we can use fewer bits per in png | |
584 static int computeBitDepth(int colorCount) { | |
585 #if 0 | |
586 int bits = SkNextLog2(colorCount); | |
587 SkASSERT(bits >= 1 && bits <= 8); | |
588 // now we need bits itself to be a power of 2 (e.g. 1, 2, 4, 8) | |
589 return SkNextPow2(bits); | |
590 #else | |
591 // for the moment, we don't know how to pack bitdepth < 8 | |
592 return 8; | |
593 #endif | |
594 } | |
595 | |
596 /* Pack palette[] with the corresponding colors, and if hasAlpha is true, also | |
597 pack trans[] and return the number of trans[] entries written. If hasAlpha | |
598 is false, the return value will always be 0. | |
599 | |
600 Note: this routine takes care of unpremultiplying the RGB values when we | |
601 have alpha in the colortable, since png doesn't support premul colors | |
602 */ | |
603 static int pack_palette(SkColorTable* ctable, png_color* SK_RESTRICT palette, | |
604 png_byte* SK_RESTRICT trans, bool hasAlpha) { | |
605 SkAutoLockColors alc(ctable); | |
606 const SkPMColor* SK_RESTRICT colors = alc.colors(); | |
607 const int ctCount = ctable->count(); | |
608 int i, num_trans = 0; | |
609 | |
610 if (hasAlpha) { | |
611 /* first see if we have some number of fully opaque at the end of the | |
612 ctable. PNG allows num_trans < num_palette, but all of the trans | |
613 entries must come first in the palette. If I was smarter, I'd | |
614 reorder the indices and ctable so that all non-opaque colors came | |
615 first in the palette. But, since that would slow down the encode, | |
616 I'm leaving the indices and ctable order as is, and just looking | |
617 at the tail of the ctable for opaqueness. | |
618 */ | |
619 num_trans = ctCount; | |
620 for (i = ctCount - 1; i >= 0; --i) { | |
621 if (SkGetPackedA32(colors[i]) != 0xFF) { | |
622 break; | |
623 } | |
624 num_trans -= 1; | |
625 } | |
626 | |
627 const SkUnPreMultiply::Scale* SK_RESTRICT table = | |
628 SkUnPreMultiply::GetScaleTable(); | |
629 | |
630 for (i = 0; i < num_trans; i++) { | |
631 const SkPMColor c = *colors++; | |
632 const unsigned a = SkGetPackedA32(c); | |
633 const SkUnPreMultiply::Scale s = table[a]; | |
634 trans[i] = a; | |
635 palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c)); | |
636 palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32(c)); | |
637 palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c)); | |
638 } | |
639 // now fall out of this if-block to use common code for the trailing | |
640 // opaque entries | |
641 } | |
642 | |
643 // these (remaining) entries are opaque | |
644 for (i = num_trans; i < ctCount; i++) { | |
645 SkPMColor c = *colors++; | |
646 palette[i].red = SkGetPackedR32(c); | |
647 palette[i].green = SkGetPackedG32(c); | |
648 palette[i].blue = SkGetPackedB32(c); | |
649 } | |
650 return num_trans; | |
651 } | |
652 | |
653 class SkPNGImageEncoder : public SkImageEncoder { | |
654 protected: | |
655 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality); | |
656 }; | |
657 | |
658 bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, | |
659 int /*quality*/) { | |
660 SkBitmap::Config config = bitmap.getConfig(); | |
661 | |
662 const bool hasAlpha = !bitmap.isOpaque(); | |
663 int colorType = PNG_COLOR_MASK_COLOR; | |
664 int bitDepth = 8; // default for color | |
665 png_color_8 sig_bit; | |
666 | |
667 switch (config) { | |
668 case SkBitmap::kIndex8_Config: | |
669 colorType |= PNG_COLOR_MASK_PALETTE; | |
670 // fall through to the ARGB_8888 case | |
671 case SkBitmap::kARGB_8888_Config: | |
672 sig_bit.red = 8; | |
673 sig_bit.green = 8; | |
674 sig_bit.blue = 8; | |
675 sig_bit.alpha = 8; | |
676 break; | |
677 case SkBitmap::kARGB_4444_Config: | |
678 sig_bit.red = 4; | |
679 sig_bit.green = 4; | |
680 sig_bit.blue = 4; | |
681 sig_bit.alpha = 4; | |
682 break; | |
683 case SkBitmap::kRGB_565_Config: | |
684 sig_bit.red = 5; | |
685 sig_bit.green = 6; | |
686 sig_bit.blue = 5; | |
687 sig_bit.alpha = 0; | |
688 break; | |
689 default: | |
690 return false; | |
691 } | |
692 | |
693 if (hasAlpha) { | |
694 // don't specify alpha if we're a palette, even if our ctable has alpha | |
695 if (!(colorType & PNG_COLOR_MASK_PALETTE)) { | |
696 colorType |= PNG_COLOR_MASK_ALPHA; | |
697 } | |
698 } else { | |
699 sig_bit.alpha = 0; | |
700 } | |
701 | |
702 SkAutoLockPixels alp(bitmap); | |
703 // readyToDraw checks for pixels (and colortable if that is required) | |
704 if (!bitmap.readyToDraw()) { | |
705 return false; | |
706 } | |
707 | |
708 // we must do this after we have locked the pixels | |
709 SkColorTable* ctable = bitmap.getColorTable(); | |
710 if (NULL != ctable) { | |
711 if (ctable->count() == 0) { | |
712 return false; | |
713 } | |
714 // check if we can store in fewer than 8 bits | |
715 bitDepth = computeBitDepth(ctable->count()); | |
716 } | |
717 | |
718 png_structp png_ptr; | |
719 png_infop info_ptr; | |
720 | |
721 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, sk_error_fn, | |
722 NULL); | |
723 if (NULL == png_ptr) { | |
724 return false; | |
725 } | |
726 | |
727 info_ptr = png_create_info_struct(png_ptr); | |
728 if (NULL == info_ptr) { | |
729 png_destroy_write_struct(&png_ptr, png_infopp_NULL); | |
730 return false; | |
731 } | |
732 | |
733 /* Set error handling. REQUIRED if you aren't supplying your own | |
734 * error handling functions in the png_create_write_struct() call. | |
735 */ | |
736 if (setjmp(png_jmpbuf(png_ptr))) { | |
737 png_destroy_write_struct(&png_ptr, &info_ptr); | |
738 return false; | |
739 } | |
740 | |
741 png_set_write_fn(png_ptr, (void*)stream, sk_write_fn, png_flush_ptr_NULL); | |
742 | |
743 /* Set the image information here. Width and height are up to 2^31, | |
744 * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on | |
745 * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, | |
746 * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, | |
747 * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or | |
748 * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST | |
749 * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED | |
750 */ | |
751 | |
752 png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(), | |
753 bitDepth, colorType, | |
754 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, | |
755 PNG_FILTER_TYPE_BASE); | |
756 | |
757 #if 0 // need to support this some day | |
758 /* set the palette if there is one. REQUIRED for indexed-color images */ | |
759 palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH | |
760 * png_sizeof (png_color)); | |
761 /* ... set palette colors ... */ | |
762 png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); | |
763 /* You must not free palette here, because png_set_PLTE only makes a link to | |
764 the palette that you malloced. Wait until you are about to destroy | |
765 the png structure. */ | |
766 #endif | |
767 | |
768 png_set_sBIT(png_ptr, info_ptr, &sig_bit); | |
769 png_write_info(png_ptr, info_ptr); | |
770 | |
771 const char* srcImage = (const char*)bitmap.getPixels(); | |
772 SkAutoSMalloc<1024> rowStorage(bitmap.width() << 2); | |
773 char* storage = (char*)rowStorage.get(); | |
774 transform_scanline_proc proc = choose_proc(config, hasAlpha); | |
775 | |
776 for (int y = 0; y < bitmap.height(); y++) { | |
777 png_bytep row_ptr = (png_bytep)storage; | |
778 proc(srcImage, bitmap.width(), storage); | |
779 png_write_rows(png_ptr, &row_ptr, 1); | |
780 srcImage += bitmap.rowBytes(); | |
781 } | |
782 | |
783 png_write_end(png_ptr, info_ptr); | |
784 | |
785 /* clean up after the write, and free any memory allocated */ | |
786 png_destroy_write_struct(&png_ptr, &info_ptr); | |
787 return true; | |
788 } | |
789 | |
790 SkImageEncoder* SkImageEncoder_PNG_Factory(); | |
791 SkImageEncoder* SkImageEncoder_PNG_Factory() { | |
792 return SkNEW(SkPNGImageEncoder); | |
793 } | |
794 | |
795 #endif /* SK_SUPPORT_IMAGE_ENCODE */ | |
OLD | NEW |