Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Ticket #369 - writing grayscale images to GIF

related change to support passing const channel arrays to i_gsamp()
  • Loading branch information...
commit 18accb2acf8562f8c69d23f7b9523f6194d641c9 1 parent 21aa4e1
authored March 25, 2002
4  Changes
@@ -610,6 +610,10 @@ Revision history for Perl extension Imager.
610 610
         - make t1log optional, defaulting to off.  You can enable the log
611 611
           with Imager::init(t1log=>1) (Ticket #369)
612 612
         - quote a few hash key strings to prevent warnings on 5.004
  613
+        - modify quantization code to handle 1 channel images 
  614
+          correctly (Ticket #365)
  615
+        - make channel pointer to i_gsamp() const int * so we can pass
  616
+          const arrays
613 617
 
614 618
 =================================================================
615 619
 
4  datatypes.h
@@ -85,9 +85,9 @@ typedef int (*i_f_glin_t)(i_img *im, int x, int r, int y, i_color *vals);
85 85
 typedef int (*i_f_glinf_t)(i_img *im, int x, int r, int y, i_fcolor *vals);
86 86
 
87 87
 typedef int (*i_f_gsamp_t)(i_img *im, int x, int r, int y, i_sample_t *samp,
88  
-                           int *chans, int chan_count);
  88
+                           const int *chans, int chan_count);
89 89
 typedef int (*i_f_gsampf_t)(i_img *im, int x, int r, int y, i_fsample_t *samp,
90  
-                            int *chan, int chan_count);
  90
+                            const int *chan, int chan_count);
91 91
 
92 92
 typedef int (*i_f_gpal_t)(i_img *im, int x, int r, int y, i_palidx *vals);
93 93
 typedef int (*i_f_ppal_t)(i_img *im, int x, int r, int y, i_palidx *vals);
14  image.c
@@ -48,10 +48,10 @@ static int i_ppixf_d(i_img *im, int x, int y, i_fcolor *val);
48 48
 static int i_gpixf_d(i_img *im, int x, int y, i_fcolor *val);
49 49
 static int i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals);
50 50
 static int i_plinf_d(i_img *im, int l, int r, int y, i_fcolor *vals);
51  
-static int i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count);
52  
-static int i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count);
53  
-static int i_psamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count);
54  
-static int i_psampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count);
  51
+static int i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, const int *chans, int chan_count);
  52
+static int i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, const int *chans, int chan_count);
  53
+/*static int i_psamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count);
  54
+  static int i_psampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count);*/
55 55
 
56 56
 /* 
57 57
 =item ICL_new_internal(r, g, b, a)
@@ -1508,7 +1508,7 @@ Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1508 1508
 static
1509 1509
 int
1510 1510
 i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, 
1511  
-              int *chans, int chan_count) {
  1511
+              const int *chans, int chan_count) {
1512 1512
   int ch, count, i, w;
1513 1513
   unsigned char *data;
1514 1514
 
@@ -1566,7 +1566,7 @@ Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1566 1566
 static
1567 1567
 int
1568 1568
 i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, 
1569  
-               int *chans, int chan_count) {
  1569
+           const int *chans, int chan_count) {
1570 1570
   int ch, count, i, w;
1571 1571
   unsigned char *data;
1572 1572
   for (ch = 0; ch < chan_count; ++ch) {
@@ -1728,7 +1728,7 @@ int i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) {
1728 1728
 =cut
1729 1729
 */
1730 1730
 int i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp, 
1731  
-                int *chans, int chan_count) {
  1731
+                int const *chans, int chan_count) {
1732 1732
   i_sample_t *work;
1733 1733
 
1734 1734
   if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
2  imagei.h
@@ -15,7 +15,7 @@ extern int i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix);
15 15
 extern int i_plinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix);
16 16
 extern int i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix);
17 17
 extern int i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp,
18  
-                       int *chans, int chan_count);
  18
+                       int const *chans, int chan_count);
19 19
 
