
#include "p.image.h"

@begin
   header "image.h";
@end

/*
 * methods of structure img_3ub_s
 */

/*
 * loading of image from bitmap file
 */

bool img_3ub_s::load_bmp_file(const char *file)
{
   if (file == NULL) return false;

   bmp_fh_s bmp_fh;
   bmp_ih_s bmp_ih;
   unsigned char *bmp_data;

   FILE *f = fopen(file,"rb");
   if (f == NULL) return false;

   fread(&bmp_fh,sizeof(bmp_fh_s),1,f);
   fread(&bmp_ih,sizeof(bmp_ih_s),1,f);

   if (bmp_ih.width == 0 || bmp_ih.height == 0) {
      fclose(f);
      return false;
   }

   unsigned line_off = (bmp_ih.width*3)%4;
   if (line_off != 0) {
      line_off = 4 - line_off;
   }

   unsigned bmp_data_size = (bmp_ih.width*3 + line_off)*bmp_ih.height;

   bmp_data = (unsigned char *)cmalloc(bmp_data_size);
   fread(bmp_data,bmp_data_size,1,f);

   fclose(f);

   create(bmp_ih.width,bmp_ih.height);

   unsigned char *ptr = data;
   unsigned char *ptr_end = ptr + width*height*3;
   unsigned char *b_ptr = bmp_data;
   unsigned widthk3 = width*3;

   do {
      unsigned char *w_ptr_end = ptr + widthk3;
      do {
	 
	 register unsigned char *r = ptr;
	 register unsigned char *r1 = b_ptr;

	 r[0] = r1[2];
	 r[1] = r1[1];
	 r[2] = r1[0];

      } while(b_ptr += 3,(ptr += 3) < w_ptr_end);

      b_ptr += line_off;
   } while(ptr < ptr_end);

   cfree(bmp_data);

   return true;
}

/*
 * saving of image to bitmap file
 */

bool img_3ub_s::save_bmp_file(const char *file)
{
   if (file == NULL || data == NULL) return false;

   bmp_fh_s bmp_fh;
   bmp_ih_s bmp_ih;
   unsigned char *bmp_data;

   unsigned line_off = (width*3)%4;
   if (line_off != 0) {
      line_off = 4 - line_off;
   }

   unsigned bmp_data_size = (width*3 + line_off)*height;

   bmp_fh.type = 19778;
   bmp_fh.size = bmp_data_size + sizeof(bmp_fh_s) + sizeof(bmp_ih_s);
   bmp_fh.res_1 = 0;
   bmp_fh.res_2 = 0;
   bmp_fh.off_bits = sizeof(bmp_fh_s) + sizeof(bmp_ih_s);

   bmp_ih.size = sizeof(bmp_ih_s);
   bmp_ih.width = width;
   bmp_ih.height = height;
   bmp_ih.planes = 1;
   bmp_ih.bit_cnt = 24;
   bmp_ih.compression = 0;
   bmp_ih.image_size = 0;
   bmp_ih.x_pel_per_meter = 0;
   bmp_ih.y_pel_per_meter = 0;
   bmp_ih.clr_used = 0;
   bmp_ih.clr_important = 0;

   bmp_data = (unsigned char *)cmalloc(bmp_data_size);

   unsigned char *ptr = data;
   unsigned char *ptr_end = ptr + width*height*3;
   unsigned char *b_ptr = bmp_data;
   unsigned widthk3 = width*3;

   do {
      unsigned char *w_ptr_end = ptr + widthk3;
      do {
	 
	 register unsigned char *r = ptr;
	 register unsigned char *r1 = b_ptr;

	 r1[0] = r[2];
	 r1[1] = r[1];
	 r1[2] = r[0];

      } while(b_ptr += 3,(ptr += 3) < w_ptr_end);

      b_ptr += line_off;
   } while(ptr < ptr_end);

   FILE *f = fopen(file,"wb");
   if (f == NULL) {
      cfree(bmp_data);
      return false;
   }

   fwrite(&bmp_fh,sizeof(bmp_fh_s),1,f);
   fwrite(&bmp_ih,sizeof(bmp_ih_s),1,f);
   fwrite(bmp_data,bmp_data_size,1,f);

   fclose(f);

   cfree(bmp_data);

   return true;
}

