Add basic svg image support

This commit is contained in:
Magnus Norddahl 2023-12-29 05:21:41 +01:00 committed by Christoph Oelckers
parent 19c2ea171d
commit 2d6203a0fe
6 changed files with 4630 additions and 10 deletions

View File

@ -13,6 +13,9 @@ set(ZWIDGET_SOURCES
src/core/schrift/schrift.h
src/core/picopng/picopng.cpp
src/core/picopng/picopng.h
src/core/nanosvg/nanosvg.cpp
src/core/nanosvg/nanosvg.h
src/core/nanosvg/nanosvgrast.h
src/widgets/lineedit/lineedit.cpp
src/widgets/mainwindow/mainwindow.cpp
src/widgets/menubar/menubar.cpp
@ -68,6 +71,7 @@ source_group("src" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/.+")
source_group("src\\core" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/core/.+")
source_group("src\\core\\schrift" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/core/schrift/.+")
source_group("src\\core\\picopng" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/core/picopng/.+")
source_group("src\\core\\nanosvg" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/core/nanosvg/.+")
source_group("src\\widgets" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/.+")
source_group("src\\widgets\\lineedit" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/lineedit/.+")
source_group("src\\widgets\\mainwindow" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/mainwindow/.+")

View File

@ -20,5 +20,5 @@ public:
virtual void* GetData() const = 0;
static std::shared_ptr<Image> Create(int width, int height, ImageFormat format, const void* data);
static std::shared_ptr<Image> LoadResource(const std::string& resourcename);
static std::shared_ptr<Image> LoadResource(const std::string& resourcename, double dpiscale = 1.0);
};

View File

@ -2,6 +2,8 @@
#include "core/image.h"
#include "core/resourcedata.h"
#include "picopng/picopng.h"
#include "nanosvg/nanosvg.h"
#include "nanosvg/nanosvgrast.h"
#include <cstring>
#include <stdexcept>
@ -11,7 +13,8 @@ public:
ImageImpl(int width, int height, ImageFormat format, const void* data) : Width(width), Height(height), Format(format)
{
Data = std::make_unique<uint32_t[]>(width * height);
memcpy(Data.get(), data, width * height * sizeof(uint32_t));
if (data)
memcpy(Data.get(), data, width * height * sizeof(uint32_t));
}
int GetWidth() const override
@ -45,13 +48,63 @@ std::shared_ptr<Image> Image::Create(int width, int height, ImageFormat format,
return std::make_shared<ImageImpl>(width, height, format, data);
}
std::shared_ptr<Image> Image::LoadResource(const std::string& resourcename)
std::shared_ptr<Image> Image::LoadResource(const std::string& resourcename, double dpiscale)
{
auto filedata = LoadWidgetImageData(resourcename);
std::vector<unsigned char> pixels;
unsigned long width = 0, height = 0;
int result = decodePNG(pixels, width, height, (const unsigned char*)filedata.data(), filedata.size(), true);
if (result != 0)
throw std::runtime_error("Could not decode PNG file");
return Image::Create(width, height, ImageFormat::R8G8B8A8, pixels.data());
size_t extensionpos = resourcename.find_last_of("./\\");
if (extensionpos == std::string::npos || resourcename[extensionpos] != '.')
throw std::runtime_error("Unsupported image format");
std::string extension = resourcename.substr(extensionpos + 1);
for (char& c : extension)
{
if (c >= 'A' && c <= 'Z')
c = c - 'A' + 'a';
}
if (extension == "png")
{
auto filedata = LoadWidgetImageData(resourcename);
std::vector<unsigned char> pixels;
unsigned long width = 0, height = 0;
int result = decodePNG(pixels, width, height, (const unsigned char*)filedata.data(), filedata.size(), true);
if (result != 0)
throw std::runtime_error("Could not decode PNG file");
return Image::Create(width, height, ImageFormat::R8G8B8A8, pixels.data());
}
else if (extension == "svg")
{
auto filedata = LoadWidgetImageData(resourcename);
filedata.push_back(0);
NSVGimage* svgimage = nsvgParse((char*)filedata.data(), "px", (float)(96.0 * dpiscale));
if (!svgimage)
throw std::runtime_error("Could not parse SVG file");
try
{
int width = (int)(svgimage->width * dpiscale);
int height = (int)(svgimage->height * dpiscale);
std::shared_ptr<Image> image = Image::Create(width, height, ImageFormat::R8G8B8A8, nullptr);
NSVGrasterizer* rast = nsvgCreateRasterizer();
if (!rast)
throw std::runtime_error("Could not create SVG rasterizer");
nsvgRasterize(rast, svgimage, 0.0f, 0.0f, (float)dpiscale, (unsigned char*)image->GetData(), width, height, width * 4);
nsvgDeleteRasterizer(rast);
nsvgDelete(svgimage);
return image;
}
catch (...)
{
nsvgDelete(svgimage);
throw;
}
}
else
{
throw std::runtime_error("Unsupported image format");
}
}

View File

@ -0,0 +1,6 @@
#define NANOSVG_IMPLEMENTATION
#include "nanosvg.h"
#define NANOSVGRAST_IMPLEMENTATION
#include "nanosvgrast.h"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff