}
struct value_name {
- char *name;
+ const char *name;
int value;
};
-static int lookup_name(const struct value_name *names, int count, char *name, int def_value)
+static int
+lookup_name(const struct value_name *names, int count, char *name, int def_value, int push_errors, const char *id, int *failed)
{
int i;
+
+ if (push_errors)
+ *failed = 0;
+
for (i = 0; i < count; ++i)
if (strEQ(names[i].name, name))
return names[i].value;
+ if (push_errors) {
+ i_push_errorf(0, "unknown value '%s' for %s", name, id);
+ *failed = 1;
+ }
+
return def_value;
}
+
static struct value_name transp_names[] =
{
{ "none", tr_none },
};
/* look through the hash for quantization options */
-static void
-ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv)
+static int
+ip_handle_quant_opts_low(pTHX_ i_quantize *quant, HV *hv, int push_errors)
{
- /*** POSSIBLY BROKEN: do I need to unref the SV from hv_fetch ***/
SV **sv;
int i;
STRLEN len;
char *str;
+ int failed = 0;
quant->mc_colors = mymalloc(quant->mc_size * sizeof(i_color));
if (sv && *sv && (str = SvPV(*sv, len))) {
quant->transp =
lookup_name(transp_names, sizeof(transp_names)/sizeof(*transp_names),
- str, tr_none);
+ str, tr_none, push_errors, "transp", &failed);
+ if (failed)
+ return 0;
if (quant->transp != tr_none) {
quant->tr_threshold = 127;
sv = hv_fetch(hv, "tr_threshold", 12, 0);
if (quant->transp == tr_errdiff) {
sv = hv_fetch(hv, "tr_errdiff", 10, 0);
if (sv && *sv && (str = SvPV(*sv, len)))
- quant->tr_errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd);
+ quant->tr_errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd, push_errors, "tr_errdiff", &failed);
+ if (failed)
+ return 0;
}
if (quant->transp == tr_ordered) {
quant->tr_orddith = od_tiny;
sv = hv_fetch(hv, "tr_orddith", 10, 0);
- if (sv && *sv && (str = SvPV(*sv, len)))
- quant->tr_orddith = lookup_name(orddith_names, sizeof(orddith_names)/sizeof(*orddith_names), str, od_random);
+ if (sv && *sv && (str = SvPV(*sv, len))) {
+ quant->tr_orddith = lookup_name(orddith_names, sizeof(orddith_names)/sizeof(*orddith_names), str, od_random, push_errors, "tr_orddith", &failed);
+ if (failed)
+ return 0;
+ }
if (quant->tr_orddith == od_custom) {
sv = hv_fetch(hv, "tr_map", 6, 0);
sv = hv_fetch(hv, "make_colors", 11, 0);
if (sv && *sv && (str = SvPV(*sv, len))) {
quant->make_colors =
- lookup_name(make_color_names, sizeof(make_color_names)/sizeof(*make_color_names), str, mc_median_cut);
+ lookup_name(make_color_names, sizeof(make_color_names)/sizeof(*make_color_names), str, mc_median_cut, push_errors, "make_colors", &failed);
+ if (failed)
+ return 0;
}
sv = hv_fetch(hv, "colors", 6, 0);
if (sv && *sv && SvROK(*sv) && SvTYPE(SvRV(*sv)) == SVt_PVAV) {
i_color *col = INT2PTR(i_color *, SvIV((SV*)SvRV(*sv1)));
quant->mc_colors[i] = *col;
}
+ else if (push_errors) {
+ i_push_errorf(0, "colors[%d] isn't an Imager::Color object", i);
+ return 0;
+ }
}
}
sv = hv_fetch(hv, "max_colors", 10, 0);
quant->translate = pt_closest;
sv = hv_fetch(hv, "translate", 9, 0);
if (sv && *sv && (str = SvPV(*sv, len))) {
- quant->translate = lookup_name(translate_names, sizeof(translate_names)/sizeof(*translate_names), str, pt_closest);
+ quant->translate = lookup_name(translate_names, sizeof(translate_names)/sizeof(*translate_names), str, pt_closest, push_errors, "translate", &failed);
+ if (failed)
+ return 0;
}
sv = hv_fetch(hv, "errdiff", 7, 0);
if (sv && *sv && (str = SvPV(*sv, len))) {
- quant->errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd);
+ quant->errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd, push_errors, "errdiff", &failed);
+ if (failed)
+ return 0;
}
if (quant->translate == pt_errdiff && quant->errdiff == ed_custom) {
/* get the error diffusion map */
for (i = 0; i < len; ++i) {
SV **sv2 = av_fetch(av, i, 0);
if (sv2 && *sv2) {
- quant->ed_map[i] = SvIV(*sv2);
+ IV iv = SvIV(*sv2);
+ if (push_errors && iv < 0) {
+ i_push_errorf(0, "errdiff_map values must be non-negative, errdiff[%d] is negative", i);
+ return 0;
+ }
+ quant->ed_map[i] = iv;
sum += quant->ed_map[i];
}
}
myfree(quant->ed_map);
quant->ed_map = 0;
quant->errdiff = ed_floyd;
+ if (push_errors) {
+ i_push_error(0, "error diffusion map must contain some non-zero values");
+ return 0;
+ }
}
}
}
sv = hv_fetch(hv, "perturb", 7, 0);
if (sv && *sv)
quant->perturb = SvIV(*sv);
+
+ return 1;
}
static void
myfree(quant->ed_map);
}
+static int
+ip_handle_quant_opts2(pTHX_ i_quantize *quant, HV *hv) {
+ int result = ip_handle_quant_opts_low(aTHX_ quant, hv, 1);
+ if (!result) {
+ ip_cleanup_quant_opts(aTHX_ quant);
+ }
+ return result;
+}
+
+static void
+ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv) {
+ (void)ip_handle_quant_opts_low(aTHX_ quant, hv, 0);
+}
+
/* copies the color map from the hv into the colors member of the HV */
static void
ip_copy_colors_back(pTHX_ HV *hv, i_quantize *quant) {
else {
return (i_poly_fill_mode_t)lookup_name
(poly_fill_mode_names, ARRAY_COUNT(poly_fill_mode_names),
- SvPV_nolen(sv), i_pfm_evenodd);
+ SvPV_nolen(sv), i_pfm_evenodd, 0, NULL, NULL);
}
}
IMAGER_PL_API_LEVEL,
ip_handle_quant_opts,
ip_cleanup_quant_opts,
- ip_copy_colors_back
+ ip_copy_colors_back,
+ ip_handle_quant_opts2
};
#define PERL_PL_SET_GLOBAL_CALLBACKS \
memset(&quant, 0, sizeof(quant));
quant.version = 1;
quant.mc_size = 256;
- ip_handle_quant_opts(aTHX_ &quant, quant_hv);
+ i_clear_error();
+ if (!ip_handle_quant_opts2(aTHX_ &quant, quant_hv)) {
+ XSRETURN_EMPTY;
+ }
RETVAL = i_img_to_pal(src, &quant);
if (RETVAL) {
ip_copy_colors_back(aTHX_ quant_hv, &quant);
memset(&quant, 0, sizeof(quant));
quant.version = 1;
quant.mc_size = 256;
- ip_handle_quant_opts(aTHX_ &quant, quant_hv);
+ if (!ip_handle_quant_opts2(aTHX_ &quant, quant_hv)) {
+ XSRETURN_EMPTY;
+ }
i_quant_makemap(&quant, imgs, count);
EXTEND(SP, quant.mc_count);
for (i = 0; i < quant.mc_count; ++i) {
#!perl -w
# some of this is tested in t01introvert.t too
use strict;
-use Test::More tests => 226;
+use Test::More;
BEGIN { use_ok("Imager", ':handy'); }
use Imager::Test qw(image_bounds_checks test_image is_color3 isnt_image is_color4 is_fcolor3);
is_color4($map[33], 33, 33, 33, 255, "check map[2]");
is_color4($map[255], 255, 255, 255, 255, "check map[15]");
}
+ {
+ my @map = Imager->make_palette({ make_colors => "xxx" }, $im);
+ is(@map, 0, "fail with bad make_colors");
+ is(Imager->errstr, "unknown value 'xxx' for make_colors");
+ }
}
my $psamp_outside_error = "Image position outside of image";
"check error message");
}
+{
+ # check error handling with zero error diffusion matrix
+ my $im = test_image;
+ my $new = $im->to_paletted
+ (
+ make_colors => "webmap",
+ translate => "errdiff",
+ errdiff => "custom",
+ errdiff_width => 2,
+ errdiff_height => 2,
+ errdiff_map => [ 0, 0, 0, 0 ],
+ );
+ ok(!$new, "can't errdiff with an all zero map");
+ is($im->errstr, "error diffusion map must contain some non-zero values",
+ "check error message");
+}
+
Imager->close_log;
+done_testing();
+
unless ($ENV{IMAGER_KEEP_FILES}) {
unlink "testout/t023palette.log"
}