/*
 * setting all pixels in image to parameter color
 */
bool img_3ub_s::fill_color(short *color_ptr)
{
   if (data == NULL) return false;

   unsigned char *ptr = data;
   unsigned char *ptr_end = ptr + width*height*3;

   do {
      
      register unsigned char *r = ptr;
      register short *r1 = color_ptr;

      r[0] = r1[0];
      r[1] = r1[1];
      r[2] = r1[2];

   } while((ptr += 3) < ptr_end);

   return true;
}

/*
 * inverting colors of all pixels in image
 */

bool img_3ub_s::invert(img_3ub_s &src)
{
   if (src.data == NULL) return false;

   create(src.width,src.height);

   unsigned char *ptr = data;
   unsigned char *ptr_end = ptr + width*height*3;
   unsigned char *s_ptr = src.data;

   do {
      
      register unsigned char *r = ptr;
      register unsigned char *r1 = s_ptr;

      r[0] = 255 - r1[0];
      r[1] = 255 - r1[1];
      r[2] = 255 - r1[2];

   } while(s_ptr += 3,(ptr += 3) < ptr_end);

   return true;
}

bool img_3ub_s::gray_scale(img_3ub_s &src)
{
   if (src.data == NULL) return false;

   create(src.width,src.height);

   unsigned char *ptr = data;
   unsigned char *ptr_end = ptr + width*height*3;
   unsigned char *s_ptr = src.data;

   do {
      
      register unsigned char *r = ptr;
      register unsigned char *r1 = s_ptr;

      unsigned char gray = (unsigned char)((r1[0] * 0.299) + (r1[1] * 0.587) + (r1[2] * 0.114));

      r[0] = gray;
      r[1] = gray;
      r[2] = gray;

   } while(s_ptr += 3,(ptr += 3) < ptr_end);

   return true;
}


bool img_3ub_s::edge_sobel(img_3ub_s &src)
{
   if (src.data == NULL) return false;

   create(src.width,src.height);

   unsigned widthk3 = width*3;
   unsigned char *ptr = data + widthk3 + 3;
   unsigned char *ptr_end = data + height*widthk3 - widthk3 - 3;
   unsigned char *s_ptr = src.data + widthk3 + 3;

   do {
      unsigned char *ptr_w_end = ptr + widthk3 - 6;

      do {
	 int v_res;
	 int h_res;
	 int res;

	 // - red color -
	 {
	    register unsigned char *r = s_ptr;

	    v_res = r[-widthk3-3] + r[-3] + r[widthk3-3] - r[-widthk3+3] - r[3] - r[widthk3+3];
	    h_res = r[-widthk3-3] + r[-widthk3] + r[-widthk3+3] - r[widthk3-3] - r[widthk3] - r[widthk3+3];
	 }

	 if (v_res < 0) v_res = -v_res;
	 if (h_res < 0) h_res = -h_res;

	 res = v_res + h_res;

	 if (res > 255) ptr[0] = 255;
	 else ptr[0] = res;

	 // - green color -
	 {
	    register unsigned char *r = s_ptr + 1;

	    v_res = r[-widthk3-3] + r[-3] + r[widthk3-3] - r[-widthk3+3] - r[3] - r[widthk3+3];
	    h_res = r[-widthk3-3] + r[-widthk3] + r[-widthk3+3] - r[widthk3-3] - r[widthk3] - r[widthk3+3];
	 }

	 if (v_res < 0) v_res = -v_res;
	 if (h_res < 0) h_res = -h_res;

	 res = v_res + h_res;

	 if (res > 255) ptr[1] = 255;
	 else ptr[1] = res;

	 // - red color -
	 {
	    register unsigned char *r = s_ptr + 2;

	    v_res = r[-widthk3-3] + r[-3] + r[widthk3-3] - r[-widthk3+3] - r[3] - r[widthk3+3];
	    h_res = r[-widthk3-3] + r[-widthk3] + r[-widthk3+3] - r[widthk3-3] - r[widthk3] - r[widthk3+3];
	 }

	 if (v_res < 0) v_res = -v_res;
	 if (h_res < 0) h_res = -h_res;

	 res = v_res + h_res;

	 if (res > 255) ptr[2] = 255;
	 else ptr[2] = res;

      } while(s_ptr += 3,(ptr += 3) < ptr_w_end);

      s_ptr += 6;
      ptr += 6;

   } while(ptr < ptr_end);

   return true;
}


