From befe399a4e7e5b2cc44eacb08dea92a1c3489e9c Mon Sep 17 00:00:00 2001
From: "Mirar (Pontus Hagland)" <pike@sort.mirar.org>
Date: Wed, 15 Apr 1998 19:36:19 +0200
Subject: [PATCH] `==, `<, `>, average, min, max, sum, sumf, find_min, find_max
 added

Rev: src/modules/Image/image.c:1.98
Rev: src/modules/Image/image.h:1.20
Rev: src/modules/Image/operator.c:1.14
---
 src/modules/Image/image.c    |  36 ++-
 src/modules/Image/image.h    |  16 +-
 src/modules/Image/operator.c | 589 ++++++++++++++++++++++++++++++++++-
 3 files changed, 630 insertions(+), 11 deletions(-)

diff --git a/src/modules/Image/image.c b/src/modules/Image/image.c
index 318884c43b..d90e6cf22a 100644
--- a/src/modules/Image/image.c
+++ b/src/modules/Image/image.c
@@ -1,9 +1,9 @@
-/* $Id: image.c,v 1.97 1998/04/06 02:36:58 mirar Exp $ */
+/* $Id: image.c,v 1.98 1998/04/15 17:36:15 mirar Exp $ */
 
 /*
 **! module Image
 **! note
-**!	$Id: image.c,v 1.97 1998/04/06 02:36:58 mirar Exp $
+**!	$Id: image.c,v 1.98 1998/04/15 17:36:15 mirar Exp $
 **! class image
 **!
 **!	The main object of the <ref>Image</ref> module, this object
@@ -82,7 +82,7 @@
 
 #include "stralloc.h"
 #include "global.h"
-RCSID("$Id: image.c,v 1.97 1998/04/06 02:36:58 mirar Exp $");
+RCSID("$Id: image.c,v 1.98 1998/04/15 17:36:15 mirar Exp $");
 #include "pike_macros.h"
 #include "object.h"
 #include "constants.h"
@@ -3417,15 +3417,35 @@ void pike_module_init(void)
 		"function(:object)",0);
 
    add_function("`-",image_operator_minus,
-		"function(object|array(int):object)",0);
+		"function(object|array(int)|int:object)",0);
    add_function("`+",image_operator_plus,
-		"function(object|array(int):object)",0);
+		"function(object|array(int)|int:object)",0);
    add_function("`*",image_operator_multiply,
-		"function(object|array(int):object)",0);
+		"function(object|array(int)|int:object)",0);
    add_function("`&",image_operator_minimum,
-		"function(object|array(int):object)",0);
+		"function(object|array(int)|int:object)",0);
    add_function("`|",image_operator_maximum,
-		"function(object|array(int):object)",0);
+		"function(object|array(int)|int:object)",0);
+
+   add_function("`==",image_operator_equal,
+		"function(object|array(int)|int:int)",0);
+   add_function("`<",image_operator_lesser,
+		"function(object|array(int)|int:int)",0);
+   add_function("`>",image_operator_greater,
+		"function(object|array(int)|int:int)",0);
+
+   add_function("min",image_min,"function(:array(int))",0);
+   add_function("max",image_max,"function(:array(int))",0);
+   add_function("sum",image_sum,"function(:array(int))",0);
+   add_function("sumf",image_sumf,"function(:array(int))",0);
+   add_function("average",image_average,"function(:array(int))",0);
+
+   add_function("find_min",image_find_min,
+		"function(:array(int))|"
+		"function(int,int,int:array(int))",0);
+   add_function("find_max",image_find_max,
+		"function(:array(int))|"
+		"function(int,int,int:array(int))",0);
 		
    add_function("read_lsb_rgb",image_read_lsb_rgb,
 		"function(:object)",0);
diff --git a/src/modules/Image/image.h b/src/modules/Image/image.h
index c031c8b0a3..3440386a90 100644
--- a/src/modules/Image/image.h
+++ b/src/modules/Image/image.h
@@ -1,7 +1,7 @@
 /*
 **! module Image
 **! note
-**!	$Id: image.h,v 1.19 1998/03/11 20:44:50 mirar Exp $
+**!	$Id: image.h,v 1.20 1998/04/15 17:36:18 mirar Exp $
 */
 
 #ifdef PIKE_IMAGE_IMAGE_H
