//
// Copyright (C) 1999-2002 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 <basic.h>
#include <unistd.h>
#ifdef TE
#include <btron/img/png.h>
extern "C" {
#include <btron/img/jpeglib.h>
#include <btron/img/jerror.h>
};
#else
#include <util/png.h>
extern "C" {
#include <util/jpeglib.h>
#include <util/jerror.h>
};
#endif

#include <WScom.h>
#include <WSCimageSet.h>
#include <WSDfileSystem.h>
#include <WStcpcom.h>
#include <btron/WSDbtronImage.h>
#include <btron/WSDbtronAppDev.h>
#include <btron/WSDbtronColor.h>

long WSGFbtronBufToPixmap(unsigned char *buf,W* pixmap,long width,long height,long* vw,long* vh,long row_bytes);
long WSGFbtronBmpReadFpToPixmap(FILE* ifile,W* pixmap,long* w,long* h);
long WSGFbtronBmpReadFileToPixmap(char* filename,W* pixmap,long* w,long* h);
long PngReadFileToPixmap(char* filename,GID* mem_gid,GID* mem_gid2,long* w,long* h);
extern long JpegReadFileToPixmap(char* filename,GID* mem_gid,GID* mem_gid2,long* w,long* h);


WSMFclassInit(WSDbtronImage,WSDimage);

WSDimage* _btronImage_create_handler(){
  WSDimage* image = new WSDbtronImage();
  return image;
};

void  _btronImage_init(){
    WSGIappImageSet()->setCreateHandler(_btronImage_create_handler);
};

WSDbtronImage::WSDbtronImage(){
}

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

long WSDbtronImage::initialize(){
dbprintf("IMG>> WSDbtronImage::initialize start..\n");
  if (WSGIbtronAppDev()->getGidInitialized() == False){
    return WS_ERR;
  }
  if (_value1 > 0){
    return WS_NO_ERR;
  }
  char* iname = getSrc();
  if (iname == NULL || !strcmp(iname,"") ){
    return WS_NO_ERR;
  }

  WSCstring tmp;
  tmp.setString(iname);
#ifdef TE
  tmp.replaceString("$(WSDIR)/sys/pixmaps/","/SYS/",1);
#endif
  WSCstring in;
  in.setString( WSGIappFileSystem()->adjustFileName(tmp.getString()) );
dbprintf("IMG>> WSDbtronImage::initialize img=%s\n",in.getString());
  if (in.isExist(".xpm") != -1 || in.isExist(".XPM") != -1){
//    long words = in.getWords("/");
//    WSCstring in2 = in.getWord(words-1,"/");
    WSCstring in2 = in;
    in2.replaceString(".xpm",".png",1);
    in2.replaceString(".XPM",".png",1);
    in = in2;
  }
  if (in.isExist(".jpg") != -1 || in.isExist(".JPG") != -1){
     GID mem_gid = 0;
     GID mem_gid2 = 0;
     long width = _w;
     long height = _h;
     char* load_file_name = in.getString();
     long reti = JpegReadFileToPixmap( load_file_name, &mem_gid,&mem_gid2,
                                       &width,&height);

     if (mem_gid == 0){
       mem_gid = -1;
     }
     if (reti == 0){
       setImageWidth(width);
       setImageHeight(height);
       setValue1((long)mem_gid);
       setValue2((long)mem_gid2);
     }else{
//WSMFtrace("ERROR. WSDbtronImage::initialize file open error. file=%s\n",load_file_name);
     }
  }else
  if (in.isExist(".png") != -1 || in.isExist(".PNG") != -1){
//WSMFtrace("WSDbtronImage::initialize %s\n",in.getString());
     W mem_gid;
     W mem_gid2;
     long width = _w;
     long height = _h;
     char* load_file_name = in.getString();
dbprintf("IMG>> WSDbtronImage::initialize png..\n");
     long reti = PngReadFileToPixmap( load_file_name, &mem_gid,&mem_gid2,
                                      &width,&height);
dbprintf("IMG>> WSDbtronImage::initialize png done..\n");
     if (mem_gid == 0){
       mem_gid = -1;
     }
     if (reti == 0){
       setImageWidth(width);
       setImageHeight(height);
       setValue1((long)mem_gid);
       setValue2((long)mem_gid2);
     }else{
//WSMFtrace("ERROR. WSDbtronImage::initialize file open error. file=%s\n",load_file_name);
     }

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

     long reti = WSGFbtronBmpReadFileToPixmap(
                       load_file_name, &mem_gid, &width,&height);
     if (mem_gid == 0){
       mem_gid = -1;
     }
     if (reti == 0){
       setImageWidth(width);
       setImageHeight(height);
       setValue1((long)mem_gid);
       setValue2((long)0);
     }else{
//WSMFtrace("ERROR. WSDbtronImage::initialize file open error. file=%s\n",load_file_name);
     }
  }
dbprintf("IMG>> WSDbtronImage::initialize done.\n",in.getString());

  return WS_NO_ERR;
}

