| 269 | } |
| 270 | |
| 271 | bool PNGImageEncoder::encode() SKR_NOEXCEPT |
| 272 | { |
| 273 | SKR_ASSERT(initialized); |
| 274 | const auto width = get_width(); |
| 275 | const auto height = get_height(); |
| 276 | const auto color_format = get_color_format(); |
| 277 | const auto raw_bit_depth = get_bit_depth(); |
| 278 | |
| 279 | //Preserve old single thread code on some platform in relation to a type incompatibility at compile time. |
| 280 | SKR_ASSERT(width > 0); |
| 281 | SKR_ASSERT(height > 0); |
| 282 | |
| 283 | // Reset to the beginning of file so we can use png_read_png(), which expects to start at the beginning. |
| 284 | read_offset = 0; |
| 285 | |
| 286 | png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, this, PNGImageCoderHelper::user_error_fn, PNGImageCoderHelper::user_warning_fn); |
| 287 | SKR_ASSERT(png_ptr); |
| 288 | |
| 289 | png_infop info_ptr = png_create_info_struct(png_ptr); |
| 290 | SKR_ASSERT(info_ptr); |
| 291 | |
| 292 | png_bytep* row_pointers = (png_bytep*) png_malloc( png_ptr, height * sizeof(png_bytep) ); |
| 293 | SKR_DEFER({ png_free(png_ptr, row_pointers); png_destroy_write_struct(&png_ptr, &info_ptr); }); |
| 294 | |
| 295 | // Store the current stack pointer in the jump buffer. setjmp will return non-zero in the case of a write error. |
| 296 | #if PLATFORM_ANDROID || PLATFORM_LUMIN || PLATFORM_LUMINGL4 |
| 297 | //Preserve old single thread code on some platform in relation to a type incompatibility at compile time. |
| 298 | if (setjmp(SetjmpBuffer) != 0) |
| 299 | #else |
| 300 | //Use libPNG jump buffer solution to allow concurrent compression\decompression on concurrent threads. |
| 301 | if (setjmp(png_jmpbuf(png_ptr)) != 0) |
| 302 | #endif |
| 303 | { |
| 304 | return false; |
| 305 | } |
| 306 | |
| 307 | // --------------------------------------------------------------------------------------------------------- |
| 308 | // Anything allocated on the stack after this point will not be destructed correctly in the case of an error |
| 309 | |
| 310 | { |
| 311 | png_set_compression_level(png_ptr, PNGDefaultZlibLevel); |
| 312 | //png_set_IHDR(png_ptr, info_ptr, width, height, raw_bit_depth, |
| 313 | // (color_format == EImageCoderColorFormat::IMAGE_CODER_COLOR_FORMAT_Gray) ? PNG_COLOR_TYPE_GRAY : PNG_COLOR_TYPE_RGBA, |
| 314 | // PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); |
| 315 | png_set_write_fn(png_ptr, this, PNGImageCoderHelper::user_write_compressed, PNGImageCoderHelper::user_flush_data); |
| 316 | |
| 317 | const uint64_t PixelChannels = (color_format == EImageCoderColorFormat::IMAGE_CODER_COLOR_FORMAT_Gray) ? 1 : 4; |
| 318 | const uint64_t BytesPerPixel = (raw_bit_depth * PixelChannels) / 8; |
| 319 | const uint64_t BytesPerRow = BytesPerPixel * width; |
| 320 | |
| 321 | for (int64_t i = 0; i < height; i++) |
| 322 | { |
| 323 | auto dv = decoded_view.data(); |
| 324 | row_pointers[i] = (png_bytep)&dv[i * BytesPerRow]; |
| 325 | } |
| 326 | png_set_rows(png_ptr, info_ptr, row_pointers); |
| 327 | |
| 328 | uint32_t Transform = (color_format == EImageCoderColorFormat::IMAGE_CODER_COLOR_FORMAT_BGRA) ? PNG_TRANSFORM_BGR : PNG_TRANSFORM_IDENTITY; |
no test coverage detected