summaryrefslogtreecommitdiffstats
path: root/ui/gfx
diff options
context:
space:
mode:
authortony@chromium.org <tony@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-28 18:24:21 +0000
committertony@chromium.org <tony@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-28 18:24:21 +0000
commitc99fcf5a1913cea79dbf53cc5ca3dba8e3ee5d64 (patch)
treeec671064fb18a8e0cf198c514680ea6f86ecc345 /ui/gfx
parenta6e70b07a557d6c1765df2560c0104a9033c4015 (diff)
downloadchromium_src-c99fcf5a1913cea79dbf53cc5ca3dba8e3ee5d64.zip
chromium_src-c99fcf5a1913cea79dbf53cc5ca3dba8e3ee5d64.tar.gz
chromium_src-c99fcf5a1913cea79dbf53cc5ca3dba8e3ee5d64.tar.bz2
Add the ability to write comments to PNGCodec::Encode.
I'm going to use this to write layout test checksums to the expected png files. Review URL: http://codereview.chromium.org/6696085 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@79592 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/gfx')
-rw-r--r--ui/gfx/codec/png_codec.cc89
-rw-r--r--ui/gfx/codec/png_codec.h24
-rw-r--r--ui/gfx/codec/png_codec_unittest.cc81
3 files changed, 164 insertions, 30 deletions
diff --git a/ui/gfx/codec/png_codec.cc b/ui/gfx/codec/png_codec.cc
index 6cd761f..0d9596e 100644
--- a/ui/gfx/codec/png_codec.cc
+++ b/ui/gfx/codec/png_codec.cc
@@ -6,6 +6,8 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "base/string_util.h"
+#include "ui/gfx/size.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkUnPreMultiply.h"
#include "third_party/skia/include/core/SkColorPriv.h"
@@ -546,6 +548,58 @@ void ConvertBGRAtoRGB(const unsigned char* bgra, int pixel_width,
}
}
+#ifdef PNG_TEXT_SUPPORTED
+class CommentWriter {
+ public:
+ explicit CommentWriter(const std::vector<PNGCodec::Comment>& comments)
+ : comments_(comments),
+ png_text_(new png_text[comments.size()]) {
+ for (size_t i = 0; i < comments.size(); ++i)
+ AddComment(i, comments[i]);
+ }
+
+ ~CommentWriter() {
+ for (size_t i = 0; i < comments_.size(); ++i) {
+ free(png_text_[i].key);
+ free(png_text_[i].text);
+ }
+ delete [] png_text_;
+ }
+
+ bool HasComments() {
+ return !comments_.empty();
+ }
+
+ png_text* get_png_text() {
+ return png_text_;
+ }
+
+ int size() {
+ return static_cast<int>(comments_.size());
+ }
+
+ private:
+ void AddComment(size_t pos, const PNGCodec::Comment& comment) {
+ png_text_[pos].compression = PNG_TEXT_COMPRESSION_NONE;
+ // A PNG comment's key can only be 79 characters long.
+ DCHECK(comment.key.length() < 79);
+ png_text_[pos].key = base::strdup(comment.key.substr(0, 78).c_str());
+ png_text_[pos].text = base::strdup(comment.text.c_str());
+ png_text_[pos].text_length = comment.text.length();
+#ifdef PNG_iTXt_SUPPORTED
+ png_text_[pos].itxt_length = 0;
+ png_text_[pos].lang = 0;
+ png_text_[pos].lang_key = 0;
+#endif
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(CommentWriter);
+
+ const std::vector<PNGCodec::Comment> comments_;
+ png_text* png_text_;
+};
+#endif // PNG_TEXT_SUPPORTED
+
// 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);
@@ -559,7 +613,8 @@ bool DoLibpngWrite(png_struct* png_ptr, png_info* info_ptr,
int width, int height, int row_byte_width,
const unsigned char* input,
int png_output_color_type, int output_color_components,
- FormatConverter converter) {
+ FormatConverter converter,
+ const std::vector<PNGCodec::Comment>& comments) {
// Make sure to not declare any locals here -- locals in the presence
// of setjmp() in C++ code makes gcc complain.
@@ -572,6 +627,15 @@ bool DoLibpngWrite(png_struct* png_ptr, png_info* info_ptr,
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);
+
+#ifdef PNG_TEXT_SUPPORTED
+ CommentWriter comment_writer(comments);
+ if (comment_writer.HasComments()) {
+ png_set_text(png_ptr, info_ptr, comment_writer.get_png_text(),
+ comment_writer.size());
+ }
+#endif
+
png_write_info(png_ptr, info_ptr);
if (!converter) {
@@ -598,8 +662,9 @@ bool DoLibpngWrite(png_struct* png_ptr, png_info* info_ptr,
// static
bool PNGCodec::Encode(const unsigned char* input, ColorFormat format,
- int w, int h, int row_byte_width,
+ const Size& size, int row_byte_width,
bool discard_transparency,
+ const std::vector<Comment>& comments,
std::vector<unsigned char>* output) {
// Run to convert an input row into the output row format, NULL means no
// conversion is necessary.
@@ -660,7 +725,7 @@ bool PNGCodec::Encode(const unsigned char* input, ColorFormat format,
}
// Row stride should be at least as long as the length of the data.
- DCHECK(input_color_components * w <= row_byte_width);
+ DCHECK(input_color_components * size.width() <= row_byte_width);
png_struct* png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL);
@@ -674,9 +739,9 @@ bool PNGCodec::Encode(const unsigned char* input, ColorFormat format,
PngEncoderState state(output);
bool success = DoLibpngWrite(png_ptr, info_ptr, &state,
- w, h, row_byte_width, input,
- png_output_color_type, output_color_components,
- converter);
+ size.width(), size.height(), row_byte_width,
+ input, png_output_color_type,
+ output_color_components, converter, comments);
png_destroy_write_struct(&png_ptr, &info_ptr);
return success;
@@ -692,8 +757,16 @@ bool PNGCodec::EncodeBGRASkBitmap(const SkBitmap& input,
DCHECK(input.empty() || input.bytesPerPixel() == bbp);
return Encode(reinterpret_cast<unsigned char*>(input.getAddr32(0, 0)),
- FORMAT_SkBitmap, input.width(), input.height(),
- input.width() * bbp, discard_transparency, output);
+ FORMAT_SkBitmap, Size(input.width(), input.height()),
+ input.width() * bbp, discard_transparency,
+ std::vector<Comment>(), output);
+}
+
+PNGCodec::Comment::Comment(const std::string& k, const std::string& t)
+ : key(k), text(t) {
+}
+
+PNGCodec::Comment::~Comment() {
}
} // namespace gfx
diff --git a/ui/gfx/codec/png_codec.h b/ui/gfx/codec/png_codec.h
index 73453fe..eac411d 100644
--- a/ui/gfx/codec/png_codec.h
+++ b/ui/gfx/codec/png_codec.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,6 +6,7 @@
#define UI_GFX_CODEC_PNG_CODEC_H_
#pragma once
+#include <string>
#include <vector>
#include "base/basictypes.h"
@@ -14,6 +15,8 @@ class SkBitmap;
namespace gfx {
+class Size;
+
// Interface for encoding and decoding PNG data. This is a wrapper around
// libpng, which has an inconvenient interface for callers. This is currently
// designed for use in tests only (where we control the files), so the handling
@@ -39,6 +42,15 @@ class PNGCodec {
FORMAT_SkBitmap
};
+ // Represents a comment in the tEXt ancillary chunk of the png.
+ struct Comment {
+ Comment(const std::string& k, const std::string& t);
+ ~Comment();
+
+ std::string key;
+ std::string text;
+ };
+
// Encodes the given raw 'input' data, with each pixel being represented as
// given in 'format'. The encoded PNG data will be written into the supplied
// vector and true will be returned on success. On failure (false), the
@@ -47,7 +59,7 @@ class PNGCodec {
// When writing alpha values, the input colors are assumed to be post
// multiplied.
//
- // w, h: dimensions of the image
+ // size: dimensions of the image
// row_byte_width: the width in bytes of each row. This may be greater than
// w * bytes_per_pixel if there is extra padding at the end of each row
// (often, each row is padded to the next machine word).
@@ -55,9 +67,13 @@ class PNGCodec {
// alpha values, these alpha values will be discarded and only RGB will be
// written to the resulting file. Otherwise, alpha values in the input
// will be preserved.
- static bool Encode(const unsigned char* input, ColorFormat format,
- int w, int h, int row_byte_width,
+ // comments: comments to be written in the png's metadata.
+ static bool 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);
// Call PNGCodec::Encode on the supplied SkBitmap |input|, which is assumed
diff --git a/ui/gfx/codec/png_codec_unittest.cc b/ui/gfx/codec/png_codec_unittest.cc
index 72ed671..b31dbd2 100644
--- a/ui/gfx/codec/png_codec_unittest.cc
+++ b/ui/gfx/codec/png_codec_unittest.cc
@@ -1,13 +1,15 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <math.h>
+#include <algorithm>
+#include <cmath>
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkUnPreMultiply.h"
#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/size.h"
namespace gfx {
@@ -79,8 +81,10 @@ TEST(PNGCodec, EncodeDecodeRGB) {
// encode
std::vector<unsigned char> encoded;
- EXPECT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB, w, h,
- w * 3, false, &encoded));
+ EXPECT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB,
+ Size(w, h), w * 3, false,
+ std::vector<PNGCodec::Comment>(),
+ &encoded));
// decode, it should have the same size as the original
std::vector<unsigned char> decoded;
@@ -106,8 +110,10 @@ TEST(PNGCodec, EncodeDecodeRGBA) {
// encode
std::vector<unsigned char> encoded;
- EXPECT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGBA, w, h,
- w * 4, false, &encoded));
+ EXPECT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGBA,
+ Size(w, h), w * 4, false,
+ std::vector<PNGCodec::Comment>(),
+ &encoded));
// decode, it should have the same size as the original
std::vector<unsigned char> decoded;
@@ -140,8 +146,10 @@ TEST(PNGCodec, DecodeCorrupted) {
// Make some compressed data.
std::vector<unsigned char> compressed;
- EXPECT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB, w, h,
- w * 3, false, &compressed));
+ EXPECT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB,
+ Size(w, h), w * 3, false,
+ std::vector<PNGCodec::Comment>(),
+ &compressed));
// Try decompressing a truncated version.
EXPECT_FALSE(PNGCodec::Decode(&compressed[0], compressed.size() / 2,
@@ -166,8 +174,10 @@ TEST(PNGCodec, EncodeDecodeBGRA) {
// Encode.
std::vector<unsigned char> encoded;
- EXPECT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_BGRA, w, h,
- w * 4, false, &encoded));
+ EXPECT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_BGRA,
+ Size(w, h), w * 4, false,
+ std::vector<PNGCodec::Comment>(),
+ &encoded));
// Decode, it should have the same size as the original.
std::vector<unsigned char> decoded;
@@ -194,10 +204,10 @@ TEST(PNGCodec, StripAddAlpha) {
// Encode RGBA data as RGB.
std::vector<unsigned char> encoded;
- EXPECT_TRUE(PNGCodec::Encode(&original_rgba[0],
- PNGCodec::FORMAT_RGBA,
- w, h,
- w * 4, true, &encoded));
+ EXPECT_TRUE(PNGCodec::Encode(&original_rgba[0], PNGCodec::FORMAT_RGBA,
+ Size(w, h), w * 4, true,
+ std::vector<PNGCodec::Comment>(),
+ &encoded));
// Decode the RGB to RGBA.
std::vector<unsigned char> decoded;
@@ -213,10 +223,10 @@ TEST(PNGCodec, StripAddAlpha) {
ASSERT_TRUE(original_rgba == decoded);
// Encode RGBA to RGBA.
- EXPECT_TRUE(PNGCodec::Encode(&original_rgba[0],
- PNGCodec::FORMAT_RGBA,
- w, h,
- w * 4, false, &encoded));
+ EXPECT_TRUE(PNGCodec::Encode(&original_rgba[0], PNGCodec::FORMAT_RGBA,
+ Size(w, h), w * 4, false,
+ std::vector<PNGCodec::Comment>(),
+ &encoded));
// Decode the RGBA to RGB.
EXPECT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
@@ -294,4 +304,39 @@ TEST(PNGCodec, EncodeBGRASkBitmapDiscardTransparency) {
}
}
+TEST(PNGCodec, EncodeWithComment) {
+ const int w = 10, h = 10;
+
+ std::vector<unsigned char> original;
+ MakeRGBImage(w, h, &original);
+
+ std::vector<unsigned char> encoded;
+ std::vector<PNGCodec::Comment> comments;
+ comments.push_back(PNGCodec::Comment("key", "text"));
+ comments.push_back(PNGCodec::Comment("test", "something"));
+ comments.push_back(PNGCodec::Comment("have some", "spaces in both"));
+ EXPECT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB,
+ Size(w, h), w * 3, false, comments, &encoded));
+
+ // Each chunk is of the form length (4 bytes), chunk type (tEXt), data,
+ // checksum (4 bytes). Make sure we find all of them in the encoded
+ // results.
+ const unsigned char kExpected1[] =
+ "\x00\x00\x00\x08tEXtkey\x00text\x9e\xe7\x66\x51";
+ const unsigned char kExpected2[] =
+ "\x00\x00\x00\x0etEXttest\x00something\x29\xba\xef\xac";
+ const unsigned char kExpected3[] =
+ "\x00\x00\x00\x18tEXthave some\x00spaces in both\x8d\x69\x34\x2d";
+
+ EXPECT_NE(search(encoded.begin(), encoded.end(), kExpected1,
+ kExpected1 + arraysize(kExpected1)),
+ encoded.end());
+ EXPECT_NE(search(encoded.begin(), encoded.end(), kExpected2,
+ kExpected2 + arraysize(kExpected2)),
+ encoded.end());
+ EXPECT_NE(search(encoded.begin(), encoded.end(), kExpected3,
+ kExpected3 + arraysize(kExpected3)),
+ encoded.end());
+}
+
} // namespace gfx