//
// Copyright (C) 1999-2004 Toshikaz Hirabayashi
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// TOSHIKAZ HIRABAYASHI BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// Except as contained in this notice, the name of Toshikaz Hirabayashi shall
// not be used in advertising or otherwise to promote the sale, use or other
// dealings in this Software without prior written authorization from
// Toshikaz Hirabayashi.

#include <X11/Xlib.h>
#include <unistd.h>
#ifndef MacOS
#include <dlfcn.h>
#else //MacOS
//#include <mach-o/dyld.h>
#define RTLD_LAZY 0
extern void* dlopen(char* fname,long);
extern void* dlsym(void*,char* procn);
#endif //MacOS
#include <WScom.h>
#include <WSCimageSet.h>
#include <WSDfileSystem.h>
#include <WStcpcom.h>
#include <x11/WSDximage.h>
#include <x11/WSDxappDev.h>
#include <x11/WSDxcolor.h>

long WSGFxBufToPixmap(Display* display,Window window,GC gc,unsigned char *buf,Pixmap* pixmap,long width,long height,long* vw,long* vh);
long WSGFxBufToBitmap(Display* display,Window window,GC gc,unsigned char *buf,Pixmap* pixmap,long width,long height,long* vw,long* vh);
long WSGFxBmpReadFpToPixmap(Display* display,Window window,GC gc,FILE* ifile,Pixmap* pixmap,Pixmap* pixmap2,long* w,long* h);
long WSGFxBmpReadFileToPixmap(Display* display,Window window,GC gc,char* filename,Pixmap* pixmap,Pixmap* pixmap2,long* w,long* h);

WSMFclassInit(WSDximage,WSDimage);

WSDimage* _ximage_create_handler(){
  WSDimage* image = new WSDximage();
  return image;
};

void  _ximage_init(){
    WSGIappImageSet()->setCreateHandler(_ximage_create_handler);
};

WSDximage::WSDximage(){
}

WSDximage::~WSDximage(){
  destroy();
}

