diff options
Diffstat (limited to 'Source/Core/Common/Image.cpp')
| -rw-r--r-- | Source/Core/Common/Image.cpp | 71 |
1 files changed, 48 insertions, 23 deletions
diff --git a/Source/Core/Common/Image.cpp b/Source/Core/Common/Image.cpp index 3833dedb6f..3b5c644c4d 100644 --- a/Source/Core/Common/Image.cpp +++ b/Source/Core/Common/Image.cpp @@ -10,6 +10,9 @@ #include "Common/CommonTypes.h" #include "Common/IOFile.h" +#include "Common/ImageC.h" +#include "Common/Logging/Log.h" +#include "Common/Timer.h" namespace Common { @@ -39,23 +42,28 @@ bool LoadPNG(const std::vector<u8>& input, std::vector<u8>* data_out, u32* width return true; } +static void WriteCallback(png_structp png_ptr, png_bytep data, size_t length) +{ + std::vector<u8>* buffer = static_cast<std::vector<u8>*>(png_get_io_ptr(png_ptr)); + buffer->insert(buffer->end(), data, data + length); +} + bool SavePNG(const std::string& path, const u8* input, ImageByteFormat format, u32 width, - u32 height, int stride) + u32 height, int stride, int level) { - png_image png = {}; - png.version = PNG_IMAGE_VERSION; - png.width = width; - png.height = height; + Common::Timer timer; + timer.Start(); size_t byte_per_pixel; + int png_format; switch (format) { case ImageByteFormat::RGB: - png.format = PNG_FORMAT_RGB; + png_format = PNG_FORMAT_RGB; byte_per_pixel = 3; break; case ImageByteFormat::RGBA: - png.format = PNG_FORMAT_RGBA; + png_format = PNG_FORMAT_RGBA; byte_per_pixel = 4; break; default: @@ -64,30 +72,47 @@ bool SavePNG(const std::string& path, const u8* input, ImageByteFormat format, u // libpng doesn't handle non-ASCII characters in path, so write in two steps: // first to memory, then to file - std::vector<u8> 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()) + std::vector<u8> buffer; + buffer.reserve(byte_per_pixel * width * height); + + std::vector<const u8*> rows; + rows.reserve(height); + for (u32 row = 0; row < height; row++) { - // 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); + rows.push_back(&input[row * stride]); } - if (!success || (png.warning_or_error & PNG_IMAGE_ERROR) != 0) - return false; - File::IOFile outfile(path, "wb"); - if (!outfile) - return false; - return outfile.WriteBytes(buffer.data(), size); + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); + png_infop info_ptr = png_create_info_struct(png_ptr); + + bool success = false; + if (png_ptr != nullptr && info_ptr != nullptr) + { + success = SavePNG0(png_ptr, info_ptr, png_format, width, height, level, &buffer, WriteCallback, + const_cast<u8**>(rows.data())); + } + png_destroy_write_struct(&png_ptr, &info_ptr); + + if (success) + { + File::IOFile outfile(path, "wb"); + if (!outfile) + return false; + success = outfile.WriteBytes(buffer.data(), buffer.size()); + + timer.Stop(); + INFO_LOG_FMT(FRAMEDUMP, "{} byte {} by {} image saved to {} at level {} in {}", buffer.size(), + width, height, path, level, timer.GetTimeElapsedFormatted()); + } + + return success; } bool ConvertRGBAToRGBAndSavePNG(const std::string& path, const u8* input, u32 width, u32 height, - int stride) + int stride, int level) { const std::vector<u8> data = RGBAToRGB(input, width, height, stride); - return SavePNG(path, data.data(), ImageByteFormat::RGB, width, height); + return SavePNG(path, data.data(), ImageByteFormat::RGB, width, height, width * 3, level); } std::vector<u8> RGBAToRGB(const u8* input, u32 width, u32 height, int row_stride) |
