void image_apply_split_channel_common(const char *target_array_name, const char *target_hash_name, const char *source_name, const char *color_type_name, const char *channel_name, int produce_array, int produce_hash, ImageSplitInfo *out_info) {
    ArrayVariable *source_var = require_array_variable(source_name);
    ArrayVariable *target_var;
    int width = source_var->screen_width;
    int height = source_var->screen_height;
    int logical_count = array_logical_count(source_var);
    long long expected_count;
    long long sample_count;
    long long i;
    int channel_offset = 0;
    int channel_kind = 0;
    const char *canonical_color_type = "RGBA";
    const char *canonical_channel = "R";
    double max_value = source_var->image_value_max;
    double resolution;
    double *output = NULL;
    image_split_info_reset(out_info);
    max_value = draw_resolve_image_value_max(source_var);
    resolution = image_resolution_from_phys(source_var->image_phys_x, source_var->image_phys_unit);
    if (out_info != NULL) {
        out_info->width = width > 0 ? width : 0;
        out_info->height = height > 0 ? height : 0;
        out_info->color_type = canonical_color_type;
        out_info->image_value_max = max_value;
        out_info->pixel_mode = source_var->image_pixel_mode;
        out_info->resolution = resolution;
    }
    if (produce_hash && target_hash_name != NULL) image_clear_hash_output(target_hash_name);
    channel_kind = image_split_channel_kind(color_type_name, channel_name, &canonical_color_type, &canonical_channel, &channel_offset);
    if (out_info != NULL) out_info->color_type = canonical_color_type;
    if (channel_kind == 0) {
        if (produce_array && target_array_name != NULL) image_prepare_plain_numeric_array(target_array_name, 0);
        return;
    }
    if (width <= 0 || height <= 0) {
        if (produce_array && target_array_name != NULL) image_prepare_plain_numeric_array(target_array_name, 0);
        return;
    }
    expected_count = (long long)width * (long long)height * 4LL;
    sample_count = (long long)width * (long long)height;
    if ((long long)logical_count < expected_count) runtime_error("IMAGE failed: pixel buffer too small / 【IMAGE】画像配列のピクセル数が不足しています。");
    if (out_info != NULL) {
        out_info->valid = 1;
        out_info->color_type = canonical_color_type;
        out_info->channel = canonical_channel;
        out_info->sample_count = sample_count;
    }
    if (produce_array && target_array_name != NULL) {
        output = (double *)malloc((size_t)sample_count * sizeof(double));
        if (output == NULL) runtime_error("IMAGE failed: out of memory / 【IMAGE】メモリ不足です。");
        for (i = 0; i < sample_count; ++i) {
            long long base = i * 4LL;
            double r = b2026_var_as_number(&source_var->data[option_base + (int)(base + 0)]);
            double g = b2026_var_as_number(&source_var->data[option_base + (int)(base + 1)]);
            double b = b2026_var_as_number(&source_var->data[option_base + (int)(base + 2)]);
            if (channel_kind >= 1 && channel_kind <= 4) {
                output[i] = b2026_var_as_number(&source_var->data[option_base + (int)(base + (long long)channel_offset)]);
            } else {
                double nr = r / max_value;
                double ng = g / max_value;
                double nb = b / max_value;
                double h = 0.0, s = 0.0, third = 0.0;
                if (channel_kind >= 101 && channel_kind <= 103) {
                    image_rgb_to_hsv(nr, ng, nb, &h, &s, &third);
                    if (channel_kind == 101) output[i] = h;
                    else if (channel_kind == 102) output[i] = s * max_value;
                    else output[i] = third * max_value;
                } else if (channel_kind >= 201 && channel_kind <= 203) {
                    image_rgb_to_hsl(nr, ng, nb, &h, &s, &third);
                    if (channel_kind == 201) output[i] = h;
                    else if (channel_kind == 202) output[i] = s * max_value;
                    else output[i] = third * max_value;
                } else if (channel_kind >= 301 && channel_kind <= 303) {
                    image_rgb_to_ycbcr(nr, ng, nb, &h, &s, &third);
                    if (channel_kind == 301) output[i] = h * max_value;
                    else if (channel_kind == 302) output[i] = s * max_value;
                    else output[i] = third * max_value;
                } else if (channel_kind >= 311 && channel_kind <= 313) {
                    image_rgb_to_yuv(nr, ng, nb, &h, &s, &third);
                    if (channel_kind == 311) output[i] = h * max_value;
                    else if (channel_kind == 312) output[i] = s * max_value;
                    else output[i] = third * max_value;
                } else if (channel_kind >= 321 && channel_kind <= 323) {
                    image_rgb_to_yiq(nr, ng, nb, &h, &s, &third);
                    if (channel_kind == 321) output[i] = h * max_value;
                    else if (channel_kind == 322) output[i] = s * max_value;
                    else output[i] = third * max_value;
                } else if (channel_kind >= 401 && channel_kind <= 404) {
                    double fourth = 0.0;
                    image_rgb_to_cmyk(nr, ng, nb, &h, &s, &third, &fourth);
                    if (channel_kind == 401) output[i] = h * max_value;
                    else if (channel_kind == 402) output[i] = s * max_value;
                    else if (channel_kind == 403) output[i] = third * max_value;
                    else output[i] = fourth * max_value;
                } else if (channel_kind >= 601 && channel_kind <= 603) {
                    image_rgb_to_xyz(nr, ng, nb, &h, &s, &third);
                    if (channel_kind == 601) output[i] = h * max_value;
                    else if (channel_kind == 602) output[i] = s * max_value;
                    else output[i] = third * max_value;
                } else if (channel_kind >= 701 && channel_kind <= 703) {
                    image_rgb_to_lch(nr, ng, nb, &h, &s, &third);
                    if (channel_kind == 701) output[i] = h;
                    else if (channel_kind == 702) output[i] = s;
                    else output[i] = third;
                } else {
                    image_rgb_to_lab(nr, ng, nb, &h, &s, &third);
                    if (channel_kind == 501) output[i] = h;
                    else if (channel_kind == 502) output[i] = s;
                    else output[i] = third;
                }
            }
        }
        image_prepare_plain_numeric_array(target_array_name, sample_count);
        target_var = require_array_variable(target_array_name);
        for (i = 0; i < sample_count; ++i) set_b2026_number(&target_var->data[option_base + (int)i], output[i]);
        free(output);
    }
    if (produce_hash && target_hash_name != NULL) image_split_info_to_hash(target_hash_name, out_info);
}

void image_apply_merge_channels_common(const char *target_name, const char *target_hash_name, const char *color_type_name, int use_info_hash, const char *info_hash_name, double width_value, double height_value, const char *r_name, int has_r, const char *g_name, int has_g, const char *b_name, int has_b, const char *a_name, int has_a, int produce_image, int produce_hash, ImageMergeInfo *out_info) {
    int width;
    int height;
    int pixel_mode = 1;
    double image_value_max = 0.0;
    double resolution = 72.0;
    int phys_value = 0;
    int phys_unit = 0;
    const char *canonical_color_type = "RGBA";
    int color_kind;
    int channel_count = 4;
    long long sample_count;
    long long logical_count;
    double *output = NULL;
    ArrayVariable *target_var;
    long long i;
    image_merge_info_reset(out_info);
    if (produce_hash && target_hash_name != NULL) image_clear_hash_output(target_hash_name);
    color_kind = image_merge_color_type_kind(color_type_name, &canonical_color_type, &channel_count);
    if (color_kind == 0) {
        if (produce_image && target_name != NULL) image_assign_empty_result(target_name);
        return;
    }
    if (use_info_hash && info_hash_name != NULL) {
        width = image_merge_hash_int_with_default(info_hash_name, "width", "width", 0);
        height = image_merge_hash_int_with_default(info_hash_name, "height", "height", 0);
        pixel_mode = image_merge_hash_int_with_default(info_hash_name, "pixelMode", "image_pixel_mode", 1);
        image_value_max = image_merge_hash_number_with_default(info_hash_name, "imageValueMax", "image_value_max", (pixel_mode == 0 ? 1.0 : (pixel_mode == 2 ? 65535.0 : 255.0)));
        resolution = image_merge_hash_number_with_default(info_hash_name, "resolution", "image_resolution", 72.0);
    } else {
        if (is_null_number(width_value) || is_null_number(height_value)) {
            if (produce_image && target_name != NULL) image_assign_empty_result(target_name);
            return;
        }
        width = (int)llround(width_value);
        height = (int)llround(height_value);
    }
    if (!(image_value_max > 0.0)) image_value_max = (pixel_mode == 0 ? 1.0 : (pixel_mode == 2 ? 65535.0 : 255.0));
    if (pixel_mode < 0 || pixel_mode > 2) pixel_mode = 1;
    if (!(resolution > 0.0)) resolution = 72.0;
    if (width <= 0 || height <= 0) {
        if (produce_image && target_name != NULL) image_assign_empty_result(target_name);
        return;
    }
    sample_count = (long long)width * (long long)height;
    logical_count = sample_count * 4LL;
    if (logical_count <= 0 || logical_count > 1073741823LL) runtime_error("IMAGE failed: size overflow / 【IMAGE】画像サイズが大きすぎます。");
    phys_value = image_phys_from_resolution(resolution);
    phys_unit = phys_value > 0 ? 1 : 0;
    if (out_info != NULL) {
        out_info->valid = 1;
        out_info->width = width;
        out_info->height = height;
        out_info->color_type = canonical_color_type;
        out_info->image_value_max = image_value_max;
        out_info->pixel_mode = pixel_mode;
        out_info->resolution = resolution;
        out_info->sample_count = sample_count;
        out_info->used_r = has_r ? 1 : 0;
        out_info->used_g = has_g ? 1 : 0;
        out_info->used_b = has_b ? 1 : 0;
        out_info->used_a = (color_kind == 2 && has_a) ? 1 : 0;
    }
    if (produce_image && target_name != NULL) {
        output = (double *)malloc((size_t)logical_count * sizeof(double));
        if (output == NULL) runtime_error("IMAGE failed: out of memory / 【IMAGE】メモリ不足です。");
        for (i = 0; i < sample_count; ++i) {
            long long base = i * 4LL;
            if (color_kind == 1 || color_kind == 2) {
                output[base + 0] = image_merge_channel_value(r_name, has_r, i, 0.0);
                output[base + 1] = image_merge_channel_value(g_name, has_g, i, 0.0);
                output[base + 2] = image_merge_channel_value(b_name, has_b, i, 0.0);
                output[base + 3] = (color_kind == 2) ? image_merge_channel_value(a_name, has_a, i, image_value_max) : image_value_max;
            } else if (color_kind == 3 || color_kind == 4) {
                double h = image_merge_channel_value(r_name, has_r, i, 0.0);
                double s = image_merge_channel_value(g_name, has_g, i, 0.0) / image_value_max;
                double t = image_merge_channel_value(b_name, has_b, i, 0.0) / image_value_max;
                double nr = 0.0, ng = 0.0, nb = 0.0;
                if (color_kind == 3) image_hsv_to_rgb(h, s, t, &nr, &ng, &nb);
                else image_hsl_to_rgb(h, s, t, &nr, &ng, &nb);
                output[base + 0] = nr * image_value_max;
                output[base + 1] = ng * image_value_max;
                output[base + 2] = nb * image_value_max;
                output[base + 3] = image_value_max;
            } else if (color_kind == 5) {
                double y = image_merge_channel_value(r_name, has_r, i, 0.0) / image_value_max;
                double cb = image_merge_channel_value(g_name, has_g, i, image_value_max * 0.5) / image_value_max;
                double cr = image_merge_channel_value(b_name, has_b, i, image_value_max * 0.5) / image_value_max;
                double nr = 0.0, ng = 0.0, nb = 0.0;
                image_ycbcr_to_rgb(y, cb, cr, &nr, &ng, &nb);
                output[base + 0] = nr * image_value_max;
                output[base + 1] = ng * image_value_max;
                output[base + 2] = nb * image_value_max;
                output[base + 3] = image_value_max;
            } else if (color_kind == 6) {
                double y = image_merge_channel_value(r_name, has_r, i, 0.0) / image_value_max;
                double u = image_merge_channel_value(g_name, has_g, i, 0.0) / image_value_max;
                double v = image_merge_channel_value(b_name, has_b, i, 0.0) / image_value_max;
                double nr = 0.0, ng = 0.0, nb = 0.0;
                image_yuv_to_rgb(y, u, v, &nr, &ng, &nb);
                output[base + 0] = nr * image_value_max;
                output[base + 1] = ng * image_value_max;
                output[base + 2] = nb * image_value_max;
                output[base + 3] = image_value_max;
            } else if (color_kind == 11) {
                double y = image_merge_channel_value(r_name, has_r, i, 0.0) / image_value_max;
                double i2 = image_merge_channel_value(g_name, has_g, i, 0.0) / image_value_max;
                double q = image_merge_channel_value(b_name, has_b, i, 0.0) / image_value_max;
                double nr = 0.0, ng = 0.0, nb = 0.0;
                image_yiq_to_rgb(y, i2, q, &nr, &ng, &nb);
                output[base + 0] = nr * image_value_max;
                output[base + 1] = ng * image_value_max;
                output[base + 2] = nb * image_value_max;
                output[base + 3] = image_value_max;
            } else if (color_kind == 7) {
                double c = image_merge_channel_value(r_name, has_r, i, 0.0) / image_value_max;
                double m = image_merge_channel_value(g_name, has_g, i, 0.0) / image_value_max;
                double y = image_merge_channel_value(b_name, has_b, i, 0.0) / image_value_max;
                double k = image_merge_channel_value(a_name, has_a, i, 0.0) / image_value_max;
                double nr = 0.0, ng = 0.0, nb = 0.0;
                image_cmyk_to_rgb(c, m, y, k, &nr, &ng, &nb);
                output[base + 0] = nr * image_value_max;
                output[base + 1] = ng * image_value_max;
                output[base + 2] = nb * image_value_max;
                output[base + 3] = image_value_max;
            } else if (color_kind == 8) {
                double x = image_merge_channel_value(r_name, has_r, i, 0.0) / image_value_max;
                double y = image_merge_channel_value(g_name, has_g, i, 0.0) / image_value_max;
                double z = image_merge_channel_value(b_name, has_b, i, 0.0) / image_value_max;
                double nr = 0.0, ng = 0.0, nb = 0.0;
                image_xyz_to_rgb(x, y, z, &nr, &ng, &nb);
                output[base + 0] = nr * image_value_max;
                output[base + 1] = ng * image_value_max;
                output[base + 2] = nb * image_value_max;
                output[base + 3] = image_value_max;
            } else if (color_kind == 9) {
                double l = image_merge_channel_value(r_name, has_r, i, 0.0);
                double c = image_merge_channel_value(g_name, has_g, i, 0.0);
                double h = image_merge_channel_value(b_name, has_b, i, 0.0);
                double nr = 0.0, ng = 0.0, nb = 0.0;
                image_lch_to_rgb(l, c, h, &nr, &ng, &nb);
                output[base + 0] = nr * image_value_max;
                output[base + 1] = ng * image_value_max;
                output[base + 2] = nb * image_value_max;
                output[base + 3] = image_value_max;
            } else {
                double l = image_merge_channel_value(r_name, has_r, i, 0.0);
                double a = image_merge_channel_value(g_name, has_g, i, 0.0);
                double b2 = image_merge_channel_value(b_name, has_b, i, 0.0);
                double nr = 0.0, ng = 0.0, nb = 0.0;
                image_lab_to_rgb(l, a, b2, &nr, &ng, &nb);
                output[base + 0] = nr * image_value_max;
                output[base + 1] = ng * image_value_max;
                output[base + 2] = nb * image_value_max;
                output[base + 3] = image_value_max;
            }
        }
        dim_array(target_name, (double)(option_base + (int)logical_count - 1));
        target_var = require_array_variable(target_name);
        for (i = 0; i < logical_count; ++i) set_b2026_number(&target_var->data[option_base + (int)i], output[i]);
        free(output);
        target_var->read_count = (int)logical_count;
        target_var->screen_width = width;
        target_var->screen_height = height;
        target_var->image_phys_x = phys_value;
        target_var->image_phys_y = phys_value;
        target_var->image_phys_unit = phys_unit;
        target_var->image_pixel_mode = pixel_mode;
        target_var->image_value_max = image_value_max;
        target_var->fft_width = 0;
        target_var->fft_height = 0;
        target_var->fft_original_width = 0;
        target_var->fft_original_height = 0;
        target_var->fft_is_complex = 0;
        target_var->fft_channels = 0;
        target_var->fft_restore_255 = 0;
    }
    if (produce_hash && target_hash_name != NULL) image_merge_info_to_hash(target_hash_name, out_info);
}

