| 119 | } |
| 120 | |
| 121 | tuple<Vec2U, PixelFormat> Image::readPngMetadata(IODevicePtr device) { |
| 122 | png_byte header[8]; |
| 123 | device->readFull((char*)header, sizeof(header)); |
| 124 | |
| 125 | if (png_sig_cmp(header, 0, sizeof(header))) |
| 126 | throw ImageException(strf("File {} is not a png image!", device->deviceName())); |
| 127 | |
| 128 | png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); |
| 129 | if (!png_ptr) |
| 130 | throw ImageException("Internal libPNG error"); |
| 131 | |
| 132 | // Use custom warning function to suppress cerr warnings |
| 133 | png_set_error_fn(png_ptr, (png_voidp)device.get(), logPngError, logPngWarning); |
| 134 | |
| 135 | png_infop info_ptr = png_create_info_struct(png_ptr); |
| 136 | if (!info_ptr) { |
| 137 | png_destroy_read_struct(&png_ptr, nullptr, nullptr); |
| 138 | throw ImageException("Internal libPNG error"); |
| 139 | } |
| 140 | |
| 141 | png_infop end_info = png_create_info_struct(png_ptr); |
| 142 | if (!end_info) { |
| 143 | png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); |
| 144 | throw ImageException("Internal libPNG error"); |
| 145 | } |
| 146 | |
| 147 | if (setjmp(png_jmpbuf(png_ptr))) { |
| 148 | png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); |
| 149 | throw ImageException("Internal error reading png."); |
| 150 | } |
| 151 | |
| 152 | png_set_read_fn(png_ptr, device.get(), readPngData); |
| 153 | |
| 154 | // Tell libPNG that we read some of the header. |
| 155 | png_set_sig_bytes(png_ptr, sizeof(header)); |
| 156 | |
| 157 | png_read_info(png_ptr, info_ptr); |
| 158 | |
| 159 | png_uint_32 img_width = png_get_image_width(png_ptr, info_ptr); |
| 160 | png_uint_32 img_height = png_get_image_height(png_ptr, info_ptr); |
| 161 | |
| 162 | png_uint_32 bitdepth = png_get_bit_depth(png_ptr, info_ptr); |
| 163 | png_uint_32 channels = png_get_channels(png_ptr, info_ptr); |
| 164 | |
| 165 | // Color type. (RGB, RGBA, Luminance, luminance alpha... palette... etc) |
| 166 | png_uint_32 color_type = png_get_color_type(png_ptr, info_ptr); |
| 167 | |
| 168 | if (color_type == PNG_COLOR_TYPE_PALETTE) { |
| 169 | png_set_palette_to_rgb(png_ptr); |
| 170 | channels = 3; |
| 171 | bitdepth = 8; |
| 172 | } |
| 173 | |
| 174 | if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { |
| 175 | if (bitdepth < 8) { |
| 176 | png_set_expand_gray_1_2_4_to_8(png_ptr); |
| 177 | bitdepth = 8; |
| 178 | } |
nothing calls this directly
no test coverage detected