Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2009, Google Inc. | 2 * Copyright 2009, Google Inc. |
| 3 * All rights reserved. | 3 * All rights reserved. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions are | 6 * modification, are permitted provided that the following conditions are |
| 7 * met: | 7 * met: |
| 8 * | 8 * |
| 9 * * Redistributions of source code must retain the above copyright | 9 * * Redistributions of source code must retain the above copyright |
| 10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 30 */ | 30 */ |
| 31 | 31 |
| 32 | 32 |
| 33 // This file contains the image codec operations for PNG files. | 33 // This file contains the image codec operations for PNG files. |
| 34 | 34 |
| 35 // precompiled header must appear before anything else. | 35 // precompiled header must appear before anything else. |
| 36 #include "core/cross/precompile.h" | 36 #include "core/cross/precompile.h" |
| 37 | 37 |
| 38 #include <fstream> | 38 #include <fstream> |
| 39 #include "core/cross/bitmap.h" | 39 #include "core/cross/bitmap.h" |
| 40 #include "core/cross/error.h" | |
| 40 #include "core/cross/types.h" | 41 #include "core/cross/types.h" |
| 41 #include "utils/cross/file_path_utils.h" | 42 #include "utils/cross/file_path_utils.h" |
| 42 #include "base/file_path.h" | 43 #include "base/file_path.h" |
| 43 #include "base/file_util.h" | 44 #include "base/file_util.h" |
| 44 #include "import/cross/memory_buffer.h" | 45 #include "import/cross/memory_buffer.h" |
| 45 #include "import/cross/memory_stream.h" | 46 #include "import/cross/memory_stream.h" |
| 46 #include "png.h" | 47 #include "png.h" |
| 48 #include "utils/cross/dataurl.h" | |
| 47 | 49 |
| 48 using file_util::OpenFile; | 50 using file_util::OpenFile; |
| 49 using file_util::CloseFile; | 51 using file_util::CloseFile; |
| 50 | 52 |
| 51 namespace o3d { | 53 namespace o3d { |
| 52 | 54 |
| 55 namespace { | |
| 56 | |
| 53 // Helper function for LoadFromPNGFile that converts a stream into the | 57 // Helper function for LoadFromPNGFile that converts a stream into the |
| 54 // necessary abstract byte reading function. | 58 // necessary abstract byte reading function. |
| 55 static void stream_read_data(png_structp png_ptr, | 59 void StreamReadData(png_structp png_ptr, png_bytep data, png_size_t length) { |
| 56 png_bytep data, | |
| 57 png_size_t length) { | |
| 58 MemoryReadStream *stream = | 60 MemoryReadStream *stream = |
| 59 static_cast<MemoryReadStream*>(png_get_io_ptr(png_ptr)); | 61 static_cast<MemoryReadStream*>(png_get_io_ptr(png_ptr)); |
| 60 stream->Read(data, length); | 62 stream->Read(data, length); |
| 61 } | 63 } |
| 62 | 64 |
| 65 // Helper function for ToDataURL that converts a stream into the necessary | |
| 66 // abstract byte writing function. | |
| 67 void StreamWriteData(png_structp png_ptr, png_bytep data, png_size_t length) { | |
| 68 std::vector<uint8>* stream = | |
| 69 static_cast<std::vector<uint8>*>(png_get_io_ptr(png_ptr)); | |
| 70 stream->insert(stream->end(), | |
| 71 static_cast<uint8*>(data), | |
| 72 static_cast<uint8*>(data) + length); | |
| 73 } | |
| 74 | |
| 75 // Because libpng requires a flush function according to the docs. | |
| 76 void StreamFlush(png_structp png_ptr) { | |
| 77 } | |
| 78 | |
| 79 } // anonymous namespace | |
| 63 | 80 |
| 64 // Loads the raw RGB data from a compressed PNG file. | 81 // Loads the raw RGB data from a compressed PNG file. |
| 65 bool Bitmap::LoadFromPNGStream(MemoryReadStream *stream, | 82 bool Bitmap::LoadFromPNGStream(MemoryReadStream *stream, |
| 66 const String &filename, | 83 const String &filename, |
| 67 bool generate_mipmaps) { | 84 bool generate_mipmaps) { |
| 68 // Read the magic header. | 85 // Read the magic header. |
| 69 char magic[4]; | 86 char magic[4]; |
| 70 size_t bytes_read = stream->Read(magic, sizeof(magic)); | 87 size_t bytes_read = stream->Read(magic, sizeof(magic)); |
| 71 if (bytes_read != sizeof(magic)) { | 88 if (bytes_read != sizeof(magic)) { |
| 72 DLOG(ERROR) << "PNG file magic header not loaded \"" << filename << "\""; | 89 DLOG(ERROR) << "PNG file magic header not loaded \"" << filename << "\""; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 110 if (setjmp(png_jmpbuf(png_ptr))) { | 127 if (setjmp(png_jmpbuf(png_ptr))) { |
| 111 // If we reach here, a fatal error occurred so free memory and exit. | 128 // If we reach here, a fatal error occurred so free memory and exit. |
| 112 DLOG(ERROR) << "Fatal error reading PNG file \"" << filename << "\""; | 129 DLOG(ERROR) << "Fatal error reading PNG file \"" << filename << "\""; |
| 113 if (row_pointers) | 130 if (row_pointers) |
| 114 png_free(png_ptr, row_pointers); | 131 png_free(png_ptr, row_pointers); |
| 115 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); | 132 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); |
| 116 return false; | 133 return false; |
| 117 } | 134 } |
| 118 | 135 |
| 119 // Set up our STL stream input control | 136 // Set up our STL stream input control |
| 120 png_set_read_fn(png_ptr, stream, &stream_read_data); | 137 png_set_read_fn(png_ptr, stream, &StreamReadData); |
| 121 | 138 |
| 122 // We have already read some of the signature, advance the pointer. | 139 // We have already read some of the signature, advance the pointer. |
| 123 png_set_sig_bytes(png_ptr, sizeof(magic)); | 140 png_set_sig_bytes(png_ptr, sizeof(magic)); |
| 124 | 141 |
| 125 // Read the PNG header information. | 142 // Read the PNG header information. |
| 126 png_uint_32 png_width = 0; | 143 png_uint_32 png_width = 0; |
| 127 png_uint_32 png_height = 0; | 144 png_uint_32 png_height = 0; |
| 128 int png_color_type = 0; | 145 int png_color_type = 0; |
| 129 int png_interlace_type = 0; | 146 int png_interlace_type = 0; |
| 130 int png_bits_per_channel = 0; | 147 int png_bits_per_channel = 0; |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 256 | 273 |
| 257 // Success. | 274 // Success. |
| 258 image_data_.swap(image_data); | 275 image_data_.swap(image_data); |
| 259 format_ = format; | 276 format_ = format; |
| 260 width_ = png_width; | 277 width_ = png_width; |
| 261 height_ = png_height; | 278 height_ = png_height; |
| 262 num_mipmaps_ = num_mipmaps; | 279 num_mipmaps_ = num_mipmaps; |
| 263 return true; | 280 return true; |
| 264 } | 281 } |
| 265 | 282 |
| 266 // Saves the BGRA data from a compressed PNG file. | 283 // TODO(gman): Use the one in chrome or skia or some other place this function |
| 267 bool Bitmap::SaveToPNGFile(const char* filename) { | 284 // 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
| |
| 285 namespace { | |
| 286 | |
| 287 const int kEncodePad = 64; | |
| 288 | |
| 289 const char kEncode[] = | |
| 290 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
| 291 "abcdefghijklmnopqrstuvwxyz" | |
| 292 "0123456789+/="; | |
| 293 | |
| 294 size_t GetBase64EncodeLength(size_t length) { | |
| 295 return (length + 2) / 3 * 4; | |
| 296 } | |
| 297 | |
| 298 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.
| |
| 299 const uint8* src = (const uint8*) srcPtr; | |
| 300 uint8* dst = (uint8*) dstPtr; | |
| 301 if (dst) { | |
| 302 size_t remainder = length % 3; | |
| 303 const uint8* end = &src[length - remainder]; | |
| 304 while (src < end) { | |
| 305 unsigned a = *src++; | |
| 306 unsigned b = *src++; | |
| 307 unsigned c = *src++; | |
| 308 unsigned d = c & 0x3F; | |
| 309 c = (c >> 6 | b << 2) & 0x3F; | |
| 310 b = (b >> 4 | a << 4) & 0x3F; | |
| 311 a = a >> 2; | |
| 312 *dst++ = kEncode[a]; | |
| 313 *dst++ = kEncode[b]; | |
| 314 *dst++ = kEncode[c]; | |
| 315 *dst++ = kEncode[d]; | |
| 316 } | |
| 317 if (remainder > 0) { | |
| 318 unsigned k1 = 0; | |
| 319 unsigned k2 = kEncodePad; | |
| 320 unsigned a = (uint8) *src++; | |
| 321 if (remainder == 2) | |
| 322 { | |
| 323 int b = *src++; | |
| 324 k1 = b >> 4; | |
| 325 k2 = (b << 2) & 0x3F; | |
| 326 } | |
| 327 *dst++ = kEncode[a >> 2]; | |
| 328 *dst++ = kEncode[(k1 | a << 4) & 0x3F]; | |
| 329 *dst++ = kEncode[k2]; | |
| 330 *dst++ = kEncode[kEncodePad]; | |
| 331 } | |
| 332 } | |
| 333 return GetBase64EncodeLength(length); | |
| 334 } | |
| 335 | |
| 336 } // anonymous namespace | |
| 337 | |
| 338 String Bitmap::ToDataURL() { | |
| 268 if (format_ != Texture::ARGB8) { | 339 if (format_ != Texture::ARGB8) { |
| 269 DLOG(ERROR) << "Can only save ARGB8 images."; | 340 O3D_ERROR(service_locator()) << "Can only get data URL from ARGB8 images."; |
| 270 return false; | 341 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
| |
| 271 } | 342 } |
| 272 if (num_mipmaps_ != 1 || is_cubemap_) { | 343 if (num_mipmaps_ != 1 || is_cubemap_) { |
| 273 DLOG(ERROR) << "Only 2D images with only the base level can be saved."; | 344 O3D_ERROR(service_locator()) << |
| 274 return false; | 345 "Can only get data URL from images with no mips."; |
| 275 } | 346 return String("data:,"); |
| 276 FILE *fp = fopen(filename, "wb"); | |
| 277 if (!fp) { | |
| 278 DLOG(ERROR) << "Could not open file " << filename << " for writing."; | |
| 279 return false; | |
| 280 } | 347 } |
| 281 | 348 |
| 282 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, | 349 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, |
| 283 NULL, NULL); | 350 NULL, NULL); |
| 284 if (!png_ptr) { | 351 if (!png_ptr) { |
| 285 DLOG(ERROR) << "Could not create PNG structure."; | 352 DLOG(ERROR) << "Could not create PNG structure."; |
| 286 fclose(fp); | 353 return String("data:,"); |
| 287 return false; | |
| 288 } | 354 } |
| 289 | 355 |
| 290 png_infop info_ptr = png_create_info_struct(png_ptr); | 356 png_infop info_ptr = png_create_info_struct(png_ptr); |
| 291 if (!info_ptr) { | 357 if (!info_ptr) { |
| 292 DLOG(ERROR) << "Could not create PNG info structure."; | 358 DLOG(ERROR) << "Could not create PNG info structure."; |
| 293 png_destroy_write_struct(&png_ptr, png_infopp_NULL); | 359 png_destroy_write_struct(&png_ptr, png_infopp_NULL); |
| 294 fclose(fp); | 360 return String("data:,"); |
| 295 return false; | |
| 296 } | 361 } |
| 297 | 362 |
| 298 scoped_array<png_bytep> row_pointers(new png_bytep[height_]); | 363 scoped_array<png_bytep> row_pointers(new png_bytep[height_]); |
| 299 for (int i = 0; i < height_; ++i) { | 364 for (int i = 0; i < height_; ++i) { |
| 300 row_pointers[height_-1-i] = image_data_.get() + i * width_ * 4; | 365 row_pointers[height_-1-i] = image_data_.get() + i * width_ * 4; |
| 301 } | 366 } |
| 302 | 367 |
| 303 if (setjmp(png_jmpbuf(png_ptr))) { | 368 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
| |
| 304 // If we get here, we had a problem reading the file. | 369 // If we get here, we had a problem reading the file. |
| 305 DLOG(ERROR) << "Error while writing file " << filename << "."; | 370 DLOG(ERROR) << "Error while getting dataURL."; |
| 306 png_destroy_write_struct(&png_ptr, &info_ptr); | 371 png_destroy_write_struct(&png_ptr, &info_ptr); |
| 307 fclose(fp); | 372 return String("data:,"); |
| 308 return false; | |
| 309 } | 373 } |
| 310 | 374 |
| 311 png_init_io(png_ptr, fp); | 375 // Set up our STL stream output. |
| 376 std::vector<uint8> stream; | |
| 377 png_set_write_fn(png_ptr, &stream, &StreamWriteData, &StreamFlush); | |
| 312 | 378 |
| 313 png_set_IHDR(png_ptr, info_ptr, width_, height_, 8, | 379 png_set_IHDR(png_ptr, info_ptr, width_, height_, 8, |
| 314 PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, | 380 PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, |
| 315 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); | 381 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); |
| 316 png_set_bgr(png_ptr); | 382 png_set_bgr(png_ptr); |
| 317 png_set_rows(png_ptr, info_ptr, row_pointers.get()); | 383 png_set_rows(png_ptr, info_ptr, row_pointers.get()); |
| 318 png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, png_voidp_NULL); | 384 png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, png_voidp_NULL); |
| 319 | 385 |
| 320 png_destroy_write_struct(&png_ptr, &info_ptr); | 386 png_destroy_write_struct(&png_ptr, &info_ptr); |
| 321 fclose(fp); | 387 |
| 322 return true; | 388 return dataurl::ToDataURL("image/png", &stream[0], stream.size()); |
| 323 } | 389 } |
| 324 | 390 |
| 325 } // namespace o3d | 391 } // namespace o3d |
| OLD | NEW |