mirror of
https://github.com/hyprwm/hyprgraphics.git
synced 2025-12-20 06:20:02 +01:00
png: handle invalid buffer size returned by libspng
Some checks failed
Build & Test (Arch) / Arch: Build and Test (gcc) (push) Has been cancelled
Build & Test (Arch) / Arch: Build and Test (clang) (push) Has been cancelled
Build & Test / nix (hyprgraphics) (push) Has been cancelled
Build & Test / nix (hyprgraphics-with-tests) (push) Has been cancelled
Some checks failed
Build & Test (Arch) / Arch: Build and Test (gcc) (push) Has been cancelled
Build & Test (Arch) / Arch: Build and Test (clang) (push) Has been cancelled
Build & Test / nix (hyprgraphics) (push) Has been cancelled
Build & Test / nix (hyprgraphics-with-tests) (push) Has been cancelled
sometimes (no clue why) spng_decoded_image_size is just plain wrong. In those cases, just guess what the size should be with 32bpp. fixes #9
This commit is contained in:
parent
23783b9603
commit
12cd7034e4
3 changed files with 32 additions and 16 deletions
|
|
@ -17,23 +17,23 @@ Hyprgraphics::CImage::CImage(const std::string& path) : filepath(path) {
|
||||||
const auto len = path.length();
|
const auto len = path.length();
|
||||||
if (path.find(".png") == len - 4 || path.find(".PNG") == len - 4) {
|
if (path.find(".png") == len - 4 || path.find(".PNG") == len - 4) {
|
||||||
CAIROSURFACE = PNG::createSurfaceFromPNG(path);
|
CAIROSURFACE = PNG::createSurfaceFromPNG(path);
|
||||||
mime = "image/png";
|
mime = "image/png";
|
||||||
} else if (path.find(".jpg") == len - 4 || path.find(".JPG") == len - 4 || path.find(".jpeg") == len - 5 || path.find(".JPEG") == len - 5) {
|
} else if (path.find(".jpg") == len - 4 || path.find(".JPG") == len - 4 || path.find(".jpeg") == len - 5 || path.find(".JPEG") == len - 5) {
|
||||||
CAIROSURFACE = JPEG::createSurfaceFromJPEG(path);
|
CAIROSURFACE = JPEG::createSurfaceFromJPEG(path);
|
||||||
imageHasAlpha = false;
|
imageHasAlpha = false;
|
||||||
mime = "image/jpeg";
|
mime = "image/jpeg";
|
||||||
} else if (path.find(".bmp") == len - 4 || path.find(".BMP") == len - 4) {
|
} else if (path.find(".bmp") == len - 4 || path.find(".BMP") == len - 4) {
|
||||||
CAIROSURFACE = BMP::createSurfaceFromBMP(path);
|
CAIROSURFACE = BMP::createSurfaceFromBMP(path);
|
||||||
imageHasAlpha = false;
|
imageHasAlpha = false;
|
||||||
mime = "image/bmp";
|
mime = "image/bmp";
|
||||||
} else if (path.find(".webp") == len - 5 || path.find(".WEBP") == len - 5) {
|
} else if (path.find(".webp") == len - 5 || path.find(".WEBP") == len - 5) {
|
||||||
CAIROSURFACE = WEBP::createSurfaceFromWEBP(path);
|
CAIROSURFACE = WEBP::createSurfaceFromWEBP(path);
|
||||||
mime = "image/webp";
|
mime = "image/webp";
|
||||||
} else if (path.find(".jxl") == len - 4 || path.find(".JXL") == len - 4) {
|
} else if (path.find(".jxl") == len - 4 || path.find(".JXL") == len - 4) {
|
||||||
|
|
||||||
#ifdef JXL_FOUND
|
#ifdef JXL_FOUND
|
||||||
CAIROSURFACE = JXL::createSurfaceFromJXL(path);
|
CAIROSURFACE = JXL::createSurfaceFromJXL(path);
|
||||||
mime = "image/jxl";
|
mime = "image/jxl";
|
||||||
#else
|
#else
|
||||||
lastError = "hyprgraphics compiled without JXL support";
|
lastError = "hyprgraphics compiled without JXL support";
|
||||||
return;
|
return;
|
||||||
|
|
@ -49,15 +49,15 @@ Hyprgraphics::CImage::CImage(const std::string& path) : filepath(path) {
|
||||||
|
|
||||||
if (first_word == "PNG") {
|
if (first_word == "PNG") {
|
||||||
CAIROSURFACE = PNG::createSurfaceFromPNG(path);
|
CAIROSURFACE = PNG::createSurfaceFromPNG(path);
|
||||||
mime = "image/png";
|
mime = "image/png";
|
||||||
} else if (first_word == "JPEG") {
|
} else if (first_word == "JPEG") {
|
||||||
CAIROSURFACE = JPEG::createSurfaceFromJPEG(path);
|
CAIROSURFACE = JPEG::createSurfaceFromJPEG(path);
|
||||||
imageHasAlpha = false;
|
imageHasAlpha = false;
|
||||||
mime = "image/jpeg";
|
mime = "image/jpeg";
|
||||||
} else if (first_word == "BMP") {
|
} else if (first_word == "BMP") {
|
||||||
CAIROSURFACE = BMP::createSurfaceFromBMP(path);
|
CAIROSURFACE = BMP::createSurfaceFromBMP(path);
|
||||||
imageHasAlpha = false;
|
imageHasAlpha = false;
|
||||||
mime = "image/bmp";
|
mime = "image/bmp";
|
||||||
} else {
|
} else {
|
||||||
lastError = "unrecognized image";
|
lastError = "unrecognized image";
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -102,8 +102,8 @@ std::expected<cairo_surface_t*, std::string> BMP::createSurfaceFromBMP(const std
|
||||||
if (!std::filesystem::exists(path))
|
if (!std::filesystem::exists(path))
|
||||||
return std::unexpected("loading bmp: file doesn't exist");
|
return std::unexpected("loading bmp: file doesn't exist");
|
||||||
|
|
||||||
std::ifstream bitmapImageStream(path);
|
std::ifstream bitmapImageStream(path);
|
||||||
BmpHeader bitmapHeader;
|
BmpHeader bitmapHeader;
|
||||||
if (const auto RET = bitmapHeader.load(bitmapImageStream); RET.has_value())
|
if (const auto RET = bitmapHeader.load(bitmapImageStream); RET.has_value())
|
||||||
return std::unexpected("loading bmp: " + *RET);
|
return std::unexpected("loading bmp: " + *RET);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,16 +31,16 @@ std::expected<cairo_surface_t*, std::string> PNG::createSurfaceFromPNG(const std
|
||||||
spng_set_png_buffer(ctx, PNGCONTENT.data(), PNGCONTENT.size());
|
spng_set_png_buffer(ctx, PNGCONTENT.data(), PNGCONTENT.size());
|
||||||
|
|
||||||
spng_ihdr ihdr{0};
|
spng_ihdr ihdr{0};
|
||||||
if (spng_get_ihdr(ctx, &ihdr))
|
if (int ret = spng_get_ihdr(ctx, &ihdr); ret)
|
||||||
return std::unexpected("loading png: file content was empty (bad file?)");
|
return std::unexpected(std::string{"loading png: spng_get_ihdr failed: "} + spng_strerror(ret));
|
||||||
|
|
||||||
int fmt = SPNG_FMT_PNG;
|
int fmt = SPNG_FMT_PNG;
|
||||||
if (ihdr.color_type == SPNG_COLOR_TYPE_INDEXED)
|
if (ihdr.color_type == SPNG_COLOR_TYPE_INDEXED)
|
||||||
fmt = SPNG_FMT_RGB8;
|
fmt = SPNG_FMT_RGB8;
|
||||||
|
|
||||||
size_t imageLength = 0;
|
size_t imageLength = 0;
|
||||||
if (spng_decoded_image_size(ctx, fmt, &imageLength))
|
if (int ret = spng_decoded_image_size(ctx, fmt, &imageLength); ret)
|
||||||
return std::unexpected("loading png: spng_decoded_image_size failed");
|
return std::unexpected(std::string{"loading png: spng_decoded_image_size failed: "} + spng_strerror(ret));
|
||||||
|
|
||||||
uint8_t* imageData = (uint8_t*)malloc(imageLength);
|
uint8_t* imageData = (uint8_t*)malloc(imageLength);
|
||||||
|
|
||||||
|
|
@ -48,9 +48,25 @@ std::expected<cairo_surface_t*, std::string> PNG::createSurfaceFromPNG(const std
|
||||||
return std::unexpected("loading png: mallocing failed, out of memory?");
|
return std::unexpected("loading png: mallocing failed, out of memory?");
|
||||||
|
|
||||||
// TODO: allow proper decode of high bitrate images
|
// TODO: allow proper decode of high bitrate images
|
||||||
if (spng_decode_image(ctx, imageData, imageLength, SPNG_FMT_RGBA8, 0)) {
|
bool succeededDecode = false;
|
||||||
|
int ret = spng_decode_image(ctx, imageData, imageLength, SPNG_FMT_RGBA8, 0);
|
||||||
|
if (!ret)
|
||||||
|
succeededDecode = true;
|
||||||
|
|
||||||
|
if (!succeededDecode && ret == SPNG_EBUFSIZ) {
|
||||||
|
// hack, but I don't know why decoded_image_size is sometimes wrong
|
||||||
|
imageLength = ihdr.height * ihdr.width * 4 /* FIXME: this is wrong if we doing >32bpp!!!! */;
|
||||||
|
imageData = (uint8_t*)realloc(imageData, imageLength);
|
||||||
|
|
||||||
|
ret = spng_decode_image(ctx, imageData, imageLength, SPNG_FMT_RGBA8, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
succeededDecode = true;
|
||||||
|
|
||||||
|
if (!succeededDecode) {
|
||||||
free(imageData);
|
free(imageData);
|
||||||
return std::unexpected("loading png: spng_decode_image failed (invalid image?)");
|
return std::unexpected(std::string{"loading png: spng_decode_image failed: "} + spng_strerror(ret) + " (bad image?)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert RGBA8888 -> ARGB8888 premult for cairo
|
// convert RGBA8888 -> ARGB8888 premult for cairo
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue