[comp.windows.x] standard for pixmap description

david@ics.COM (David B. Lewis) (10/18/89)

Several months ago someone posted information on the development of
a standard for writing X pixmaps to files. As I recall, it had been named
PAX but was quickly renamed.

Does anyone know what has become of this effort?
Does anyone have the address of the people reponsible?

Thanks in advance.

-- 
David B. Lewis david@ics.com ics!david@buita.bu.edu david%ics.UUCP@buita.bu.edu

"No, I'm a member of the X User's Group, not the Ex-User's Group."

colas@trinidad.inria.fr (Colas Nahaboo) (10/19/89)

In article <3381@ics.COM>, david@ics.COM (David B. Lewis) writes:
> Several months ago someone posted information on the development of
> a standard for writing X pixmaps to files. As I recall, it had been named
> PAX but was quickly renamed.

We have renamed it XPM (X PixMap), and we call our bitmaps XBM (X BitMaps)

> Does anyone know what has become of this effort?

It is used by GWM and by the font editor xfedor (made by Daniel Dardailler
of the Koala team -- BULL Research). The C routines work but are not optimized
(slow), and only support 2 ascii chars for a color.

> Does anyone have the address of the people reponsible?

Daniel DARDAILLER
Colas NAHABOO       BULL Research FRANCE -- Koala Project 
                    (GWM X11 Window Manager)
    Internet:       daniel@mirsa.inria.fr, colas@mirsa.inria.fr
Surface Mail:       INRIA - Sophia Antipolis, 
                    2004, route des Lucioles, 06565 Valbonne Cedex -- FRANCE
 Voice phone:       (33) 93.65.77.71, Fax: (33) 93 65 77 66, Telex: 97 00 50 F

And, if anybody else is interested, here is the code of the C routines
patterned along the Xlib ones for bitmaps. Take them, and may the source be
with you!

Feed the rest of this mail to /bin/sh:

#/bin/sh
cat > xpm.h << \END_OF_SHAR_FOR_xpm.h
/* Copyright 1989 GROUPE BULL -- See licence conditions in file COPYRIGHT */
/**************************************************************************
 ****  Constant used in xpm library functions :
 ****
 ****  int XWritePixmapFile(dpy, cmap, filename, pixmap, w, h)
 ****  int XReadPixmapFile(dpy, d, cmap, filename, w, h, depth, pixmap)
 ****  Pixmap XCreatePixmapFromData(dpy, d, cmap, w, h, depth, n, c, col, pix)
 ****
 ****  Daniel Dardailler - Bull RC (89/02/22) e-mail: daniel@mirsa.inria.fr
 **************************************************************************/

#define XPM_FORMAT 1

/* we keep the same codes as for Bitmap management */
#ifndef _XUTIL_H_
#include <X11/Xutil.h>
#endif
#define PixmapSuccess        BitmapSuccess 
#define PixmapOpenFailed     BitmapOpenFailed
#define PixmapFileInvalid    BitmapFileInvalid
#define PixmapNoMemory       BitmapNoMemory


typedef struct _Cixel {
     char c1,c2 ;
   } Cixel ;                    /* 2 chars for one pixel value */

typedef struct _CmapEntry {
     Cixel cixel ;               
     int red,green,blue ;
   } CmapEntry ;                    


#define MAXPRINTABLE 93             /* number of printable ascii chars 
				       minus \ and " for string compat. */