20 20
 /* wrapper functions that forward palette calls to the underlying image,
21 21
    assuming the underlying image is the first pointer in whatever
8  img16.c
@@ -32,9 +32,9 @@ static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val);
32 32
 static int i_glinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals);
33 33
 static int i_plinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals);
34 34
 static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps, 
35  
-                       int *chans, int chan_count);
  35
+                       int const *chans, int chan_count);
36 36
 static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps, 
37  
-                        int *chans, int chan_count);
  37
+                        int const *chans, int chan_count);
38 38
 
39 39
 /*
40 40
 =item IIM_base_16bit_direct
@@ -313,7 +313,7 @@ static int i_plinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) {
313 313
 }
314 314
 
315 315
 static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps, 
316  
-                       int *chans, int chan_count) {
  316
+                       int const *chans, int chan_count) {
317 317
   int ch, count, i, w;
318 318
   int off;
319 319
 
@@ -358,7 +358,7 @@ static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps,
358 358
 }
359 359
 
360 360
 static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps, 
361  
-                        int *chans, int chan_count) {
  361
+                        int const *chans, int chan_count) {
362 362
   int ch, count, i, w;
363 363
   int off;
364 364
 
8  imgdouble.c
@@ -32,9 +32,9 @@ static int i_gpixf_ddoub(i_img *im, int x, int y, i_fcolor *val);
32 32
 static int i_glinf_ddoub(i_img *im, int l, int r, int y, i_fcolor *vals);
33 33
 static int i_plinf_ddoub(i_img *im, int l, int r, int y, i_fcolor *vals);
34 34
 static int i_gsamp_ddoub(i_img *im, int l, int r, int y, i_sample_t *samps, 
35  
-                       int *chans, int chan_count);
  35
+                       int const *chans, int chan_count);
36 36
 static int i_gsampf_ddoub(i_img *im, int l, int r, int y, i_fsample_t *samps, 
37  
-                        int *chans, int chan_count);
  37
+                        int const *chans, int chan_count);
38 38
 
39 39
 /*
40 40
 =item IIM_base_16bit_direct
@@ -260,7 +260,7 @@ static int i_plinf_ddoub(i_img *im, int l, int r, int y, i_fcolor *vals) {
260 260
 }
261 261
 
262 262
 static int i_gsamp_ddoub(i_img *im, int l, int r, int y, i_sample_t *samps, 
263  
-                       int *chans, int chan_count) {
  263
+                       int const *chans, int chan_count) {
264 264
   int ch, count, i, w;
265 265
   int off;
266 266
 
@@ -305,7 +305,7 @@ static int i_gsamp_ddoub(i_img *im, int l, int r, int y, i_sample_t *samps,
305 305
 }
306 306
 
307 307
 static int i_gsampf_ddoub(i_img *im, int l, int r, int y, i_fsample_t *samps, 
308  
-                        int *chans, int chan_count) {
  308
+                        int const *chans, int chan_count) {
309 309
   int ch, count, i, w;
310 310
   int off;
311 311
 
8  maskimg.c
@@ -43,9 +43,9 @@ static int i_gpixf_masked(i_img *im, int x, int y, i_fcolor *pix);
43 43
 static int i_glin_masked(i_img *im, int l, int r, int y, i_color *vals);
44 44
 static int i_glinf_masked(i_img *im, int l, int r, int y, i_fcolor *vals);
45 45
 static int i_gsamp_masked(i_img *im, int l, int r, int y, i_sample_t *samp, 
46  
-                          int *chans, int chan_count);
  46
+                          int const *chans, int chan_count);
47 47
 static int i_gsampf_masked(i_img *im, int l, int r, int y, i_fsample_t *samp, 
48  
-                           int *chans, int chan_count);
  48
+                           int const *chans, int chan_count);
49 49
 static int i_gpal_masked(i_img *im, int l, int r, int y, i_palidx *vals);
50 50
 static int i_ppal_masked(i_img *im, int l, int r, int y, i_palidx *vals);
51 51
 
@@ -438,7 +438,7 @@ static int i_glinf_masked(i_img *im, int l, int r, int y, i_fcolor *vals) {
438 438
 }
439 439
 
440 440
 static int i_gsamp_masked(i_img *im, int l, int r, int y, i_sample_t *samp, 
441  
-                          int *chans, int chan_count) {
  441
+                          int const *chans, int chan_count) {
442 442
   i_img_mask_ext *ext = MASKEXT(im);
443 443
   if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
444 444
     if (r > im->xsize)
@@ -452,7 +452,7 @@ static int i_gsamp_masked(i_img *im, int l, int r, int y, i_sample_t *samp,
452 452
 }
453 453
 
454 454
 static int i_gsampf_masked(i_img *im, int l, int r, int y, i_fsample_t *samp, 
455  
-                          int *chans, int chan_count) {
  455
+                          int const *chans, int chan_count) {
456 456
   i_img_mask_ext *ext = MASKEXT(im);
457 457
   if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
458 458
     if (r > im->xsize)
4  palimg.c
@@ -26,7 +26,7 @@ static int i_ppix_p(i_img *im, int x, int y, i_color *val);
26 26
 static int i_gpix_p(i_img *im, int x, int y, i_color *val);
27 27
 static int i_glin_p(i_img *im, int l, int r, int y, i_color *vals);
28 28
 static int i_plin_p(i_img *im, int l, int r, int y, i_color *vals);
29  
-static int i_gsamp_p(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count);
  29
+static int i_gsamp_p(i_img *im, int l, int r, int y, i_sample_t *samps, int const *chans, int chan_count);
30 30
 static int i_gpal_p(i_img *pm, int l, int r, int y, i_palidx *vals);
31 31
 static int i_ppal_p(i_img *pm, int l, int r, int y, i_palidx *vals);
32 32
 static int i_addcolors_p(i_img *im, i_color *color, int count);
@@ -353,7 +353,7 @@ static int i_plin_p(i_img *im, int l, int r, int y, i_color *vals) {
353 353
 =cut
354 354
 */
