The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
MODULE = IUP::Canvas::Bitmap        PACKAGE = IUP::Canvas::Bitmap   PREFIX = __Bitmap__

IUP::Canvas::Bitmap
__Bitmap__new(CLASS,...)
                char *CLASS
        INIT:
                cdBitmap * b;
                int w, h, type, error;
                int wr, hr, wg, hg, wb, hb, wa, ha, wi, hi, wc, hc;
                unsigned char *data_r=NULL, *data_g=NULL, *data_b=NULL, *data_a=NULL;
                unsigned char *index=NULL;
                long *colors=NULL;
                long *colors256=NULL;
                int color_count;
        CODE:
                b = NULL;
                if (items==2) {
                  /* warn("XXX-DEBUG: IUP::Canvas::Bitmap->new($file)"); */
                  b = BitmapFromFile(SvPV_nolen(ST(1)));                  
                }
                else if (items==3 && !SvROK(ST(1))
                                  && SvROK(ST(2)) && SvTYPE(SvRV(ST(2)))==SVt_PVAV) {
                  /* warn("XXX-DEBUG: IUP::Canvas::Bitmap->new($type, $pixels)"); */
                  type = SvIV(ST(1));
                  if (type==CD_RGBA) {
                    if (!AV2bitmap(ST(2),&data_r,&data_g,&data_b,&data_a,&w,&h)) XSRETURN_UNDEF;
                    b = cdInitBitmap(w, h, type, data_r, data_g, data_b, data_a);
                  }
                  else if (type==CD_RGB) {
                    if (!AV2bitmap(ST(2),&data_r,&data_g,&data_b,NULL,&w,&h)) XSRETURN_UNDEF;
                    b = cdInitBitmap(w, h, type, data_r, data_g, data_b);
                  }
                  else {
                    XSRETURN_UNDEF;
                  }
                }
                else if (items==4 && SvROK(ST(2)) && SvTYPE(SvRV(ST(2)))==SVt_PVAV
                                  && SvROK(ST(3)) && SvTYPE(SvRV(ST(3)))==SVt_PVAV) {
                  /* warn("XXX-DEBUG: IUP::Canvas::Bitmap->new($type, $pixels, $palette)"); */
                  type = SvIV(ST(1));                  
                  if (type!=CD_MAP) XSRETURN_UNDEF;
                  error = 0;
                  colors256 = malloc(sizeof(long)*256);
                  if (!colors256) error=1;
                  if (!AV2uchar2D(ST(2),&index,&w,&h)) error=1;
                  if (!AV2long(ST(3),&colors,&color_count)) error=1;
                  if (error) {
                    if (index) free(index);
                    if (colors) free(colors);
                    if (colors256) free(colors256);
                    XSRETURN_UNDEF;
                  }
                  /* palette buffer passed to cdInitBitmap has to be 256 colors long */                  
                  memset(colors256, 0, sizeof(long)*256);
                  if (color_count>256) color_count = 256;
                  memcpy(colors256, colors, sizeof(long)*color_count);
                  free(colors);                  
                  b = cdInitBitmap(w, h, type, index, colors256);
                }
                else if (items==4) {
                  /*warn("XXX-DEBUG: IUP::Canvas::Bitmap->new($type, $width, $height)");*/
                  type = SvIV(ST(1));
                  w = SvIV(ST(2));
                  h = SvIV(ST(3));                  
                  if (w<=0 || h<=0) XSRETURN_UNDEF;
                  /*warn("XXX-DEBUG: w=%d h=%d type=%d b=%p\n",w,h,type,b);*/
                  b = cdCreateBitmap(w, h, type);
                  /*warn("XXX-DEBUG: w=%d h=%d type=%d b=%p\n",w,h,type,b);*/
                }
                else {
                  warn("Error: invalid parameters for IUP::Canvas::Bitmap->new()");
                }
                /* check if we have consistent data */
                RETVAL = NULL;
                if (b) {
                  data_r = cdBitmapGetData(b, CD_IRED);
                  data_g = cdBitmapGetData(b, CD_IGREEN);
                  data_b = cdBitmapGetData(b, CD_IBLUE);
                  data_a = cdBitmapGetData(b, CD_IALPHA);
                  index  = cdBitmapGetData(b, CD_INDEX);
                  colors = (long*)cdBitmapGetData(b, CD_COLORS);
                  if (b->type==CD_RGBA && data_r && data_g && data_b && data_a) RETVAL = b;
                  if (b->type==CD_RGB && data_r && data_g && data_b) RETVAL = b;
                  if (b->type==CD_MAP && index && colors) RETVAL = b;
                  if (!RETVAL) {
                    warn("Error: image data not loaded correctly");
                    cdKillBitmap(b);
                  }
                }
        OUTPUT:
                RETVAL