static char * printable = "
.XoO+@#$%&*=-;:?>,<1234567890qwertyuipasdfghjklzxcvbnmMNBVCZASDFGHJKLPIU
YTREWQ!~^/()_`'][{}|" ;
           /* printable begin with a space, so in most case, due to
	      my algorythm, when the number of different colors is
	      less than MAXPRINTABLE, it will give a char follow by 
	      "nothing" (a space) in the readable xpm file */

END_OF_SHAR_FOR_xpm.h
cat > xpm.c << \END_OF_SHAR_FOR_xpm.c
/* Copyright 1989 GROUPE BULL -- See licence conditions in file COPYRIGHT */
/**************************************************************************
 ****  Read/Write package for XPM file format (X PixMap) 
 ****
 ****  int    XWritePixmapFile(dpy, cmap, filename, pixmap, w, h)
 ****  int    XReadPixmapFile(dpy, d, cmap, filename, w, h, depth, pixmap)
 ****  Pixmap XCreatePixmapFromData(dpy, d, cmap, w, h, depth, n, c, col, pix)
 ****
 ****  Daniel Dardailler - Bull RC (89/02/22) e-mail: daniel@mirsa.inria.fr
 **************************************************************************/

/***************************************************************************
 **** Look of XPM file : .. something like X11 'C includable' format

#define drunk_format 1
#define drunk_width 18
#define drunk_height 21
#define drunk_ncolors 4
#define drunk_chars_per_pixel 2
static  char * drunk_colors[] = {
"  " , "#FFFFFFFFFFFF",
". " , "#A800A800A800",
"X " , "White",
"o " , "#540054005400"  
} ;
static char * drunk_pixels[] = {
"                                    ",
"                                    ",
"            . . . . . . .           ",
"          X         . . . .         ",
"        X     X       . . . .       ",
"      o         X       . . .       ",
"    o o     X           . . . .     ",
"  o o o               . . . . .     ",
"o o o               . . . . . .     ",
"o o o                   . . . .     ",
"  X                 X   . . .       ",
"  X   X               . . . .       ",
"    X               . . . .         ",
"    X                 . .           ",
"      X                   X X X     ",
"        X X X               X   X   ",
"              X           X X       ",
"            X X X       X X         ",
"          X       X X X             ",
"      X X                           ",
"                                    " 
} ;


*************************************************************************
*  Version 1 can handle a variable number of chars per pixel
*  - for each different color : n chars can represent the pixel value 
*    and is associed with red, green and blue intensity or colorname.

**************************************************************************/
/*************************************************************************/

#include <stdio.h>
#include <X11/Xlib.h>

#include "xpm.h"      /* PixmapOpenFailed, PixmapSuccess .. MAXPRINTABLE */


/*----------------------------------------------------------------------*/
/* 
 * Write a X Color Pixmap through a specified colormap
 * (THIS VERSION PRODUCE ONLY 2 CHARS PER PIXEL FORMAT : '_chars_per_pixel 2')
 */
int XWritePixmapFile(display, colormap, filename, pixmap, width, height)
/*------------------*/
     Display * display;
     Colormap  colormap ;
     char *filename;
     Pixmap pixmap;
     unsigned int width, height;
{
   XImage *image;                /* client image */
   
   FILE *stream;
   char *name, *stripname;     

   int ncolors = 0 ;             /* number of different colors */

   CmapEntry * cmap ;            /* indexed by ncolors, 
				    dynamicaly allocated by width */

   Cixel * Map ;                 /* should be [width][height] */
   int i,j,p ;

   XColor * colors ;

   int MaxCixel ;               /* theorytical max */

   if (!filename) return(PixmapOpenFailed);
   stripname = (char *) malloc(strlen(filename));
   if (stripname == NULL)
     return PixmapNoMemory ;

   strcpy(stripname,filename);           /* no more use of filename */

   /* extract the short name of the pixmap */
   if (!(name = (char *)rindex(stripname, '/')))
     name = stripname;
   else
     name++;

   if (!(stream = fopen(stripname, "w")))
     return(PixmapOpenFailed);            

   if (stripname = (char *)index(name, '.'))
     *stripname = '\0' ;                  /* modify both name and stripname */
   

   /* Convert pixmap to an image in client memory */
   image = XGetImage(display, pixmap, 0,0,width, height, AllPlanes, ZPixmap);

   /* calcul of ncolors, cmap, Map in a while */
   colors = (XColor *) malloc(width*sizeof(XColor));
   cmap = (CmapEntry *) malloc(MAXPRINTABLE*sizeof(CmapEntry)); 
   Map = (Cixel *) malloc(sizeof(Cixel)*width*height);

   if ((colors == NULL) || (cmap == NULL) || (Map == NULL))
     return PixmapNoMemory ;

   MaxCixel = (MAXPRINTABLE*MAXPRINTABLE)-1 ;

   for (j=0 ; j<height ; j++) {
     for (i=0; i<width ; i++) colors[i].pixel = XGetPixel(image,i,j) ;
     /* ask server for rgb values line by line */
     XQueryColors(display,colormap,colors,width);  /* return : colors */
     for (i=0; i<width ; i++) {
       for (p=0; p<ncolors; p++)
	 if ((colors[i].red   == cmap[p].red) &&
	     (colors[i].green == cmap[p].green) &&
	     (colors[i].blue  == cmap[p].blue)) {  /* already present */
	   *(Map + j*width + i) = cmap[p].cixel ;
	   break ;                     /* stop with p < ncolors */
	 }
       if (p == ncolors) {             /* new rgb value in cmap */
	 cmap[ncolors].red = colors[i].red ;
	 cmap[ncolors].green = colors[i].green ;
	 cmap[ncolors].blue = colors[i].blue ;
	 cmap[ncolors].cixel.c1 = printable[ncolors % MAXPRINTABLE];
	 cmap[ncolors].cixel.c2 = printable[ncolors / MAXPRINTABLE];
	 *(Map + j*width + i) = cmap[ncolors].cixel ;  
	 if (ncolors < MaxCixel) ncolors++ ;
	 if (ncolors % MAXPRINTABLE)          /*  => much memory for cmap */
	   cmap = (CmapEntry *) realloc((char*)cmap,
				(ncolors+MAXPRINTABLE)*sizeof(CmapEntry)); 
	   if (cmap == NULL)
	     return PixmapNoMemory ;
       }
     }
   }       

   /* Write out standard header */
   fprintf(stream, "#define %s_format %d\n",name,XPM_FORMAT);
   fprintf(stream, "#define %s_width %d\n",name,width);
   fprintf(stream, "#define %s_height %d\n",name,height);
   fprintf(stream, "#define %s_ncolors %d\n",name,ncolors);
   fprintf(stream, "#define %s_chars_per_pixel %d\n",name,2);

   fprintf(stream, "static char * %s_colors[] = {\n",name);

   for (i=0; i<ncolors ; i++) {
     fprintf(stream, "\"%c%c\" , \"#%X%X%X\"",
	     cmap[i].cixel.c1,cmap[i].cixel.c2,
	     cmap[i].red,cmap[i].green,cmap[i].blue);
     if (i != (ncolors - 1)) fprintf(stream,",\n"); else
                            fprintf(stream,"\n"); 
   }     
   fprintf(stream, "} ;\n");
   fprintf(stream, "static char * %s_pixels[] = {\n",name);

   for (j=0; j<height ; j++) {
     fprintf(stream, "\"");
     for (i=0; i<width ; i++) 
       fprintf(stream, "%c%c", (*(Map + j*width + i)).c1,
	       (*(Map + j*width + i)).c2);
     if (j != (height - 1)) fprintf(stream,"\",\n"); else
                            fprintf(stream,"\"\n"); 
   }

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

   free(colors);
   free(cmap);
   free(Map) ;
   XDestroyImage(image);

   fclose(stream);
   return PixmapSuccess ;
}


/*------------------------------------------------------------*/
/*------------------------------------------------------------*/
/* following routines are used in XReadPixmapFile() function */
/*------------------------------------------------------------*/

/*
 * read the next line and jump blank lines 
 */
static char *
getline(s,pF)
     char * s ;
     FILE * pF ;
{
    s = fgets(s,256,pF);

    while (s) {
	int len = strlen(s);
	if (len && s[len-1] == '\015')
	    s[--len] = '\0';
	if (len==0) s = fgets(s,256,pF);
	else break;
    }
    return(s);
}
	    

/*
 * fatal message : return code, no exit 
 */
static int fatal(msg, p1, p2, p3, p4)
    char *msg;
{
    fprintf(stderr,"\n");
    fprintf(stderr, msg, p1, p2, p3, p4);
    fprintf(stderr,"\n");
    return PixmapFileInvalid ;
}



/*
 *  Read a Pixmap file in a X Pixmap with specified depth and colormap
 * (THIS VERSION READ ONLY 2 CHARS PER PIXEL FORMAT : '_chars_per_pixel 2')
 */
int XReadPixmapFile (display,d,colormap,filename,width,height,depth,pixmap)
/*-----------------*/
     Display *display;
     Drawable d;
     Colormap colormap ;
     char *filename;
     unsigned int *width, *height;       /* RETURNED */
     int depth ;   
     Pixmap *pixmap;                     /* RETURNED */
{
  GC Gc ;
  XGCValues xgcv;

  FILE *fstream;			/* handle on file  */
  char linebuf[256] ;
  char namebuf[256];
  char type[256];
  char name[256];

  int ncolors ;

  CmapEntry * cmap ;           
  int * Tpixel ;

  char c1, c2, c;
  int red, green, blue ;
  XColor xcolor ;
  int i,j,p;

  
  if ((fstream = fopen(filename, "r")) == NULL) {
    return PixmapOpenFailed;
  }

  getline(linebuf,fstream);
  if ((sscanf(linebuf, "#define %[^_]%s %d", namebuf, type, &p) != 3) 
      || ((strcmp("_format",type)) && (strcmp("_paxformat",type)))
      || (p != XPM_FORMAT)) 
    return fatal("bad '#define NAME_format 1'"); 
  else strcpy(name,namebuf);

  getline(linebuf,fstream);
  if ((sscanf(linebuf, "#define %[^_]%s %d", namebuf, type, width) != 3)
      || (strcmp(name,namebuf)) 
      || (strcmp("_width",type))) 
	return fatal("bad '#define NAME_width w'");

  getline(linebuf,fstream);
  if ((sscanf(linebuf, "#define %[^_]%s %d", namebuf, type, height) != 3)
      || (strcmp(name,namebuf)) 
      || (strcmp("_height",type))) 
	return fatal("bad '#define NAME_height w'");

  getline(linebuf,fstream);
  if ((sscanf(linebuf, "#define %[^_]%s %d", namebuf, type, &ncolors) != 3)
      || (strcmp(name,namebuf)) 
      || (strcmp("_ncolors",type))) 
	return fatal("bad '#define NAME_ncolors w'");

  if (ncolors > (MAXPRINTABLE*MAXPRINTABLE)) 
    return fatal("Too many different colors, version 1");

  getline(linebuf,fstream);
  if ((sscanf(linebuf, "#define %[^_]%s %d", namebuf, type, &p) != 3)
      || (strcmp(name,namebuf)) || (p != 2)
      || (strcmp("_chars_per_pixel",type)))
	return fatal("bad '#define NAME_chars_per_pixel 2'");

  getline(linebuf,fstream);
  if ((sscanf(linebuf, "static char * %[^_]%s = {",namebuf,type) != 2)
      || (strcmp(name,namebuf))
      || (strcmp("_colors[]",type))) 
	return fatal("bad 'static char * NAME_colors[] = {'");

  cmap = (CmapEntry *) malloc(ncolors*sizeof(CmapEntry)) ;
  Tpixel = (int *) malloc(ncolors*sizeof(int)) ;
  if ((cmap == NULL) || (Tpixel == NULL))
    return PixmapNoMemory ;

  getline(linebuf,fstream);
  for (i=0; i<ncolors ; i++) {
    if (sscanf(linebuf, "\"%c%c\" , \"%[^\"]%s",
	       &c1,&c2,
	       namebuf,type) != 4)
      return fatal("bad colormap entry : must be '\"cC\" , \"colordef\",'"); 
    if ((index(printable,c1)) &&
	(index(printable,c2))) {
      cmap[i].cixel.c1 = c1 ;
      cmap[i].cixel.c2 = c2 ;
      if (!XParseColor(display,colormap,namebuf,&xcolor))
	return fatal("bad colordef specification : #RGB or colorname");
      XAllocColor(display,colormap,&xcolor);
      Tpixel[i] = xcolor.pixel ;
    } else
      return fatal("bad cixel value : must be printable");
    
    getline(linebuf,fstream);
  }

  if (strncmp(linebuf, "} ;",3))
    return fatal("missing '} ;'");

  getline(linebuf,fstream);
  if ((sscanf(linebuf, "static char * %[^_]%s = {",namebuf,type) != 2)
      || (strcmp(name,namebuf))
      || (strcmp("_pixels[]",type))) 
	return fatal("bad 'static char * NAME_pixels[] = {'");

  *pixmap = XCreatePixmap(display,d,*width,*height,depth);
  Gc = XCreateGC(display,*pixmap,0,&xgcv);
  
  getline(linebuf,fstream);
  j = 0 ;
  while((j < *height) && strncmp(linebuf, "} ;",3)) {  
    if (strlen(linebuf) < (2*(*width)+2)) 
      return fatal("bad pixmap line length %d",strlen(linebuf));
    for (i=1; i<(2*(*width)) ; i+=2) {
      c1 = linebuf[i] ;
      c2 = linebuf[i+1] ;
      for (p = 0 ; p < ncolors ; p++)
	if ((cmap[p].cixel.c1 == c1)&&(cmap[p].cixel.c2 == c2)) break ;
      if (p != ncolors)
	XSetForeground(display,Gc,Tpixel[p]);
      else 
	return fatal("cixel %c%c not in previous colormap",c1,c2);
      XDrawPoint(display,*pixmap,Gc,i/2,j) ;
    }
    j++ ;
    getline(linebuf,fstream);    
  }

  if (strncmp(linebuf, "} ;",3))
    return fatal("missing '} ;'");

  if (j != *height)
    return fatal("%d too few pixmap line", *height - j);

  free(cmap) ;
  free(Tpixel) ;
  fclose(fstream) ;
  return PixmapSuccess ;
}



  
/*
 *  This function allows you to include in your C program (using #include)
 *  a pixmap file in XPM format that was written by XWritePixmapFile
 * (THIS VERSION MANAGE ONLY 2 CHARS PER PIXEL FORMAT : '_chars_per_pixel 2')
 */
Pixmap XCreatePixmapFromData(display, d, colormap, width, height, depth, 
			      ncolors, chars_per_pixel, colors, pixels)
/*-------------------------*/
     Display *display;
     Drawable d;
     Colormap colormap ;
     unsigned int width, height;       
     int depth ;   
     unsigned int ncolors ;
     unsigned int chars_per_pixel ;
     char ** colors ;           /* array of colormap entries  "cc","#RRGGBB" */
     char ** pixels ;           /* array of pixels lines    "cc..cc00cccc.." */
{
  Pixmap pixmap ;
  GC Gc ;
  XGCValues xgcv;

  CmapEntry * cmap ;           
  int * Tpixel ;

  char c1, c2, c;
  int red, green, blue ;
  XColor xcolor ;
  int i,j,p;
  
  if (ncolors > (MAXPRINTABLE*MAXPRINTABLE)) 
    return fatal("Too many different colors, version 1");

  if (chars_per_pixel != 2) 
    return fatal("version 1 handle only 2 chars_per_pixel");

  /* now we construct cmap and Tpixel from colors array parameter */
  cmap = (CmapEntry *) malloc(ncolors*sizeof(CmapEntry)) ;
  Tpixel = (int *) malloc(ncolors*sizeof(int)) ;
  if ((cmap == NULL) || (Tpixel == NULL))
    return PixmapNoMemory ;

  if (!colors) return fatal("colors not defined");

  for (i=0; i<2*ncolors ; i+=2) {
    if (sscanf(colors[i],"%c%c", &c1,&c2) != 2)
      return fatal("bad colormap entry : must be '\"cC\" , \"colordef\",'"); 
    if ((index(printable,c1)) &&
	(index(printable,c2))) {
      cmap[i/2].cixel.c1 = c1 ;
      cmap[i/2].cixel.c2 = c2 ;
      if (!XParseColor(display,colormap,colors[i+1],&xcolor))
	return fatal("bad colordef specification : #RGB or colorname");
      XAllocColor(display,colormap,&xcolor);
      Tpixel[i] = xcolor.pixel ;
    } else
      return fatal("bad cixel value : must be printable");
  }

  pixmap = XCreatePixmap(display,d,width,height,depth);
  Gc = XCreateGC(display,pixmap,0,&xgcv);

  if (!pixels) return fatal("pixels not defined");
  j = 0 ;
  while (j < height) {  
    if (strlen(pixels[j]) != (2*width))
      return fatal("bad pixmap line length %d",strlen(pixels[j]));
    for (i=0; i< (2*width) ; i+=2) {
      c1 = pixels[j][i] ;
      c2 = pixels[j][i+1] ;
      for (p = 0 ; p < ncolors ; p++)
	if ((cmap[p].cixel.c1 == c1)&&(cmap[p].cixel.c2 == c2)) break ;
      if (p != ncolors)
	XSetForeground(display,Gc,Tpixel[p]);
      else 
	return fatal("cixel %c%c not in previous colormap",c1,c2);
      XDrawPoint(display,pixmap,Gc,i/2,j) ;
    }
    j++ ;
  }

  free(cmap) ;
  free(Tpixel) ;
  return pixmap ;

}
END_OF_SHAR_FOR_xpm.c

david@ics.COM (David B. Lewis) (10/19/89)

In article <3381@ics.COM>, david@ics.COM (David B. Lewis) writes:
> Several months ago someone posted information on the development of
> a standard for writing X pixmaps to files. As I recall, it had been named
> PAX but was quickly renamed.
> 
> Does anyone know what has become of this effort?
> Does anyone have the address of the people reponsible?

Daniel Dardailler of the BULL Centre de Sophia Antipolis has forwarded
details of his XPM text-based pixmap-description scheme to me.
-- 
David B. Lewis david@ics.com ics!david@buita.bu.edu david%ics.UUCP@buita.bu.edu
Some financial models, on the other hand, yield a positive societal value for a
pack of cigarettes: smokers ... inflate group life-insurance premiums, but they
tend to die before costing society much in pensions or nursing-home care. - SA