Milán Major

netscape-revival

1 branch
Code

cmd/xfe/mkicons.c

/* -*- Mode: C; tab-width: 8 -*-
   mkicons.c --- converting transparent GIFs to embeddable XImage data.
   Copyright © 1995 Netscape Communications Corporation, all rights reserved.
   Created: Jamie Zawinski <jwz@netscape.com>, 17-Aug-95.
   (Danger.  Here be monsters.)
 */

#include "if.h"
#include "nspr/prcpucfg.h"

#define MAX_ANIMS 10

/* =========================================================================
   All this junk is just to get it to link.
   =========================================================================
 */

#ifdef MOCHA
void LM_SendImageEvent(MWContext *context, LO_ImageStruct *image_data,
                       void * event) { return;}
#endif

int NET_URL_Type(const char *URL) {return 0;}
    
void * FE_SetTimeout(TimeoutCallbackFunction func, void * closure,
                     uint32 msecs) { return 0; }
void FE_ClearTimeout(void *timer_id) {}
void XP_Trace(const char * format, ...) {}
void FE_ImageDelete(IL_Image *portableImage) {}
int32 NET_GetMemoryCacheSize(void) { return 1000000; }
int32 NET_GetMaxMemoryCacheSize(void) { return 1000000; }
void NET_FreeURLStruct(URL_Struct * URL_s) {}
int NET_InterruptWindow(MWContext * window_id) {return 0;}
URL_Struct *NET_CreateURLStruct(const char *url, NET_ReloadMethod reload) { return 0; }
History_entry *  SHIST_GetCurrent(History * hist) { return 0; }
int NET_GetURL (URL_Struct * URL_s, FO_Present_Types output_format,
		MWContext * context, Net_GetUrlExitFunc* exit_routine) 
{ return -1; }
Bool LO_BlockedOnImage(MWContext *c, LO_ImageStruct *image) { return FALSE; }
Bool NET_IsURLInDiskCache(URL_Struct *URL_s) {return TRUE;}
XP_Bool NET_IsLocalFileURL(char *address) {return TRUE;}

NET_StreamClass * NET_StreamBuilder (FO_Present_Types  format_out,
				     URL_Struct *anchor, MWContext *window_id)
{ return 0; }

Bool NET_AreThereActiveConnectionsForWindow(MWContext * window_id)
{ return FALSE; }
Bool NET_AreThereStoppableConnectionsForWindow(MWContext * window_id)
{ return FALSE; }
void LO_RefreshAnchors(MWContext *context) { }
void GH_UpdateGlobalHistory(URL_Struct * URL_s) { }
char * NET_EscapeHTML(const char * string) { return (char *)string; }
Bool LO_LocateNamedAnchor(MWContext *context, URL_Struct *url_struct,
			  int32 *xpos, int32 *ypos) { return FALSE; }
Bool LO_HasBGImage(MWContext *context) {return FALSE; }

void FE_UpdateStopState(MWContext *context) {}

void
FE_Alert (MWContext *context, const char *message) {}

#ifdef MOCHA
void LM_RemoveWindowContext(MWContext *context) { }
#endif

extern int il_first_write(void *dobj, const unsigned char *str, int32 len);

/* you loser */
void fe_ReLayout (MWContext *context, NET_ReloadMethod force_reload) {}

char *XP_GetBuiltinString(int16 i);

char *
XP_GetString(int16 i)
{
	return XP_GetBuiltinString(i);
}

Bool
NET_IsURLInMemCache(URL_Struct *URL_s)
{
	return FALSE;
}



/* =========================================================================
   Now it gets REALLY nasty.
   =========================================================================
 */

struct image {
  int width, height;
  char *color_bits;
  char *mono_bits;
  char *mask_bits;
};

int total_images = 0;
struct image images[500] = { { 0, }, };

int total_colors;
IL_IRGB cmap[256];


XP_Bool did_size = FALSE;
int column = 0;

int in_anim = 0;
int inactive_icon_p = 0;
int anim_frames[100] = { 0, };

XP_Bool sgi_p = FALSE;

static unsigned char *bitrev = 0;