long WSDximage::initialize(){
  if (_value1 > 0){
    return WS_NO_ERR;
  }
  char* iname = getSrc();
  if (iname == NULL || !strcmp(iname,"") ){
    return WS_NO_ERR;
  }

  WSCstring in;
  in.setString( WSGIappFileSystem()->adjustFileName(iname) );
   
  if (in.isExist(".xpm") != -1 || in.isExist(".XPM") != -1){
     static void* dl = NULL;
     static long dl_init = 0;
     static long (*fn)(Display*,Window,Colormap,char*,Pixmap*,Pixmap*,
                       long*,long*) = NULL;
     static long (*fn2)(Display*,Window,Colormap,char**,Pixmap*,Pixmap*,
                       long*,long*) = NULL;

     if (dl_init == 0){
#ifndef MacOS
       dl = dlopen("xpm.so",RTLD_LAZY);
       if (dl == NULL){
         dl = dlopen("./xpm.so",RTLD_LAZY);
       }
#else //MacOS
       dl = dlopen("/usr/lib/xpm.bundle",RTLD_LAZY);
       if (dl == NULL){
         dl = dlopen("./xpm.bundle",RTLD_LAZY);
       }
#endif //MacOS
       dl_init = 1;
       if (dl == NULL){
#ifndef MacOS
WSMFtrace("ERROR. in WSDximage::initialize(). Library xpm.so open error. \nso, Xpm image can not support...\n");
#else //MacOS
WSMFtrace("ERROR. in WSDximage::initialize(). Library /usr/lib/xpm.bundle open error. \nso, Xpm image can not support...\n");
#endif //MacOS
       }else{
         fn = (long (*)(Display*,Window,Colormap,char*,
                        Pixmap*,Pixmap*,long*,long*))
                dlsym(dl,"ReadXpm");
         fn2 = (long (*)(Display*,Window,Colormap,char**,
                        Pixmap*,Pixmap*,long*,long*))
                dlsym(dl,"CreateXpmFromData");
         if (fn == NULL){
WSMFtrace("ERROR. in WSDximage::initialize(). Library libXpm.so is invalid. \nso, Xpm image can not support...\n");
         }
       }
     }
     if (fn == NULL){
       return WS_NO_ERR;
     }
     Pixmap pixmap_file;
     Pixmap pixmap_file2;
     int reti;
     long width = _w,height = _h;

     char* load_file_name = in.getString();
     WSDxappDev* app   = WSGIxwinAppDev(); 
     in.delHeadSpace();
     if (strncmp("http://",in.getString(),7)){
       reti = fn( app->display(),XtWindow(app->appWidget()),
                  WSDxcolor::getColormap(),
                  load_file_name,&pixmap_file, &pixmap_file2,&width,&height);

       if (reti != 0 && fn2 != NULL){
         void* data = WSGIappImageSet()->getDefaultImageHandle(iname);
         if (data != NULL){
           reti = fn2( app->display(),XtWindow(app->appWidget()),
                  WSDxcolor::getColormap(),
                  (char**)data,&pixmap_file, &pixmap_file2,&width,&height);
         }
       }
     }else{
       char*  pbuf = NULL;
       char*  ctype = NULL;
       long  size = 0;
       long  ishtml = 0;
       WSGFloadRemoteFile(in.getString(),&pbuf,&ctype,&size,&ishtml,1);
       if (pbuf != NULL){
         reti = fn( app->display(),XtWindow(app->appWidget()),
                    WSDxcolor::getColormap(),
                    pbuf, &pixmap_file, &pixmap_file2,&width,&height);
         free(pbuf);
       }else{
         reti = 1;
       }
     }

     if (reti == 0){
       setImageWidth(width);
       setImageHeight(height);
       setValue1((long)pixmap_file);
       setValue2((long)pixmap_file2);
     }else{
//WSMFtrace("ERROR. WSDximage::initialize() file open error. file=%s\n",load_file_name);
     }

  }else if (in.isExist(".jpg") != -1 || in.isExist(".JPG") != -1){
//WSMFtrace("WSDximage::initialize %s\n",in.getString());
     Pixmap pixmap_file;
     long width = _w;
     long height = _h;
     char* load_file_name = in.getString();
     WSDxappDev* app   = WSGIxwinAppDev(); 
     in.delHeadSpace();
     GC gc = WSGIxwinAppDev()->appGC2();
     static void* dl = NULL;
     static long dl_init = 0;
     static long (*fn)(Display*,Window,GC,char*,Pixmap*,long*,long*) = NULL;

     if (dl_init == 0){
#ifndef MacOS
       dl = dlopen("jpg.so",RTLD_LAZY);
       if (dl == NULL){
         dl = dlopen("./jpg.so",RTLD_LAZY);
       }
#else //MacOS
       dl = dlopen("/usr/lib/jpg.bundle",RTLD_LAZY);
       if (dl == NULL){
         dl = dlopen("./jpg.bundle",RTLD_LAZY);
       }
#endif //MacOS
       dl_init = 1;
       if (dl == NULL){
#ifndef MacOS
WSMFtrace("ERROR. in WSDximage::initialize(). Library jpg.so open error. \nso, jpeg image can not support...\n");
#else //MacOS
WSMFtrace("ERROR. in WSDximage::initialize(). Library jpg.bundle open error. \nso, jpeg image can not support...\n");
#endif //MacOS
       }else{
         fn = (long (*)(Display*,Window,GC,char*,Pixmap*,long*,long*))
                dlsym(dl,"JpegReadFileToPixmap");
         if (fn == NULL){
WSMFtrace("ERROR. in WSDximage::initialize(). Library jpg.so is invalid. \nso, jpeg image can not support...\n");
         }
       }
     }
     if (fn != NULL){
       long reti = fn( app->display(), XtWindow(app->appWidget()),gc,
                       load_file_name, &pixmap_file, &width,&height);

       if (reti == 0){
         setImageWidth(width);
         setImageHeight(height);
         setValue1((long)pixmap_file);
         setValue2((long)0);
       }else{
//WSMFtrace("ERROR. WSDximage::initialize file open error. file=%s\n",load_file_name);
       }
     }
  }else if (in.isExist(".png") != -1 || in.isExist(".PNG") != -1){
//WSMFtrace("WSDximage::initialize %s\n",in.getString());
     Pixmap pixmap_file;
     Pixmap pixmap_file2;
     long width = _w;
     long height = _h;
     char* load_file_name = in.getString();
     WSDxappDev* app   = WSGIxwinAppDev(); 
     in.delHeadSpace();
     GC gc = WSGIxwinAppDev()->appGC2();
     static void* dl = NULL;
     static long dl_init = 0;
     static long (*fn)(Display*,Window,GC,char*,Pixmap*,Pixmap*,long*,long*) = NULL;

     if (dl_init == 0){
#ifndef MacOS
       dl = dlopen("png.so",RTLD_LAZY);
       if (dl == NULL){
         dl = dlopen("./png.so",RTLD_LAZY);
       }
#else //MacOS
       dl = dlopen("/usr/lib/png.bundle",RTLD_LAZY);
       if (dl == NULL){
         dl = dlopen("./png.bundle",RTLD_LAZY);
       }
#endif //MacOS
       dl_init = 1;
       if (dl == NULL){
#ifndef MacOS
WSMFtrace("ERROR. in WSDximage::initialize(). Library png.so open error. \nso, jpeg image can not support...\n");
#else //MacOS
WSMFtrace("ERROR. in WSDximage::initialize(). Library png.bundle open error. \nso, jpeg image can not support...\n");
#endif //MacOS
       }else{
         fn = (long (*)(Display*,Window,GC,char*,Pixmap*,Pixmap*,long*,long*))
                dlsym(dl,"PngReadFileToPixmap");
         if (fn == NULL){
WSMFtrace("ERROR. in WSDximage::initialize(). Library png.so is invalid. \nso, jpeg image can not support...\n");
         }
       }
     }
     if (fn != NULL){
       long reti = fn( app->display(), XtWindow(app->appWidget()),gc,
                       load_file_name, &pixmap_file,&pixmap_file2, &width,&height);

       if (reti == 0){
         setImageWidth(width);
         setImageHeight(height);
         setValue1((long)pixmap_file);
         setValue2((long)pixmap_file2);
       }else{
//WSMFtrace("ERROR. WSDximage::initialize file open error. file=%s\n",load_file_name);
       }
     }

  }else if (in.isExist(".bmp") != -1 || in.isExist(".BMP") != -1){
//WSMFtrace("WSDximage::initialize %s\n",in.getString());
     Pixmap pixmap_file;
     Pixmap pixmap_file2;
     long width = _w;
     long height = _h;
     char* load_file_name = in.getString();
     WSDxappDev* app   = WSGIxwinAppDev(); 
     in.delHeadSpace();
     GC gc = WSGIxwinAppDev()->appGC2();

     long reti = WSGFxBmpReadFileToPixmap( app->display(),
                       XtWindow(app->appWidget()),gc,
                       load_file_name, &pixmap_file, &pixmap_file2,&width,&height);

     if (reti == 0){
       setImageWidth(width);
       setImageHeight(height);
       setValue1((long)pixmap_file);
       setValue2((long)pixmap_file2);
     }else{
//WSMFtrace("ERROR. WSDximage::initialize file open error. file=%s\n",load_file_name);
     }
  }

  return WS_NO_ERR;
}