long WSDbtronImage::destroy(){
  W memgid1 = (W)_value1;
  if (memgid1 != 0 && memgid1 != -1 ){
    gcls_env(memgid1);
    setValue1((long)-1);
  }
  W memgid2 = (W)_value2;
  if (memgid2 != 0 && memgid2 != -1 ){
    gcls_env(memgid2);
    setValue2((long)-1);
  }

  return WS_NO_ERR;
}
long WSDbtronImage::createImage(){
  return WS_NO_ERR;
}

int WSGFbtrongetbyte(FILE *fp) {
  int c;
  if ((c = fgetc(fp)) == EOF){
    return -1;
  }
  return c;
}

int WSGFbtronreadLittleShort(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 WSGFbtronreadLittleLong(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 WSGFbtronBmpReadFpToPixmap(FILE* ifile,W* pixmap,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
  unsigned char red[256], green[256], blue[256];
  if ((WSGFbtrongetbyte(ifile) != 'B') || (WSGFbtrongetbyte(ifile) != 'M')){  //  0
    // not a .bmp file
    return -1;
  }
  long width, height, long_tmp, fsize, foffs, cmapsize, cmptype;
  short bit_cnt, short_tmp;
  if (WSGFbtronreadLittleLong(ifile, &fsize) == -1){                //  2
    return -1;
  }
  if (WSGFbtronreadLittleLong(ifile, &long_tmp) == -1){             //  6
    return -1;
  }
  if (WSGFbtronreadLittleLong(ifile, &foffs) == -1){                 // 10
    return -1;
  }
  if (WSGFbtronreadLittleLong(ifile, &long_tmp) == -1){             // 14
    return -1;
  }
  if (long_tmp != 40){
    // not a Windows 3.x bmp file
    return -1;
  }
  if (WSGFbtronreadLittleLong(ifile, &width) == -1){                 // 18
    return -1;
  }
  if (WSGFbtronreadLittleLong(ifile, &height) == -1){                // 22
    return -1;
  }
  if (WSGFbtronreadLittleShort(ifile, &short_tmp) == -1){            // 26
    return -1;
  }
  if (short_tmp != 1){
    // plane != 1 is not supported
    return -1;
  }
  if (WSGFbtronreadLittleShort(ifile, &bit_cnt) == -1){              // 28
    return -1;
  }
  if ((bit_cnt != 1) && (bit_cnt != 4) && (bit_cnt != 8) && (bit_cnt != 24)){
    // bit_cnt=16 is not supported
    return -1;
  }
  if (WSGFbtronreadLittleLong(ifile, &cmptype) == -1){              // 30
    return -1;
  }
  if (cmptype > 2){
    // compressed file is not supported
    return -1;
  }
  if (WSGFbtronreadLittleLong(ifile, &long_tmp) == -1){              // 34
    return -1;
  }
  if (WSGFbtronreadLittleLong(ifile, &long_tmp) == -1){              // 38
    return -1;
  }
  if (WSGFbtronreadLittleLong(ifile, &long_tmp) == -1){              // 42
    return -1;
  }
  if (WSGFbtronreadLittleLong(ifile, &cmapsize) == -1){              // 46
    return -1;
  }
  if (WSGFbtronreadLittleLong(ifile, &long_tmp) == -1){              // 50
    return -1;
  }
  int n, c;
  for (n = 0; n < cmapsize; n++) {
    if ((c = WSGFbtrongetbyte(ifile)) == -1){
      return -1;
    }
    blue[n] = (unsigned char)c;
    if ((c = WSGFbtrongetbyte(ifile)) == -1){
      return -1;
    }
    green[n] = (unsigned char)c;
    if ((c = WSGFbtrongetbyte(ifile)) == -1){
      return -1;
    }
    red[n] = (unsigned char)c;
    if (WSGFbtrongetbyte(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 *tmp, *ftmp;

  int line, dat, x, y;

  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;
        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
            ftmp += 3;
          }
        }
        break;
    }
  }
  delete fbuf;
  long reti = WSGFbtronBufToPixmap(buf, pixmap, width, height,w,h,width*3);

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

long WSGFbtronBufToPixmap(unsigned char *buf,W* mem_gid,long rwidth,long rheight,long* w,long* h,long row_bytes){

  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;

  *mem_gid = WSGIbtronAppDev()->getNewMemGid(vwidth,vheight);
//printf(">>>> mem_gid=0x%x  w,h=%d,%d\n",*mem_gid,vwidth,vheight);
  if (*mem_gid == 0){
    return -1;
  }
  long i,j;
  long ptr=0;
  unsigned char r,g,b;
  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++];
      unsigned long val = 0x10000000;
      val |= r << 16;
      val |= g << 8;
      val |= b;
      PIXVAL pixval;
      gcnv_col(*mem_gid,val,&pixval);
      PNT pt;
      pt.x = j;
      pt.y = i;
      gdra_pnt(*mem_gid,pt,pixval,G_STORE);
    }
    ptr = row_bytes*i;
  }
  return 0;
}
long WSGFbtronBufToPixmap2(unsigned char *buf,W* mem_gid,W* mem_gid2,long rwidth,long rheight,long* w,long* h,long row_bytes){

  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;

  *mem_gid = WSGIbtronAppDev()->getNewMemGid(vwidth,vheight);
  *mem_gid2 = WSGIbtronAppDev()->getNewMemGid(vwidth,vheight);
//printf(">>>> mem_gid=0x%x  w,h=%d,%d\n",*mem_gid,vwidth,vheight);
  if (*mem_gid == 0){
    return -1;
  }
  long i,j;
  long ptr=0;
  unsigned char r,g,b,a;
  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++];
      a = buf[ptr++];
      unsigned long val = 0x10000000;
      val |= r << 16;
      val |= g << 8;
      val |= b;
      PIXVAL pixval;
      gcnv_col(*mem_gid,val,&pixval);
      PNT pt;
      pt.x = j;
      pt.y = i;
      gdra_pnt(*mem_gid,pt,pixval,G_STORE);
      a = ~a;
      val = 0x10000000;
      val |= a << 16;
      val |= a << 8;
      val |= a;
      gcnv_col(*mem_gid2,val,&pixval);
      gdra_pnt(*mem_gid2,pt,pixval,G_STORE);
    }
    ptr = row_bytes*i;
  }
  return 0;
}
long WSGFbtronBmpReadFileToPixmap(char* filename,W* pixmap,long* w,long* h){

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

  long reti = WSGFbtronBmpReadFpToPixmap(ifile, pixmap, w, h);
  fclose(ifile);
  return reti;
}

