[RT #68508] do error diffusion on gray scale if the supplied palette is all gray
authorTony Cook <tony@develop-help.com>
Mon, 30 May 2011 10:22:09 +0000 (20:22 +1000)
committerTony Cook <tony@develop-help.com>
Mon, 30 May 2011 10:22:09 +0000 (20:22 +1000)
Changes
imageri.h
lib/Imager/ImageTypes.pod
paste.im
quant.c
t/t023palette.t

diff --git a/Changes b/Changes
index 2d09e03..d8fa09e 100644 (file)
--- a/Changes
+++ b/Changes
@@ -22,6 +22,11 @@ Bug fixes:
  - Imager no longer exports anything by default
    https://rt.cpan.org/Ticket/Display.html?id=65228
 
+ - convert colors to grayscale if the supplied (or generated) palette
+   contains only grays when performing error diffusion color
+   translation.
+   https://rt.cpan.org/Ticket/Display.html?id=68508
+
 Imager 0.83 - 21 May 2011
 ===========
 
index 36d6ed9..9037ff5 100644 (file)
--- a/imageri.h
+++ b/imageri.h
@@ -114,4 +114,6 @@ i_img_dim i_maxx(i_img_dim x, i_img_dim y);
 #define i_min(a, b) i_minx((a), (b))
 #define i_max(a, b) i_maxx((a), (b))
 
+#define color_to_grey(col) ((col)->rgb.r * 0.222  + (col)->rgb.g * 0.707 + (col)->rgb.b * 0.071)
+
 #endif
index 4a36c64..81512e6 100644 (file)
@@ -1047,7 +1047,8 @@ Possible values are:
 
 =item *
 
-C<giflib> - the C<giflib> native quantization function is used.
+C<giflib> - this is a historical equivalent for C<closest> that also
+forces C<make_colors> to C<mediancut>.
 
 =item *
 
@@ -1060,7 +1061,9 @@ closest color is chosen.
 
 =item *
 
-C<errdiff> - an error diffusion dither is performed.
+C<errdiff> - an error diffusion dither is performed.  If the supplied
+(or generated) palette contains only grays the source colors are
+converted to gray before error diffusion is performed.
 
 =back
 
index 6bc58a7..220e017 100644 (file)
--- a/paste.im
+++ b/paste.im
@@ -1,4 +1,5 @@
 #include "imager.h"
+#include "imageri.h"
 
 /*
 =item i_copyto(C<dest>, C<src>, C<x1>, C<y1>, C<x2>, C<y2>, C<tx>, C<ty>)
@@ -59,8 +60,6 @@ i_copyto(i_img *im, i_img *src, int x1, int y1, int x2, int y2, int tx, int ty)
 #/code
 }
 
-#define color_to_grey(col) ((col)->rgb.r * 0.222  + (col)->rgb.g * 0.707 + (col)->rgb.b * 0.071)
-
 #code
 void
 #ifdef IM_EIGHT_BIT
diff --git a/quant.c b/quant.c
index ca4e34e..de14b29 100644 (file)
--- a/quant.c
+++ b/quant.c
@@ -223,9 +223,12 @@ eucl_d_ch(cvec* cv,i_sample_t *chans) {
     + PWR2(cv->b - chans[2]);
 }
 
-static
-int
-ceucl_d(i_color *c1, i_color *c2) { return PWR2(c1->channel[0]-c2->channel[0])+PWR2(c1->channel[1]-c2->channel[1])+PWR2(c1->channel[2]-c2->channel[2]); }
+static int
+ceucl_d(i_color *c1, i_color *c2) {
+return PWR2(c1->channel[0]-c2->channel[0])
+  +PWR2(c1->channel[1]-c2->channel[1])
+  +PWR2(c1->channel[2]-c2->channel[2]);
+}
 
 static const int
 gray_samples[] = { 0, 0, 0 };
@@ -755,6 +758,23 @@ makemap_mono(i_quantize *quant) {
 /*#define IM_CFRAND2DIST*/
 #endif
 
+/* return true if the color map contains only grays */
+static int
+is_gray_map(const i_quantize *quant) {
+  int i;
+
+  for (i = 0; i < quant->mc_count; ++i) {
+    if (quant->mc_colors[i].rgb.r != quant->mc_colors[i].rgb.g
+       || quant->mc_colors[i].rgb.r != quant->mc_colors[i].rgb.b) {
+      mm_log((1, "  not a gray map\n"));
+      return 0;
+    }
+  }
+
+  mm_log((1, "  is a gray map\n"));
+  return 1;
+}
+
 #ifdef IM_CFHASHBOX
 
 /* The original version I wrote for this used the sort.
@@ -1205,6 +1225,7 @@ translate_errdiff(i_quantize *quant, i_img *img, i_palidx *out) {
   int difftotal;
   int x, y, dx, dy;
   int bst_idx = 0;
+  int is_gray = is_gray_map(quant);
   CF_VARS;
 
   if ((quant->errdiff & ed_mask) == ed_custom) {
@@ -1249,6 +1270,10 @@ translate_errdiff(i_quantize *quant, i_img *img, i_palidx *out) {
       if (img->channels < 3) {
         val.channel[1] = val.channel[2] = val.channel[0];
       }
+      else if (is_gray) {
+       int gray = 0.5 + color_to_grey(&val);
+       val.channel[0] = val.channel[1] = val.channel[2] = gray;
+      }
       perr = err[x+mapo];
       perr.r = perr.r < 0 ? -((-perr.r)/difftotal) : perr.r/difftotal;
       perr.g = perr.g < 0 ? -((-perr.g)/difftotal) : perr.g/difftotal;
index 2f50f29..a7ed1b0 100644 (file)
@@ -1,10 +1,10 @@
 #!perl -w
 # some of this is tested in t01introvert.t too
 use strict;
-use Test::More tests => 126;
+use Test::More tests => 128;
 BEGIN { use_ok("Imager"); }
 
-use Imager::Test qw(image_bounds_checks test_image is_color3);
+use Imager::Test qw(image_bounds_checks test_image is_color3 isnt_image);
 
 Imager->open_log(log => "testout/t023palette.log");
 
@@ -345,6 +345,15 @@ cmp_ok(Imager->errstr, '=~', qr/Channels must be positive and <= 4/,
   is_color3($colors[8], 0, 0x33, 0x66, "9th should be 003366");
 }
 
+{ # RT 68508
+  my $im = Imager->new(xsize => 10, ysize => 10);
+  $im->box(filled => 1, color => Imager::Color->new(255, 0, 0));
+  my $palim = $im->to_paletted(make_colors => "mono", translate => "errdiff");
+  ok($palim, "convert to mono with error diffusion");
+  my $blank = Imager->new(xsize => 10, ysize => 10);
+  isnt_image($palim, $blank, "make sure paletted isn't all black");
+}
+
 Imager->close_log;
 
 unless ($ENV{IMAGER_KEEP_FILES}) {