long WSDximage::destroy(){
//WSMFtrace("WSDximage::destroy  destroyed.\n");
//  Pixmap pix1 = (Pixmap)getValue1();
//  Pixmap pix2 = (Pixmap)getValue2();
  Pixmap pix1 = (Pixmap)_value1;
  Pixmap pix2 = (Pixmap)_value2;
  WSDxappDev* app   = WSGIxwinAppDev(); 
  if ( pix1 != (Pixmap)-1 && pix1 != (Pixmap)NULL){
    XFreePixmap(app->display(),pix1);
    setValue1(-1);
  }
  if ( pix2 != (Pixmap)-1 && pix2 != (Pixmap)NULL){
    XFreePixmap(app->display(),pix2);
    setValue2(-1);
  }
//  XImage* image = (XImage*)getValue3();
  XImage* image = (XImage*)_value3;
  if ((long)image != 0 && (long)image != -1){
    if ( image->data != NULL){
      delete image->data;
      image->data = NULL;
    }
    XDestroyImage(image);
    setValue3(-1);
  }
//  _bitmap = 0;
  return WS_NO_ERR;
}
long WSDximage::createImage(){
  Pixmap pix1 = (Pixmap)getValue1();
  if ((long)pix1 == 0 || (long)pix1 == -1){
    return WS_ERR;
  }
  XImage* image = (XImage*)getValue3();
  if ((long)image != 0 && (long)image != -1){
    if ( image->data != NULL){
      delete image->data;
      image->data = NULL;
    }
    XDestroyImage(image);
    setValue3(-1);
  }
  WSDxappDev* app   = WSGIxwinAppDev();
#if 0
  long display_depth = XDefaultDepth(app->display(),
                                     XDefaultScreen(app->display()));
  long bit = 32;
  if (display_depth >16){
     bit = 32;
  }else
  if (display_depth >8){
     bit = 16;
  }else{
     bit = 8;
  }
  Visual* visual = XDefaultVisual(display,XDefaultScreen(display));
  image = XCreateImage(app->display(), visual,
                       display_depth,
                       ZPixmap,0,0,
                       getImageWidth(), getImageHeight(), bit,0);
//  XInitImage(image);
  image->data = new char[image->bytes_per_line * getImageHeight()];
#endif
  image = XGetImage(app->display(),pix1,0,0,getImageWidth(),
                    getImageHeight(),0xffffffff,ZPixmap);
//printf("XGetImage w,h=%d,%d\n",getImageWidth(),getImageHeight());
  setValue3((long)image);
  return WS_NO_ERR;
}
XImage* WSDximage::createMaskImage(){
  Pixmap pix2 = (Pixmap)getValue2();
  if ((long)pix2 == 0 || (long)pix2 == -1){
    return NULL;
  }
  WSDxappDev* app   = WSGIxwinAppDev();
  XImage* image = XGetImage(app->display(),pix2,0,0,getImageWidth(),
                    getImageHeight(),0xffffffff,ZPixmap);
  return image;
}
int WSGFxgetbyte(FILE *fp) {
  int c;
  if ((c = fgetc(fp)) == EOF){
    return -1;
  }
  return c;
}

int WSGFxreadLittleShort(FILE *fp, short *d) {
  int c;
  if ((c = fgetc(fp)) == EOF){
    return -1;
  }
  *d = c & 0xff;
  if ((c = fgetc(fp)) == EOF){
    return -1;
  }
  *d |= (c & 0xff) << 8;
  return 0;
}

int WSGFxreadLittleLong(FILE *fp, long *d) {
  int c;

  if ((c = fgetc(fp)) == EOF){
    return -1;
  }
  *d = c & 0xff;
  if ((c = fgetc(fp)) == EOF){
    return -1;
  }
  *d |= ((c & 0xff) << 8);
  if ((c = fgetc(fp)) == EOF){
    return -1;
  }
  *d |= ((c & 0xff) << 16);
  if ((c = fgetc(fp)) == EOF){
    return -1;
  }
  *d |= ((c & 0xff) << 24);
  return 0;
}