//PNG

void png_cexcept_error(png_structp png_ptr, png_const_charp msg){
   if(png_ptr){
     fprintf(stderr, "png file read error: %s\n", msg);
   }
}
void png_read_data_fn(png_structp png_ptr,png_bytep data,png_size_t length){
  png_size_t check;
   check = (png_size_t)fread(data, (png_size_t)1, length,
      (png_FILE_p)png_ptr->io_ptr);
   if (check != length)
      png_error(png_ptr, "Read Error");
}
long PngReadFileToPixmap(char* filename,GID* mem_gid,GID* mem_gid2,long* w,long* h){

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

    png_byte            sig[8];
    fread(sig, 1, 8, ifile);
    if (!png_check_sig(sig, 8)){
      fclose(ifile);
      return -1;
    }
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
      (png_error_ptr)png_cexcept_error, (png_error_ptr)NULL);
    if (png_ptr == NULL){
      fclose(ifile);
      return -1;
    } 
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL){
      png_destroy_read_struct(&png_ptr, NULL, NULL);
      fclose(ifile);
      return -1;
    }

//    png_init_io(png_ptr, ifile);
//    png_ptr->io_ptr = (png_voidp)ifile;
    png_set_read_fn(png_ptr,(png_voidp)ifile,png_read_data_fn);
    png_set_sig_bytes(png_ptr, 8);
    png_read_info(png_ptr, info_ptr);
    png_uint_32 png_width;
    png_uint_32 png_height;
    int png_depth;
    int png_color_type;
    png_get_IHDR(png_ptr, info_ptr, &png_width, &png_height, &png_depth,
            &png_color_type, NULL, NULL, NULL);
    if (png_depth == 16){
      png_set_strip_16(png_ptr);
    }
    png_uint_32 png_row_bytes = png_get_rowbytes(png_ptr, info_ptr);
    png_uint_32 png_channels = png_get_channels(png_ptr, info_ptr);
    if (png_depth < 8){
      if (png_color_type == PNG_COLOR_TYPE_GRAY ){
        png_set_gray_1_2_4_to_8(png_ptr);
        png_row_bytes = png_width * 3;
        png_channels = 3;
dbprintf("IMG> PNG_COLOR_TYPE_GRAY c=%d\n",png_channels);
      }else if (png_color_type == PNG_COLOR_TYPE_GRAY_ALPHA){
        png_set_gray_1_2_4_to_8(png_ptr);
        png_row_bytes = png_width * 4;
        png_channels = 4;
dbprintf("IMG> PNG_COLOR_TYPE_GRAY_ALPHA c=%d\n",png_channels);
      }else{
        png_set_expand(png_ptr);
        png_row_bytes = png_width * 3;
        png_channels = 3;
dbprintf("IMG> other c=%d\n",png_channels);
      }
    }
    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)){
      png_set_expand(png_ptr);
      png_row_bytes = png_width;
dbprintf("IMG> PNG_INFO_tRNS c=%d\n",png_channels);
      if (png_channels == 1){
        png_row_bytes = png_width * 4;
        png_channels = 4;
dbprintf("IMG> PNG_INFO_tRNS fixed c=%d\n",png_channels);
      }
      if (png_channels == 3){
        png_row_bytes = png_width * 4;
        png_channels = 4;
dbprintf("IMG> PNG_INFO_tRNS fixed c=%d\n",png_channels);
      }
    }
    if (png_color_type == PNG_COLOR_TYPE_GRAY ||
        png_color_type == PNG_COLOR_TYPE_GRAY_ALPHA){
      png_set_gray_to_rgb(png_ptr);
dbprintf("IMG> PNG_COLOR_TYPE_GRAY || GRAY_ALPHA c=%d\n",png_channels);
      if (png_channels < 2){
        png_row_bytes = png_width;
      }
    }

    if (png_color_type == PNG_COLOR_TYPE_PALETTE){
      png_set_palette_to_rgb(png_ptr);
      png_row_bytes = png_width * 3;
      png_channels = 3;
dbprintf("IMG> PNG_COLOR_TYPE_PALETTE\n");
    }
    if (png_channels == 2){
      png_row_bytes = png_width * 4;
      png_channels = 4;
    }
    if (png_channels == 1){
      png_row_bytes = png_width * 3;
      png_channels = 3;
    }

    long rwidth = png_width;
    long rheight = png_height;
    long components = png_channels;

