| 341 | } |
| 342 | |
| 343 | bool WriteImageToBuffer( |
| 344 | const void* image, int width, int height, int row_bytes, int num_channels, |
| 345 | int channel_bits, int compression, string* png_string, |
| 346 | const std::vector<std::pair<string, string> >* metadata) { |
| 347 | CHECK_NOTNULL(image); |
| 348 | CHECK_NOTNULL(png_string); |
| 349 | // Although this case is checked inside png.cc and issues an error message, |
| 350 | // that error causes memory corruption. |
| 351 | if (width == 0 || height == 0) return false; |
| 352 | |
| 353 | png_string->resize(0); |
| 354 | png_infop info_ptr = nullptr; |
| 355 | png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, |
| 356 | ErrorHandler, WarningHandler); |
| 357 | if (png_ptr == nullptr) return false; |
| 358 | if (setjmp(png_jmpbuf(png_ptr))) { |
| 359 | png_destroy_write_struct(&png_ptr, info_ptr ? &info_ptr : nullptr); |
| 360 | return false; |
| 361 | } |
| 362 | info_ptr = png_create_info_struct(png_ptr); |
| 363 | if (info_ptr == nullptr) { |
| 364 | png_destroy_write_struct(&png_ptr, nullptr); |
| 365 | return false; |
| 366 | } |
| 367 | |
| 368 | int color_type = -1; |
| 369 | switch (num_channels) { |
| 370 | case 1: |
| 371 | color_type = PNG_COLOR_TYPE_GRAY; |
| 372 | break; |
| 373 | case 2: |
| 374 | color_type = PNG_COLOR_TYPE_GRAY_ALPHA; |
| 375 | break; |
| 376 | case 3: |
| 377 | color_type = PNG_COLOR_TYPE_RGB; |
| 378 | break; |
| 379 | case 4: |
| 380 | color_type = PNG_COLOR_TYPE_RGB_ALPHA; |
| 381 | break; |
| 382 | default: |
| 383 | png_destroy_write_struct(&png_ptr, &info_ptr); |
| 384 | return false; |
| 385 | } |
| 386 | |
| 387 | png_set_write_fn(png_ptr, png_string, StringWriter, StringWriterFlush); |
| 388 | if (compression < 0) compression = Z_DEFAULT_COMPRESSION; |
| 389 | png_set_compression_level(png_ptr, compression); |
| 390 | png_set_compression_mem_level(png_ptr, MAX_MEM_LEVEL); |
| 391 | // There used to be a call to png_set_filter here turning off filtering |
| 392 | // entirely, but it produced pessimal compression ratios. I'm not sure |
| 393 | // why it was there. |
| 394 | png_set_IHDR(png_ptr, info_ptr, width, height, channel_bits, color_type, |
| 395 | PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, |
| 396 | PNG_FILTER_TYPE_DEFAULT); |
| 397 | // If we have metadata write to it. |
| 398 | if (metadata && !metadata->empty()) { |
| 399 | std::vector<png_text> text; |
| 400 | for (const auto& pair : *metadata) { |