long WSGFxBmpReadFpToPixmap(Display* display,Window window,GC gc,FILE* ifile,Pixmap* pixmap,Pixmap* pixmap2,long* w,long* h){

  // bmp (Windows 3.x) header
  //       implemented
  //            1. uncompressed 1bit black & white
  //            2. uncompressed 4bit  16 color
  //            3. uncompressed 8bit 256 color
  //            4. uncompressed 24bit true color
  //            5. RLE 4bit  16 color
  //            6. RLE 8bit 256 color
  *pixmap2 = (Pixmap)0;
  unsigned char red[256], green[256], blue[256];
  if ((WSGFxgetbyte(ifile) != 'B') || (WSGFxgetbyte(ifile) != 'M')){  //  0
    // not a .bmp file
    return -1;
  }
  long width, height, long_tmp, fsize, foffs, cmapsize, cmptype;
  short bit_cnt, short_tmp;
  if (WSGFxreadLittleLong(ifile, &fsize) == -1){                //  2
    return -1;
  }
  if (WSGFxreadLittleLong(ifile, &long_tmp) == -1){             //  6
    return -1;
  }
  if (WSGFxreadLittleLong(ifile, &foffs) == -1){                 // 10
    return -1;
  }
  if (WSGFxreadLittleLong(ifile, &long_tmp) == -1){             // 14
    return -1;
  }
  if (long_tmp != 40){
    // not a Windows 3.x bmp file
    if (long_tmp != 0x6c){
      return -1;
    }
  }
  if (WSGFxreadLittleLong(ifile, &width) == -1){                 // 18
    return -1;
  }
  if (WSGFxreadLittleLong(ifile, &height) == -1){                // 22
    return -1;
  }
  if (WSGFxreadLittleShort(ifile, &short_tmp) == -1){            // 26
    return -1;
  }
  if (short_tmp != 1){
    // plane != 1 is not supported
    return -1;
  }
  if (WSGFxreadLittleShort(ifile, &bit_cnt) == -1){              // 28
    return -1;
  }
  if ((bit_cnt != 1) && (bit_cnt != 4) && (bit_cnt != 8) &&
      (bit_cnt != 24) && (bit_cnt != 32)){
    // bit_cnt=16 is not supported
    return -1;
  }
  if (WSGFxreadLittleLong(ifile, &cmptype) == -1){              // 30
    return -1;
  }
  if (cmptype > 2){
    if (cmptype == 3 && bit_cnt == 32){
      // 24bit + mask.
    }else{
      // compressed file is not supported
      return -1;
    }
  }
  if (WSGFxreadLittleLong(ifile, &long_tmp) == -1){              // 34
    return -1;
  }
  if (WSGFxreadLittleLong(ifile, &long_tmp) == -1){              // 38
    return -1;
  }
  if (WSGFxreadLittleLong(ifile, &long_tmp) == -1){              // 42
    return -1;
  }
  if (WSGFxreadLittleLong(ifile, &cmapsize) == -1){              // 46
    return -1;
  }
  if (WSGFxreadLittleLong(ifile, &long_tmp) == -1){              // 50
    return -1;
  }
  if ((cmapsize == 0) && (bit_cnt <=8)){
    cmapsize = 1 << bit_cnt;
  }
  int n, c;
  for (n = 0; n < cmapsize; n++) {
    if ((c = WSGFxgetbyte(ifile)) == -1){
      return -1;
    }
    blue[n] = (unsigned char)c;
    if ((c = WSGFxgetbyte(ifile)) == -1){
      return -1;
    }
    green[n] = (unsigned char)c;
    if ((c = WSGFxgetbyte(ifile)) == -1){
      return -1;
    }
    red[n] = (unsigned char)c;
    if (WSGFxgetbyte(ifile) == -1){
        return -1;
    }
  }
  if (fseek(ifile, foffs, SEEK_SET) != 0){
    return -1;
  }
  unsigned char* fbuf = new unsigned char[fsize - foffs];
  if (fread(fbuf, fsize - foffs, 1, ifile) != 1) {
    delete fbuf;
    return -1;
  }
  unsigned char* buf = new unsigned char[width * height * 3];
  unsigned char* buf_mask = NULL;
  if (cmptype == 3){
    buf_mask = new unsigned char[width * height];
  }
  unsigned char *tmp, *ftmp;
  unsigned char *tmp_mask;

  int line, dat, x, y;
//printf("cmptype=%d w,h=%d,%d bit=%d\n",cmptype,width,height,bit_cnt);
  if (cmptype) {
    for (y = 0; y < height; y++) {
      tmp = buf + (height - 1 - y) * width * 3;
      for (x = 0; x < width; x++) {
        *(tmp++) = red[0];        // red
        *(tmp++) = green[0];      // green
        *(tmp++) = blue[0];       // blue
      }
    }
  }
  if (cmptype == 1) {
    // BI_RLE8
    x = 0;
    y = 0;
    ftmp = fbuf;
    while (1) {
      if (*ftmp) {
        // copy N times
        tmp = buf + (((height - 1 - y) * width) + x) * 3;
        for (n = 0; n < *ftmp; n++, x++) {
          if (x<width){
            *(tmp++) = red[*(ftmp + 1)];        // red
            *(tmp++) = green[*(ftmp + 1)];      // green
            *(tmp++) = blue[*(ftmp + 1)];       // blue
          }
        }
        ftmp += 2;
      } else {
        if (*(ftmp + 1) == 0) {
          // newline
          x = 0;
          y++;
          ftmp += 2;
        } else if (*(ftmp + 1) == 1) {
          // end
          break;
        } else if (*(ftmp + 1) == 2) {
          // jump
          x += *(ftmp + 2);
          y += *(ftmp + 3);
          ftmp += 4;
        } else {
          // copy
          tmp = buf + (((height - 1 - y) * width) + x) * 3;
          for (n = 0; n < *(ftmp + 1); n++, x++) {
            if (x<width){
              *(tmp++) = red[*(ftmp + n + 2)];        // red
              *(tmp++) = green[*(ftmp + n + 2)];      // green
              *(tmp++) = blue[*(ftmp + n + 2)];       // blue
            }
          }
          ftmp += (*(ftmp + 1) + 2 + (*(ftmp + 1) % 2)?1:0);
        }
      }
    }
  } else if (cmptype == 2) {
    // BI_RLE4
    int m;
    x = 0;
    y = 0;
    ftmp = fbuf;
    while (1) {
      if (*ftmp) {
        // copy N times
        tmp = buf + (((height - 1 - y) * width) + x) * 3;
        for (n = 0; n < *ftmp; n++, x++) {
          if (x % 2)
            dat = *(ftmp + 1) & 0x0f;         // left
          else
            dat = (*(ftmp + 1) & 0xf0) >> 4;  // right
          *(tmp++) = red[dat];        // red
          *(tmp++) = green[dat];      // green
          *(tmp++) = blue[dat];       // blue
        }
        ftmp += 2;
      } else {
        if (*(ftmp + 1) == 0) {
          // newline
          x = 0;
          y++;
          ftmp += 2;
        } else if (*(ftmp + 1) == 1) {
          // end
          break;
        } else if (*(ftmp + 1) == 2) {
          // jump
          x += *(ftmp + 2);
          y += *(ftmp + 3);
          ftmp += 4;
        } else {
          // copy
          m = 0;
          tmp = buf + (((height - 1 - y) * width) + x) * 3;
          for (n = 0; n < *(ftmp + 1); n++, x++) {
            if (x % 2) {
              dat = *(ftmp + m + 2) & 0x0f;         // left
              m++;
            } else
              dat = (*(ftmp + m + 2) & 0xf0) >> 4;  // right
            *(tmp++) = red[dat];        // red
            *(tmp++) = green[dat];      // green
            *(tmp++) = blue[dat];       // blue
          }
          m = (*(ftmp + 1) + 1) / 2;
          ftmp += (m + 2 + ((m % 2)?1:0));
        }
      }
    }
  } else {
    // uncompress
    switch(bit_cnt) {
      case 1:
        line = ((width + 31) / 32) * 4;
        tmp = buf;
        for (y = 0; y < height; y++){
          ftmp = fbuf + ((height - 1 - y) * line);
          for (x = 0; x < width; x++){
            dat = (*ftmp >> (7 - (x % 8))) & 0x01;
            if ((x % 8) == 7){
              ftmp++;
            }
            *(tmp++) = red[dat];          // red
            *(tmp++) = green[dat];        // green
            *(tmp++) = blue[dat];         // blue
          }
        }
        break;
      case 4:
        line = ((width + 7) / 8) * 4;
        tmp = buf;
        for (y = 0; y < height; y++){
          ftmp = fbuf + ((height - 1 - y) * line);
          for (x = 0; x < width; x++){
            if (x % 2) {
              dat = *ftmp & 0x0f;         // left
              ftmp++;
            }else{
              dat = (*ftmp & 0xf0) >> 4;  // right
            }
            *(tmp++) = red[dat];          // red
            *(tmp++) = green[dat];        // green
            *(tmp++) = blue[dat];         // blue
          }
        }
        break;
      case 8:
        line = ((width + 3) / 4) * 4;
        tmp = buf;
        for (y = 0; y < height; y++){
          ftmp = fbuf + ((height - 1 - y) * line);
          for (x = 0; x < width; x++){
            *(tmp++) = red[*ftmp];        // red
            *(tmp++) = green[*ftmp];      // green
            *(tmp++) = blue[*ftmp];       // blue
            ftmp++;
          }
        }
        break;
      case 24:
        tmp = buf;
        tmp_mask = buf_mask;
        for (y = 0; y < height; y++){
          ftmp = fbuf + ((height - 1 - y) * width * 3);
          for (x = 0; x < width; x++){
            *(tmp++) = *(ftmp + 2);       // red
            *(tmp++) = *(ftmp + 1);       // green
            *(tmp++) = *(ftmp + 0);       // blue
            if (cmptype != 3){
              ftmp += 3;
            }else{
              ftmp += 4;
            }
          }
        }
        break;
      case 32:
        tmp = buf;
        tmp_mask = buf_mask;
        for (y = 0; y < height; y++){
          ftmp = fbuf + ((height - 1 - y) * width * 4);
          for (x = 0; x < width; x++){
            *(tmp++) = *(ftmp + 2);       // red
            *(tmp++) = *(ftmp + 1);       // green
            *(tmp++) = *(ftmp + 0);       // blue
           
            if (cmptype == 3){
              *(tmp_mask++) = *(ftmp + 3);       // blue
//printf("i=%d j=%d pt=%d mask=0x%x\n",y,x,tmp_mask-1 - buf_mask,*(tmp_mask -1));
            }
            ftmp += 4;
          }
        }
        break;
     }
  }
  delete fbuf;
  long reti = WSGFxBufToPixmap(display, window, gc, buf, pixmap, width, height,w,h);
  delete buf;
  if (cmptype == 3){
    WSGFxBufToBitmap(display, window, gc, buf_mask, pixmap2, width, height,w,h);
    delete buf_mask;
  }

//  *w = width;
//  *h = height;
  return reti;
}

