From 5bbd5fce2f1c0287e0d28b1334f0ccfe216cc969 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Sat, 19 Dec 2020 17:21:58 +0100 Subject: [PATCH] Common: Write PNGs in two steps to allow Unicode target paths. --- Source/Core/Common/Image.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/Source/Core/Common/Image.cpp b/Source/Core/Common/Image.cpp index 678a64db8c..478d4b42ab 100644 --- a/Source/Core/Common/Image.cpp +++ b/Source/Core/Common/Image.cpp @@ -10,6 +10,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/File.h" namespace Common { @@ -47,22 +48,39 @@ bool SavePNG(const std::string& path, const u8* input, ImageByteFormat format, u png.width = width; png.height = height; + size_t byte_per_pixel; switch (format) { case ImageByteFormat::RGB: png.format = PNG_FORMAT_RGB; + byte_per_pixel = 3; break; case ImageByteFormat::RGBA: png.format = PNG_FORMAT_RGBA; + byte_per_pixel = 4; break; default: return false; } - png_image_write_to_file(&png, path.c_str(), 0, input, stride, nullptr); - if (png.warning_or_error & PNG_IMAGE_ERROR) + // libpng doesn't handle non-ASCII characters in path, so write in two steps: + // first to memory, then to file + std::vector buffer(byte_per_pixel * width * height); + png_alloc_size_t size = buffer.size(); + int success = png_image_write_to_memory(&png, buffer.data(), &size, 0, input, stride, nullptr); + if (!success && size > buffer.size()) + { + // initial buffer size guess was too small, set to the now-known size and retry + buffer.resize(size); + png.warning_or_error = 0; + success = png_image_write_to_memory(&png, buffer.data(), &size, 0, input, stride, nullptr); + } + if (!success || (png.warning_or_error & PNG_IMAGE_ERROR) != 0) return false; - return true; + File::IOFile outfile(path, "wb"); + if (!outfile) + return false; + return outfile.WriteBytes(buffer.data(), size); } } // namespace Common