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 |