Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions examples/cli/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ bool save_results(const SDCliParams& cli_params,
std::string ext_lower = ext.string();
std::transform(ext_lower.begin(), ext_lower.end(), ext_lower.begin(), ::tolower);
bool is_jpg = (ext_lower == ".jpg" || ext_lower == ".jpeg" || ext_lower == ".jpe");
bool is_qoi = (ext_lower == ".qoi");

int output_begin_idx = cli_params.output_begin_idx;
if (output_begin_idx < 0) {
Expand All @@ -415,14 +416,16 @@ bool save_results(const SDCliParams& cli_params,
int ok = 0;
if (is_jpg) {
ok = stbi_write_jpg(path.string().c_str(), img.width, img.height, img.channel, img.data, 90, params.c_str());
} else if (is_qoi) {
ok = save_image_as_qoi(path.string().c_str(), img.width, img.height, img.channel, img.data) ? 1 : 0;
} else {
ok = stbi_write_png(path.string().c_str(), img.width, img.height, img.channel, img.data, 0, params.c_str());
}
LOG_INFO("save result image %d to '%s' (%s)", idx, path.string().c_str(), ok ? "success" : "failure");
};

if (std::regex_search(cli_params.output_path, format_specifier_regex)) {
if (!is_jpg && ext_lower != ".png")
if (!is_qoi && !is_jpg && ext_lower != ".png")
ext = ".png";
fs::path pattern = base_path;
pattern += ext;
Expand All @@ -444,7 +447,7 @@ bool save_results(const SDCliParams& cli_params,
return true;
}

if (!is_jpg && ext_lower != ".png")
if (!is_qoi && !is_jpg && ext_lower != ".png")
ext = ".png";

for (int i = 0; i < num_results; ++i) {
Expand Down
69 changes: 65 additions & 4 deletions examples/common/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ namespace fs = std::filesystem;
#define STB_IMAGE_RESIZE_STATIC
#include "stb_image_resize.h"

#define QOI_IMPLEMENTATION
#include "qoi.h"

#define SAFE_STR(s) ((s) ? (s) : "")
#define BOOL_STR(b) ((b) ? "true" : "false")

Expand Down Expand Up @@ -1982,13 +1985,47 @@ uint8_t* load_image_common(bool from_memory,
int c = 0;
const char* image_path;
uint8_t* image_buffer = nullptr;

bool is_qoi = false;
if (from_memory) {
image_path = "memory";
image_buffer = (uint8_t*)stbi_load_from_memory((const stbi_uc*)image_path_or_bytes, len, &width, &height, &c, expected_channel);
// magic bytes
is_qoi = len >= 4 &&
reinterpret_cast<const unsigned char*>(image_path_or_bytes)[0] == 'q' &&
reinterpret_cast<const unsigned char*>(image_path_or_bytes)[1] == 'o' &&
reinterpret_cast<const unsigned char*>(image_path_or_bytes)[2] == 'i' &&
reinterpret_cast<const unsigned char*>(image_path_or_bytes)[3] == 'f';
} else if (image_path_or_bytes) {
const char* ext = strrchr(image_path_or_bytes, '.');
is_qoi = ext && (_stricmp(ext, ".qoi") == 0);
}

if (is_qoi) {
// Use QOI.h
qoi_desc desc;
if (from_memory) {
image_buffer = (uint8_t*)qoi_decode(image_path_or_bytes, len, &desc, expected_channel);
} else {
image_buffer = (uint8_t*)qoi_read(image_path_or_bytes, &desc, expected_channel);
}
if (image_buffer) {
width = desc.width;
height = desc.height;
c = desc.channels;
}
image_path = from_memory ? "memory" : image_path_or_bytes;
} else {
image_path = image_path_or_bytes;
image_buffer = (uint8_t*)stbi_load(image_path_or_bytes, &width, &height, &c, expected_channel);
// Use stb_image
if (from_memory) {
image_path = "memory";
image_buffer = (uint8_t*)stbi_load_from_memory(
(const stbi_uc*)image_path_or_bytes, len, &width, &height, &c, expected_channel);
} else {
image_path = image_path_or_bytes;
image_buffer = (uint8_t*)stbi_load(
image_path_or_bytes, &width, &height, &c, expected_channel);
}
}

if (image_buffer == nullptr) {
LOG_ERROR("load image from '%s' failed", image_path);
return nullptr;
Expand Down Expand Up @@ -2092,3 +2129,27 @@ uint8_t* load_image_from_memory(const char* image_bytes,
int expected_channel = 3) {
return load_image_common(true, image_bytes, len, width, height, expected_width, expected_height, expected_channel);
}

uint8_t* load_qoi_from_memory(const char* qoi_data,
int len,
int& width,
int& height,
int expected_channel = 3) {
qoi_desc desc;
uint8_t* image_buffer = (uint8_t*)qoi_decode(qoi_data, len, &desc, expected_channel);
if (image_buffer) {
width = desc.width;
height = desc.height;
}
return image_buffer;
}

bool save_image_as_qoi(const char* filename, int width, int height, int channels, const void* data) {
qoi_desc desc;
desc.width = width;
desc.height = height;
desc.channels = channels;
desc.colorspace = QOI_SRGB;

return qoi_write(filename, data, &desc) > 0;
}
37 changes: 30 additions & 7 deletions examples/server/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,8 @@ std::string extract_and_remove_sd_cpp_extra_args(std::string& text) {
}

enum class ImageFormat { JPEG,
PNG };
PNG,
QOI };

std::vector<uint8_t> write_image_to_vector(
ImageFormat format,
Expand Down Expand Up @@ -247,6 +248,22 @@ std::vector<uint8_t> write_image_to_vector(
case ImageFormat::PNG:
result = stbi_write_png_to_func(c_func, &ctx, width, height, channels, image, width * channels);
break;
case ImageFormat::QOI: {
qoi_desc desc;
desc.width = width;
desc.height = height;
desc.channels = channels;
desc.colorspace = QOI_SRGB;

int out_len = 0;
void* qoi_data = qoi_encode(image, &desc, &out_len);
if (qoi_data) {
c_func(&ctx, qoi_data, out_len);
free(qoi_data);
result = 1;
}
break;
}
default:
throw std::runtime_error("invalid image format");
}
Expand Down Expand Up @@ -372,9 +389,9 @@ int main(int argc, const char** argv) {

std::string sd_cpp_extra_args_str = extract_and_remove_sd_cpp_extra_args(prompt);

if (output_format != "png" && output_format != "jpeg") {
if (output_format != "png" && output_format != "jpeg" && output_format != "qoi") {
res.status = 400;
res.set_content(R"({"error":"invalid output_format, must be one of [png, jpeg]"})", "application/json");
res.set_content(R"({"error":"invalid output_format, must be one of [png, jpeg, qoi]"})", "application/json");
return;
}
if (n <= 0)
Expand Down Expand Up @@ -464,7 +481,10 @@ int main(int argc, const char** argv) {
if (results[i].data == nullptr) {
continue;
}
auto image_bytes = write_image_to_vector(output_format == "jpeg" ? ImageFormat::JPEG : ImageFormat::PNG,
auto image_bytes = write_image_to_vector(
output_format == "jpeg" ? ImageFormat::JPEG :
output_format == "qoi" ? ImageFormat::QOI :
ImageFormat::PNG,
results[i].data,
results[i].width,
results[i].height,
Expand Down Expand Up @@ -555,9 +575,9 @@ int main(int argc, const char** argv) {
std::string output_format = "png";
if (req.form.has_field("output_format"))
output_format = req.form.get_field("output_format");
if (output_format != "png" && output_format != "jpeg") {
if (output_format != "png" && output_format != "jpeg" && output_format != "qoi") {
res.status = 400;
res.set_content(R"({"error":"invalid output_format, must be one of [png, jpeg]"})", "application/json");
res.set_content(R"({"error":"invalid output_format, must be one of [png, jpeg, qoi]"})", "application/json");
return;
}

Expand Down Expand Up @@ -684,7 +704,10 @@ int main(int argc, const char** argv) {
for (int i = 0; i < num_results; i++) {
if (results[i].data == nullptr)
continue;
auto image_bytes = write_image_to_vector(output_format == "jpeg" ? ImageFormat::JPEG : ImageFormat::PNG,
auto image_bytes = write_image_to_vector(
output_format == "jpeg" ? ImageFormat::JPEG :
output_format == "qoi" ? ImageFormat::QOI :
ImageFormat::PNG,
results[i].data,
results[i].width,
results[i].height,
Expand Down
4 changes: 3 additions & 1 deletion thirdparty/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@
- httplib.h from: https://github.com/yhirose/cpp-httplib/blob/master/httplib.h
- LICENSE: https://github.com/yhirose/cpp-httplib/blob/master/LICENSE
- stb_image.h/stb_image_resize.h/stb_image_write.h from: https://github.com/nothings/stb
- LICENSE: https://github.com/nothings/stb/blob/master/LICENSE
- LICENSE: https://github.com/nothings/stb/blob/master/LICENSE
- qoi.h library from: https://github.com/phoboslab/qoi
- https://github.com/phoboslab/qoi/blob/master/LICENSE
Loading