/* w1gif.c   capture pixels and write w1gif.gif */

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef XBITS
  long int background = 0xFFFF; /* user must use white background 16 bit */
                                /* 0xffff on PC, FFFFFF on Sun */
#else
  long int background = 0xFFFFFF; /* user must use white background 24 bit */
#endif

static void doInitialize(void);          /* function prototypes used below */
static void doCreateWindows(void);
static void doCreateGraphicsContext(void);
static void doExpose(XEvent *eventP);
static void doHandleEvents(void);
static void write_gif_file(char filename[]);
static void write_gif_data(unsigned char datablk[], unsigned char *byte_count,
                           int * nbit, FILE * FpGif);

/* just w1.c pasted in here to put some bits on the screen */
Display *dpy;
Window window1;
GC gc;
Screen *screen;

int frame_xmax = 199; /* capture area, must be visible */
int frame_xmin = 1;
int frame_ymax = 99;
int frame_ymin = 1;


/********************** The main program *******************************/
int main(int argc, char *argv[])
{          
    doInitialize();
    doHandleEvents(); /* this never returns */
    return 0;
}                                        

/***************** doInitialize **************************/
static void doInitialize(void)
{
    dpy = XOpenDisplay(0); 
    if (!dpy){
        printf("Display not opened!\n");
        exit(1);
    }
    screen = XDefaultScreenOfDisplay(dpy);

    doCreateWindows();

    doCreateGraphicsContext();

    XStoreName(dpy, window1, "W1  click to exit");

    XMapWindow(dpy, window1);
} 

/******* doCreateWindows *********/
static void doCreateWindows(void)
{   
  int window1X = 300;
  int window1Y = 200;
  int window1W = 200;
  int window1H = 100;
  XSetWindowAttributes xswa;
                   
  /* Create the window1 window */
  xswa.event_mask = ExposureMask | ButtonPressMask;
  xswa.background_pixel = XWhitePixelOfScreen(screen);

  window1 = XCreateWindow(dpy,
                          XRootWindowOfScreen(screen),
                          window1X, 
                          window1Y,
                          window1W,
                          window1H,
                          0,
                          XDefaultDepthOfScreen(screen),
                          InputOutput,
                          XDefaultVisualOfScreen(screen),
                          CWEventMask | CWBackPixel,
                          &xswa);
}

/******** Create the graphics context *********/    
static void doCreateGraphicsContext(void)
{                                                
  XGCValues xgcv;
    
  /* Create graphics context. */
  xgcv.background = XWhitePixelOfScreen(screen);
  xgcv.foreground = XBlackPixelOfScreen(screen);
  gc = XCreateGC(dpy, window1, GCForeground | GCBackground, &xgcv);   
}


/****************** doHandleEvents ***********************/
static void doHandleEvents(void)
{
  XEvent event;         

  for ( ; ; )
  {
    XNextEvent(dpy, &event);
    switch (event.type)
    { 
      case Expose:
        doExpose(&event);
        break;
      case ButtonPress: /* added write .gif file here */

        write_gif_file("w1gif.gif");

        exit(0); /* shut down */
    }
  }                                           
}

/***** draw and write the message in the window *****/
static void doExpose(XEvent *eventP)
{
  static char message[] = {"Click here to exit"}; 

  /* If this is an expose event on our window1 window,
     then write the text and rectangle. */

  if (eventP->xexpose.window != window1) return;
  XClearWindow(dpy, window1);
  XDrawImageString(dpy, window1, gc, 50, 25, message, strlen(message));
  XDrawRectangle(dpy, window1, gc, 50, 50, 100, 25);
} /* end old w1.c */