long WSGFxBufToPixmap(Display* display,Window window,GC gc,unsigned char *buf,Pixmap* pixmap,long rwidth,long rheight,long* w,long* h){

  int red_mask, green_mask, blue_mask;
  int red_shift, green_shift, blue_shift;
  int start_shift;
  unsigned int start_mask, udat;
  XWindowAttributes win_attr;
  long stretched = 0;
  long vwidth = *w;
  long vheight = *h;
  if (vwidth == 0 || vheight == 0){
    vwidth = rwidth;
    vheight = rheight;
  }else{
    if ((long)((double)rwidth * vheight/vwidth) < rheight){
      vwidth = (long)((double)vheight * rwidth/rheight);
    }else{
      vheight = (long)((double)vwidth * rheight/rwidth);
    }
    stretched = 1;
  }
  *w = vwidth;
  *h = vheight;

  red_mask = green_mask = blue_mask = 0;
  red_shift = green_shift = blue_shift = 0;

  int msb_flag = (ImageByteOrder(display) == MSBFirst)?1:0;

  if (XGetWindowAttributes(display,
            RootWindow(display, DefaultScreen(display)), &win_attr) == 0){
    return -1;
  }

  if ((win_attr.depth == 24) || (win_attr.depth == 16)) {
    if (win_attr.depth == 24) {
      start_shift = 24;
      start_mask = 0x80000000;
    }else{
      start_shift = 8;
      start_mask = 0x8000;
    }
    red_mask = win_attr.visual->red_mask;
    red_shift = start_shift;
    unsigned int n = start_mask;
    while (!(n & red_mask)) {
      n >>= 1;
      red_shift--;
    }
    green_mask = win_attr.visual->green_mask;
    green_shift = start_shift;
    n = start_mask;
    while (!(n & green_mask)) {
      n >>= 1;
      green_shift--;
    }
    blue_mask = win_attr.visual->blue_mask;
    blue_shift = start_shift;
    n = start_mask;
    while (!(n & blue_mask)) {
      n >>= 1;
      blue_shift--;
    }
  }

  long display_depth = XDefaultDepth(display,XDefaultScreen(display));

  XImage* image = 0;
  Visual* visual = XDefaultVisual(display,XDefaultScreen(display));
  if (display_depth >16){
    image = XCreateImage(display,visual, display_depth,
                         ZPixmap,0,0,vwidth,vheight,32,0);
  }else if (display_depth >8){
    image = XCreateImage(display,visual, display_depth,
                         ZPixmap,0,0,vwidth,vheight,16,0);
  }else{
    image = XCreateImage(display,visual, display_depth,
                         ZPixmap,0,0,vwidth,vheight,8,0);
  }

  image->data = new char[image->bytes_per_line * vheight];

  unsigned char r,g,b;
  long ptr = 0;
  long ptr2 = 0;
  long i, j;

  if (image->bits_per_pixel ==32){
    for(i=0; i<vheight; i++){
      for(j=0; j<vwidth; j++){
        if (stretched != 0){
          ptr = (long)((double)i*rheight/vheight)*rwidth
               + (long)((double)j*rwidth/vwidth);
          ptr *= 3;
        }

        r = buf[ptr++];
        g = buf[ptr++];
        b = buf[ptr++];

        udat = 0;
        if (red_shift >= 0){
          udat |= (((int)r << red_shift) & red_mask);
        }else{
          udat |= (((int)r >> (-red_shift)) & red_mask);
        }
        if (green_shift >= 0){
          udat |= (((int)g << green_shift) & green_mask);
        }else{
          udat |= (((int)g >> (-green_shift)) & green_mask);
        }
        if (blue_shift >= 0){
          udat |= (((int)b << blue_shift) & blue_mask);
        }else{
          udat |= (((int)b >> (-blue_shift)) & blue_mask);
        }
        if (msb_flag){
          ((unsigned char*)image->data)[ptr2++] = (udat & 0xff000000)>>24;
          ((unsigned char*)image->data)[ptr2++] = (udat & 0xff0000)>>16;
          ((unsigned char*)image->data)[ptr2++] = (udat & 0xff00)>>8;
          ((unsigned char*)image->data)[ptr2++] = (udat & 0xff);
        }else{
          ((unsigned char*)image->data)[ptr2++] = (udat & 0xff);
          ((unsigned char*)image->data)[ptr2++] = (udat & 0xff00)>>8;
          ((unsigned char*)image->data)[ptr2++] = (udat & 0xff0000)>>16;
          ((unsigned char*)image->data)[ptr2++] = (udat & 0xff000000)>>24;
        }
      }
    }
  }else if (image->bits_per_pixel ==24){
    for(i=0; i<vheight; i++){
      ptr2 = i * image->bytes_per_line;
      for(j=0; j<vwidth; j++){
        if (stretched != 0){
          ptr = (long)((double)i*rheight/vheight)*rwidth
               + (long)((double)j*rwidth/vwidth);
          ptr *= 3;
        }
        r = buf[ptr++];
        g = buf[ptr++];
        b = buf[ptr++];

        udat = 0;
        if (red_shift >= 0){
          udat |= (((int)r << red_shift) & red_mask);
        }else{
          udat |= (((int)r >> (-red_shift)) & red_mask);
        }
        if (green_shift >= 0){
          udat |= (((int)g << green_shift) & green_mask);
        }else{
          udat |= (((int)g >> (-green_shift)) & green_mask);
        }
        if (blue_shift >= 0){
          udat |= (((int)b << blue_shift) & blue_mask);
        }else{
          udat |= (((int)b >> (-blue_shift)) & blue_mask);
        }
        if (msb_flag){
          ((unsigned char*)image->data)[ptr2++] = (udat & 0xff0000)>>16;
          ((unsigned char*)image->data)[ptr2++] = (udat & 0xff00)>>8;
          ((unsigned char*)image->data)[ptr2++] = (udat & 0xff);
        }else{
          ((unsigned char*)image->data)[ptr2++] = (udat & 0xff);
          ((unsigned char*)image->data)[ptr2++] = (udat & 0xff00)>>8;
          ((unsigned char*)image->data)[ptr2++] = (udat & 0xff0000)>>16;
        }
      }
    }
  }else if (image->bits_per_pixel ==16){
    for(i=0; i<vheight; i++){
      for(j=0; j<vwidth; j++){
        if (stretched != 0){
          ptr = (long)((double)i*rheight/vheight)*rwidth
               + (long)((double)j*rwidth/vwidth);
          ptr *= 3;
        }
        unsigned int rr = buf[ptr++];
        unsigned int gg = buf[ptr++];
        unsigned int bb = buf[ptr++];

        udat = 0;
        if (red_shift >= 0){
                udat |= (((int)rr << red_shift) & red_mask);
        }else{
          udat |= (((int)rr >> (-red_shift)) & red_mask);
        }
        if (green_shift >= 0){
          udat |= (((int)gg << green_shift) & green_mask);
        }else{
          udat |= (((int)gg >> (-green_shift)) & green_mask);
        }
        if (blue_shift >= 0){
          udat |= (((int)bb << blue_shift) & blue_mask);
        }else{
          udat |= (((int)bb >> (-blue_shift)) & blue_mask);
        }
        if (msb_flag) {
          ((unsigned char*)image->data)[ptr2++] = (udat >> 8) & 0xff;
          ((unsigned char*)image->data)[ptr2++] = (udat & 0xff);
        }else{
          ((unsigned char*)image->data)[ptr2++] = (udat & 0xff);
          ((unsigned char*)image->data)[ptr2++] = (udat & 0xff00)>>8;
        }
      }
    }
  }else if (image->bits_per_pixel == 8){
    XColor col[5*5*5];
    Colormap cm = DefaultColormap(display,DefaultScreen(display));
    long k;
    long cnt=0;
    for(i=0; i<5; i++){
      for(j=0; j<5; j++){
        for(k=0; k<5; k++){
          if (i != 4){
            col[cnt].red = i*64*256;
          }else{
            col[cnt].red = 0xffff;
          }
          if (j != 4){
            col[cnt].green = j*64*256;
          }else{
            col[cnt].green = 0xffff;
          }
          if (k != 4){
            col[cnt].blue = k*64*256;
          }else{
            col[cnt].blue = 0xffff;
          }
          XAllocColor(display,cm,&(col[cnt]));
          cnt++;
        }
      }
    }

    long colptr = 0;
    long rr = 0,gg = 0,bb = 0;
    long tr1,tg1,tb1;
    signed char dr1,dg1,db1;
    for(i=0; i<vheight; i++){
      dr1 = 0;
      dg1 = 0;
      db1 = 0;
      for(j=0; j<vwidth; j++){
        if (stretched != 0){
          ptr = (long)((double)i*rheight/vheight)*rwidth
               + (long)((double)j*rwidth/vwidth);
          ptr *= 3;
        }
        tr1 = buf[ptr++];
        tg1 = buf[ptr++];
        tb1 = buf[ptr++];

        if ((0 < tr1 + dr1) && (tr1 + dr1) < 256){
          if ((-32 < dr1) && (dr1 < 32)){
            rr = (tr1 + dr1 + 31) & 0x1c0;
          }else if (dr1 > 31){
            rr = (tr1 + 63) & 0x1c0;
          }else{
            rr = tr1  & 0x1c0;
          }
        }else if (tr1 + dr1 > 255){
          rr = 0x100;
        }else{
          rr = 0;
        }
        dr1 += (tr1 - rr);
        if (0 < tg1 + dg1  &&tg1 + dg1 < 256){
          if (-32 < dg1 && dg1 < 32 ){
            gg = (tg1 + dg1 + 31) & 0x1c0;
          }else if (dg1 > 31){
            gg = (tg1 + 63) & 0x1c0;
          }else{
            gg = tg1  & 0x1c0;
          }
        }else if (tg1 + dg1 > 255){
          gg = 0x100;
        }else{
          gg = 0;
        }
        dg1 += (tg1 - gg);

        if (0 < tb1 + db1 && tb1 + db1 < 256){
          if (-32 < db1 && db1 < 32){
            bb = (tb1 + db1 + 31) & 0x1c0;
          }else if (db1 > 31){
            bb = (tb1 + 63) & 0x1c0;
          }else{
            bb = tb1 & 0x1c0;
          }
        }else if (tb1 + db1 > 255){
            bb = 0x100;
        }else{
          bb = 0;
        }
        db1 += (tb1 - bb);
        db1 += (tb1 - bb);
        colptr = (rr>>6)*5*5  + (gg>>6)*5 + (bb>>6);
        image->data[ptr2++] =  col[colptr].pixel;
      }
    }
  }

  Pixmap pix = XCreatePixmap(display,window, vwidth,vheight,display_depth);
  *pixmap = pix;
  XPutImage(display,pix,gc,image,0,0,0,0,vwidth,vheight);
  if (image->data != NULL){
    delete image->data;
    image->data = NULL;
  }
  XDestroyImage(image);
  return 0;
}

