add stb png and jpg encoders, untested
This commit is contained in:
parent
f1f67fe1ba
commit
62b00a4bd6
2
external/solanaceae_tox
vendored
2
external/solanaceae_tox
vendored
@ -1 +1 @@
|
|||||||
Subproject commit f12e609c21e84b77f5252e6b00e5fdb933b168ab
|
Subproject commit 0e6556cd86c558c86dfde60d82891a46bf32b64f
|
@ -71,6 +71,7 @@ target_link_libraries(tomato PUBLIC
|
|||||||
imgui_backend_sdlrenderer3
|
imgui_backend_sdlrenderer3
|
||||||
|
|
||||||
stb_image
|
stb_image
|
||||||
|
stb_image_write
|
||||||
webpdemux
|
webpdemux
|
||||||
libwebpmux # the f why (needed for anim encode)
|
libwebpmux # the f why (needed for anim encode)
|
||||||
)
|
)
|
||||||
|
@ -33,7 +33,6 @@ struct ImageEncoderI {
|
|||||||
|
|
||||||
using ImageResult = ImageLoaderI::ImageResult;
|
using ImageResult = ImageLoaderI::ImageResult;
|
||||||
|
|
||||||
virtual std::vector<uint8_t> encodeToMemoryRGBA(const ImageResult& input_image) = 0;
|
virtual std::vector<uint8_t> encodeToMemoryRGBA(const ImageResult& input_image, const std::map<std::string, float>& extra_options = {}) = 0;
|
||||||
virtual std::vector<uint8_t> encodeToMemoryRGBAExt(const ImageResult& input_image, const std::map<std::string, float>& extra_options) = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
#include "./image_loader_stb.hpp"
|
#include "./image_loader_stb.hpp"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <stb/stb_image.h>
|
#include <stb/stb_image.h>
|
||||||
|
#include <stb/stb_image_write.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
ImageLoaderSTB::ImageInfo ImageLoaderSTB::loadInfoFromMemory(const uint8_t* data, uint64_t data_size) {
|
ImageLoaderSTB::ImageInfo ImageLoaderSTB::loadInfoFromMemory(const uint8_t* data, uint64_t data_size) {
|
||||||
ImageInfo res;
|
ImageInfo res;
|
||||||
@ -64,3 +68,68 @@ ImageLoaderSTB::ImageResult ImageLoaderSTB::loadFromMemoryRGBA(const uint8_t* da
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> ImageEncoderSTBPNG::encodeToMemoryRGBA(const ImageResult& input_image, const std::map<std::string, float>& extra_options) {
|
||||||
|
if (input_image.frames.empty()) {
|
||||||
|
std::cerr << "IESTBPNG error: empty image\n";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input_image.frames.size() > 1) {
|
||||||
|
std::cerr << "IESTBPNG warning: image with animation, only first frame will be encoded!\n";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
int png_compression_level = 8;
|
||||||
|
if (extra_options.count("png_compression_level")) {
|
||||||
|
png_compression_level = extra_options.at("png_compression_level");
|
||||||
|
}
|
||||||
|
// TODO:
|
||||||
|
//int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode
|
||||||
|
|
||||||
|
struct Context {
|
||||||
|
std::vector<uint8_t> new_data;
|
||||||
|
} context;
|
||||||
|
auto write_f = +[](void* context, void* data, int size) -> void {
|
||||||
|
Context* ctx = reinterpret_cast<Context*>(context);
|
||||||
|
uint8_t* d = reinterpret_cast<uint8_t*>(data);
|
||||||
|
ctx->new_data.insert(ctx->new_data.cend(), d, d + size);
|
||||||
|
};
|
||||||
|
|
||||||
|
stbi_write_png_compression_level = png_compression_level;
|
||||||
|
|
||||||
|
if (!stbi_write_png_to_func(write_f, &context, input_image.width, input_image.height, 4, input_image.frames.front().data.data(), 4*input_image.width)) {
|
||||||
|
std::cerr << "IESTBPNG error: stbi_write_png failed!\n";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.new_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> ImageEncoderSTBJpeg::encodeToMemoryRGBA(const ImageResult& input_image, const std::map<std::string, float>&) {
|
||||||
|
if (input_image.frames.empty()) {
|
||||||
|
std::cerr << "IESTBJpeg error: empty image\n";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input_image.frames.size() > 1) {
|
||||||
|
std::cerr << "IESTBJpeg warning: image with animation, only first frame will be encoded!\n";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Context {
|
||||||
|
std::vector<uint8_t> new_data;
|
||||||
|
} context;
|
||||||
|
auto write_f = +[](void* context, void* data, int size) -> void {
|
||||||
|
Context* ctx = reinterpret_cast<Context*>(context);
|
||||||
|
uint8_t* d = reinterpret_cast<uint8_t*>(data);
|
||||||
|
ctx->new_data.insert(ctx->new_data.cend(), d, d + size);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!stbi_write_jpg_to_func(write_f, &context, input_image.width, input_image.height, 4, input_image.frames.front().data.data(), 4*input_image.width)) {
|
||||||
|
std::cerr << "IESTBJpeg error: stbi_write_jpg failed!\n";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.new_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -7,3 +7,11 @@ struct ImageLoaderSTB : public ImageLoaderI {
|
|||||||
ImageResult loadFromMemoryRGBA(const uint8_t* data, uint64_t data_size) override;
|
ImageResult loadFromMemoryRGBA(const uint8_t* data, uint64_t data_size) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ImageEncoderSTBPNG : public ImageEncoderI {
|
||||||
|
std::vector<uint8_t> encodeToMemoryRGBA(const ImageResult& input_image, const std::map<std::string, float>& extra_options = {}) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ImageEncoderSTBJpeg : public ImageEncoderI {
|
||||||
|
std::vector<uint8_t> encodeToMemoryRGBA(const ImageResult& input_image, const std::map<std::string, float>& extra_options = {}) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
@ -81,11 +81,7 @@ ImageLoaderWebP::ImageResult ImageLoaderWebP::loadFromMemoryRGBA(const uint8_t*
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> ImageEncoderWebP::encodeToMemoryRGBA(const ImageResult& input_image) {
|
std::vector<uint8_t> ImageEncoderWebP::encodeToMemoryRGBA(const ImageResult& input_image, const std::map<std::string, float>& extra_options) {
|
||||||
return encodeToMemoryRGBAExt(input_image, {{"quality", 80.f}});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint8_t> ImageEncoderWebP::encodeToMemoryRGBAExt(const ImageResult& input_image, const std::map<std::string, float>& extra_options) {
|
|
||||||
// setup options
|
// setup options
|
||||||
float quality = 80.f;
|
float quality = 80.f;
|
||||||
if (extra_options.count("quality")) {
|
if (extra_options.count("quality")) {
|
||||||
|
@ -8,7 +8,6 @@ struct ImageLoaderWebP : public ImageLoaderI {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ImageEncoderWebP : public ImageEncoderI {
|
struct ImageEncoderWebP : public ImageEncoderI {
|
||||||
std::vector<uint8_t> encodeToMemoryRGBA(const ImageResult& input_image) override;
|
std::vector<uint8_t> encodeToMemoryRGBA(const ImageResult& input_image, const std::map<std::string, float>& extra_options = {}) override;
|
||||||
std::vector<uint8_t> encodeToMemoryRGBAExt(const ImageResult& input_image, const std::map<std::string, float>& extra_options) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ bool SendImagePopup::load(void) {
|
|||||||
std::vector<uint8_t> SendImagePopup::compressWebp(const ImageLoaderI::ImageResult& input_image, uint32_t quality) {
|
std::vector<uint8_t> SendImagePopup::compressWebp(const ImageLoaderI::ImageResult& input_image, uint32_t quality) {
|
||||||
// HACK: generic list
|
// HACK: generic list
|
||||||
|
|
||||||
return ImageEncoderWebP{}.encodeToMemoryRGBAExt(input_image, {{"quality", quality}});
|
return ImageEncoderWebP{}.encodeToMemoryRGBA(input_image, {{"quality", quality}});
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageLoaderI::ImageResult SendImagePopup::crop(const ImageLoaderI::ImageResult& input_image, const Rect& crop_rect) {
|
ImageLoaderI::ImageResult SendImagePopup::crop(const ImageLoaderI::ImageResult& input_image, const Rect& crop_rect) {
|
||||||
|
Loading…
Reference in New Issue
Block a user