Chromium Code Reviews| Index: core/cross/bitmap_png.cc |
| =================================================================== |
| --- core/cross/bitmap_png.cc (revision 22687) |
| +++ core/cross/bitmap_png.cc (working copy) |
| @@ -37,6 +37,7 @@ |
| #include <fstream> |
| #include "core/cross/bitmap.h" |
| +#include "core/cross/error.h" |
| #include "core/cross/types.h" |
| #include "utils/cross/file_path_utils.h" |
| #include "base/file_path.h" |
| @@ -44,23 +45,39 @@ |
| #include "import/cross/memory_buffer.h" |
| #include "import/cross/memory_stream.h" |
| #include "png.h" |
| +#include "utils/cross/dataurl.h" |
| using file_util::OpenFile; |
| using file_util::CloseFile; |
| namespace o3d { |
| +namespace { |
| + |
| // Helper function for LoadFromPNGFile that converts a stream into the |
| // necessary abstract byte reading function. |
| -static void stream_read_data(png_structp png_ptr, |
| - png_bytep data, |
| - png_size_t length) { |
| +void StreamReadData(png_structp png_ptr, png_bytep data, png_size_t length) { |
| MemoryReadStream *stream = |
| static_cast<MemoryReadStream*>(png_get_io_ptr(png_ptr)); |
| stream->Read(data, length); |
| } |
| +// Helper function for ToDataURL that converts a stream into the necessary |
| +// abstract byte writing function. |
| +void StreamWriteData(png_structp png_ptr, png_bytep data, png_size_t length) { |
| + std::vector<uint8>* stream = |
| + static_cast<std::vector<uint8>*>(png_get_io_ptr(png_ptr)); |
| + stream->insert(stream->end(), |
| + static_cast<uint8*>(data), |
| + static_cast<uint8*>(data) + length); |
| +} |
| +// Because libpng requires a flush function according to the docs. |
| +void StreamFlush(png_structp png_ptr) { |
| +} |
| + |
| +} // anonymous namespace |
| + |
| // Loads the raw RGB data from a compressed PNG file. |
| bool Bitmap::LoadFromPNGStream(MemoryReadStream *stream, |
| const String &filename, |
| @@ -117,7 +134,7 @@ |
| } |
| // Set up our STL stream input control |
| - png_set_read_fn(png_ptr, stream, &stream_read_data); |
| + png_set_read_fn(png_ptr, stream, &StreamReadData); |
| // We have already read some of the signature, advance the pointer. |
| png_set_sig_bytes(png_ptr, sizeof(magic)); |
| @@ -263,36 +280,84 @@ |
| return true; |
| } |
| -// Saves the BGRA data from a compressed PNG file. |
| -bool Bitmap::SaveToPNGFile(const char* filename) { |
| +// TODO(gman): Use the one in chrome or skia or some other place this function |
| +// is implemented. |
|
apatrick
2009/08/07 18:25:45
isn't this also in core/cross/base64.cc
gman
2009/08/07 21:34:31
doh, forgot to delete this.
Done
|
| +namespace { |
| + |
| +const int kEncodePad = 64; |
| + |
| +const char kEncode[] = |
| + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| + "abcdefghijklmnopqrstuvwxyz" |
| + "0123456789+/="; |
| + |
| +size_t GetBase64EncodeLength(size_t length) { |
| + return (length + 2) / 3 * 4; |
| +} |
| + |
| +size_t Base64Encode(const void* srcPtr, size_t length, void* dstPtr) { |
|
apatrick
2009/08/07 18:25:45
src_ptr, dst_ptr
gman
2009/08/07 21:34:31
Done.
|
| + const uint8* src = (const uint8*) srcPtr; |
| + uint8* dst = (uint8*) dstPtr; |
| + if (dst) { |
| + size_t remainder = length % 3; |
| + const uint8* end = &src[length - remainder]; |
| + while (src < end) { |
| + unsigned a = *src++; |
| + unsigned b = *src++; |
| + unsigned c = *src++; |
| + unsigned d = c & 0x3F; |
| + c = (c >> 6 | b << 2) & 0x3F; |
| + b = (b >> 4 | a << 4) & 0x3F; |
| + a = a >> 2; |
| + *dst++ = kEncode[a]; |
| + *dst++ = kEncode[b]; |
| + *dst++ = kEncode[c]; |
| + *dst++ = kEncode[d]; |
| + } |
| + if (remainder > 0) { |
| + unsigned k1 = 0; |
| + unsigned k2 = kEncodePad; |
| + unsigned a = (uint8) *src++; |
| + if (remainder == 2) |
| + { |
| + int b = *src++; |
| + k1 = b >> 4; |
| + k2 = (b << 2) & 0x3F; |
| + } |
| + *dst++ = kEncode[a >> 2]; |
| + *dst++ = kEncode[(k1 | a << 4) & 0x3F]; |
| + *dst++ = kEncode[k2]; |
| + *dst++ = kEncode[kEncodePad]; |
| + } |
| + } |
| + return GetBase64EncodeLength(length); |
| +} |
| + |
| +} // anonymous namespace |
| + |
| +String Bitmap::ToDataURL() { |
| if (format_ != Texture::ARGB8) { |
| - DLOG(ERROR) << "Can only save ARGB8 images."; |
| - return false; |
| + O3D_ERROR(service_locator()) << "Can only get data URL from ARGB8 images."; |
| + return String("data:,"); |
|
apatrick
2009/08/07 18:25:45
Could these refer to a constant for empty data url
gman
2009/08/07 21:34:31
strange. for some reason this didn't get uploaded
|
| } |
| if (num_mipmaps_ != 1 || is_cubemap_) { |
| - DLOG(ERROR) << "Only 2D images with only the base level can be saved."; |
| - return false; |
| + O3D_ERROR(service_locator()) << |
| + "Can only get data URL from images with no mips."; |
| + return String("data:,"); |
| } |
| - FILE *fp = fopen(filename, "wb"); |
| - if (!fp) { |
| - DLOG(ERROR) << "Could not open file " << filename << " for writing."; |
| - return false; |
| - } |
| png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, |
| NULL, NULL); |
| if (!png_ptr) { |
| DLOG(ERROR) << "Could not create PNG structure."; |
| - fclose(fp); |
| - return false; |
| + return String("data:,"); |
| } |
| png_infop info_ptr = png_create_info_struct(png_ptr); |
| if (!info_ptr) { |
| DLOG(ERROR) << "Could not create PNG info structure."; |
| png_destroy_write_struct(&png_ptr, png_infopp_NULL); |
| - fclose(fp); |
| - return false; |
| + return String("data:,"); |
| } |
| scoped_array<png_bytep> row_pointers(new png_bytep[height_]); |
| @@ -302,13 +367,14 @@ |
| if (setjmp(png_jmpbuf(png_ptr))) { |
|
apatrick
2009/08/07 18:25:45
setjmp messes up invocation of constructors and de
piman
2009/08/07 19:04:32
setjmp/longjmp are unfortunately the standard way
gman
2009/08/07 21:34:31
I put it in another function and hope that's enoug
|
| // If we get here, we had a problem reading the file. |
| - DLOG(ERROR) << "Error while writing file " << filename << "."; |
| + DLOG(ERROR) << "Error while getting dataURL."; |
| png_destroy_write_struct(&png_ptr, &info_ptr); |
| - fclose(fp); |
| - return false; |
| + return String("data:,"); |
| } |
| - png_init_io(png_ptr, fp); |
| + // Set up our STL stream output. |
| + std::vector<uint8> stream; |
| + png_set_write_fn(png_ptr, &stream, &StreamWriteData, &StreamFlush); |
| png_set_IHDR(png_ptr, info_ptr, width_, height_, 8, |
| PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, |
| @@ -318,8 +384,8 @@ |
| png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, png_voidp_NULL); |
| png_destroy_write_struct(&png_ptr, &info_ptr); |
| - fclose(fp); |
| - return true; |
| + |
| + return dataurl::ToDataURL("image/png", &stream[0], stream.size()); |
| } |
| } // namespace o3d |