forked from Green-Sky/tomato
92 lines
2.1 KiB
C++
92 lines
2.1 KiB
C++
|
#include "./image_loader_qoi.hpp"
|
||
|
|
||
|
#include <cstdint>
|
||
|
#include <qoi/qoi.h>
|
||
|
|
||
|
#include <iostream>
|
||
|
|
||
|
ImageLoaderQOI::ImageInfo ImageLoaderQOI::loadInfoFromMemory(const uint8_t* data, uint64_t data_size) {
|
||
|
ImageInfo res;
|
||
|
|
||
|
qoi_desc desc;
|
||
|
// TODO: only read the header
|
||
|
auto* ret = qoi_decode(data, data_size, &desc, 4);
|
||
|
if (ret == nullptr) {
|
||
|
return res;
|
||
|
}
|
||
|
free(ret);
|
||
|
|
||
|
res.width = desc.width;
|
||
|
res.height = desc.height;
|
||
|
//desc.colorspace;
|
||
|
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
ImageLoaderQOI::ImageResult ImageLoaderQOI::loadFromMemoryRGBA(const uint8_t* data, uint64_t data_size) {
|
||
|
ImageResult res;
|
||
|
|
||
|
qoi_desc desc;
|
||
|
|
||
|
uint8_t* img_data = static_cast<uint8_t*>(
|
||
|
qoi_decode(data, data_size, &desc, 4)
|
||
|
);
|
||
|
if (img_data == nullptr) {
|
||
|
// not readable
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
res.width = desc.width;
|
||
|
res.height = desc.height;
|
||
|
|
||
|
auto& new_frame = res.frames.emplace_back();
|
||
|
new_frame.ms = 0;
|
||
|
new_frame.data.insert(new_frame.data.cbegin(), img_data, img_data+(desc.width*desc.height*4));
|
||
|
|
||
|
free(img_data);
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
std::vector<uint8_t> ImageEncoderQOI::encodeToMemoryRGBA(const ImageResult& input_image, const std::map<std::string, float>&) {
|
||
|
if (input_image.frames.empty()) {
|
||
|
std::cerr << "IEQOI error: empty image\n";
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
if (input_image.frames.size() > 1) {
|
||
|
std::cerr << "IEQOI warning: image with animation, only first frame will be encoded!\n";
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
// TODO: look into RDO (eg https://github.com/richgel999/rdopng)
|
||
|
//int png_compression_level = 8;
|
||
|
//if (extra_options.count("png_compression_level")) {
|
||
|
//png_compression_level = extra_options.at("png_compression_level");
|
||
|
//}
|
||
|
|
||
|
qoi_desc desc;
|
||
|
desc.width = input_image.width;
|
||
|
desc.height = input_image.height;
|
||
|
desc.channels = 4;
|
||
|
desc.colorspace = QOI_SRGB; // TODO: decide
|
||
|
|
||
|
int out_len {0};
|
||
|
uint8_t* enc_data = static_cast<uint8_t*>(qoi_encode(
|
||
|
input_image.frames.front().data.data(),
|
||
|
&desc,
|
||
|
&out_len
|
||
|
));
|
||
|
|
||
|
if (enc_data == nullptr) {
|
||
|
std::cerr << "IEQOI error: qoi_encode failed!\n";
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
std::vector<uint8_t> new_data(enc_data, enc_data+out_len);
|
||
|
|
||
|
free(enc_data); // TODO: a streaming encoder would be better
|
||
|
|
||
|
return new_data;
|
||
|
}
|
||
|
|