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) |