bool img_3ub_s::blur(img_3ub_s &src)
{
   if (src.data == NULL) return false;

   create(src.width,src.height);

   unsigned widthk3 = width*3;
   unsigned char *ptr = data + widthk3 + 3;
   unsigned char *ptr_end = data + height*widthk3 - widthk3 - 3;
   unsigned char *s_ptr = src.data + widthk3 + 3;

   do {
      
      unsigned char *ptr_w_end = ptr + widthk3 - 6;

      do {
	 register unsigned res;
	 register unsigned char *r = s_ptr;
	 register unsigned char *r1 = ptr;

	 res = r[-widthk3-3] + r[-widthk3] + r[-widthk3+3] + r[-3] + r[0] + r[3] + r[widthk3-3] + r[widthk3] + r[widthk3+3];
	 r1[0] = res/9;

	 res = r[-widthk3-2] + r[-widthk3+1] + r[-widthk3+4] + r[-2] + r[1] + r[4] + r[widthk3-2] + r[widthk3+1] + r[widthk3+4     ];     
	 r1[1] = res/9;

	 res = r[-widthk3-1] + r[-widthk3+2] + r[-widthk3+5] + r[-1] + r[2] + r[4] + r[widthk3-1] + r[widthk3+2] + r[widthk3+5     ];     
	 r1[2] = res/9;

      } while(s_ptr += 3,(ptr += 3) < ptr_w_end);

      s_ptr += 6;
      ptr += 6;

   } while(ptr < ptr_end);

   return true;
}

bool img_3ub_s::sharp(img_3ub_s &src)
{
   if (src.data == NULL) return false;

   create(src.width,src.height);

   unsigned widthk3 = width*3;
   unsigned char *ptr = data + widthk3 + 3;
   unsigned char *ptr_end = data + height*widthk3 - widthk3 - 3;
   unsigned char *s_ptr = src.data + widthk3 + 3;

   do {
      unsigned char *ptr_w_end = ptr + widthk3 - 6;

      do {
	 int res[3];

	 {
	    register unsigned char *r = s_ptr;
	    register int *r1 = res;

	    r1[0] = 5*r[0] - r[-widthk3] - r[widthk3] - r[-3] - r[3];
	    r1[1] = 5*r[1] - r[-widthk3+1] - r[widthk3+1] - r[-2] - r[4];
	    r1[2] = 5*r[2] - r[-widthk3+2] - r[widthk3+2] - r[-1] - r[5];
	 }

	 if (res[0] < 0) ptr[0] = 0;
	 else if (res[0] > 255) ptr[0] = 255;
	 else ptr[0] = res[0];

	 if (res[1] < 0) ptr[1] = 0;
	 else if (res[1] > 255) ptr[1] = 255;
	 else ptr[1] = res[1];

	 if (res[2] < 0) ptr[2] = 0;
	 else if (res[2] > 255) ptr[2] = 255;
	 else ptr[2] = res[2];

      } while(s_ptr += 3,(ptr += 3) < ptr_w_end);

      s_ptr += 6;
      ptr += 6;

   } while(ptr < ptr_end);

   return true;
}

bool img_3ub_s::treshold(img_3ub_s &src,short *color_ptr)
{
   if (src.data == NULL) return false;

   create(src.width,src.height);

   unsigned char *ptr = data;
   unsigned char *ptr_end = ptr + height*width*3;
   unsigned char *s_ptr = src.data;

   do {

      if (s_ptr[0] < color_ptr[0]) ptr[0] = 0;
      else ptr[0] = 255;

      if (s_ptr[1] < color_ptr[1]) ptr[1] = 0;
      else ptr[1] = 255;

      if (s_ptr[2] < color_ptr[2]) ptr[2] = 0;
      else ptr[2] = 255;

   } while(s_ptr += 3,(ptr += 3) < ptr_end);

   return true;
}

