| 262 | } |
| 263 | |
| 264 | bool PNGBufferLoader(RGBA8Image* image, const void* buffer, size_t buffer_size) |
| 265 | { |
| 266 | png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); |
| 267 | if (!png_ptr) |
| 268 | return false; |
| 269 | |
| 270 | png_infop info_ptr = png_create_info_struct(png_ptr); |
| 271 | if (!info_ptr) |
| 272 | { |
| 273 | png_destroy_read_struct(&png_ptr, nullptr, nullptr); |
| 274 | return false; |
| 275 | } |
| 276 | |
| 277 | ScopedGuard cleanup([&png_ptr, &info_ptr]() { png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); }); |
| 278 | |
| 279 | std::vector<u32> new_data; |
| 280 | std::vector<png_bytep> row_pointers; |
| 281 | |
| 282 | if (setjmp(png_jmpbuf(png_ptr))) |
| 283 | return false; |
| 284 | |
| 285 | struct IOData |
| 286 | { |
| 287 | const u8* buffer; |
| 288 | size_t buffer_size; |
| 289 | size_t buffer_pos; |
| 290 | }; |
| 291 | IOData data = {static_cast<const u8*>(buffer), buffer_size, 0}; |
| 292 | |
| 293 | png_set_read_fn(png_ptr, &data, [](png_structp png_ptr, png_bytep data_ptr, png_size_t size) { |
| 294 | IOData* data = static_cast<IOData*>(png_get_io_ptr(png_ptr)); |
| 295 | const size_t read_size = std::min<size_t>(data->buffer_size - data->buffer_pos, size); |
| 296 | if (read_size > 0) |
| 297 | { |
| 298 | std::memcpy(data_ptr, data->buffer + data->buffer_pos, read_size); |
| 299 | data->buffer_pos += read_size; |
| 300 | } |
| 301 | }); |
| 302 | |
| 303 | return PNGCommonLoader(image, png_ptr, info_ptr, new_data, row_pointers); |
| 304 | } |
| 305 | |
| 306 | static void PNGSaveCommon(const RGBA8Image& image, png_structp png_ptr, png_infop info_ptr, u8 quality) |
| 307 | { |
nothing calls this directly
no test coverage detected