void
__Bitmap__SetRect(self,xmin,xmax,ymin,ymax)
                IUP::Canvas::Bitmap self;
                int xmin;
                int xmax;
                int ymin;
                int ymax;
        CODE:
                cdBitmapSetRect(self,xmin,xmax,ymin,ymax);

IUP::Canvas::Bitmap
__Bitmap__RGB2Map(self)
                IUP::Canvas::Bitmap self;
        PREINIT:
                /* char *CLASS = "IUP::Canvas::Bitmap"; / * XXX-CHECKLATER ugly hack to handle return value conversion */
                unsigned char* index;
                long* colors;
        CODE:
                index = malloc(sizeof(unsigned char)*self->w*self->h);
                colors = malloc(sizeof(long)*256);
                if (!index || !colors) {
                  if (index) free(index);
                  if (colors) free(colors);
                  XSRETURN_UNDEF;
                }
                RETVAL = cdInitBitmap(self->w, self->h, CD_MAP, index, colors);
                if (!RETVAL) XSRETURN_UNDEF;
                cdBitmapRGB2Map(self,RETVAL);
        OUTPUT:
                RETVAL

int
__Bitmap__Width(self)
                IUP::Canvas::Bitmap self;
        CODE:
                RETVAL = self->w;
        OUTPUT:
                RETVAL

int
__Bitmap__Height(self)
                IUP::Canvas::Bitmap self;
        CODE:
                RETVAL = self->h;
        OUTPUT:
                RETVAL

int
__Bitmap__Type(self)
                IUP::Canvas::Bitmap self;
        CODE:
                RETVAL = self->type;
        OUTPUT:
                RETVAL

SV*
__Bitmap__Data(self)
                IUP::Canvas::Bitmap self;
        PREINIT:
                unsigned char *r, *g, *b, *a, *m;
        CODE:
                /* warn("XXX-DEBUG: Bitmap->Data type=%d, w=%d h=%d\n",self->type,self->w,self->h); */
                if (self->type == CD_RGBA) {
                  /* warn("XXX-DEBUG: Bitmap->Data RGBA 1\n"); */
                  r = cdBitmapGetData(self, CD_IRED);
                                  g = cdBitmapGetData(self, CD_IGREEN);
                  b = cdBitmapGetData(self, CD_IBLUE);
                  a = cdBitmapGetData(self, CD_IALPHA);
                  /* warn("XXX-DEBUG: Bitmap->Data RGBA 2 r=%p g=%p b=%p a=%p\n",r,g,b,a); */
                  if (!r || !g || !b || !a) XSRETURN_UNDEF;
                  /* warn("XXX-DEBUG: Bitmap->Data RGBA 3\n"); */
                  RETVAL = Bitmap2AV(r,g,b,a,NULL,self->w,self->h);
                }
                else if (self->type == CD_RGB) {
                  r = cdBitmapGetData(self, CD_IRED);
                  g = cdBitmapGetData(self, CD_IGREEN);
                  b = cdBitmapGetData(self, CD_IBLUE);
                  if (!r || !g || !b) XSRETURN_UNDEF;
                  RETVAL = Bitmap2AV(r,g,b,NULL,NULL,self->w,self->h);
                }
                else if (self->type == CD_MAP) {
                  m = cdBitmapGetData(self, CD_INDEX);
                  if (!m) XSRETURN_UNDEF;
                  RETVAL = Bitmap2AV(NULL,NULL,NULL,NULL,m,self->w,self->h);
                }
                else XSRETURN_UNDEF;
        OUTPUT:
                RETVAL