static void
init_reverse_bits(void)
{
  if(!bitrev) 
    {
      int i, x, br;
      bitrev = (unsigned char *)XP_ALLOC(256);
      for(i=0; i<256; i++) 
        {
          br = 0;
          for(x=0; x<8; x++) 
            {
              br = br<<1;
              if(i&(1<<x))
                br |= 1;
            }
          bitrev[i] = br;
        }
    }
}

int
image_size (MWContext *context, IL_ImageStatus message,
	    IL_Image *il_image, void *data)
{
  if (il_image->bits)
    free (il_image->bits);
  if (!did_size)
    {
      fprintf (stdout, " %d, %d,\n", il_image->width, il_image->height);
      column = 2;
      did_size = TRUE;
    }

  il_image->bits = malloc (il_image->widthBytes * il_image->height);
  memset (il_image->bits, ~0, (il_image->widthBytes * il_image->height));
  if (!il_image->mask && il_image->transparent)
    {
      int size = il_image->maskWidthBytes * il_image->height;
      il_image->mask = malloc (size);
      memset (il_image->mask, ~0, size);
    }

  return 0;
}

void
image_data (MWContext *context, IL_ImageStatus message, IL_Image *il_image,
	    void *data, int start_row, int num_rows, XP_Bool update_image)
{
  int i;
  int row_parity;
  unsigned char *s, *m, *scanline, *mask_scanline, *end;

  if (message != ilComplete) abort ();
  images[total_images].width = il_image->width;
  images[total_images].height = il_image->height;
  if (il_image->depth == 1)
    images[total_images].mono_bits = il_image->bits;
  else
    images[total_images].color_bits = il_image->bits;
  if (il_image->mask)
    images[total_images].mask_bits = il_image->mask;

  for (i = 0; i < il_image->colors; i++)
    {
      int j;
      for (j = 0; j < total_colors; j++)
	{
	  if (il_image->map[i].red   == cmap[j].red &&
	      il_image->map[i].green == cmap[j].green &&
	      il_image->map[i].blue  == cmap[j].blue)
	    goto FOUND;
	}
      cmap[total_colors].red   = il_image->map[i].red;
      cmap[total_colors].green = il_image->map[i].green;
      cmap[total_colors].blue  = il_image->map[i].blue;

      total_colors++;
      if (total_colors > 100)
	abort();
    FOUND:
      ;
    }

  if (il_image->depth == 1)
    return;
  if (il_image->depth != 32) abort();

  /* Generate monochrome icon from color data. */
  scanline = il_image->bits;
  mask_scanline = il_image->mask;
  end = scanline + (il_image->widthBytes * il_image->height);
  row_parity = 0;
      
  fprintf (stdout, "\n (unsigned char*)\n \"");
  column = 2;
  while (scanline < end)
    {
      unsigned char *scanline_end = scanline + (il_image->width * 4);
      int luminance, pixel;
      int bit = 0;
      int byte = 0;

      row_parity ^= 1;
      for (m = mask_scanline, s = scanline; s < scanline_end; s += 4)
        {
          unsigned char r = s[3];
          unsigned char g = s[2];
          unsigned char b = s[1];
          if (column > 74)
            {
              fprintf (stdout, "\"\n \"");
              column = 2;
            }
          luminance = (0.299 * r) + (0.587 * g) + (0.114 * b);

          pixel =
            ((luminance < 128))                      ||
            ((r ==  66) && (g == 154) && (b == 167)); /* Magic: blue */
          byte |= pixel << bit++;

          if ((bit == 8) || ((s + 4) >= scanline_end)) {
            /* Handle transparent areas of the icon */
            if (il_image->mask)
              byte &= bitrev[*m++];

            /* If this is a grayed-out inactive icon, superimpose a 
               checkerboard mask over the data */
            if (inactive_icon_p)
              byte &= 0x55 << row_parity;

            fprintf (stdout, "\\%03o", byte);
            column += 4;
            bit = 0;
            byte = 0;
          }
        }
      scanline += il_image->widthBytes;
      mask_scanline += il_image->maskWidthBytes;
    }

  fprintf (stdout, "\",\n");
  column = 0;

  /* Mask data */
  if (il_image->mask)
    {
      scanline = il_image->mask;
      end = scanline + (il_image->maskWidthBytes * il_image->height);
      fprintf (stdout, "\n (unsigned char*)\n \"");
      column = 2;
      for (;scanline < end; scanline += il_image->maskWidthBytes)
        {
          unsigned char *scanline_end = scanline + ((il_image->width + 7) / 8);
          for (s = scanline; s < scanline_end; s++)
            {
              if (column > 74)
                {
                  fprintf (stdout, "\"\n \"");
                  column = 2;
                }
              fprintf (stdout, "\\%03o", bitrev[*s]);
              column += 4;
            }
        }

      fprintf (stdout, "\",\n");
      column = 0;
    }
  else
    {
      fprintf (stdout, "\n  0,\n");
      column = 0;
    }

  /* Color icon */
  fprintf (stdout, "\n (unsigned char*)\n \"");
  column = 2;

  scanline = il_image->bits;
  end = scanline + (il_image->widthBytes * il_image->height);
  for (;scanline < end; scanline += il_image->widthBytes)
    {
      unsigned char *scanline_end = scanline + (il_image->width * 4);
      for (s = scanline; s < scanline_end; s += 4)
        {
          unsigned char r = s[3];
          unsigned char g = s[2];
          unsigned char b = s[1];
          int j;
          for (j = 0; j < total_colors; j++)
            if (r == cmap[j].red &&
                g == cmap[j].green &&
                b == cmap[j].blue)
              {
                if (column > 74)
                  {
                    fprintf (stdout, "\"\n \"");
                    column = 2;
                  }
                fprintf (stdout, "\\%03o", j);
                column += 4;
                goto DONE;
              }
          abort();
        DONE:
          ;
        }
    }
      

  if (!in_anim)
    fprintf (stdout, "\"\n};\n\n");
  column = 0;

  if (il_image->bits) free (il_image->bits);
  il_image->bits = 0;
  if (il_image->mask) free (il_image->mask);
  il_image->mask = 0;
}


