Image: Support loading webp files

This commit is contained in:
Stenzek 2023-10-02 16:58:46 +10:00 committed by Connor McLaughlin
parent 2b0593e5ff
commit 10b217e0c2
5 changed files with 107 additions and 3 deletions

View File

@ -61,6 +61,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zydis", "3rdparty\zydis\zyd
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demangler", "3rdparty\demangler\demangler.vcxproj", "{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libwebp", "3rdparty\libwebp\libwebp.vcxproj", "{522DAF2A-1F24-4742-B2C4-A956411F6AB2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug AVX2|x64 = Debug AVX2|x64
@ -737,6 +739,30 @@ Global
{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F}.Release Clang|x64.Build.0 = Release Clang|x64
{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F}.Release|x64.ActiveCfg = Release|x64
{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F}.Release|x64.Build.0 = Release|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Debug AVX2|x64.ActiveCfg = Debug|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Debug AVX2|x64.Build.0 = Debug|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Debug Clang AVX2|x64.ActiveCfg = Debug Clang|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Debug Clang AVX2|x64.Build.0 = Debug Clang|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Debug Clang|x64.ActiveCfg = Debug Clang|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Debug Clang|x64.Build.0 = Debug Clang|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Debug|x64.ActiveCfg = Debug|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Debug|x64.Build.0 = Debug|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Devel AVX2|x64.ActiveCfg = Devel|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Devel AVX2|x64.Build.0 = Devel|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Devel Clang AVX2|x64.ActiveCfg = Debug Clang|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Devel Clang AVX2|x64.Build.0 = Debug Clang|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Devel Clang|x64.ActiveCfg = Devel Clang|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Devel Clang|x64.Build.0 = Devel Clang|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Devel|x64.ActiveCfg = Devel|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Devel|x64.Build.0 = Devel|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Release AVX2|x64.ActiveCfg = Release|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Release AVX2|x64.Build.0 = Release|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Release Clang AVX2|x64.ActiveCfg = Release Clang|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Release Clang AVX2|x64.Build.0 = Release Clang|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Release Clang|x64.ActiveCfg = Release Clang|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Release Clang|x64.Build.0 = Release Clang|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Release|x64.ActiveCfg = Release|x64
{522DAF2A-1F24-4742-B2C4-A956411F6AB2}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -765,6 +791,7 @@ Global
{E960DFDF-1BD3-4C29-B251-D1A0919C9B09} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{67D0160C-0FE4-44B9-AC2E-82BBCF4104DF} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{522DAF2A-1F24-4742-B2C4-A956411F6AB2} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0BC474EA-3628-45D3-9DBC-E22D0B7E0F77}

View File

@ -130,6 +130,7 @@ add_library(fast_float INTERFACE)
target_include_directories(fast_float INTERFACE 3rdparty/rapidyaml/rapidyaml/ext/c4core/src/c4/ext/fast_float/include)
add_subdirectory(3rdparty/jpgd EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/libwebp EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/simpleini EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/imgui EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/cpuinfo EXCLUDE_FROM_ALL)

View File

@ -190,6 +190,7 @@ target_link_libraries(common PRIVATE
${LIBC_LIBRARIES}
PNG::PNG
jpgd
WebP::libwebp
)
target_link_libraries(common PUBLIC

View File

@ -24,6 +24,8 @@
#include "jpgd.h"
#include "jpge.h"
#include <png.h>
#include <webp/decode.h>
//#include <webp/encode.h>
using namespace Common;
@ -37,6 +39,11 @@ static bool JPEGBufferSaver(const RGBA8Image& image, std::vector<u8>* buffer, in
static bool JPEGFileLoader(RGBA8Image* image, const char* filename, std::FILE* fp);
static bool JPEGFileSaver(const RGBA8Image& image, const char* filename, std::FILE* fp, int quality);
static bool WebPBufferLoader(RGBA8Image* image, const void* buffer, size_t buffer_size);
static bool WebPBufferSaver(const RGBA8Image& image, std::vector<u8>* buffer, int quality);
static bool WebPFileLoader(RGBA8Image* image, const char* filename, std::FILE* fp);
static bool WebPFileSaver(const RGBA8Image& image, const char* filename, std::FILE* fp, int quality);
struct FormatHandler
{
const char* extension;
@ -50,6 +57,7 @@ static constexpr FormatHandler s_format_handlers[] = {
{"png", PNGBufferLoader, PNGBufferSaver, PNGFileLoader, PNGFileSaver},
{"jpg", JPEGBufferLoader, JPEGBufferSaver, JPEGFileLoader, JPEGFileSaver},
{"jpeg", JPEGBufferLoader, JPEGBufferSaver, JPEGFileLoader, JPEGFileSaver},
{"webp", WebPBufferLoader, WebPBufferSaver, WebPFileLoader, WebPFileSaver},
};
static const FormatHandler* GetFormatHandler(const std::string_view& extension)
@ -155,7 +163,7 @@ bool RGBA8Image::SaveToFile(const char* filename, std::FILE* fp, int quality) co
return false;
}
if (!handler->file_saver(*this, filename, fp, quality))
if (!IsValid() || !handler->file_saver(*this, filename, fp, quality))
return false;
return (std::fflush(fp) == 0);
@ -175,7 +183,7 @@ std::optional<std::vector<u8>> RGBA8Image::SaveToBuffer(const char* filename, in
}
ret = std::vector<u8>();
if (!handler->buffer_saver(*this, &ret.value(), quality))
if (!IsValid() || !handler->buffer_saver(*this, &ret.value(), quality))
ret.reset();
return ret;
@ -543,3 +551,63 @@ bool JPEGFileSaver(const RGBA8Image& image, const char* filename, std::FILE* fp,
FileStream stream(fp);
return JPEGCommonSaver(image, stream, quality);
}
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)
{
Console.Error("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)))
{
Console.Error("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, int quality)
{
#if 0
u8* encoded_data;
const size_t encoded_size = WebPEncodeRGBA(reinterpret_cast<const u8*>(image.GetPixels()),
image.GetWidth(), image.GetHeight(), image.GetByteStride(), 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;
#else
Console.Error("Not compiled with WebP encoder.");
return false;
#endif
}
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, int quality)
{
std::vector<u8> buffer;
if (!WebPBufferSaver(image, &buffer, quality))
return false;
return (std::fwrite(buffer.data(), buffer.size(), 1, fp) == 1);
}

View File

@ -34,9 +34,10 @@
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\rapidyaml\rapidyaml\ext\c4core\src\c4\ext\fast_float\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\fmt\fmt\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\libpng</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\jpgd</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\fmt\fmt\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\libwebp\libwebp\src</AdditionalIncludeDirectories>
<PrecompiledHeader>Use</PrecompiledHeader>
<ForcedIncludeFiles>PrecompiledHeader.h</ForcedIncludeFiles>
<PrecompiledHeaderFile>PrecompiledHeader.h</PrecompiledHeaderFile>
@ -178,6 +179,12 @@
<ProjectReference Include="..\3rdparty\jpgd\jpgd.vcxproj">
<Project>{ed2f21fd-0a36-4a8f-9b90-e7d92a2acb63}</Project>
</ProjectReference>
<ProjectReference Include="..\3rdparty\libpng\projects\vstudio\libpng\libpng.vcxproj">
<Project>{d6973076-9317-4ef2-a0b8-b7a18ac0713e}</Project>
</ProjectReference>
<ProjectReference Include="..\3rdparty\libwebp\libwebp.vcxproj">
<Project>{522daf2a-1f24-4742-b2c4-a956411f6ab2}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">