SV*
__Bitmap__Palette(self)
                IUP::Canvas::Bitmap self;
        PREINIT:
                long *c;
                unsigned char *m;
                int max_index=0, i;
        CODE:
                if (self->type != CD_MAP) XSRETURN_UNDEF;
                c = (long*)cdBitmapGetData(self, CD_COLORS);
                m = (unsigned char*)cdBitmapGetData(self, CD_INDEX);
                if (!c || !m) XSRETURN_UNDEF;
                for(i=0; i<self->w*self->h; i++) if(m[i]>max_index) max_index=m[i];                
                if (max_index>255) max_index=255;
                RETVAL = long2AV(c, max_index+1);
        OUTPUT:
                RETVAL

long
__Bitmap__Color(self,n,...)
                IUP::Canvas::Bitmap self;
                int n;
        PREINIT:
                long *c;
        CODE:
                if (self->type!=CD_MAP) XSRETURN_UNDEF;
                if (n<0 || n>=256) XSRETURN_UNDEF;
                c = (long*)cdBitmapGetData(self, CD_COLORS);
                if (!c) XSRETURN_UNDEF;
                if (items>2) {
                  c[n] = SvIV(ST(2));
                  XSRETURN_UNDEF;
                }
                RETVAL = c[n];
        OUTPUT:
                RETVAL

void
__Bitmap__Pixel(self,x,y,...)
                IUP::Canvas::Bitmap self;
                int x;
                int y;
        PREINIT:
                unsigned char *data_buffer=NULL, *r=NULL, *g=NULL, *b=NULL, *a=NULL, *m=NULL;
                int color_space, plane_size=0, plane_count=0, color_count=0;
                int width = self->w;
                int height = self->h;
        PPCODE:
                /* warn("XXX-DEBUG: bitmap.pixel x=%d y=%d items=%d w=%d h=%d\n",x,y,items,width,height); */
                /* warn("XXX-DEBUG: rgb=%d rgba=%d\n", (self->type==CD_RGB), (self->type==CD_RGBA)); */
                if (x<0 || x>=width || y<0 || y>=height ) {
                  warn("Error: x or y out of range");
                }
                else if (self->type==CD_RGBA) {
                  plane_count = 4;
                  r = cdBitmapGetData(self, CD_IRED);
                  g = cdBitmapGetData(self, CD_IGREEN);
                  b = cdBitmapGetData(self, CD_IBLUE);
                  a = cdBitmapGetData(self, CD_IALPHA);
                  if (r && g && b && a) {
                    if (items==3) {
                      XPUSHs(sv_2mortal(newSVuv(r[width*y+x])));
                      XPUSHs(sv_2mortal(newSVuv(g[width*y+x])));
                      XPUSHs(sv_2mortal(newSVuv(b[width*y+x])));
                      XPUSHs(sv_2mortal(newSVuv(a[width*y+x])));
                    }
                                        else if (items>3 && items<7) {
                                          warn("Error: not enough parameters, expected: Pixel(x,y,r,g,b,a)");
                                        }
                    else {
                      r[width*y+x] = SvUV(ST(3));
                      g[width*y+x] = SvUV(ST(4)); 
                      b[width*y+x] = SvUV(ST(5));
                      a[width*y+x] = SvUV(ST(6));
                    }
                  }
                }
                else if (self->type==CD_RGB) {
                  plane_count = 3;
                  r = cdBitmapGetData(self, CD_IRED);
                  g = cdBitmapGetData(self, CD_IGREEN);
                  b = cdBitmapGetData(self, CD_IBLUE);
                  if (r && g && b) {
                    if (items==3) {
                      XPUSHs(sv_2mortal(newSVuv(r[width*y+x])));
                      XPUSHs(sv_2mortal(newSVuv(g[width*y+x])));
                      XPUSHs(sv_2mortal(newSVuv(b[width*y+x])));
                    }
                                        else if (items>3 && items<6) {
                                          warn("Error: not enough parameters, expected: Pixel(x,y,r,g,b)");
                                        }
                    else {
                      r[width*y+x] = SvUV(ST(3));
                      g[width*y+x] = SvUV(ST(4)); 
                      b[width*y+x] = SvUV(ST(5));
                    }
                  }
                }
                else if (self->type==CD_MAP) {
                  plane_count = 1;
                  m = cdBitmapGetData(self, CD_INDEX);
                  if (m) {
                    if (items==3) {
                      XPUSHs(sv_2mortal(newSVuv(m[width*y+x])));
                    }
                    else if (items==4) {
                      m[width*y+x] = SvUV(ST(3));
                    }
                  }
                }