bool img_3ub_s::resize_width_up(img_3ub_s &src,unsigned a_width)
{
   if (src.data == NULL || a_width <= src.width) return false;

   create(a_width,src.height);

   unsigned s_widthm1 = src.width - 1;
   unsigned widthk3 = width*3;

   unsigned char *ptr = data;
   unsigned char *ptr_end = ptr + height*widthk3;
   unsigned char *s_ptr = src.data;

   do {
      unsigned char *ptr_w_end = ptr + widthk3;
      unsigned cnt = 0;
      
      do {
	 unsigned neg_cnt = width - cnt;

	 ptr[0] = (s_ptr[0]*neg_cnt)/width + (s_ptr[3]*cnt)/width;
	 ptr[1] = (s_ptr[1]*neg_cnt)/width + (s_ptr[4]*cnt)/width;
	 ptr[2] = (s_ptr[2]*neg_cnt)/width + (s_ptr[5]*cnt)/width;

	 cnt += s_widthm1;
	 if (cnt >= width) {
	    s_ptr += 3;
	    cnt -= width;
	 }

      } while((ptr += 3) < ptr_w_end);

      s_ptr += 3;
   } while(ptr < ptr_end);

   return true;
}

bool img_3ub_s::resize_height_up(img_3ub_s &src,unsigned a_height)
{
   if (src.data == NULL || a_height <= src.height) return false;

   create(src.width,a_height);

   unsigned widthk3 = width*3;
   unsigned s_widthk3 = src.width*3;
   unsigned s_heightm1 = src.height - 1;

   unsigned char *ptr = data;
   unsigned char *ptr_end = data + height*widthk3;
   unsigned char *s_ptr = src.data;

   unsigned cnt = 0;

   do {
      unsigned char *ptr_w_end = ptr + widthk3;
      unsigned neg_cnt = height - cnt;

      do {
	 ptr[0] = (s_ptr[0]*neg_cnt)/height + (s_ptr[s_widthk3]*cnt)/height;
	 ptr[1] = (s_ptr[1]*neg_cnt)/height + (s_ptr[s_widthk3+1]*cnt)/height;
	 ptr[2] = (s_ptr[2]*neg_cnt)/height + (s_ptr[s_widthk3+2]*cnt)/height;

      } while(s_ptr += 3,(ptr += 3) < ptr_w_end);

      cnt += s_heightm1;
      if (cnt >= height) {
	 cnt -= height;
      }
      else {
	 s_ptr -= widthk3;
      }

   } while(ptr < ptr_end);

   return true;
}

bool img_3ub_s::resize_width_down(img_3ub_s &src,unsigned a_width)
{
   //TODO
   return false;
}

bool img_3ub_s::resize_height_down(img_3ub_s &src,unsigned a_height)
{
   //TODO
   return false;
}

bool img_3ub_s::resize(img_3ub_s &src,unsigned a_width,unsigned a_height)
{
   //TODO
   return false;
}

/*
 * adding of colors of two images
 */

bool img_3ub_s::add(img_3ub_s &first,img_3ub_s &second)
{
   if (first.data == NULL || second.data == NULL || first.width != second.width || first.height != second.height) {
      return false;
   }

   create(first.width,first.height);

   unsigned char *ptr = data;
   unsigned char *ptr_end = ptr + width*height*3;
   unsigned char *f_ptr = first.data;
   unsigned char *s_ptr = second.data;
   int res;

   do {
      res = f_ptr[0] + s_ptr[0];
      if (res > 255) ptr[0] = 255;
      else ptr[0] = res;

      res = f_ptr[1] + s_ptr[1];
      if (res > 255) ptr[1] = 255;
      else ptr[1] = res;

      res = f_ptr[2] + s_ptr[2];
      if (res > 255) ptr[2] = 255;
      else ptr[2] = res;

   } while(f_ptr += 3,s_ptr += 3,(ptr += 3) < ptr_end);

   return true;
}

/*
 * compute difference of colors of all pixels in two images
 */

