| 45 | } |
| 46 | |
| 47 | std::unique_ptr<PngImage> PngImage::loadFromFile(const std::filesystem::path& filePath) |
| 48 | { |
| 49 | std::ifstream inFile(filePath, std::ios::binary); |
| 50 | |
| 51 | png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, libpngErrorHandler, libpngWarningHandler); |
| 52 | if (!png) |
| 53 | { |
| 54 | Logging::error("Failed to create PNG read struct"); |
| 55 | return nullptr; |
| 56 | } |
| 57 | |
| 58 | png_infop info = png_create_info_struct(png); |
| 59 | if (!info) |
| 60 | { |
| 61 | Logging::error("Failed to create PNG info struct"); |
| 62 | png_destroy_read_struct(&png, nullptr, nullptr); |
| 63 | return nullptr; |
| 64 | } |
| 65 | |
| 66 | try |
| 67 | { |
| 68 | png_set_read_fn(png, static_cast<void*>(&inFile), [](png_structp png_ptr, png_bytep data, png_size_t length) { |
| 69 | std::istream* inStream = static_cast<std::istream*>(png_get_io_ptr(png_ptr)); |
| 70 | inStream->read(reinterpret_cast<char*>(data), length); |
| 71 | }); |
| 72 | |
| 73 | png_read_info(png, info); |
| 74 | |
| 75 | // Apply transformations to normalize to RGBA format |
| 76 | png_byte colorType = png_get_color_type(png, info); |
| 77 | png_byte bitDepth = png_get_bit_depth(png, info); |
| 78 | |
| 79 | // Convert palette to RGB |
| 80 | if (colorType == PNG_COLOR_TYPE_PALETTE) |
| 81 | { |
| 82 | png_set_palette_to_rgb(png); |
| 83 | } |
| 84 | |
| 85 | // Convert grayscale to RGB if less than 8 bits |
| 86 | if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) |
| 87 | { |
| 88 | png_set_expand_gray_1_2_4_to_8(png); |
| 89 | } |
| 90 | |
| 91 | // Add alpha channel if not present |
| 92 | if (colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_PALETTE) |
| 93 | { |
| 94 | png_set_add_alpha(png, 0xFF, PNG_FILLER_AFTER); |
| 95 | } |
| 96 | |
| 97 | // Convert 16-bit to 8-bit |
| 98 | if (bitDepth == 16) |
| 99 | { |
| 100 | png_set_strip_16(png); |
| 101 | } |
| 102 | |
| 103 | // Convert grayscale to RGB |
| 104 | if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) |