dbprintf("IMG> png_depth=%d w,h=%d,%d row_bytes=%d c=%d\n",png_depth,png_width,png_height,png_row_bytes,png_channels);
    unsigned char* buf = NULL;
//    if (components == 2){
//      buf = new unsigned char[png_row_bytes * png_height * sizeof(png_byte)*2];
//    }else{
      buf = new unsigned char[png_row_bytes * png_height * sizeof(png_byte)];
//    }
    if (buf == NULL){
fprintf(stderr,"png read error: out of memory..\n");
      png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
      fclose(ifile);
      return -1;
    }
    png_byte** png_row_ptrs = new png_bytep[png_height];
    if (png_row_ptrs == NULL){
fprintf(stderr,"png read error: out of memory..\n");
      png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
      fclose(ifile);
      return -1;
    }
    int i;
    for(i = 0; i < (int)png_height; i++){
//      if (components == 2){
//        png_row_ptrs[i] = (png_byte*)(buf + i * png_row_bytes*2);
//      }else{
        png_row_ptrs[i] = (png_byte*)(buf + i * png_row_bytes);
//      }
    }
    png_read_image(png_ptr, png_row_ptrs);
    png_read_end(png_ptr,NULL);
    delete png_row_ptrs;
    if (components == 4){
      WSGFbtronBufToPixmap2(buf, mem_gid,mem_gid2,png_width,png_height,w,h,png_row_bytes);
    }else if (components == 3){
      *mem_gid2 = 0;
      WSGFbtronBufToPixmap(buf, mem_gid,png_width,png_height,w,h,png_row_bytes);
    }else if (components == 2){
      WSGFbtronBufToPixmap2(buf, mem_gid,mem_gid2,png_width,png_height,w,h,png_row_bytes);
    }else{
      delete buf;
      png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
      fclose(ifile);
      return -1;
    }
    delete buf;
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    fclose(ifile);
//printf("png mem_gid=0x%x w,h=%d,%d\n",mem_gid,*w,*h);
    return 0;
}