355 355
 static int i_gsamp_p(i_img *im, int l, int r, int y, i_sample_t *samps, 
356  
-              int *chans, int chan_count) {
  356
+              int const *chans, int chan_count) {
357 357
   int ch;
358 358
   if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
359 359
     int palsize = PALEXT(im)->count;
253  quant.c
@@ -102,7 +102,8 @@ i_palidx *quant_translate(i_quantize *quant, i_img *img) {
102 102
   return result;
103 103
 }
104 104
 
105  
-#ifdef HAVE_LIBGIF
  105
+#ifdef HAVE_LIBGIF_THIS_NOT_USED
  106
+
106 107
 #include "gif_lib.h"
107 108
 
108 109
 #define GET_RGB(im, x, y, ri, gi, bi, col) \
@@ -112,6 +113,7 @@ i_palidx *quant_translate(i_quantize *quant, i_img *img) {
112 113
 static int 
113 114
 quant_replicate(i_img *im, i_palidx *output, i_quantize *quant);
114 115
 
  116
+
115 117
 /* Use the gif_lib quantization functions to quantize the image */
116 118
 static void translate_giflib(i_quantize *quant, i_img *img, i_palidx *out) {
117 119
   int x,y,ColorMapSize,colours_in;
@@ -286,7 +288,7 @@ typedef struct {
286 288
   int pdc;
287 289
 } pbox;
288 290
 
289  
-static void prescan(i_img **im,int count, int cnum, cvec *clr);
  291
+static void prescan(i_img **im,int count, int cnum, cvec *clr, i_sample_t *line);
290 292
 static void reorder(pbox prescan[512]);
291 293
 static int pboxcmp(const pbox *a,const pbox *b);
292 294
 static void boxcenter(int box,cvec *cv);
@@ -303,6 +305,9 @@ static int maxdist(int boxnum,cvec *cv);
303 305
 static int
304 306
 pixbox(i_color *ic) { return ((ic->channel[0] & 224)<<1)+ ((ic->channel[1]&224)>>2) + ((ic->channel[2] &224) >> 5); }
305 307
 
  308
+static int
  309
+pixbox_ch(i_sample_t *chans) { return ((chans[0] & 224)<<1)+ ((chans[1]&224)>>2) + ((chans[2] &224) >> 5); }
  310
+
306 311
 static unsigned char
307 312
 g_sat(int in) {
308 313
   if (in>255) { return 255; }
@@ -322,8 +327,18 @@ eucl_d(cvec* cv,i_color *cl) { return PWR2(cv->r-cl->channel[0])+PWR2(cv->g-cl->
322 327
 
323 328
 static
324 329
 int
  330
+eucl_d_ch(cvec* cv,i_sample_t *chans) { 
  331
+  return PWR2(cv->r - chans[0]) + PWR2(cv->g - chans[1]) 
  332
+    + PWR2(cv->b - chans[2]);
  333
+}
  334
+
  335
+static
  336
+int
325 337
 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]); }
326 338
 
  339
+static const int
  340
+gray_samples[] = { 0, 0, 0 };
  341
+
327 342
 /* 
328 343
 
329 344
 This quantization algorithm and implementation routines are by Arnar
@@ -380,12 +395,18 @@ static void
380 395
 makemap_addi(i_quantize *quant, i_img **imgs, int count) {
381 396
   cvec *clr;
382 397
   int cnum, i, x, y, bst_idx=0, ld, cd, iter, currhb, img_num;
383  
-  i_color val;
  398
+  i_sample_t *val;
384 399
   float dlt, accerr;
385 400
   hashbox *hb;
  401
+  i_mempool mp;
  402
+  int maxwidth = 0;
  403
+  i_sample_t *line;
  404
+  const int *sample_indices;
386 405
 
387  
-  clr = (cvec *)mymalloc(sizeof(cvec) * quant->mc_size);
388  
-  hb = mymalloc(sizeof(hashbox) * 512);
  406
+  i_mempool_init(&mp);
  407
+
  408
+  clr = i_mempool_alloc(&mp, sizeof(cvec) * quant->mc_size);
  409
+  hb = i_mempool_alloc(&mp, sizeof(hashbox) * 512);
389 410
   for (i=0; i < quant->mc_count; ++i) {
390 411
     clr[i].r = quant->mc_colors[i].rgb.r;
391 412
     clr[i].g = quant->mc_colors[i].rgb.g;
@@ -401,7 +422,13 @@ makemap_addi(i_quantize *quant, i_img **imgs, int count) {
401 422
   cnum = quant->mc_size;
402 423
   dlt = 1;
403 424
 
404  
-  prescan(imgs, count, cnum, clr);
  425
+  for (img_num = 0; img_num < count; ++img_num) {
  426
+    if (imgs[img_num]->xsize > maxwidth)
  427
+      maxwidth = imgs[img_num]->xsize;
  428
+  }
  429
+  line = i_mempool_alloc(&mp, 3 * maxwidth * sizeof(*line));
  430
+
  431
+  prescan(imgs, count, cnum, clr, line);
405 432
   cr_hashindex(clr, cnum, hb);
406 433
 
407 434
   for(iter=0;iter<3;iter++) {
@@ -409,51 +436,64 @@ makemap_addi(i_quantize *quant, i_img **imgs, int count) {
409 436
     
410 437
     for (img_num = 0; img_num < count; ++img_num) {
411 438
       i_img *im = imgs[img_num];
412  
-      for(y=0;y<im->ysize;y++) for(x=0;x<im->xsize;x++) {
413  
-	ld=196608;
414  
-	i_gpix(im,x,y,&val);
415  
-	currhb=pixbox(&val);
416  
-	/*      printf("box = %d \n",currhb); */
417  
-	for(i=0;i<hb[currhb].cnt;i++) { 
418  
-	  /*	printf("comparing: pix (%d,%d,%d) vec (%d,%d,%d)\n",val.channel[0],val.channel[1],val.channel[2],clr[hb[currhb].vec[i]].r,clr[hb[currhb].vec[i]].g,clr[hb[currhb].vec[i]].b); */
419  
-	  
420  
-	  cd=eucl_d(&clr[hb[currhb].vec[i]],&val);
421  
-	  if (cd<ld) {
422  
-	    ld=cd;     /* shortest distance yet */
423  
-	    bst_idx=hb[currhb].vec[i]; /* index of closest vector  yet */
424  
-	  }
425  
-	}
426  
-	
427  
-	clr[bst_idx].mcount++;
428  
-	accerr+=(ld);
429  
-	clr[bst_idx].dr+=val.channel[0];
430  
-	clr[bst_idx].dg+=val.channel[1];
431  
-	clr[bst_idx].db+=val.channel[2];
  439
+      sample_indices = im->channels >= 3 ? NULL : gray_samples;
  440
+      for(y=0;y<im->ysize;y++) {
  441
+        i_gsamp(im, 0, im->xsize, y, line, sample_indices, 3);
  442
+        val = line;
  443
+        for(x=0;x<im->xsize;x++) {
  444
+          ld=196608;
  445
+          /*i_gpix(im,x,y,&val);*/
  446
+          currhb=pixbox_ch(val);
  447
+          /*      printf("box = %d \n",currhb); */
  448
+          for(i=0;i<hb[currhb].cnt;i++) { 
  449
+            /*	printf("comparing: pix (%d,%d,%d) vec (%d,%d,%d)\n",val.channel[0],val.channel[1],val.channel[2],clr[hb[currhb].vec[i]].r,clr[hb[currhb].vec[i]].g,clr[hb[currhb].vec[i]].b); */
  450
+            
  451
+            cd=eucl_d_ch(&clr[hb[currhb].vec[i]],val);
  452
+            if (cd<ld) {
  453
+              ld=cd;     /* shortest distance yet */
  454
+              bst_idx=hb[currhb].vec[i]; /* index of closest vector  yet */
  455
+            }
  456
+          }
  457
+          
  458
+          clr[bst_idx].mcount++;
  459
+          accerr+=(ld);
  460
+          clr[bst_idx].dr+=val[0];
  461
+          clr[bst_idx].dg+=val[1];
  462
+          clr[bst_idx].db+=val[2];
  463
+          
  464
+          val += 3; /* next 3 samples (next pixel) */
  465
+        }
432 466
       }
433 467
     }
434  
-    for(i=0;i<cnum;i++) if (clr[i].mcount) { clr[i].dr/=clr[i].mcount; clr[i].dg/=clr[i].mcount; clr[i].db/=clr[i].mcount; }
435  
-
  468
+    
  469
+    for(i=0;i<cnum;i++) 
  470
+      if (clr[i].mcount) { 
  471
+        clr[i].dr/=clr[i].mcount; 
  472
+        clr[i].dg/=clr[i].mcount; 
  473
+        clr[i].db/=clr[i].mcount; 
  474
+      }
  475
+      
436 476
     /*    for(i=0;i<cnum;i++) printf("vec(%d)=(%d,%d,%d) dest=(%d,%d,%d) matchcount=%d\n",
437  
-	  i,clr[i].r,clr[i].g,clr[i].b,clr[i].dr,clr[i].dg,clr[i].db,clr[i].mcount); */
438  
-
  477
+          i,clr[i].r,clr[i].g,clr[i].b,clr[i].dr,clr[i].dg,clr[i].db,clr[i].mcount); */
  478
+    
439 479
     /*    printf("total error: %.2f\n",sqrt(accerr)); */
440  
-
  480
+    
441 481
     for(i=0;i<cnum;i++) {
442 482
       if (clr[i].fixed) continue; /* skip reserved colors */
443  
-
  483
+      
444 484
       if (clr[i].mcount) {
445  
-	clr[i].used = 1;
446  
-	clr[i].r=clr[i].r*(1-dlt)+dlt*clr[i].dr;
447  
-	clr[i].g=clr[i].g*(1-dlt)+dlt*clr[i].dg;
448  
-	clr[i].b=clr[i].b*(1-dlt)+dlt*clr[i].db;
  485
+        clr[i].used = 1;
  486
+        clr[i].r=clr[i].r*(1-dlt)+dlt*clr[i].dr;
  487
+        clr[i].g=clr[i].g*(1-dlt)+dlt*clr[i].dg;
  488
+        clr[i].b=clr[i].b*(1-dlt)+dlt*clr[i].db;
449 489
       } else {
450  
-	/* let's try something else */
451  
-	clr[i].used = 0;
452  
-	clr[i].r=rand();
453  
-	clr[i].g=rand();
454  
-	clr[i].b=rand();
  490
+        /* let's try something else */
  491
+        clr[i].used = 0;
  492
+        clr[i].r=rand();
  493
+        clr[i].g=rand();
  494
+        clr[i].b=rand();
455 495
       }
456  
-
  496
+      
457 497
       clr[i].dr=0;
458 498
       clr[i].dg=0;
459 499
       clr[i].db=0;
@@ -498,9 +538,7 @@ makemap_addi(i_quantize *quant, i_img **imgs, int count) {
498 538
   quant->mc_count = cnum;
499 539
 #endif
500 540
 
501  
-  /* don't want to keep this */
502  
-  myfree(hb);
503  
-  myfree(clr);
  541
+  i_mempool_destroy(&mp);
504 542
 }
505 543
 
506 544
 typedef struct {
@@ -513,6 +551,9 @@ typedef struct {
513 551
 #define MED_CUT_INDEX(c) ((((c).rgb.r & 0xF8) << 7) | \
514 552
         (((c).rgb.g & 0xF8) << 2) | (((c).rgb.b & 0xF8) >> 3))
515 553
 
  554
+#define MED_CUT_GRAY_INDEX(c) ((((c).rgb.r & 0xF8) << 7) | \
  555
+        (((c).rgb.r & 0xF8) << 2) | (((c).rgb.r & 0xF8) >> 3))
  556
+
516 557
 /* scale these to cover the whole range */
517 558
 #define MED_CUT_RED(index) ((((index) & 0x7C00) >> 10) * 255 / 31)
518 559
 #define MED_CUT_GREEN(index) ((((index) & 0x3E0) >> 5) * 255 / 31)
@@ -597,6 +638,9 @@ makemap_mediancut(i_quantize *quant, i_img **imgs, int count) {
597 638
   medcut_partition *parts;
598 639
   int part_num;
599 640
   int in, out;
  641
+  /* number of channels we search for the best channel to partition
  642
+     this isn't terribly efficient, but it should work */
  643
+  int chan_count; 
600 644
 
601 645
   /*printf("images %d  pal size %d\n", count, quant->mc_size);*/
602 646
 
@@ -619,12 +663,22 @@ makemap_mediancut(i_quantize *quant, i_img **imgs, int count) {
619 663
 
620 664
   /* build the stats */
621 665
   total_pixels = 0;
  666
+  chan_count = 1; /* assume we just have grayscale */
622 667
   for (imgn = 0; imgn < count; ++imgn) {
623 668
     total_pixels += imgs[imgn]->xsize * imgs[imgn]->ysize;
624 669
     for (y = 0; y < imgs[imgn]->ysize; ++y) {
625 670
       i_glin(imgs[imgn], 0, imgs[imgn]->xsize, y, line);
626  
-      for (x = 0; x < imgs[imgn]->xsize; ++x) {
627  
-        ++colors[MED_CUT_INDEX(line[x])].count;
  671
+      if (imgs[imgn]->channels > 2) {
  672
+        chan_count = 3;
  673
+        for (x = 0; x < imgs[imgn]->xsize; ++x) {
  674
+          ++colors[MED_CUT_INDEX(line[x])].count;
  675
+        }
  676
+      }
  677
+      else {
  678
+        /* a gray-scale image, just use the first channel */
  679
+        for (x = 0; x < imgs[imgn]->xsize; ++x) {
  680
+          ++colors[MED_CUT_GRAY_INDEX(line[x])].count;
  681
+        }
628 682
       }
629 683
     }
630 684
   }
@@ -674,7 +728,7 @@ makemap_mediancut(i_quantize *quant, i_img **imgs, int count) {
674 728
          one color */
675 729
       max_size = -1;
676 730
       for (i = 0; i < color_count; ++i) {
677  
-        for (ch = 0; ch < 3; ++ch) {
  731
+        for (ch = 0; ch < chan_count; ++ch) {
678 732
           if (parts[i].width[ch] > max_size 
679 733
               && parts[i].size > 1) {
680 734
             max_index = i;
@@ -1142,22 +1196,44 @@ static void translate_addi(i_quantize *quant, i_img *img, i_palidx *out) {
1142 1196
 
1143 1197
   CF_SETUP;
1144 1198
 
1145  
-  if (pixdev) {
1146  
-    k=0;
1147  
-    for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1148  
-      i_gpix(img,x,y,&val);
1149  
-      val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn()));
1150  
-      val.channel[1]=g_sat(val.channel[1]+(int)(pixdev*frandn()));
1151  
-      val.channel[2]=g_sat(val.channel[2]+(int)(pixdev*frandn()));
1152  
-      CF_FIND;
1153  
-      out[k++]=bst_idx;
  1199
+  if (img->channels >= 3) {
  1200
+    if (pixdev) {
  1201
+      k=0;
  1202
+      for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
  1203
+        i_gpix(img,x,y,&val);
  1204
+        val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn()));
  1205
+        val.channel[1]=g_sat(val.channel[1]+(int)(pixdev*frandn()));
  1206
+        val.channel[2]=g_sat(val.channel[2]+(int)(pixdev*frandn()));
  1207
+        CF_FIND;
  1208
+        out[k++]=bst_idx;
  1209
+      }
  1210
+    } else {
  1211
+      k=0;
  1212
+      for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
  1213
+        i_gpix(img,x,y,&val);
  1214
+        CF_FIND;
  1215
+        out[k++]=bst_idx;
  1216
+      }
1154 1217
     }
1155  
-  } else {
1156  
-    k=0;
1157  
-    for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1158  
-      i_gpix(img,x,y,&val);
1159  
-      CF_FIND;
1160  
-      out[k++]=bst_idx;
  1218
+  }
  1219
+  else {
  1220
+    if (pixdev) {
  1221
+      k=0;
  1222
+      for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
  1223
+        i_gpix(img,x,y,&val);
  1224
+        val.channel[1] = val.channel[2] =
  1225
+          val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn()));
  1226
+        CF_FIND;
  1227
+        out[k++]=bst_idx;
  1228
+      }
  1229
+    } else {
  1230
+      k=0;
  1231
+      for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
  1232
+        i_gpix(img,x,y,&val);
  1233
+        val.channel[1] = val.channel[2] = val.channel[0];
  1234
+        CF_FIND;
  1235
+        out[k++]=bst_idx;
  1236
+      }
1161 1237
     }
1162 1238
   }
1163 1239
   CF_CLEANUP;
@@ -1254,6 +1330,9 @@ translate_errdiff(i_quantize *quant, i_img *img, i_palidx *out) {
1254 1330
       long ld, cd;
1255 1331
       errdiff_t perr;
1256 1332
       i_gpix(img, x, y, &val);
  1333
+      if (img->channels < 3) {
  1334
+        val.channel[1] = val.channel[2] = val.channel[0];
  1335
+      }
1257 1336
       perr = err[x+mapo];
1258 1337
       perr.r = perr.r < 0 ? -((-perr.r)/difftotal) : perr.r/difftotal;
1259 1338
       perr.g = perr.g < 0 ? -((-perr.g)/difftotal) : perr.g/difftotal;
@@ -1290,9 +1369,10 @@ translate_errdiff(i_quantize *quant, i_img *img, i_palidx *out) {
1290 1369
    and that result is used as the initial value for the vectores */
1291 1370
 
1292 1371
 
1293  
-static void prescan(i_img **imgs,int count, int cnum, cvec *clr) {
  1372
+static void prescan(i_img **imgs,int count, int cnum, cvec *clr, i_sample_t *line) {
1294 1373
   int i,k,j,x,y;
1295  
-  i_color val;
  1374
+  i_sample_t *val;
  1375
+  const int *chans;
1296 1376
 
1297 1377
   pbox prebox[512];
1298 1378
   for(i=0;i<512;i++) {
@@ -1304,9 +1384,13 @@ static void prescan(i_img **imgs,int count, int cnum, cvec *clr) {
1304 1384
   /* process each image */
1305 1385
   for (i = 0; i < count; ++i) {
1306 1386
     i_img *im = imgs[i];
1307  
-    for(y=0;y<im->ysize;y++) for(x=0;x<im->xsize;x++) {
1308  
-      i_gpix(im,x,y,&val);
1309  
-      prebox[pixbox(&val)].pixcnt++;
  1387
+    chans = im->channels >= 3 ? NULL : gray_samples;
  1388
+    for(y=0;y<im->ysize;y++) {
  1389
+      i_gsamp(im, 0, im->xsize, y, line, chans, 3);
  1390
+      val = line;
  1391
+      for(x=0;x<im->xsize;x++) {
  1392
+        prebox[pixbox_ch(val)].pixcnt++;
  1393
+      }
1310 1394
     }
1311 1395
   }
1312 1396
 
@@ -1515,15 +1599,17 @@ transparent_threshold(i_quantize *quant, i_palidx *data, i_img *img,
1515 1599
 		      i_palidx trans_index)
1516 1600
 {
1517 1601
   int x, y;
  1602
+  i_sample_t *line = mymalloc(img->xsize * sizeof(i_sample_t));
  1603
+  int trans_chan = img->channels > 2 ? 3 : 1;
1518 1604
   
1519 1605
   for (y = 0; y < img->ysize; ++y) {
  1606
+    i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
1520 1607
     for (x = 0; x < img->xsize; ++x) {
1521  
-      i_color val;
1522  
-      i_gpix(img, x, y, &val);
1523  
-      if (val.rgba.a < quant->tr_threshold)
  1608
+      if (line[x] < quant->tr_threshold)
1524 1609
 	data[y*img->xsize+x] = trans_index;
1525 1610
     }
1526 1611
   }
  1612
+  myfree(line);
1527 1613
 }
1528 1614
 
1529 1615
 static void
@@ -1536,6 +1622,8 @@ transparent_errdiff(i_quantize *quant, i_palidx *data, i_img *img,
1536 1622
   int errw, *err, *errp;
1537 1623
   int difftotal, out, error;
1538 1624
   int x, y, dx, dy, i;
  1625
+  i_sample_t *line;
  1626
+  int trans_chan = img->channels > 2 ? 3 : 1;
1539 1627
 
1540 1628
   /* no custom map for transparency (yet) */
1541 1629
   index = quant->tr_errdiff & ed_mask;
@@ -1550,22 +1638,22 @@ transparent_errdiff(i_quantize *quant, i_palidx *data, i_img *img,
1550 1638
   errp = err+mapo;
1551 1639
   memset(err, 0, sizeof(*err) * maph * errw);
1552 1640
 
  1641
+  line = mymalloc(img->xsize * sizeof(i_sample_t));
1553 1642
   difftotal = 0;
1554 1643
   for (i = 0; i < maph * mapw; ++i)
1555 1644
     difftotal += map[i];
1556 1645
   for (y = 0; y < img->ysize; ++y) {
  1646
+    i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
1557 1647
     for (x = 0; x < img->xsize; ++x) {
1558  
-      i_color val;
1559  
-      i_gpix(img, x, y, &val);
1560  
-      val.rgba.a = g_sat(val.rgba.a-errp[x]/difftotal);
1561  
-      if (val.rgba.a < 128) {
  1648
+      line[x] = g_sat(line[x]-errp[x]/difftotal);
  1649
+      if (line[x] < 128) {
1562 1650
 	out = 0;
1563 1651
 	data[y*img->xsize+x] = trans_index;
1564 1652
       }
1565 1653
       else {
1566 1654
 	out = 255;
1567 1655
       }
1568  
-      error = out - val.rgba.a;
  1656
+      error = out - line[x];
1569 1657
       for (dx = 0; dx < mapw; ++dx) {
1570 1658
 	for (dy = 0; dy < maph; ++dy) {
1571 1659
 	  errp[x+dx-mapo+dy*errw] += error * map[dx+mapw*dy];
@@ -1577,6 +1665,8 @@ transparent_errdiff(i_quantize *quant, i_palidx *data, i_img *img,
1577 1665
       memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1578 1666
     memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1579 1667
   }
  1668
+  myfree(err);
  1669
+  myfree(line);
1580 1670
 }
1581 1671
 
1582 1672
 /* builtin ordered dither maps */
@@ -1690,16 +1780,21 @@ transparent_ordered(i_quantize *quant, i_palidx *data, i_img *img,
1690 1780
 {
1691 1781
   unsigned char *spot;
1692 1782
   int x, y;
  1783
+  i_sample_t *line;
  1784
+  int trans_chan = img->channels > 2 ? 3 : 1;
1693 1785
   if (quant->tr_orddith == od_custom)
1694 1786
     spot = quant->tr_custom;
1695 1787
   else
1696 1788
     spot = orddith_maps[quant->tr_orddith];
  1789
+
  1790
+  line = mymalloc(img->xsize * sizeof(i_sample_t));
1697 1791
   for (y = 0; y < img->ysize; ++y) {
  1792
+    i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
1698 1793
     for (x = 0; x < img->xsize; ++x) {
1699  
-      i_color val;
1700  
-      i_gpix(img, x, y, &val);
1701  
-      if (val.rgba.a < spot[(x&7)+(y&7)*8])
  1794
+      if (line[x] < spot[(x&7)+(y&7)*8])
1702 1795
 	data[x+y*img->xsize] = trans_index;
1703 1796
     }
1704 1797
   }
  1798
+  myfree(line);
1705 1799
 }
  1800
+
57  t/t105gif.t
... ...
@@ -1,7 +1,7 @@
1 1
 #!perl -w
2 2
 use strict;
3 3
 $|=1;
4  
-print "1..45\n";
  4
+print "1..60\n";
5 5
 use Imager qw(:all);
6 6
 
7 7
 sub ok ($$$);
@@ -468,6 +468,61 @@ EOS
468 468
       ok(45, !grep(/Obsolete .* interlace .* gif_interlace/, @warns),
469 469
         "check for warning");
470 470
     }
  471
+
  472
+    # test that we get greyscale from 1 channel images
  473
+    # we check for each makemap, and for each translate
  474
+    print "# test writes of grayscale images - ticket #365\n"; 
  475
+    my $num = 46;
  476
+    my $ooim = Imager->new(xsize=>50, ysize=>50, channels=>1);
  477
+    for (my $y = 0; $y < 50; $y += 10) {
  478
+      $ooim->box(box=>[ 0, $y, 49, $y+9], color=>NC($y*5,0,0), filled=>1);
  479
+    }
  480
+    my $ooim3 = $ooim->convert(preset=>'rgb');
  481
+    #$ooim3->write(file=>'testout/t105gray.ppm');
  482
+    my %maxerror = ( mediancut => 51000, 
  483
+                     addi => 0,
  484
+                     closest => 0,
  485
+                     perturb => 0,
  486
+                     errdiff => 0 );
  487
+    for my $makemap (qw(mediancut addi)) {
  488
+      print "# make_colors => $makemap\n";
  489
+      ok($num++, $ooim->write(file=>"testout/t105gray-$makemap.gif",
  490
+                              make_colors=>$makemap,
  491
+                              gifquant=>'gen'),
  492
+         "writing gif with makemap $makemap");
  493
+      my $im2 = Imager->new;
  494
+      if (ok($num++, $im2->read(file=>"testout/t105gray-$makemap.gif"),
  495
+             "reading written grayscale gif")) {
  496
+        my $diff = i_img_diff($ooim3->{IMG}, $im2->{IMG});
  497
+        ok($num++, $diff <= $maxerror{$makemap}, "comparing images $diff");
  498
+        #$im2->write(file=>"testout/t105gray-$makemap.ppm");
  499
+      }
  500
+      else {
  501
+        print "ok $num # skip\n";
  502
+        ++$num;
  503
+      }
  504
+    }
  505
+    for my $translate (qw(closest perturb errdiff)) {
  506
+      print "# translate => $translate\n";
  507
+      my @colors = map NC($_*50, $_*50, $_*50), 0..4;
  508
+      ok($num++, $ooim->write(file=>"testout/t105gray-$translate.gif",
  509
+                              translate=>$translate,
  510
+                              make_colors=>'none',
  511
+                              colors=>\@colors,
  512
+                              gifquant=>'gen'),
  513
+         "writing gif with translate $translate");
  514
+      my $im2 = Imager->new;
  515
+      if (ok($num++, $im2->read(file=>"testout/t105gray-$translate.gif"),
  516
+             "reading written grayscale gif")) {
  517
+        my $diff = i_img_diff($ooim3->{IMG}, $im2->{IMG});
  518
+        ok($num++, $diff <= $maxerror{$translate}, "comparing images $diff");
  519
+        #$im2->write(file=>"testout/t105gray-$translate.ppm");
  520
+      }
  521
+      else {
  522
+        print "ok $num # skip\n";
  523
+        ++$num;
  524
+      }
  525
+    }
471 526
 }
472 527
 
473 528
 sub ok ($$$) {

0 notes on commit 18accb2

Please sign in to comment.
Something went wrong with that request. Please try again.