void
set_title (MWContext *context, char *title)
{
}


void
do_file (char *file)
{
  static int counter = 0;
  FILE *fp;
  char *data;
  int size;
  NET_StreamClass *stream;
  struct stat st;
  char *s;

  URL_Struct *url;
  il_container *ic;
  il_process *proc;
  MWContext cx;
  ContextFuncs fns;
  IL_IRGB trans;
  XP_Bool wrote_header = FALSE;

  memset (&cx, 0, sizeof(cx));
  memset (&fns, 0, sizeof(fns));
  
  url = XP_NEW_ZAP (URL_Struct);
  proc = XP_NEW_ZAP (il_process);

  url->address = strdup("\000\000");
  cx.funcs = &fns;

  fns.ImageSize = image_size;
  fns.ImageData = image_data;
  fns.SetDocTitle = set_title;

  {
    /* make a container */
    ic = XP_NEW_ZAP(il_container);
    ic->hash = 0;
    ic->urlhash = 0;
    ic->cx = &cx;
    ic->forced = 0;

    ic->image = XP_NEW_ZAP(IL_Image);

    ic->next = 0;
    ic->ip = proc;
    cx.imageProcess = proc;

    ic->state = IC_START;
  }

  url->fe_data = ic;

  ic->clients = XP_NEW_ZAP(il_client);
  ic->clients->cx = &cx;

  if (stat (file, &st))
    return;
  size = st.st_size;

  data = (char *) malloc (size + 1);
  fp = fopen (file, "r");
  fread (data, 1, size, fp);
  fclose (fp);

  s = strrchr (file, '.');
  if (s) *s = 0;
  s = strrchr (file, '/');
  if (s)
    s++;
  else
    s = file;

  if (in_anim && strncmp (s, "Anim", 4))
    /* once you've started anim frames, don't stop. */
    abort ();

  if ((!strcmp (s, "AnimSm00") || !strcmp (s, "AnimHuge00")) ||
      ((!strcmp (s, "AnimSm01") || !strcmp (s, "AnimHuge01")) &&
       (!in_anim ||
	anim_frames[in_anim-1] > 1)))
    {
      char *s2;
      if (in_anim)
	{
	  fprintf (stdout, "\"\n }\n};\n\n");
	  if (sgi_p)
	    {
	      fprintf (stdout, "\n#endif /* __sgi */\n\n");
	      sgi_p = FALSE;
	    }
	}

      s2 = s - 2;
      while (s2 > file && *s2 != '/')
	s2--;
      s[-1] = 0;
      if (*s2 == '/')
	s2++;

      if (strstr (s2, "sgi"))
	{
	  fprintf (stdout, "#ifdef __sgi\n");
	  sgi_p = TRUE;
	}

      fprintf (stdout, "struct fe_icon_data anim_%s_%s[] = {\n",
	       s2, (!strncmp (s, "AnimHuge", 8) ? "large" : "small"));
      wrote_header = TRUE;
      in_anim++;
    }

  if (in_anim)
    {
      if (strncmp (s, "Anim", 4)) abort ();
      if (!wrote_header)
	fprintf (stdout, "\"\n },\n\n");
      fprintf (stdout, "  /* %s */\n  { ", s);
      anim_frames[in_anim-1]++;
    }
  else
    {
      char *s2 = s;
      while (*s2)
	{
	  if (*s2 == '.') *s2 = '_';
	  s2++;
	}
      fprintf (stdout, "\nstruct fe_icon_data %s = {\n", s);
    }

  column = 0;
  did_size = FALSE;

  trans.red = trans.green = trans.blue = 0xC0;

  cx.colorSpace = NULL;

  IL_EnableTrueColor (&cx, 32,
#if defined(IS_LITTLE_ENDIAN)
		      24, 16, 8,
#elif defined(IS_BIG_ENDIAN)
		      0, 8, 16,
#else
  ERROR!  Endianness unknown.
#endif
		      8, 8, 8,
		      &trans, FALSE);

  ic->cs = cx.colorSpace;
  IL_SetPreferences (&cx, FALSE, ilClosestColor);
  url->address[0] = counter++;
  stream = IL_NewStream (FO_PRESENT,
			 (strstr (file, ".gif") ? (void *) IL_GIF :
			  strstr (file, ".jpg") ? (void *) IL_JPEG :
			  strstr (file, ".jpeg") ? (void *) IL_JPEG :
			  strstr (file, ".xbm") ? (void *) IL_XBM :
			  (void *) IL_GIF),
			 url, &cx);
  stream->put_block (stream->data_object, data, size);
  stream->complete (stream->data_object);

  free (data);

  total_images++;


}