static void ehandler(j_common_ptr jinf,int level){
}

static void exhandler(j_common_ptr jinf){
}
static int chandler(j_decompress_ptr jinf){
return TRUE;
}

#define BTRON_ADDED
#ifdef BTRON_ADDED
typedef struct {
  struct jpeg_source_mgr pub;   /* public fields */
  FILE * infile;        /* source stream */
  JOCTET * buffer;      /* start of buffer */
  boolean start_of_file;    /* have we gotten any data yet? */
} _source_mgr;

#define JFREAD(file,buf,sizeofbuf)  \
  ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file)))

void init_source (j_decompress_ptr cinfo)
{
  _source_mgr* src = (_source_mgr*) cinfo->src;
  src->start_of_file = TRUE;
}
boolean fill_input_buffer (j_decompress_ptr cinfo){
  _source_mgr* src = (_source_mgr*) cinfo->src;
  size_t nbytes;
  nbytes = JFREAD(src->infile, src->buffer, 4096);
  if (nbytes <= 0) {
    if (src->start_of_file) /* Treat empty input file as fatal error */
      ERREXIT(cinfo, JERR_INPUT_EMPTY);
    WARNMS(cinfo, JWRN_JPEG_EOF);
    /* Insert a fake EOI marker */
    src->buffer[0] = (JOCTET) 0xFF;
    src->buffer[1] = (JOCTET) JPEG_EOI;
    nbytes = 2;
  }
                                                                                
  src->pub.next_input_byte = src->buffer;
  src->pub.bytes_in_buffer = nbytes;
  src->start_of_file = FALSE;
                                                                                
  return TRUE;
}
void skip_input_data (j_decompress_ptr cinfo, long num_bytes){
  _source_mgr* src = (_source_mgr*) cinfo->src;
  if (num_bytes > 0) {
    while (num_bytes > (long) src->pub.bytes_in_buffer) {
      num_bytes -= (long) src->pub.bytes_in_buffer;
      (void) fill_input_buffer(cinfo);
    }
    src->pub.next_input_byte += (size_t) num_bytes;
    src->pub.bytes_in_buffer -= (size_t) num_bytes;
  }
}
void term_source(j_decompress_ptr){
}
void jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile){
  _source_mgr* src;
  if (cinfo->src == NULL) { /* first time for this JPEG object? */
    cinfo->src = (struct jpeg_source_mgr *)
      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
                  sizeof(_source_mgr));
    src = (_source_mgr*) cinfo->src;
    src->buffer = (JOCTET *)
      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
                  4096 * sizeof(JOCTET));
  }
  src = (_source_mgr*) cinfo->src;
  src->pub.init_source = init_source;
  src->pub.fill_input_buffer = fill_input_buffer;
  src->pub.skip_input_data = skip_input_data;
  src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
  src->pub.term_source = term_source;
  src->infile = infile;
  src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
  src->pub.next_input_byte = NULL; /* until buffer loaded */
}
#endif //BTRON_ADDED

