mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-22 22:05:38 +00:00
Image: Support loading/saving WebP
This commit is contained in:
parent
cd3c88ad7e
commit
f3c0c14b2a
|
@ -13,6 +13,8 @@
|
||||||
|
|
||||||
#include <jpeglib.h>
|
#include <jpeglib.h>
|
||||||
#include <png.h>
|
#include <png.h>
|
||||||
|
#include <webp/decode.h>
|
||||||
|
#include <webp/encode.h>
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
@ -33,6 +35,11 @@ static bool JPEGBufferSaver(const RGBA8Image& image, std::vector<u8>* buffer, u8
|
||||||
static bool JPEGFileLoader(RGBA8Image* image, const char* filename, std::FILE* fp);
|
static bool JPEGFileLoader(RGBA8Image* image, const char* filename, std::FILE* fp);
|
||||||
static bool JPEGFileSaver(const RGBA8Image& image, const char* filename, std::FILE* fp, u8 quality);
|
static bool JPEGFileSaver(const RGBA8Image& image, const char* filename, std::FILE* fp, u8 quality);
|
||||||
|
|
||||||
|
static bool WebPBufferLoader(RGBA8Image* image, const void* buffer, size_t buffer_size);
|
||||||
|
static bool WebPBufferSaver(const RGBA8Image& image, std::vector<u8>* buffer, u8 quality);
|
||||||
|
static bool WebPFileLoader(RGBA8Image* image, const char* filename, std::FILE* fp);
|
||||||
|
static bool WebPFileSaver(const RGBA8Image& image, const char* filename, std::FILE* fp, u8 quality);
|
||||||
|
|
||||||
struct FormatHandler
|
struct FormatHandler
|
||||||
{
|
{
|
||||||
const char* extension;
|
const char* extension;
|
||||||
|
@ -46,6 +53,7 @@ static constexpr FormatHandler s_format_handlers[] = {
|
||||||
{"png", PNGBufferLoader, PNGBufferSaver, PNGFileLoader, PNGFileSaver},
|
{"png", PNGBufferLoader, PNGBufferSaver, PNGFileLoader, PNGFileSaver},
|
||||||
{"jpg", JPEGBufferLoader, JPEGBufferSaver, JPEGFileLoader, JPEGFileSaver},
|
{"jpg", JPEGBufferLoader, JPEGBufferSaver, JPEGFileLoader, JPEGFileSaver},
|
||||||
{"jpeg", JPEGBufferLoader, JPEGBufferSaver, JPEGFileLoader, JPEGFileSaver},
|
{"jpeg", JPEGBufferLoader, JPEGBufferSaver, JPEGFileLoader, JPEGFileSaver},
|
||||||
|
{"webp", WebPBufferLoader, WebPBufferSaver, WebPFileLoader, WebPFileSaver},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const FormatHandler* GetFormatHandler(const std::string_view& extension)
|
static const FormatHandler* GetFormatHandler(const std::string_view& extension)
|
||||||
|
@ -607,3 +615,58 @@ bool JPEGFileSaver(const RGBA8Image& image, const char* filename, std::FILE* fp,
|
||||||
{
|
{
|
||||||
return WrapJPEGCompress(image, quality, [fp](jpeg_compress_struct& info) { jpeg_stdio_dest(&info, fp); });
|
return WrapJPEGCompress(image, quality, [fp](jpeg_compress_struct& info) { jpeg_stdio_dest(&info, fp); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WebPBufferLoader(RGBA8Image* image, const void* buffer, size_t buffer_size)
|
||||||
|
{
|
||||||
|
int width, height;
|
||||||
|
if (!WebPGetInfo(static_cast<const u8*>(buffer), buffer_size, &width, &height) || width <= 0 || height <= 0)
|
||||||
|
{
|
||||||
|
Log_ErrorPrint("WebPGetInfo() failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<u32> pixels;
|
||||||
|
pixels.resize(static_cast<u32>(width) * static_cast<u32>(height));
|
||||||
|
if (!WebPDecodeRGBAInto(static_cast<const u8*>(buffer), buffer_size, reinterpret_cast<u8*>(pixels.data()),
|
||||||
|
sizeof(u32) * pixels.size(), sizeof(u32) * static_cast<u32>(width)))
|
||||||
|
{
|
||||||
|
Log_ErrorPrint("WebPDecodeRGBAInto() failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
image->SetPixels(static_cast<u32>(width), static_cast<u32>(height), std::move(pixels));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebPBufferSaver(const RGBA8Image& image, std::vector<u8>* buffer, u8 quality)
|
||||||
|
{
|
||||||
|
u8* encoded_data;
|
||||||
|
const size_t encoded_size =
|
||||||
|
WebPEncodeRGBA(reinterpret_cast<const u8*>(image.GetPixels()), image.GetWidth(), image.GetHeight(),
|
||||||
|
image.GetPitch(), static_cast<float>(quality), &encoded_data);
|
||||||
|
if (encoded_size == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
buffer->resize(encoded_size);
|
||||||
|
std::memcpy(buffer->data(), encoded_data, encoded_size);
|
||||||
|
WebPFree(encoded_data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebPFileLoader(RGBA8Image* image, const char* filename, std::FILE* fp)
|
||||||
|
{
|
||||||
|
std::optional<std::vector<u8>> data = FileSystem::ReadBinaryFile(fp);
|
||||||
|
if (!data.has_value())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return WebPBufferLoader(image, data->data(), data->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebPFileSaver(const RGBA8Image& image, const char* filename, std::FILE* fp, u8 quality)
|
||||||
|
{
|
||||||
|
std::vector<u8> buffer;
|
||||||
|
if (!WebPBufferSaver(image, &buffer, quality))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return (std::fwrite(buffer.data(), buffer.size(), 1, fp) == 1);
|
||||||
|
}
|
Loading…
Reference in a new issue