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 namespace { |
267 bool Bitmap::SaveToPNGFile(const char* filename) { | 284 |
268 if (format_ != Texture::ARGB8) { | 285 bool CreatePNGInUInt8Vector(const Bitmap& bitmap, std::vector<uint8>* buffer) { |
269 DLOG(ERROR) << "Can only save ARGB8 images."; | 286 DCHECK(bitmap.format() == Texture::ARGB8); |
270 return false; | 287 DCHECK(bitmap.num_mipmaps() == 1); |
271 } | 288 DCHECK(!bitmap.is_cubemap()); |
272 if (num_mipmaps_ != 1 || is_cubemap_) { | |
273 DLOG(ERROR) << "Only 2D images with only the base level can be saved."; | |
274 return false; | |
275 } | |
276 FILE *fp = fopen(filename, "wb"); | |
277 if (!fp) { | |
278 DLOG(ERROR) << "Could not open file " << filename << " for writing."; | |
279 return false; | |
280 } | |
281 | 289 |
282 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, | 290 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, |
283 NULL, NULL); | 291 NULL, NULL); |
284 if (!png_ptr) { | 292 if (!png_ptr) { |
285 DLOG(ERROR) << "Could not create PNG structure."; | 293 DLOG(ERROR) << "Could not create PNG structure."; |
286 fclose(fp); | |
287 return false; | 294 return false; |
288 } | 295 } |
289 | 296 |
290 png_infop info_ptr = png_create_info_struct(png_ptr); | 297 png_infop info_ptr = png_create_info_struct(png_ptr); |
291 if (!info_ptr) { | 298 if (!info_ptr) { |
292 DLOG(ERROR) << "Could not create PNG info structure."; | 299 DLOG(ERROR) << "Could not create PNG info structure."; |
293 png_destroy_write_struct(&png_ptr, png_infopp_NULL); | 300 png_destroy_write_struct(&png_ptr, png_infopp_NULL); |
294 fclose(fp); | |
295 return false; | 301 return false; |
296 } | 302 } |
297 | 303 |
298 scoped_array<png_bytep> row_pointers(new png_bytep[height_]); | 304 unsigned width = bitmap.width(); |
299 for (int i = 0; i < height_; ++i) { | 305 unsigned height = bitmap.height(); |
300 row_pointers[height_-1-i] = image_data_.get() + i * width_ * 4; | 306 scoped_array<png_bytep> row_pointers(new png_bytep[height]); |
| 307 for (int i = 0; i < height; ++i) { |
| 308 row_pointers[height - 1 - i] = bitmap.GetMipData(0) + i * width * 4; |
301 } | 309 } |
302 | 310 |
303 if (setjmp(png_jmpbuf(png_ptr))) { | 311 if (setjmp(png_jmpbuf(png_ptr))) { |
304 // If we get here, we had a problem reading the file. | 312 // If we get here, we had a problem reading the file. |
305 DLOG(ERROR) << "Error while writing file " << filename << "."; | 313 DLOG(ERROR) << "Error while getting dataURL."; |
306 png_destroy_write_struct(&png_ptr, &info_ptr); | 314 png_destroy_write_struct(&png_ptr, &info_ptr); |
307 fclose(fp); | |
308 return false; | 315 return false; |
309 } | 316 } |
310 | 317 |
311 png_init_io(png_ptr, fp); | 318 // Set up our STL stream output. |
| 319 png_set_write_fn(png_ptr, buffer, &StreamWriteData, &StreamFlush); |
312 | 320 |
313 png_set_IHDR(png_ptr, info_ptr, width_, height_, 8, | 321 png_set_IHDR(png_ptr, info_ptr, width, height, 8, |
314 PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, | 322 PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, |
315 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); | 323 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); |
316 png_set_bgr(png_ptr); | 324 png_set_bgr(png_ptr); |
317 png_set_rows(png_ptr, info_ptr, row_pointers.get()); | 325 png_set_rows(png_ptr, info_ptr, row_pointers.get()); |
318 png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, png_voidp_NULL); | 326 png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, png_voidp_NULL); |
319 | 327 |
320 png_destroy_write_struct(&png_ptr, &info_ptr); | 328 png_destroy_write_struct(&png_ptr, &info_ptr); |
321 fclose(fp); | 329 } |
322 return true; | 330 |
| 331 } // anonymous namespace |
| 332 |
| 333 String Bitmap::ToDataURL() { |
| 334 if (format_ != Texture::ARGB8) { |
| 335 O3D_ERROR(service_locator()) << "Can only get data URL from ARGB8 images."; |
| 336 return dataurl::kEmptyDataURL; |
| 337 } |
| 338 if (num_mipmaps_ != 1 || is_cubemap_) { |
| 339 O3D_ERROR(service_locator()) << |
| 340 "Can only get data URL from 2d images with no mips."; |
| 341 return dataurl::kEmptyDataURL; |
| 342 } |
| 343 |
| 344 std::vector<uint8> stream; |
| 345 if (!CreatePNGInUInt8Vector(*this, &stream)) { |
| 346 return dataurl::kEmptyDataURL; |
| 347 } |
| 348 |
| 349 return dataurl::ToDataURL("image/png", &stream[0], stream.size()); |
323 } | 350 } |
324 | 351 |
325 } // namespace o3d | 352 } // namespace o3d |
OLD | NEW |