long WSGFxBufToBitmap(Display* display,Window window,GC gc,unsigned char *buf,Pixmap* pixmap,long rwidth,long rheight,long* w,long* h){
  long stretched = 0;
  long vwidth = *w;
  long vheight = *h;
  if (vwidth == 0 || vheight == 0){
    vwidth = rwidth;
    vheight = rheight;
  }else{
    if ((long)((double)rwidth * vheight/vwidth) < rheight){
      vwidth = (long)((double)vheight * rwidth/rheight);
    }else{
      vheight = (long)((double)vwidth * rheight/rwidth);
    }
    stretched = 1;
  }
  *w = vwidth;
  *h = vheight;

  Visual* visual = XDefaultVisual(display,XDefaultScreen(display));
  XImage* image = XCreateImage(display,visual, 1,
                         ZPixmap,0,0,vwidth,vheight,8,0);

//printf("here1 image=0x%x bytes_per_line=%d w.h\n",image,image->bytes_per_line,vwidth,vheight);
  image->data = new char[image->bytes_per_line * vheight];

  unsigned char v;
  long ptr = 0;
  long ptr2 = 0;
  long i, j;

  for(i=0; i<vheight; i++){
    for(j=0; j<vwidth; j++){
      if (stretched != 0){
        ptr = ((long)((double)i*rheight/vheight)*rwidth
             + (long)((double)j*rwidth/vwidth));
      }
      if ( (j%8) == 0){
        v = 0;
      }
      if (buf[ptr++] == 0){
        v |= (1<<(j%8));
      }
//printf("i=%d j=%d pt=%d pt2=%d bit=%d val=0x%x v=0x%x\n",i,j,ptr,ptr2,j%8,buf[ptr-1],v);
      if ( (j%8) == 7){
        ((unsigned char*)image->data)[ptr2] = v;
        ptr2++;
      }else
      if (j == vwidth-1){
        ((unsigned char*)image->data)[ptr2] = v;
        ptr2++;
      }
    }
  }
  GC gc2;
  XGCValues values;

  values.foreground = 1;
  values.background = 0;
  Pixmap pix = XCreatePixmap(display,window, vwidth,vheight,1);
  gc2 = XCreateGC(display, pix, GCForeground | GCBackground, &values);

  *pixmap = pix;
  XPutImage(display,pix,gc2,image,0,0,0,0,vwidth,vheight);
  if (image->data != NULL){
    delete image->data;
    image->data = NULL;
  }
  XFreeGC(display,gc2);
  XDestroyImage(image);
  return 0;
}

long WSGFxBmpReadFileToPixmap(Display* display,Window window,GC gc,char* filename,Pixmap* pixmap,Pixmap* pixmap2,long* w,long* h){

  FILE* ifile = fopen(filename,"r");
  if (ifile == NULL){
    return -1;
  }

  long reti = WSGFxBmpReadFpToPixmap(display, window, gc, ifile, pixmap,pixmap2, w, h);
  fclose(ifile);
  return reti;
}

