mirror of
https://github.com/leejet/stable-diffusion.cpp.git
synced 2026-11-10 19:06:33 +00:00
fix: add alpha channel input for Qwen Image 2.1 and relative docs (#2021)
This commit is contained in:
1 parent
e01206574b
commit
e112ab5a50
12 files changed
+125
-50
No files matched your search
+14
-12
@@ -1848,20 +1848,22 @@ bool decode_base64_image(const std::string& encoded_input,
|
||||
return false;
|
||||
}
|
||||
|
||||
int decoded_width = 0;
|
||||
int decoded_height = 0;
|
||||
uint8_t* raw_data = load_image_from_memory(reinterpret_cast<const char*>(image_bytes.data()),
|
||||
static_cast<int>(image_bytes.size()),
|
||||
decoded_width,
|
||||
decoded_height,
|
||||
expected_width,
|
||||
expected_height,
|
||||
target_channels);
|
||||
int decoded_width = 0;
|
||||
int decoded_height = 0;
|
||||
int resolved_channel = target_channels;
|
||||
uint8_t* raw_data = load_image_from_memory(reinterpret_cast<const char*>(image_bytes.data()),
|
||||
static_cast<int>(image_bytes.size()),
|
||||
decoded_width,
|
||||
decoded_height,
|
||||
resolved_channel,
|
||||
expected_width,
|
||||
expected_height,
|
||||
target_channels);
|
||||
if (raw_data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
out_image.reset({(uint32_t)decoded_width, (uint32_t)decoded_height, (uint32_t)target_channels, raw_data});
|
||||
out_image.reset({(uint32_t)decoded_width, (uint32_t)decoded_height, (uint32_t)resolved_channel, raw_data});
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2215,7 +2217,7 @@ bool SDGenerationParams::from_json_str(
|
||||
LOG_ERROR("invalid lora");
|
||||
return false;
|
||||
}
|
||||
if (!parse_image_json_field(j, "init_image", 3, width, height, init_image)) {
|
||||
if (!parse_image_json_field(j, "init_image", 0, width, height, init_image)) {
|
||||
LOG_ERROR("invalid init_image");
|
||||
return false;
|
||||
}
|
||||
@@ -2225,7 +2227,7 @@ bool SDGenerationParams::from_json_str(
|
||||
}
|
||||
if (!parse_image_array_json_field(j,
|
||||
"ref_images",
|
||||
3,
|
||||
0,
|
||||
auto_resize_ref_image ? width : 0,
|
||||
auto_resize_ref_image ? height : 0,
|
||||
ref_images)) {
|
||||
|
||||
@@ -261,6 +261,10 @@ uint8_t* decode_webp_image_to_buffer(const uint8_t* data,
|
||||
height = features.height;
|
||||
source_channel_count = features.has_alpha ? 4 : 3;
|
||||
|
||||
if (expected_channel == 0) {
|
||||
expected_channel = source_channel_count;
|
||||
}
|
||||
|
||||
const size_t pixel_count = static_cast<size_t>(width) * static_cast<size_t>(height);
|
||||
|
||||
if (expected_channel == 1) {
|
||||
@@ -481,7 +485,8 @@ uint8_t* load_image_common(bool from_memory,
|
||||
int& height,
|
||||
int expected_width,
|
||||
int expected_height,
|
||||
int expected_channel) {
|
||||
int expected_channel,
|
||||
int& out_channel) {
|
||||
const char* image_path;
|
||||
FreeUniquePtr<uint8_t> image_buffer;
|
||||
int source_channel_count = 0;
|
||||
@@ -538,6 +543,32 @@ uint8_t* load_image_common(bool from_memory,
|
||||
LOG_ERROR("load image from '%s' failed", image_path);
|
||||
return nullptr;
|
||||
}
|
||||
if (expected_channel == 0) {
|
||||
expected_channel = source_channel_count == 2 ? 4 : (source_channel_count == 1 ? 3 : source_channel_count);
|
||||
if (expected_channel != source_channel_count) {
|
||||
FreeUniquePtr<uint8_t> promoted((uint8_t*)malloc((size_t)width * height * expected_channel));
|
||||
if (promoted == nullptr) {
|
||||
LOG_ERROR("error: allocate memory for channel promotion, image_path = %s", image_path);
|
||||
return nullptr;
|
||||
}
|
||||
const size_t pixel_count = (size_t)width * (size_t)height;
|
||||
for (size_t i = 0; i < pixel_count; ++i) {
|
||||
if (source_channel_count == 1) {
|
||||
promoted.get()[i * 3 + 0] = image_buffer.get()[i];
|
||||
promoted.get()[i * 3 + 1] = image_buffer.get()[i];
|
||||
promoted.get()[i * 3 + 2] = image_buffer.get()[i];
|
||||
} else {
|
||||
promoted.get()[i * 4 + 0] = image_buffer.get()[i * 2];
|
||||
promoted.get()[i * 4 + 1] = image_buffer.get()[i * 2];
|
||||
promoted.get()[i * 4 + 2] = image_buffer.get()[i * 2];
|
||||
promoted.get()[i * 4 + 3] = image_buffer.get()[i * 2 + 1];
|
||||
}
|
||||
}
|
||||
image_buffer = std::move(promoted);
|
||||
source_channel_count = expected_channel;
|
||||
}
|
||||
}
|
||||
// stb reports the source channel count even when it converts the output.
|
||||
if (source_channel_count < expected_channel) {
|
||||
fprintf(stderr,
|
||||
"the number of channels for the input image must be >= %d,"
|
||||
@@ -597,7 +628,7 @@ uint8_t* load_image_common(bool from_memory,
|
||||
}
|
||||
stbir_resize(image_buffer.get(), width, height, 0,
|
||||
resized_image_buffer.get(), expected_width, expected_height, 0, STBIR_TYPE_UINT8,
|
||||
expected_channel, STBIR_ALPHA_CHANNEL_NONE, 0,
|
||||
expected_channel, expected_channel == 4 ? 3 : STBIR_ALPHA_CHANNEL_NONE, 0,
|
||||
STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP,
|
||||
STBIR_FILTER_BOX, STBIR_FILTER_BOX,
|
||||
STBIR_COLORSPACE_SRGB, nullptr);
|
||||
@@ -605,6 +636,7 @@ uint8_t* load_image_common(bool from_memory,
|
||||
height = expected_height;
|
||||
image_buffer = std::move(resized_image_buffer);
|
||||
}
|
||||
out_channel = expected_channel;
|
||||
return image_buffer.release();
|
||||
}
|
||||
|
||||
@@ -777,10 +809,11 @@ bool write_image_to_file(const std::string& path,
|
||||
uint8_t* load_image_from_file(const char* image_path,
|
||||
int& width,
|
||||
int& height,
|
||||
int& out_channel,
|
||||
int expected_width,
|
||||
int expected_height,
|
||||
int expected_channel) {
|
||||
return load_image_common(false, image_path, 0, width, height, expected_width, expected_height, expected_channel);
|
||||
return load_image_common(false, image_path, 0, width, height, expected_width, expected_height, expected_channel, out_channel);
|
||||
}
|
||||
|
||||
bool load_sd_image_from_file(sd_image_t* image,
|
||||
@@ -790,13 +823,14 @@ bool load_sd_image_from_file(sd_image_t* image,
|
||||
int expected_channel) {
|
||||
int width;
|
||||
int height;
|
||||
image->data = load_image_common(false, image_path, 0, width, height, expected_width, expected_height, expected_channel);
|
||||
int resolved_channel = expected_channel;
|
||||
image->data = load_image_common(false, image_path, 0, width, height, expected_width, expected_height, expected_channel, resolved_channel);
|
||||
if (image->data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
image->width = width;
|
||||
image->height = height;
|
||||
image->channel = expected_channel;
|
||||
image->channel = resolved_channel;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -804,10 +838,11 @@ uint8_t* load_image_from_memory(const char* image_bytes,
|
||||
int len,
|
||||
int& width,
|
||||
int& height,
|
||||
int& out_channel,
|
||||
int expected_width,
|
||||
int expected_height,
|
||||
int expected_channel) {
|
||||
return load_image_common(true, image_bytes, len, width, height, expected_width, expected_height, expected_channel);
|
||||
return load_image_common(true, image_bytes, len, width, height, expected_width, expected_height, expected_channel, out_channel);
|
||||
}
|
||||
|
||||
static void append_avi_metadata(std::vector<uint8_t>& data, const std::string& parameters) {
|
||||
|
||||
@@ -32,9 +32,12 @@ bool write_image_to_file(const std::string& path,
|
||||
const std::string& parameters = "",
|
||||
int quality = 90);
|
||||
|
||||
// expected_channel == 0 preserves native channels (grayscale -> RGB, gray+alpha -> RGBA).
|
||||
// out_channel receives the output channel count.
|
||||
uint8_t* load_image_from_file(const char* image_path,
|
||||
int& width,
|
||||
int& height,
|
||||
int& out_channel,
|
||||
int expected_width = 0,
|
||||
int expected_height = 0,
|
||||
int expected_channel = 3);
|
||||
@@ -49,6 +52,7 @@ uint8_t* load_image_from_memory(const char* image_bytes,
|
||||
int len,
|
||||
int& width,
|
||||
int& height,
|
||||
int& out_channel,
|
||||
int expected_width = 0,
|
||||
int expected_height = 0,
|
||||
int expected_channel = 3);
|
||||
|
||||
Reference in new issue
Block a user