@@ -128,8 +128,22 @@ void image_operator_plus(INT32 args);
 void image_operator_multiply(INT32 args);
 void image_operator_maximum(INT32 args);
 void image_operator_minimum(INT32 args);
+
+void image_operator_equal(INT32 args);
+void image_operator_lesser(INT32 args);
+void image_operator_greater(INT32 args);
+
 void image_cast(INT32 args);
 
+void image_min(INT32 args);
+void image_max(INT32 args);
+void image_sum(INT32 args);
+void image_sumf(INT32 args);
+void image_average(INT32 args);
+
+void image_find_max(INT32 args);
+void image_find_min(INT32 args);
+
 /* x.c */
 
 void image_to8bit_closest(INT32 args);
diff --git a/src/modules/Image/operator.c b/src/modules/Image/operator.c
index 6b9a2bb365..ad05376e25 100644
--- a/src/modules/Image/operator.c
+++ b/src/modules/Image/operator.c
@@ -1,9 +1,9 @@
-/* $Id: operator.c,v 1.13 1998/01/25 10:13:49 mirar Exp $ */
+/* $Id: operator.c,v 1.14 1998/04/15 17:36:19 mirar Exp $ */
 
 /*
 **! module Image
 **! note
-**!	$Id: operator.c,v 1.13 1998/01/25 10:13:49 mirar Exp $
+**!	$Id: operator.c,v 1.14 1998/04/15 17:36:19 mirar Exp $
 **! class image
 */
 
@@ -303,3 +303,588 @@ STANDARD_OPERATOR_HEADER("`& 'minimum'")
 }
 
 
