| 145 | } |
| 146 | |
| 147 | bool PNGImageDecoder::decode(EImageCoderColorFormat in_format, uint32_t in_bit_depth) SKR_NOEXCEPT |
| 148 | { |
| 149 | SKR_ASSERT(initialized); |
| 150 | const auto width = get_width(); |
| 151 | const auto height = get_height(); |
| 152 | const auto bit_depth = get_bit_depth(); |
| 153 | |
| 154 | read_offset = 0; |
| 155 | // create png read struct |
| 156 | png_structp png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, this, |
| 157 | PNGImageCoderHelper::user_error_fn, PNGImageCoderHelper::user_warning_fn, |
| 158 | NULL, PNGImageCoderHelper::user_malloc, PNGImageCoderHelper::user_free); |
| 159 | png_infop info_ptr = png_create_info_struct(png_ptr); |
| 160 | png_bytep* row_pointers = (png_bytep*) png_malloc( png_ptr, height * sizeof(png_bytep) ); |
| 161 | SKR_DEFER({ png_free(png_ptr, row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); }); |
| 162 | if (setjmp(png_jmpbuf(png_ptr)) != 0) |
| 163 | { |
| 164 | return false; |
| 165 | } |
| 166 | if (png_color_type == PNG_COLOR_TYPE_PALETTE) |
| 167 | { |
| 168 | png_set_palette_to_rgb(png_ptr); |
| 169 | } |
| 170 | if ((png_color_type & PNG_COLOR_MASK_COLOR) == 0 && bit_depth < 8) |
| 171 | { |
| 172 | png_set_expand_gray_1_2_4_to_8(png_ptr); |
| 173 | } |
| 174 | // insert alpha channel if there is no alpha channel |
| 175 | if ((png_color_type & PNG_COLOR_MASK_ALPHA) == 0 && (in_format == IMAGE_CODER_COLOR_FORMAT_RGBA || in_format == IMAGE_CODER_COLOR_FORMAT_BGRA)) |
| 176 | { |
| 177 | // png images don't set PNG_COLOR_MASK_ALPHA if they have alpha from a tRNS chunk, but png_set_add_alpha seems to be safe regardless |
| 178 | if ((png_color_type & PNG_COLOR_MASK_COLOR) == 0) |
| 179 | { |
| 180 | png_set_tRNS_to_alpha(png_ptr); |
| 181 | } |
| 182 | else if (png_color_type == PNG_COLOR_TYPE_PALETTE) |
| 183 | { |
| 184 | png_set_tRNS_to_alpha(png_ptr); |
| 185 | } |
| 186 | if (in_bit_depth == 8) |
| 187 | { |
| 188 | png_set_add_alpha(png_ptr, 0xff , PNG_FILLER_AFTER); |
| 189 | } |
| 190 | else if (in_bit_depth == 16) |
| 191 | { |
| 192 | png_set_add_alpha(png_ptr, 0xffff , PNG_FILLER_AFTER); |
| 193 | } |
| 194 | } |
| 195 | // calculate pixel depth |
| 196 | const uint64_t pixel_channels = (in_format == IMAGE_CODER_COLOR_FORMAT_Gray) ? 1 : 4; |
| 197 | const uint64_t bytes_per_pixel = pixel_channels * in_bit_depth / 8; |
| 198 | const uint64_t bytes_per_row = width * bytes_per_pixel; |
| 199 | // reallocate raw data |
| 200 | decoded_size = bytes_per_row * height; |
| 201 | decoded_data = PNGImageDecoder::Allocate(decoded_size, get_alignment()); |
| 202 | // read png data |
| 203 | png_set_read_fn(png_ptr, this, PNGImageCoderHelper::user_read_compressed); |
| 204 | for (uint32_t i = 0; i < height; i++) |
no test coverage detected