int
__Bitmap__SaveAs(self,filename,format,...)
                IUP::Canvas::Bitmap self;
                char *filename;
                char *format;
        PREINIT:
                unsigned char *data_buffer=NULL, *r=NULL, *g=NULL, *b=NULL, *a=NULL, *m=NULL;
                                unsigned char *data;
                long *c=NULL;
                imImage *image;
                int color_space, plane_size=0, plane_count=0, color_count=0;                                
        CODE:                
                plane_size = sizeof(unsigned char)*self->w*self->h;
                if (self->type==CD_RGBA) {
                  plane_count = 4;
                  color_space = (IM_RGB | IM_ALPHA);
                                  data = cdBitmapGetData(self, CD_IRED); /* full image buffer */
                }
                else if (self->type==CD_RGB) {
                  plane_count = 3;
                  color_space = IM_RGB;
                                  data = cdBitmapGetData(self, CD_IRED); /* full image buffer */
                }
                else if (self->type==CD_MAP) {
                  plane_count = 1;
                  color_space = IM_MAP;
                                  data = cdBitmapGetData(self, CD_INDEX);
                  c = (long*)cdBitmapGetData(self, CD_COLORS);
                  color_count = 256; /* XXX-CHECKLATER */
                }
                RETVAL = 999; /* means "error somewhere in perl XS code" */
                if (plane_count>0)  {
                  if (data) {                                        
                                        image = imImageInit(self->w, self->h, color_space, IM_BYTE, data, c, color_count);                    
                    if (image) {
                      if (items>=4) {
                        float res = (float)SvNV(ST(3));
                        /* warn("XXX-DEBUG: setting resolution to '%f' DPI\n", res); */
                        imImageSetAttribute(image, "XResolution", IM_FLOAT, 1, &res);
                        imImageSetAttribute(image, "YResolution", IM_FLOAT, 1, &res);
                        imImageSetAttribute(image, "ResolutionUnit", IM_BYTE, -1, "DPI"); /* "DPI" or "DPC" */
                      }
                      RETVAL = imFileImageSave(filename, format, image);  /* valid formats: TIFF JPEG PNG GIF BMP RAS ICO PNM KRN LED SGI PCX TGA */
                                          image->data[0] = NULL; /* to avoid duplicate memory release */
                      imImageDestroy(image);
                      /* warn("XXX-DEBUG: imFileImageSave RETVAL=%d\n",RETVAL); */
                    }
                  }
                }             
        OUTPUT:
                RETVAL

void
__Bitmap__DESTROY(self)
                IUP::Canvas::Bitmap self;
        CODE:
                cdKillBitmap(self);