bool img_3ub_s::sub(img_3ub_s &first,img_3ub_s &second)
{
   if (first.data == NULL || second.data == NULL || first.width != second.width || first.height != second.height) {
      return false;
   }

   create(first.width,first.height);

   unsigned char *ptr = data;
   unsigned char *ptr_end = ptr + width*height*3;
   unsigned char *f_ptr = first.data;
   unsigned char *s_ptr = second.data;
   int res;

   do {
      res = f_ptr[0] - s_ptr[0];
      if (res < 0) ptr[0] = 0;
      else ptr[0] = res;

      res = f_ptr[1] - s_ptr[1];
      if (res < 0) ptr[1] = 0;
      else ptr[1] = res;

      res = f_ptr[2] - s_ptr[2];
      if (res < 0) ptr[2] = 0;
      else ptr[2] = res;

   } while(f_ptr += 3,s_ptr += 3,(ptr += 3) < ptr_end);

   return true;
}

/*
 * multiply colors of all pixels of two images
 */

bool img_3ub_s::mul(img_3ub_s &first,img_3ub_s &second)
{
   if (first.data == NULL || second.data == NULL || first.width != second.width || first.height != second.height) {
      return false;
   }

   create(first.width,first.height);

   unsigned char *ptr = data;
   unsigned char *ptr_end = ptr + width*height*3;
   unsigned char *f_ptr = first.data;
   unsigned char *s_ptr = second.data;

   do {
      
      register unsigned char *r = ptr;
      register unsigned char *r1 = f_ptr;
      register unsigned char *r2 = s_ptr;

      r[0] = (r1[0] * r2[0])/255;
      r[1] = (r1[1] * r2[1])/255;
      r[2] = (r1[2] * r2[2])/255;

   } while(f_ptr += 3,s_ptr += 3,(ptr += 3) < ptr_end);

   return true;
}

/*
 * adding of constant value to colors of image pixels
 */

bool img_3ub_s::add_color(img_3ub_s &src,short *color_ptr)
{
   if (src.data == NULL) return false;

   create(src.width,src.height);

   unsigned char *ptr = data;
   unsigned char *ptr_end = ptr + width*height*3;
   unsigned char *s_ptr = src.data;
   int res;

   do {
      res = s_ptr[0] + color_ptr[0];
      if (res > 255) ptr[0] = 255;
      else ptr[0] = res;

      res = s_ptr[1] + color_ptr[1];
      if (res > 255) ptr[1] = 255;
      else ptr[1] = res;

      res = s_ptr[2] + color_ptr[2];
      if (res > 255) ptr[2] = 255;
      else ptr[2] = res;

   } while(s_ptr += 3,(ptr += 3) < ptr_end);

   return true;
}

/*
 * substract constant color from colors of all image pixels
 */

bool img_3ub_s::sub_color(img_3ub_s &src,short *color_ptr)
{
   if (src.data == NULL) return false;

   create(src.width,src.height);

   unsigned char *ptr = data;
   unsigned char *ptr_end = ptr + width*height*3;
   unsigned char *s_ptr = src.data;
   int res;

   do {
      res = s_ptr[0] - color_ptr[0];
      if (res < 0) ptr[0] = 0;
      else ptr[0] = res;

      res = s_ptr[1] - color_ptr[1];
      if (res < 0) ptr[1] = 0;
      else ptr[1] = res;

      res = s_ptr[2] - color_ptr[2];
      if (res < 0) ptr[2] = 0;
      else ptr[2] = res;

   } while(s_ptr += 3,(ptr += 3) < ptr_end);

   return true;
}

/*
 * multiply colors of pixels by constant color
 */

bool img_3ub_s::mul_color(img_3ub_s &src,short *color_ptr)
{
   if (src.data == NULL) return false;

   create(src.width,src.height);

   unsigned char *ptr = data;
   unsigned char *ptr_end = ptr + width*height*3;
   unsigned char *s_ptr = src.data;

   do {

      register unsigned char *r = ptr;
      register unsigned char *r1 = s_ptr;
      register short *r2 = color_ptr;

      r[0] = (r1[0] * r2[0])/255;
      r[1] = (r1[1] * r2[1])/255;
      r[2] = (r1[2] * r2[2])/255;

   } while(s_ptr += 3,(ptr += 3) < ptr_end);

   return true;
}

