summaryrefslogtreecommitdiffstats
path: root/gfx
diff options
context:
space:
mode:
Diffstat (limited to 'gfx')
-rw-r--r--gfx/codec/png_codec.cc100
1 files changed, 52 insertions, 48 deletions
diff --git a/gfx/codec/png_codec.cc b/gfx/codec/png_codec.cc
index eaf94f0..9db0095 100644
--- a/gfx/codec/png_codec.cc
+++ b/gfx/codec/png_codec.cc
@@ -541,21 +541,53 @@ void ConvertBGRAtoRGB(const unsigned char* bgra, int pixel_width,
}
}
-// Automatically destroys the given write structs on destruction to make
-// cleanup and error handling code cleaner.
-class PngWriteStructDestroyer {
- public:
- PngWriteStructDestroyer(png_struct** ps, png_info** pi) : ps_(ps), pi_(pi) {
- }
- ~PngWriteStructDestroyer() {
- png_destroy_write_struct(ps_, pi_);
+// The type of functions usable for converting between pixel formats.
+typedef void (*FormatConverter)(const unsigned char* in, int w,
+ unsigned char* out, bool* is_opaque);
+
+// libpng uses a wacky setjmp-based API, which makes the compiler nervous.
+// We constrain all of the calls we make to libpng where the setjmp() is in
+// place to this function.
+// Returns true on success.
+bool DoLibpngWrite(png_struct* png_ptr, png_info* info_ptr,
+ PngEncoderState* state,
+ int width, int height, int row_byte_width,
+ const unsigned char* input,
+ int png_output_color_type, int output_color_components,
+ FormatConverter converter) {
+ // Make sure to not declare any locals here -- locals in the presence
+ // of setjmp() in C++ code makes gcc complain.
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ return false;
+
+ // Set our callback for libpng to give us the data.
+ png_set_write_fn(png_ptr, state, EncoderWriteCallback, NULL);
+
+ png_set_IHDR(png_ptr, info_ptr, width, height, 8, png_output_color_type,
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT);
+ png_write_info(png_ptr, info_ptr);
+
+ if (!converter) {
+ // No conversion needed, give the data directly to libpng.
+ for (int y = 0; y < height; y ++) {
+ png_write_row(png_ptr,
+ const_cast<unsigned char*>(&input[y * row_byte_width]));
+ }
+ } else {
+ // Needs conversion using a separate buffer.
+ unsigned char* row = new unsigned char[width * output_color_components];
+ for (int y = 0; y < height; y ++) {
+ converter(&input[y * row_byte_width], width, row, NULL);
+ png_write_row(png_ptr, row);
+ }
+ delete[] row;
}
- private:
- png_struct** ps_;
- png_info** pi_;
- DISALLOW_EVIL_CONSTRUCTORS(PngWriteStructDestroyer);
-};
+ png_write_end(png_ptr, info_ptr);
+ return true;
+}
} // namespace
@@ -566,8 +598,7 @@ bool PNGCodec::Encode(const unsigned char* input, ColorFormat format,
std::vector<unsigned char>* output) {
// Run to convert an input row into the output row format, NULL means no
// conversion is necessary.
- void (*converter)(const unsigned char* in, int w, unsigned char* out,
- bool* is_opaque) = NULL;
+ FormatConverter converter = NULL;
int input_color_components, output_color_components;
int png_output_color_type;
@@ -635,42 +666,15 @@ bool PNGCodec::Encode(const unsigned char* input, ColorFormat format,
png_destroy_write_struct(&png_ptr, NULL);
return false;
}
- PngWriteStructDestroyer destroyer(&png_ptr, &info_ptr);
-
- if (setjmp(png_jmpbuf(png_ptr))) {
- // The destroyer will ensure that the structures are cleaned up in this
- // case, even though we may get here as a jump from random parts of the
- // PNG library called below.
- return false;
- }
- // Set our callback for libpng to give us the data.
PngEncoderState state(output);
- png_set_write_fn(png_ptr, &state, EncoderWriteCallback, NULL);
+ bool success = DoLibpngWrite(png_ptr, info_ptr, &state,
+ w, h, row_byte_width, input,
+ png_output_color_type, output_color_components,
+ converter);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
- png_set_IHDR(png_ptr, info_ptr, w, h, 8, png_output_color_type,
- PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
- PNG_FILTER_TYPE_DEFAULT);
- png_write_info(png_ptr, info_ptr);
-
- if (!converter) {
- // No conversion needed, give the data directly to libpng.
- for (int y = 0; y < h; y ++) {
- png_write_row(png_ptr,
- const_cast<unsigned char*>(&input[y * row_byte_width]));
- }
- } else {
- // Needs conversion using a separate buffer.
- unsigned char* row = new unsigned char[w * output_color_components];
- for (int y = 0; y < h; y ++) {
- converter(&input[y * row_byte_width], w, row, NULL);
- png_write_row(png_ptr, row);
- }
- delete[] row;
- }
-
- png_write_end(png_ptr, info_ptr);
- return true;
+ return success;
}
// static