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 |