+/*
+**! method int `==(object operand)
+**! method int `==(array(int) color)
+**! method int `==(int value)
+**! method int `<(object operand)
+**! method int `<(array(int) color)
+**! method int `<(int value)
+**! method int `>(object operand)
+**! method int `>(array(int) color)
+**! method int `>(int value)
+**!	Compares an image with another image or a color.
+**!
+**!	Comparision is strict and on pixel-by-pixel basis. 
+**!	(Means if not all pixel r,g,b values are 
+**!	correct compared with the corresponding
+**!	pixel values, 0 is returned.)
+**!
+**! returns true (1) or false (0).
+**!
+**! arg object operand
+**!	the other image to compare with;
+**!	the images must have the same size.
+**! arg array(int) color
+**!	an array in format ({r,g,b}), this is equal
+**!	to using an uniform-colored image.
+**! arg int value
+**!	equal to ({value,value,value}).
+**!
+**! see also: `-, `+, `|, `*, `&
+**!	
+**! note:
+**!	`< or `> on empty ("no image") image objects or images
+**!	with different size will result in an error. 
+**!	`== is always true on two empty image objects and
+**!	always false if one and only one of the image objects
+**!	is empty or the images differs in size.
+**!
+**!	a>=b and a<=b between objects is equal to !(a<b) and !(a>b),
+**!	which may not be what you want (since both < and > can return
+**!	false, comparing the same images).
+*/
+
+void image_operator_equal(INT32 args)
+{
+   struct image *oper;
+   rgb_group *s1,*s2,rgb;
+   INT32 i;
+   int res=1;
+
+   if (args && sp[-args].type==T_INT)
+   {
+      rgb.r=sp[-args].u.integer;
+      rgb.g=sp[-args].u.integer;
+      rgb.b=sp[-args].u.integer;
+      oper=NULL;
+      if (!THIS->img)
+      {
+	 pop_n_elems(args);
+	 push_int(1); /* no image has all colors */
+	 return;
+      }
+   }
+   else if (args && sp[-args].type==T_ARRAY
+       && sp[-args].u.array->size>=3
+       && sp[-args].u.array->item[0].type==T_INT
+       && sp[-args].u.array->item[1].type==T_INT
+       && sp[-args].u.array->item[2].type==T_INT)
+   {
+      rgb.r=sp[-args].u.array->item[0].u.integer;
+      rgb.g=sp[-args].u.array->item[1].u.integer;
+      rgb.b=sp[-args].u.array->item[2].u.integer;
+      oper=NULL;
+      if (!THIS->img)
+      {
+	 pop_n_elems(args);
+	 push_int(1); /* no image has all colors */
+	 return;
+      }
+   }
+   else
+   {
+      if (args<1 || sp[-args].type!=T_OBJECT
+       || !sp[-args].u.object
+       || !(oper=(struct image*)get_storage(sp[-args].u.object,image_program)))
+	 error("`==: illegal argument 2\n");
+
+      if (!oper->img || !THIS->img)
+      {
+	 pop_n_elems(args);
+	 push_int(oper->img == THIS->img); /* 1 if NULL == NULL */
+	 return;
+      }
+      if (oper->xsize!=THIS->xsize
+          || oper->ysize!=THIS->ysize)
+      {
+	 pop_n_elems(args);
+	 push_int(0);
+	 return;
+      }
+   }
+
+   s1=THIS->img;
+   if (oper) s2=oper->img; else s2=NULL;
+
+   if (s1==s2)
+   {
+      pop_n_elems(args);
+      push_int(1);
+      return; /* same image is equal */
+   }
+
+   i=THIS->xsize*THIS->ysize;
+   THREADS_ALLOW();
+   if (s2)
+      while (i--)
+      {
+	 if (s1->r!=s1->r || s1->g!=s1->g || s1->b!=s1->b) { res=0; break; }
+	 s1++; s2++;
+      }
+   else
+      while (i--)
+      {
+	 if (s1->r!=rgb.r || s1->g!=rgb.g || s1->b!=rgb.b) { res=0; break; }
+	 s1++;
+      }
+   THREADS_DISALLOW();
+   pop_n_elems(args);
+   push_int(res);
+}
+
+void image_operator_lesser(INT32 args)
+{
+   struct image *oper;
+   rgb_group *s1,*s2,rgb;
+   INT32 i;
+   int res=1;
+
+   if (!THIS->img)
+      error("image->`<: operator 1 has no image\n");
+
+   if (args && sp[-args].type==T_INT)
+   {
+      rgb.r=sp[-args].u.integer;
+      rgb.g=sp[-args].u.integer;
+      rgb.b=sp[-args].u.integer;
+      oper=NULL;
+   }
+   else if (args && sp[-args].type==T_ARRAY
+       && sp[-args].u.array->size>=3
+       && sp[-args].u.array->item[0].type==T_INT
+       && sp[-args].u.array->item[1].type==T_INT
+       && sp[-args].u.array->item[2].type==T_INT)
+   {
+      rgb.r=sp[-args].u.array->item[0].u.integer;
+      rgb.g=sp[-args].u.array->item[1].u.integer;
+      rgb.b=sp[-args].u.array->item[2].u.integer;
+      oper=NULL;
+   }
+   else
+   {
+      if (args<1 || sp[-args].type!=T_OBJECT
+       || !sp[-args].u.object
+       || !(oper=(struct image*)get_storage(sp[-args].u.object,image_program)))
+	 error("`==: illegal argument 2\n");
+
+      if (!oper->img)
+	 error("image->`<: operator 2 has no image\n");
+      if (oper->xsize!=THIS->xsize
+          || oper->ysize!=THIS->ysize)
+	 error("image->`<: operators differ in size\n");
+   }
+
+   s1=THIS->img;
+   if (oper) s2=oper->img; else s2=NULL;
+
+   if (s1==s2)
+   {
+      pop_n_elems(args);
+      push_int(0);
+      return; /* same image is not less */
+   }
+
+   i=THIS->xsize*THIS->ysize;
+   THREADS_ALLOW();
+   if (s2)
+      while (i--)
+      {
+	 if (s1->r>=s1->r || s1->g>=s1->g || s1->b>=s1->b) { res=0; break; }
+	 s1++; s2++;
+      }
+   else
+      while (i--)
+      {
+	 if (s1->r>=rgb.r || s1->g>=rgb.g || s1->b>=rgb.b) { res=0; break; }
+	 s1++;
+      }
+   THREADS_DISALLOW();
+   pop_n_elems(args);
+   push_int(res);
+}
+
+
+void image_operator_greater(INT32 args)
+{
+   struct image *oper;
+   rgb_group *s1,*s2,rgb;
+   INT32 i;
+   int res=1;
+
+   if (!THIS->img)
+      error("image->`>: operator 1 has no image\n");
+
+   if (args && sp[-args].type==T_INT)
+   {
+      rgb.r=sp[-args].u.integer;
+      rgb.g=sp[-args].u.integer;
+      rgb.b=sp[-args].u.integer;
+      oper=NULL;
+   }
+   else if (args && sp[-args].type==T_ARRAY
+       && sp[-args].u.array->size>=3
+       && sp[-args].u.array->item[0].type==T_INT
+       && sp[-args].u.array->item[1].type==T_INT
+       && sp[-args].u.array->item[2].type==T_INT)
+   {
+      rgb.r=sp[-args].u.array->item[0].u.integer;
+      rgb.g=sp[-args].u.array->item[1].u.integer;
+      rgb.b=sp[-args].u.array->item[2].u.integer;
+      oper=NULL;
+   }
+   else
+   {
+      if (args<1 || sp[-args].type!=T_OBJECT
+       || !sp[-args].u.object
+       || !(oper=(struct image*)get_storage(sp[-args].u.object,image_program)))
+	 error("`==: illegal argument 2\n");
+
+      if (!oper->img)
+	 error("image->`>: operator 2 has no image\n");
+      if (oper->xsize!=THIS->xsize
+          || oper->ysize!=THIS->ysize)
+	 error("image->`>: operators differ in size\n");
+   }
+
+   s1=THIS->img;
+   if (oper) s2=oper->img; else s2=NULL;
+
+   if (s1==s2)
+   {
+      pop_n_elems(args);
+      push_int(0);
+      return; /* same image is not less */
+   }
+
+   i=THIS->xsize*THIS->ysize;
+   THREADS_ALLOW();
+   if (s2)
+      while (i--)
+      {
+	 if (s1->r<=s1->r || s1->g<=s1->g || s1->b<=s1->b) { res=0; break; }
+	 s1++; s2++;
+      }
+   else
+      while (i--)
+      {
+	 if (s1->r<=rgb.r || s1->g<=rgb.g || s1->b<=rgb.b) { res=0; break; }
+	 s1++;
+      }
+   THREADS_DISALLOW();
+   pop_n_elems(args);
+   push_int(res);
+}
+
+
+/*
+**! method array(float) average()
+**! method array(int) min()
+**! method array(int) max()
+**! method array(int) sum()
+**! method array(float) sumf()
+**!     Gives back the average, minimum, maximum color value, 
+**!	and the sum of all pixel's color value.
+**!
+**! note:
+**!	sum() values can wrap! Most systems only have 31 bits
+**!	available for positive integers. (Meaning, be careful 
+**!	with images that have more than 8425104 pixels.)
+**!
+**!	average() and sumf() may also wrap, but on a line basis.
+**!	(Meaning, be careful with images that are wider 
+**!      than 8425104 pixels.) These functions may have a precision
+**!	problem instead, during to limits in the 'double' C type and/or
+**!	'float' Pike type.
+*/
+
+void image_average(INT32 args)
+{
+   unsigned long x,y,xz;
+   struct { double r,g,b; } sumy={0.0,0.0,0.0};
+   rgb_group *s=THIS->img;
+
+   pop_n_elems(args);
+
+   if (!THIS->img)
+      error("Image.image->average(): no image\n");
+   if (!THIS->xsize || !THIS->ysize)
+      error("Image.image->average(): no pixels in image (division by zero)\n");
+
+   y=THIS->ysize;
+   xz=THIS->xsize;
+   THREADS_ALLOW();
+   while (y--)
+   {
+      rgbl_group sumx={0,0,0};
+      x=xz;
+      while (x--)
+      {
+	 sumx.r+=s->r;
+	 sumx.g+=s->g;
+	 sumx.b+=s->b;
+	 s++;
+      }
+      sumy.r+=((float)sumx.r)/(float)xz;
+      sumy.g+=((float)sumx.g)/(float)xz;
+      sumy.b+=((float)sumx.b)/(float)xz;
+   }
+   THREADS_DISALLOW();
+
+   push_float(sumy.r/(float)THIS->ysize);
+   push_float(sumy.g/(float)THIS->ysize);
+   push_float(sumy.b/(float)THIS->ysize);
+
+   f_aggregate(3);
+}
+
+
+void image_sumf(INT32 args)
+{
+   unsigned long x,y,xz;
+   struct { double r,g,b; } sumy={0.0,0.0,0.0};
+   rgb_group *s=THIS->img;
+
+   pop_n_elems(args);
+
+   if (!THIS->img)
+      error("Image.image->sumf(): no image\n");
+
+   y=THIS->ysize;
+   xz=THIS->xsize;
+   THREADS_ALLOW();
+   while (y--)
+   {
+      rgbl_group sumx={0,0,0};
+      x=xz;
+      while (x--)
+      {
+	 sumx.r+=s->r;
+	 sumx.g+=s->g;
+	 sumx.b+=s->b;
+	 s++;
+      }
+      sumy.r+=(float)sumx.r;
+      sumy.g+=(float)sumx.g;
+      sumy.b+=(float)sumx.b;
+   }
+   THREADS_DISALLOW();
+
+   push_float(sumy.r);
+   push_float(sumy.g);
+   push_float(sumy.b);
+
+   f_aggregate(3);
+}
+
+void image_sum(INT32 args)
+{
+   unsigned long n;
+   rgb_group *s=THIS->img;
+   rgbl_group sum={0,0,0};
+
+   pop_n_elems(args);
+
+   if (!THIS->img)
+      error("Image.image->sum(): no image\n");
+
+   n=THIS->ysize*THIS->xsize;
+   THREADS_ALLOW();
+   while (n--)
+   {
+      sum.r+=s->r;
+      sum.g+=s->g;
+      sum.b+=s->b;
+      s++;
+   }
+   THREADS_DISALLOW();
+
+   push_int(sum.r);
+   push_int(sum.g);
+   push_int(sum.b);
+
+   f_aggregate(3);
+}
+
+void image_min(INT32 args)
+{
+   unsigned long n;
+   rgb_group *s=THIS->img;
+   rgb_group x={255,255,255};
+
+   pop_n_elems(args);
+
+   if (!THIS->img)
+      error("Image.image->min(): no image\n");
+
+   n=THIS->ysize*THIS->xsize;
+   THREADS_ALLOW();
+   while (n--)
+   {
+      if (x.r>s->r) x.r=s->r;
+      if (x.g>s->g) x.g=s->g;
+      if (x.b>s->b) x.b=s->b;
+      s++;
+   }
+   THREADS_DISALLOW();
+
+   push_int(x.r);
+   push_int(x.g);
+   push_int(x.b);
+
+   f_aggregate(3);
+}
+
+void image_max(INT32 args)
+{
+   unsigned long n;
+   rgb_group *s=THIS->img;
+   rgb_group x={0,0,0};
+
+   pop_n_elems(args);
+
+   if (!THIS->img)
+      error("Image.image->max(): no image\n");
+
+   n=THIS->ysize*THIS->xsize;
+   THREADS_ALLOW();
+   while (n--)
+   {
+      if (x.r<s->r) x.r=s->r;
+      if (x.g<s->g) x.g=s->g;
+      if (x.b<s->b) x.b=s->b;
+      s++;
+   }
+   THREADS_DISALLOW();
+
+   push_int(x.r);
+   push_int(x.g);
+   push_int(x.b);
+
+   f_aggregate(3);
+}
+
+
+/*
+**! method array(int) find_min()
+**! method array(int) find_max()
+**! method array(int) find_min(int r,int g,int b)
+**! method array(int) find_max(int r,int g,int b)
+**!     Gives back the position of the minimum or maximum
+**!	pixel value, weighted to grey.
+**!
+**! arg int r
+**! arg int g
+**! arg int b
+**!     weight of color, default is r=87,g=127,b=41, same
+**!	as the <ref>grey</ref>() method.
+*/
+
+static INLINE void getrgbl(rgbl_group *rgb,INT32 args_start,INT32 args,char *name)
+{
+   INT32 i;
+   if (args-args_start<3) return;
+   for (i=0; i<3; i++)
+      if (sp[-args+i+args_start].type!=T_INT)
+         error("Illegal r,g,b argument to %s\n",name);
+   rgb->r=sp[-args+args_start].u.integer;
+   rgb->g=sp[1-args+args_start].u.integer;
+   rgb->b=sp[2-args+args_start].u.integer;
+}
+
+void image_find_min(INT32 args)
+{
+   unsigned long x,y,xz,xp=0,yp=0,yz;
+   rgb_group *s=THIS->img;
+   rgbl_group rgb;
+   double div,min;
+
+   if (args<3)
+   {
+      rgb.r=87;
+      rgb.g=127;
+      rgb.b=41;
+   }
+   else
+      getrgbl(&rgb,0,args,"Image.image->find_min()");
+   if (rgb.r||rgb.g||rgb.b)
+      div=1.0/(rgb.r+rgb.g+rgb.b);
+   else
+      div=1.0;
+   
+   pop_n_elems(args);
+
+   if (!THIS->img)
+      error("Image.image->find_min(): no image\n");
+   if (!THIS->xsize || !THIS->ysize)
+      error("Image.image->find_min(): no pixels in image (none to find)\n");
+
+   yz=THIS->ysize;
+   xz=THIS->xsize;
+   min=(rgb.r+rgb.g+rgb.b)*256.0;
+   THREADS_ALLOW();
+   for (y=0; y<yz; y++)
+   {
+      for (x=0; x<xz; x++)
+      {
+	 double val=(s->r*rgb.r+s->g*rgb.g+s->b*rgb.b)*div;
+	 if (val<min) xp=x,yp=y,min=val;
+	 s++;
+      }
+   }
+   THREADS_DISALLOW();
+
+   push_int(xp);
+   push_int(yp);
+
+   f_aggregate(2);
+}
+
+void image_find_max(INT32 args)
+{
+   unsigned long x,y,xz,xp=0,yp=0,yz;
+   rgb_group *s=THIS->img;
+   rgbl_group rgb;
+   double div,max;
+
+   if (args<3)
+   {
+      rgb.r=87;
+      rgb.g=127;
+      rgb.b=41;
+   }
+   else
+      getrgbl(&rgb,0,args,"Image.image->find_max()");
+   if (rgb.r||rgb.g||rgb.b)
+      div=1.0/(rgb.r+rgb.g+rgb.b);
+   else
+      div=1.0;
+   
+   pop_n_elems(args);
+
+   if (!THIS->img)
+      error("Image.image->find_max(): no image\n");
+   if (!THIS->xsize || !THIS->ysize)
+      error("Image.image->find_max(): no pixels in image (none to find)\n");
+
+   yz=THIS->ysize;
+   xz=THIS->xsize;
+   max=0.0;
+   THREADS_ALLOW();
+   for (y=0; y<yz; y++)
+   {
+      for (x=0; x<xz; x++)
+      {
+	 double val=(s->r*rgb.r+s->g*rgb.g+s->b*rgb.b)*div;
+	 if (val>max) xp=x,yp=y,max=val;
+	 s++;
+      }
+   }
+   THREADS_DISALLOW();
+
+   push_int(xp);
+   push_int(yp);
+
+   f_aggregate(2);
+}
+
-- 
GitLab