long JpegReadFileToPixmap(char* filename,GID* mem_gid,GID* mem_gid2,long* w,long* h){
    FILE* ifile = fopen(filename,"r");
    if (ifile == NULL){
      return -1;
    }
    struct jpeg_decompress_struct    jinf;
    struct jpeg_error_mgr            jerr;

    jinf.err = jpeg_std_error(&jerr);
    jinf.err->emit_message = ehandler;
    jinf.err->error_exit = exhandler;

    jpeg_create_decompress(&jinf);
    jpeg_set_marker_processor(&jinf,JPEG_COM,chandler);

    jpeg_stdio_src(&jinf,ifile);
    jpeg_read_header(&jinf,TRUE);
    jpeg_calc_output_dimensions(&jinf);
    jpeg_start_decompress(&jinf);

    long rwidth = jinf.output_width;
    long rheight = jinf.output_height;
    long vwidth = *w;
    long vheight = *h;
    long stretched =0;
    if (*w == 0 || *h == 0){
      *w = rwidth;
      *h = rheight;
    }else{
      if ((long)((double)rwidth * vheight/vwidth) < rheight){
        *w = (long)((double)vheight * rwidth/rheight);
      }else{
        *h = (long)((double)vwidth * rheight/rwidth);
      }
      stretched = 1;
    }
    vwidth = *w;
    vheight = *h;

    long components = jinf.output_components;

    unsigned char* buf = new unsigned char[components * rheight * rwidth*sizeof(JSAMPLE)];
    JSAMPROW rowptr[1];
    long i;
    for(i=0; i< rheight; i++){
      rowptr[0] = (JSAMPROW)&(buf[i * rwidth * components]);
      jpeg_read_scanlines(&jinf, rowptr,1);
    }
    if (components == 4){
      WSGFbtronBufToPixmap2(buf, mem_gid,mem_gid2,rwidth,rheight,w,h,components*rwidth*sizeof(JSAMPLE));
    }else
    if (components == 3){
      *mem_gid2 = 0;
      WSGFbtronBufToPixmap(buf, mem_gid,rwidth,rheight,w,h,components*rwidth*sizeof(JSAMPLE));
    }else{
      delete buf;
      jpeg_finish_decompress(&jinf);
      jpeg_destroy_decompress(&jinf);
      fclose(ifile);
      return -1;
    }
    delete buf;
    jpeg_finish_decompress(&jinf);
    jpeg_destroy_decompress(&jinf);
    fclose(ifile);
    return 0;
}