static void write_gif_file(char filename[])
{
  /* frame_xmin, ... needed first */
  FILE * FpGif;
  int i, j, this_bit;
  long int my_pixel;
  XImage * my_image;
  unsigned char byte_count;
  unsigned char datablk[1280]; /* [257] */
  int nbit;
  int dbit, jbit;
  int dbyte;
  int ncode = 3; /* smallest for 1 bit */
  int width, height;   /* from frame */
  int xoffs, yoffs;    /* from frame */
  unsigned char head[13]={ 0x47, 0x49, 0x46, 0x38, 0x39, 0x61,
                           0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00};
                         /* head[6]=low width,  head[7]=high width,
                            head[8]=low height, head[9]=high height */
  unsigned char coltab[6]= {0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF};
  unsigned char imgblk[11]= {0x2C, 0x00, 0x00, 0x00, 0x00, 
                             0x00, 0x00, 0x00, 0x00,
                             0x00, 0x02};
                       /* imgblk[5]=low width,  imgblk[6]=high width,
                          imgblk[7]=low height, imgblk[8]=high height */


  printf("gif_out stating to write %s \n", filename);
  FpGif=fopen(filename,"wb");
  if(FpGif==NULL)
  {
    printf("could not open %s for write\n", filename);
    return;
  }
  width =  frame_xmax-frame_xmin-1; /* omit frame line */
  height = frame_ymax-frame_ymin-1;

  my_image = XGetImage(dpy, window1,
		       frame_xmin+1, frame_ymin+1,
                       frame_xmax-frame_xmin-1, frame_ymax-frame_ymin-1,
                       0xFFFFFF, XYPixmap);
  if(my_image == NULL)
  {
    printf("can't get my_image\n");
    fclose(FpGif);
    return;
  }
  head[6]=width&0xFF;
  head[7]=width>>8;
  head[8]=height&0xFF;
  head[9]=height>>8;
  for(i=0; i<13; i++) putc(head[i], FpGif); /* header */
  for(i=0; i<6; i++) putc(coltab[i], FpGif); /* color table */
  imgblk[5]=width&0xFF;
  imgblk[6]=width>>8;
  imgblk[7]=height&0xFF;
  imgblk[8]=height>>8;
  for(i=0; i<11; i++) putc(imgblk[i], FpGif); /* image desc */
  /* read pixels and do non LZW encode */
  /* pack bits in datablk */
  for(i=0; i<1280; i++)datablk[i]=0;  /* zero image data */
  nbit = 0;

  for(i=0; i<frame_ymax-frame_ymin-1; i++) /* XImage rightside up */
  {                                        /* on PC and Sun       */
    for(j=0; j<frame_xmax-frame_xmin-1; j++)
    {
      my_pixel = XGetPixel(my_image, j, i);
      printf("my_pixel[%d][%d]=%X \n", i, j, my_pixel);
      this_bit = 0;
      if(my_pixel == background) this_bit = 1; /* reverse image */

      dbit = 0x04;          /* Q&D reset code */
      dbyte = nbit/8;       /* byte index */
      jbit  = nbit-dbyte*8; /* bit index in byte */
      datablk[dbyte] = (datablk[dbyte]+(dbit<<jbit))&0xFF;
      if(jbit+ncode>7) datablk[dbyte+1] = dbit>>(8-jbit);
      nbit = nbit + ncode;

      dbit = this_bit;      /* index into color table to write out */
      dbyte = nbit/8;       /* byte index */
      jbit  = nbit-dbyte*8; /* bit index in byte */
      datablk[dbyte] = (datablk[dbyte]+(dbit<<jbit))&0xFF;
      if(jbit+ncode>7) datablk[dbyte+1] = dbit>>(8-jbit);
      nbit = nbit + ncode;
      byte_count = nbit/8;
      if(byte_count >=253)
                   write_gif_data(datablk, &byte_count, &nbit, FpGif);
    } /* end j loop */
  } /* end i loop */
  dbit = 0x05;          /* end code */
  dbyte = nbit/8;       /* byte index */
  jbit  = nbit-dbyte*8; /* bit index in byte */
  datablk[dbyte] = (datablk[dbyte]+(dbit<<jbit))&0xFF;
  if(jbit+ncode>7) datablk[dbyte+1] = dbit>>(8-jbit);
  nbit = nbit + ncode;
  byte_count = (nbit+7)/8;
  write_gif_data(datablk, &byte_count, &nbit, FpGif);
  putc(0x00, FpGif); /* byte count of zero, indicating last data */
  putc(0x3b, FpGif); /* file terminator */
  fclose(FpGif);
} /* end write_gif_file */

static void write_gif_data(unsigned char datablk[], unsigned char *byte_count,
                           int * nbit, FILE * FpGif)
{
  int j;
  /* write byte count of 254 or less, doing a data block */
  putc(*byte_count, FpGif); /* image data byte count */

  /* write packed bits as bytes */
  for(j=0; j<(*byte_count); j++)
  {
    putc(datablk[j], FpGif); /* image data */
  }
  datablk[0] = datablk[*byte_count];
  for(j=1; j<1280; j++)datablk[j]=0;  /* zero image data */
  *nbit = (*nbit)-(*byte_count)*8;
  *byte_count = 0;
} /* end write_gif_data */

/* end w1gif.c */

