Chromium Code Reviews| Index: ui/gfx/codec/png_codec.cc |
| diff --git a/ui/gfx/codec/png_codec.cc b/ui/gfx/codec/png_codec.cc |
| index b3f4345343f0d15a49c0cfc9c759bed662cc4189..25a125d9ec73d4c0174548e48ba12bfdc681f0a2 100644 |
| --- a/ui/gfx/codec/png_codec.cc |
| +++ b/ui/gfx/codec/png_codec.cc |
| @@ -18,6 +18,21 @@ namespace gfx { |
| namespace { |
| +// Transform coefficients (expressed in 16.16 fixed-point numbers) |
| +// for RGB into grayscale. |
| +// Same coefficients as used in png_do_rgb_to_gray() in pngtran.c in libpng |
| +static const uint32_t RED_TO_GRAY_COEF = 6969; // .212671 * 32768 |
|
sadrul
2014/01/15 21:43:06
two spaces before EOL // comments
|
| +static const uint32_t GREEN_TO_GRAY_COEF = 23434; // .715160 * 32768 |
| +static const uint32_t BLUE_TO_GRAY_COEF = 32768 - RED_TO_GRAY_COEF - |
| + GREEN_TO_GRAY_COEF; |
| + |
| +static inline unsigned char PixelRgbtoGray(unsigned char r, unsigned char b, |
| + unsigned char g) { |
| + return (RED_TO_GRAY_COEF * r + GREEN_TO_GRAY_COEF * g + |
| + BLUE_TO_GRAY_COEF * b) >> 15; |
| +} |
| + |
| + |
| // Converts BGRA->RGBA and RGBA->BGRA. |
| void ConvertBetweenBGRAandRGBA(const unsigned char* input, int pixel_width, |
| unsigned char* output, bool* is_opaque) { |
| @@ -31,6 +46,32 @@ void ConvertBetweenBGRAandRGBA(const unsigned char* input, int pixel_width, |
| } |
| } |
| +void ConvertBGRAtoGray(const unsigned char* bgra, int pixel_width, |
| + unsigned char* gray, bool* is_opaque) { |
| + for (int x = 0; x < pixel_width; x++) { |
| + const unsigned char* pixel_in = &bgra[x * 4]; |
| + gray[x] = PixelRgbtoGray(pixel_in[2], pixel_in[1], pixel_in[0]); |
| + } |
| +} |
| + |
| +void ConvertBGRAtoGrayAlpha(const unsigned char* bgra, int pixel_width, |
| + unsigned char* grayalpha, bool* is_opaque) { |
| + for (int x = 0; x < pixel_width; x++) { |
| + const unsigned char* pixel_in = &bgra[x * 4]; |
| + unsigned char* pixel_out = &grayalpha[x * 2]; |
| + pixel_out[0] = PixelRgbtoGray(pixel_in[2], pixel_in[1], pixel_in[0]); |
| + pixel_out[1] = pixel_in[3]; // alpha |
| + } |
| +} |
| + |
| +void ConvertRGBtoGray(const unsigned char* rgb, int pixel_width, |
| + unsigned char* gray, bool* is_opaque) { |
| + for (int x = 0; x < pixel_width; x++) { |
| + const unsigned char* pixel_in = &rgb[x * 3]; |
| + gray[x] = PixelRgbtoGray(pixel_in[0], pixel_in[1], pixel_in[2]); |
| + } |
| +} |
| + |
| void ConvertRGBAtoRGB(const unsigned char* rgba, int pixel_width, |
| unsigned char* rgb, bool* is_opaque) { |
| for (int x = 0; x < pixel_width; x++) { |
| @@ -42,6 +83,25 @@ void ConvertRGBAtoRGB(const unsigned char* rgba, int pixel_width, |
| } |
| } |
| +void ConvertRGBAtoGray(const unsigned char* rgba, int pixel_width, |
| + unsigned char* gray, bool* is_opaque) { |
| + for (int x = 0; x < pixel_width; x++) { |
| + const unsigned char* pixel_in = &rgba[x * 4]; |
| + gray[x] = PixelRgbtoGray(pixel_in[0], pixel_in[1], pixel_in[2]); |
| + } |
| +} |
| + |
| +void ConvertRGBAtoGrayAlpha(const unsigned char* rgba, int pixel_width, |
| + unsigned char* grayalpha, bool* is_opaque) { |
| + for (int x = 0; x < pixel_width; x++) { |
| + const unsigned char* pixel_in = &rgba[x * 4]; |
| + unsigned char* pixel_out = &grayalpha[x * 2]; |
| + pixel_out[0] = PixelRgbtoGray(pixel_in[0], pixel_in[1], pixel_in[2]); |
| + pixel_out[1] = pixel_in[3]; // alpha |
| + } |
| +} |
| + |
| + |
| void ConvertSkiatoRGB(const unsigned char* skia, int pixel_width, |
| unsigned char* rgb, bool* is_opaque) { |
| for (int x = 0; x < pixel_width; x++) { |
| @@ -67,6 +127,48 @@ void ConvertSkiatoRGBA(const unsigned char* skia, int pixel_width, |
| gfx::ConvertSkiaToRGBA(skia, pixel_width, rgba); |
| } |
| +void ConvertSkiatoGray(const unsigned char* skia, int pixel_width, |
| + unsigned char* gray, bool* is_opaque) { |
| + for (int x = 0; x < pixel_width; x++) { |
| + const uint32_t pixel_in = *reinterpret_cast<const uint32_t*>(&skia[x * 4]); |
| + unsigned char* pixel_out = &gray[x]; |
| + |
| + int alpha = SkGetPackedA32(pixel_in); |
| + if (alpha != 0 && alpha != 255) { |
| + SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel_in); |
| + pixel_out[0] = PixelRgbtoGray(SkColorGetR(unmultiplied), |
| + SkColorGetG(unmultiplied), |
| + SkColorGetB(unmultiplied)); |
| + } else { |
| + pixel_out[0] = PixelRgbtoGray(SkGetPackedR32(pixel_in), |
| + SkGetPackedG32(pixel_in), |
| + SkGetPackedB32(pixel_in)); |
| + } |
| + } |
| +} |
| + |
| +void ConvertSkiatoGrayAlpha(const unsigned char* skia, int pixel_width, |
| + unsigned char* grayalpha, bool* is_opaque) { |
| + for (int x = 0; x < pixel_width; x++) { |
| + const uint32_t pixel_in = *reinterpret_cast<const uint32_t*>(&skia[x * 4]); |
| + unsigned char* pixel_out = &grayalpha[x * 2]; |
| + |
| + int alpha = SkGetPackedA32(pixel_in); |
| + if (alpha != 0 && alpha != 255) { |
| + SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel_in); |
| + pixel_out[0] = PixelRgbtoGray(SkColorGetR(unmultiplied), |
| + SkColorGetG(unmultiplied), |
| + SkColorGetB(unmultiplied)); |
| + } else { |
| + pixel_out[0] = PixelRgbtoGray(SkGetPackedR32(pixel_in), |
| + SkGetPackedG32(pixel_in), |
| + SkGetPackedB32(pixel_in)); |
| + } |
| + pixel_out[1] = alpha; |
| + } |
| +} |
| + |
| + |
| } // namespace |
| // Decoder -------------------------------------------------------------------- |
| @@ -635,6 +737,7 @@ bool EncodeWithCompressionLevel(const unsigned char* input, |
| const Size& size, |
| int row_byte_width, |
| bool discard_transparency, |
| + bool discard_color, |
| const std::vector<PNGCodec::Comment>& comments, |
| int compression_level, |
| std::vector<unsigned char>* output) { |
| @@ -647,46 +750,89 @@ bool EncodeWithCompressionLevel(const unsigned char* input, |
| switch (format) { |
| case PNGCodec::FORMAT_RGB: |
| input_color_components = 3; |
| - output_color_components = 3; |
| - png_output_color_type = PNG_COLOR_TYPE_RGB; |
| + if (discard_color) { |
| + output_color_components = 1; |
| + png_output_color_type = PNG_COLOR_TYPE_GRAY; |
| + converter = ConvertRGBtoGray; |
| + } else { |
| + output_color_components = 3; |
| + png_output_color_type = PNG_COLOR_TYPE_RGB; |
| + converter = NULL; |
| + } |
| break; |
| case PNGCodec::FORMAT_RGBA: |
| input_color_components = 4; |
| if (discard_transparency) { |
| - output_color_components = 3; |
| - png_output_color_type = PNG_COLOR_TYPE_RGB; |
| - converter = ConvertRGBAtoRGB; |
| + if (discard_color) { |
| + output_color_components = 1; |
| + png_output_color_type = PNG_COLOR_TYPE_GRAY; |
| + converter = ConvertRGBAtoGray; |
| + } else { |
| + output_color_components = 3; |
| + png_output_color_type = PNG_COLOR_TYPE_RGB; |
| + converter = ConvertRGBAtoRGB; |
| + } |
| } else { |
| - output_color_components = 4; |
| - png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA; |
| - converter = NULL; |
| + if (discard_color) { |
| + output_color_components = 2; |
| + png_output_color_type = PNG_COLOR_TYPE_GRAY_ALPHA; |
| + converter = ConvertRGBAtoGrayAlpha; |
| + } else { |
| + output_color_components = 4; |
| + png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA; |
| + converter = NULL; |
| + } |
| } |
| break; |
| case PNGCodec::FORMAT_BGRA: |
| input_color_components = 4; |
| if (discard_transparency) { |
| - output_color_components = 3; |
| - png_output_color_type = PNG_COLOR_TYPE_RGB; |
| - converter = ConvertBGRAtoRGB; |
| + if (discard_color) { |
| + output_color_components = 1; |
| + png_output_color_type = PNG_COLOR_TYPE_GRAY; |
| + converter = ConvertBGRAtoGray; |
| + } else { |
| + output_color_components = 3; |
| + png_output_color_type = PNG_COLOR_TYPE_RGB; |
| + converter = ConvertBGRAtoRGB; |
| + } |
| } else { |
| - output_color_components = 4; |
| - png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA; |
| - converter = ConvertBetweenBGRAandRGBA; |
| + if (discard_color) { |
| + output_color_components = 2; |
| + png_output_color_type = PNG_COLOR_TYPE_GRAY_ALPHA; |
| + converter = ConvertBGRAtoGrayAlpha; |
| + } else { |
| + output_color_components = 4; |
| + png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA; |
| + converter = ConvertBetweenBGRAandRGBA; |
| + } |
| } |
| break; |
| case PNGCodec::FORMAT_SkBitmap: |
| input_color_components = 4; |
| if (discard_transparency) { |
| - output_color_components = 3; |
| - png_output_color_type = PNG_COLOR_TYPE_RGB; |
| - converter = ConvertSkiatoRGB; |
| + if (discard_color) { |
| + output_color_components = 1; |
| + png_output_color_type = PNG_COLOR_TYPE_GRAY; |
| + converter = ConvertSkiatoGray; |
| + } else { |
| + output_color_components = 3; |
| + png_output_color_type = PNG_COLOR_TYPE_RGB; |
| + converter = ConvertSkiatoRGB; |
| + } |
| } else { |
| - output_color_components = 4; |
| - png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA; |
| - converter = ConvertSkiatoRGBA; |
| + if (discard_color) { |
| + output_color_components = 2; |
| + png_output_color_type = PNG_COLOR_TYPE_GRAY_ALPHA; |
| + converter = ConvertSkiatoGrayAlpha; |
| + } else { |
| + output_color_components = 4; |
| + png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA; |
| + converter = ConvertSkiatoRGBA; |
| + } |
|
sadrul
2014/01/15 21:43:06
I wonder if this could somehow be simplified, e.g.
|
| } |
| break; |
| @@ -727,12 +873,14 @@ bool PNGCodec::Encode(const unsigned char* input, ColorFormat format, |
| const Size& size, int row_byte_width, |
| bool discard_transparency, |
| const std::vector<Comment>& comments, |
| - std::vector<unsigned char>* output) { |
| + std::vector<unsigned char>* output, |
| + bool discard_color) { |
| return EncodeWithCompressionLevel(input, |
| format, |
| size, |
| row_byte_width, |
| discard_transparency, |
| + discard_color, |
| comments, |
| Z_DEFAULT_COMPRESSION, |
| output); |
| @@ -741,7 +889,8 @@ bool PNGCodec::Encode(const unsigned char* input, ColorFormat format, |
| // static |
| bool PNGCodec::EncodeBGRASkBitmap(const SkBitmap& input, |
| bool discard_transparency, |
| - std::vector<unsigned char>* output) { |
| + std::vector<unsigned char>* output, |
| + bool discard_color) { |
| static const int bbp = 4; |
| if (input.empty()) |
| @@ -753,13 +902,14 @@ bool PNGCodec::EncodeBGRASkBitmap(const SkBitmap& input, |
| return Encode(reinterpret_cast<unsigned char*>(input.getAddr32(0, 0)), |
| FORMAT_SkBitmap, Size(input.width(), input.height()), |
| static_cast<int>(input.rowBytes()), discard_transparency, |
| - std::vector<Comment>(), output); |
| + std::vector<Comment>(), output, discard_color); |
| } |
| // static |
| bool PNGCodec::FastEncodeBGRASkBitmap(const SkBitmap& input, |
| bool discard_transparency, |
| - std::vector<unsigned char>* output) { |
| + std::vector<unsigned char>* output, |
| + bool discard_color) { |
| static const int bbp = 4; |
| if (input.empty()) |
| @@ -772,7 +922,7 @@ bool PNGCodec::FastEncodeBGRASkBitmap(const SkBitmap& input, |
| reinterpret_cast<unsigned char*>(input.getAddr32(0, 0)), |
| FORMAT_SkBitmap, Size(input.width(), input.height()), |
| static_cast<int>(input.rowBytes()), discard_transparency, |
| - std::vector<Comment>(), Z_BEST_SPEED, output); |
| + discard_color, std::vector<Comment>(), Z_BEST_SPEED, output); |
| } |
| PNGCodec::Comment::Comment(const std::string& k, const std::string& t) |