int
main (argc, argv)
     int argc;
     char **argv;
{
  int i;

  init_reverse_bits();

  fprintf (stdout,
	   "/* -*- Mode: Fundamental -*- */\n\n#include \"icondata.h\"\n");

  for (i = 1; i < argc; i++)
    {
      char *filename = argv[i];
      inactive_icon_p = (strstr(filename, ".i.gif") != NULL);
      do_file (filename);
    }

  if (in_anim)
    {
      fprintf (stdout, "\"\n }\n};\n\n");
      if (sgi_p)
	{
	  fprintf (stdout, "\n#endif /* __sgi */\n\n");
	  sgi_p = FALSE;
	}
    }

  fprintf (stdout, "unsigned int fe_n_icon_colors = %d;\n", total_colors);

  if (in_anim)
    {
      fprintf (stdout, "unsigned int fe_anim_frames[%d] = { ", MAX_ANIMS);
      i = 0;
      while (anim_frames[i])
	{
	  fprintf (stdout, "%d%s", anim_frames[i],
		   anim_frames[i+1] ? ", " : "");
	  i++;
	}
      fprintf (stdout, " };\n\n");
    }

  fprintf (stdout, "unsigned short fe_icon_colors[256][3] = {\n");
  for (i = 0; i < total_colors; i++)
    fprintf (stdout, " { 0x%02x%02x, 0x%02x%02x, 0x%02x%02x }%s\n",
	     cmap[i].red,   cmap[i].red,
	     cmap[i].green, cmap[i].green,
	     cmap[i].blue,  cmap[i].blue,
	     (i == total_colors-1) ? "" : ",");

  if ( total_colors == 0 ) {
      fprintf(stdout, "0\n");
  }

  fprintf (stdout, "};\n");

  return 0;
}