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

Unified Diff: ui/gfx/codec/png_codec.cc

Issue 9496004: Support for interlaced PNGs (in gfx::PNGCodec) (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 8 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/libpng/pngusr.h ('k') | ui/gfx/codec/png_codec_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/gfx/codec/png_codec.cc
===================================================================
--- ui/gfx/codec/png_codec.cc (revision 125325)
+++ ui/gfx/codec/png_codec.cc (working copy)
@@ -54,34 +54,6 @@
}
}
-void ConvertRGBtoSkia(const unsigned char* rgb, int pixel_width,
- unsigned char* rgba, bool* is_opaque) {
- for (int x = 0; x < pixel_width; x++) {
- const unsigned char* pixel_in = &rgb[x * 3];
- uint32_t* pixel_out = reinterpret_cast<uint32_t*>(&rgba[x * 4]);
- *pixel_out = SkPackARGB32(0xFF, pixel_in[0], pixel_in[1], pixel_in[2]);
- }
-}
-
-void ConvertRGBAtoSkia(const unsigned char* rgb, int pixel_width,
- unsigned char* rgba, bool* is_opaque) {
- int total_length = pixel_width * 4;
- for (int x = 0; x < total_length; x += 4) {
- const unsigned char* pixel_in = &rgb[x];
- uint32_t* pixel_out = reinterpret_cast<uint32_t*>(&rgba[x]);
-
- unsigned char alpha = pixel_in[3];
- if (alpha != 255) {
- *is_opaque = false;
- *pixel_out = SkPreMultiplyARGB(alpha,
- pixel_in[0], pixel_in[1], pixel_in[2]);
- } else {
- *pixel_out = SkPackARGB32(alpha,
- pixel_in[0], pixel_in[1], pixel_in[2]);
- }
- }
-}
-
void ConvertSkiatoRGB(const unsigned char* skia, int pixel_width,
unsigned char* rgb, bool* is_opaque) {
for (int x = 0; x < pixel_width; x++) {
@@ -148,7 +120,6 @@
bitmap(NULL),
is_opaque(true),
output(o),
- row_converter(NULL),
width(0),
height(0),
done(false) {
@@ -161,7 +132,6 @@
bitmap(skbitmap),
is_opaque(true),
output(NULL),
- row_converter(NULL),
width(0),
height(0),
done(false) {
@@ -181,11 +151,6 @@
// instead of directly to an SkBitmap.
std::vector<unsigned char>* output;
- // Called to convert a row from the library to the correct output format.
- // When NULL, no conversion is necessary.
- void (*row_converter)(const unsigned char* in, int w, unsigned char* out,
- bool* is_opaque);
-
// Size of the image, set in the info callback.
int width;
int height;
@@ -197,27 +162,29 @@
DISALLOW_COPY_AND_ASSIGN(PngDecoderState);
};
-void ConvertRGBtoRGBA(const unsigned char* rgb, int pixel_width,
- unsigned char* rgba, bool* is_opaque) {
- for (int x = 0; x < pixel_width; x++) {
- const unsigned char* pixel_in = &rgb[x * 3];
- unsigned char* pixel_out = &rgba[x * 4];
- pixel_out[0] = pixel_in[0];
- pixel_out[1] = pixel_in[1];
- pixel_out[2] = pixel_in[2];
- pixel_out[3] = 0xff;
- }
-}
+// User transform (passed to libpng) which converts a row decoded by libpng to
+// Skia format. Expects the row to have 4 channels, otherwise there won't be
+// enough room in |data|.
+void ConvertRGBARowToSkia(png_structp png_ptr,
+ png_row_infop row_info,
+ png_bytep data) {
+ const int channels = row_info->channels;
+ DCHECK_EQ(channels, 4);
-void ConvertRGBtoBGRA(const unsigned char* rgb, int pixel_width,
- unsigned char* bgra, bool* is_opaque) {
- for (int x = 0; x < pixel_width; x++) {
- const unsigned char* pixel_in = &rgb[x * 3];
- unsigned char* pixel_out = &bgra[x * 4];
- pixel_out[0] = pixel_in[2];
- pixel_out[1] = pixel_in[1];
- pixel_out[2] = pixel_in[0];
- pixel_out[3] = 0xff;
+ PngDecoderState* state =
+ static_cast<PngDecoderState*>(png_get_user_transform_ptr(png_ptr));
+ DCHECK(state) << "LibPNG user transform pointer is NULL";
+
+ unsigned char* const end = data + row_info->rowbytes;
+ for (unsigned char* p = data; p < end; p += channels) {
+ uint32_t* sk_pixel = reinterpret_cast<uint32_t*>(p);
+ const unsigned char alpha = p[channels - 1];
+ if (alpha != 255) {
+ state->is_opaque = false;
+ *sk_pixel = SkPreMultiplyARGB(alpha, p[0], p[1], p[2]);
+ } else {
+ *sk_pixel = SkPackARGB32(alpha, p[0], p[1], p[2]);
+ }
}
}
@@ -228,7 +195,7 @@
png_get_progressive_ptr(png_ptr));
int bit_depth, color_type, interlace_type, compression_type;
- int filter_type, channels;
+ int filter_type;
png_uint_32 w, h;
png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type,
&interlace_type, &compression_type, &filter_type);
@@ -245,94 +212,99 @@
state->width = static_cast<int>(w);
state->height = static_cast<int>(h);
+ // The following png_set_* calls have to be done in the order dictated by
+ // the libpng docs. Please take care if you have to move any of them. This
+ // is also why certain things are done outside of the switch, even though
+ // they look like they belong there.
+
// Expand to ensure we use 24-bit for RGB and 32-bit for RGBA.
if (color_type == PNG_COLOR_TYPE_PALETTE ||
(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8))
png_set_expand(png_ptr);
+ // The '!= 0' is for silencing a Windows compiler warning.
+ bool input_has_alpha = ((color_type & PNG_COLOR_MASK_ALPHA) != 0);
+
// Transparency for paletted images.
- if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
png_set_expand(png_ptr);
+ input_has_alpha = true;
+ }
// Convert 16-bit to 8-bit.
if (bit_depth == 16)
png_set_strip_16(png_ptr);
- // Expand grayscale to RGB.
- if (color_type == PNG_COLOR_TYPE_GRAY ||
- color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
- png_set_gray_to_rgb(png_ptr);
-
- // Deal with gamma and keep it under our control.
- double gamma;
- if (png_get_gAMA(png_ptr, info_ptr, &gamma)) {
- if (gamma <= 0.0 || gamma > kMaxGamma) {
- gamma = kInverseGamma;
- png_set_gAMA(png_ptr, info_ptr, gamma);
- }
- png_set_gamma(png_ptr, kDefaultGamma, gamma);
- } else {
- png_set_gamma(png_ptr, kDefaultGamma, kInverseGamma);
- }
-
- // Tell libpng to send us rows for interlaced pngs.
- if (interlace_type == PNG_INTERLACE_ADAM7)
- png_set_interlace_handling(png_ptr);
-
- // Update our info now
- png_read_update_info(png_ptr, info_ptr);
- channels = png_get_channels(png_ptr, info_ptr);
-
// Pick our row format converter necessary for this data.
- if (channels == 3) {
+ if (!input_has_alpha) {
switch (state->output_format) {
case PNGCodec::FORMAT_RGB:
- state->row_converter = NULL; // no conversion necessary
state->output_channels = 3;
break;
case PNGCodec::FORMAT_RGBA:
- state->row_converter = &ConvertRGBtoRGBA;
state->output_channels = 4;
+ png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER);
break;
case PNGCodec::FORMAT_BGRA:
- state->row_converter = &ConvertRGBtoBGRA;
state->output_channels = 4;
+ png_set_bgr(png_ptr);
+ png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER);
break;
case PNGCodec::FORMAT_SkBitmap:
- state->row_converter = &ConvertRGBtoSkia;
state->output_channels = 4;
+ png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER);
break;
- default:
- NOTREACHED() << "Unknown output format";
- break;
}
- } else if (channels == 4) {
+ } else {
switch (state->output_format) {
case PNGCodec::FORMAT_RGB:
- state->row_converter = &ConvertRGBAtoRGB;
state->output_channels = 3;
+ png_set_strip_alpha(png_ptr);
break;
case PNGCodec::FORMAT_RGBA:
- state->row_converter = NULL; // no conversion necessary
state->output_channels = 4;
break;
case PNGCodec::FORMAT_BGRA:
- state->row_converter = &ConvertBetweenBGRAandRGBA;
state->output_channels = 4;
+ png_set_bgr(png_ptr);
break;
case PNGCodec::FORMAT_SkBitmap:
- state->row_converter = &ConvertRGBAtoSkia;
state->output_channels = 4;
break;
- default:
- NOTREACHED() << "Unknown output format";
- break;
}
+ }
+
+ // Expand grayscale to RGB.
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb(png_ptr);
+
+ // Deal with gamma and keep it under our control.
+ double gamma;
+ if (png_get_gAMA(png_ptr, info_ptr, &gamma)) {
+ if (gamma <= 0.0 || gamma > kMaxGamma) {
+ gamma = kInverseGamma;
+ png_set_gAMA(png_ptr, info_ptr, gamma);
+ }
+ png_set_gamma(png_ptr, kDefaultGamma, gamma);
} else {
- NOTREACHED() << "Unknown input channels";
- longjmp(png_jmpbuf(png_ptr), 1);
+ png_set_gamma(png_ptr, kDefaultGamma, kInverseGamma);
}
+ // Setting the user transforms here (as opposed to inside the switch above)
+ // because all png_set_* calls need to be done in the specific order
+ // mandated by libpng.
+ if (state->output_format == PNGCodec::FORMAT_SkBitmap) {
+ png_set_read_user_transform_fn(png_ptr, ConvertRGBARowToSkia);
+ png_set_user_transform_info(png_ptr, state, 0, 0);
+ }
+
+ // Tell libpng to send us rows for interlaced pngs.
+ if (interlace_type == PNG_INTERLACE_ADAM7)
+ png_set_interlace_handling(png_ptr);
+
+ png_read_update_info(png_ptr, info_ptr);
+
if (state->bitmap) {
state->bitmap->setConfig(SkBitmap::kARGB_8888_Config,
state->width, state->height);
@@ -345,11 +317,12 @@
void DecodeRowCallback(png_struct* png_ptr, png_byte* new_row,
png_uint_32 row_num, int pass) {
+ if (!new_row)
+ return; // Interlaced image; row didn't change this pass.
+
PngDecoderState* state = static_cast<PngDecoderState*>(
png_get_progressive_ptr(png_ptr));
- DCHECK(pass == 0) << "We didn't turn on interlace handling, but libpng is "
- "giving us interlaced data.";
if (static_cast<int>(row_num) > state->height) {
NOTREACHED() << "Invalid row";
return;
@@ -362,10 +335,7 @@
base = &state->output->front();
unsigned char* dest = &base[state->width * state->output_channels * row_num];
- if (state->row_converter)
- state->row_converter(new_row, state->width, dest, &state->is_opaque);
- else
- memcpy(dest, new_row, state->width * state->output_channels);
+ png_progressive_combine_row(png_ptr, dest, new_row);
}
void DecodeEndCallback(png_struct* png_ptr, png_info* info) {
« no previous file with comments | « third_party/libpng/pngusr.h ('k') | ui/gfx/codec/png_codec_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698