/* Copyright 1990,91 GROUPE BULL -- See licence conditions in file COPYRIGHT */
/*****************************************************************************\
* XpmCrDataFI.c:                                                              *
*                                                                             *
*  XPM library                                                                *
*  Scan an image and possibly its mask and create an XPM array                *
*                                                                             *
*  Developed by Arnaud Le Hors                                                *
\*****************************************************************************/

#include "xpmP.h"
#ifdef VMS
#include "sys$library:string.h"
#else
#ifdef SYSV
#include <string.h>
#else
#include <strings.h>
#endif
#endif

LFUNC(CreateData, int, (char ***data_return,
		    xpmInternAttrib * attrib, XpmAttributes * attributes));

int
XpmCreateDataFromImage(display, data_return, image, shapeimage, attributes)
    Display *display;
    char ***data_return;
    XImage *image;
    XImage *shapeimage;
    XpmAttributes *attributes;
{
    int ErrorStatus;
    xpmInternAttrib attrib;

    /*
     * initialize return values 
     */
    *data_return = NULL;

    xpmInitInternAttrib(&attrib);

    /*
     * Scan image then create data 
     */
    ErrorStatus = xpmScanImage(display, image, shapeimage,
			       attributes, &attrib);

    if (ErrorStatus == XpmSuccess)
	ErrorStatus = CreateData(data_return, &attrib, attributes);

    xpmFreeInternAttrib(&attrib);

    return (ErrorStatus);
}


#undef RETURN
#define RETURN(status) \
  { if (header) { \
        for (a = 0; a < header_nlines; a++) \
	    if (header[a]) \
		free(header[a]); \
	free(header); \
    } \
    return(status); }

static int
CreateData(data_return, attrib, attributes)
    char ***data_return;
    xpmInternAttrib *attrib;
    XpmAttributes *attributes;
{
    /* calculation variables */
    xpmRgbName rgbn[MAX_RGBNAMES];
    int rgbn_max = 0;
    char *colorname;
    unsigned int *iptr;
    unsigned int a, b, c, x, y, key, d, e;
    char buf[BUFSIZ];
    char **header = NULL;
    unsigned int header_size, header_nlines;
    unsigned int data_size, data_nlines;

    /*
     * read the rgb file if any was specified 
     */
    if (attributes && (attributes->valuemask & XpmRgbFilename))
	rgbn_max = xpmReadRgbNames(attributes->rgb_fname, rgbn);

    /*
     * alloc a temporary array of char pointer for the header section which
     * is the hints line + the color table lines 
     */
    header_nlines = 1 + attrib->ncolors;
    header_size = sizeof(char *) * header_nlines;
    header = (char **) calloc(header_size, sizeof(char *));
    if (!header)
	RETURN(XpmNoMemory);

    /*
     * print the hints line 
     */
    sprintf(buf, "%d %d %d %d",
	    attrib->width, attrib->height, attrib->ncolors, attrib->cpp);

    if (attributes && (attributes->valuemask & XpmHotspot))
	sprintf(&buf[strlen(buf)], " %d %d",
		attributes->x_hotspot, attributes->y_hotspot);

    header[0] = (char *) malloc(strlen(buf) + 1);
    if (!header[0])
	RETURN(XpmNoMemory);
    header_size += strlen(buf) + 1;
    strcpy(header[0], buf);

    /*
     * print colors 
     */
    if (attrib->mask_pixel != UNDEF_PIXEL) {	/* transparent pixel */

	for (b = 0; b < attrib->cpp; b++)
	    buf[b] = attrib->colorStrings[0][b];
	buf[b] = '\0';

	if (attributes && (attributes->valuemask & XpmInfos)
	    && attributes->mask_pixel != UNDEF_PIXEL) {
	    for (key = 1; key < NKEYS + 1; key++) {
		if (attributes->colorTable[attributes->mask_pixel][key])
		    sprintf(&buf[strlen(buf)], "\t%s %s",
			    xpmColorKeys[key - 1],
			attributes->colorTable[attributes->mask_pixel][key]
			);
	    }
	} else
	    sprintf(&buf[strlen(buf)], "\tc %s", TRANSPARENT_COLOR);

	header[1] = (char *) malloc(strlen(buf) + 1);
	if (!header[1])
	    RETURN(XpmNoMemory);
	header_size += strlen(buf) + 1;
	strcpy(header[1], buf);

	d = 1;
    } else
	d = 0;

    for (a = d; a < attrib->ncolors; a++) {	/* other colors */
	for (b = 0; b < attrib->cpp; b++)
	    buf[b] = attrib->colorStrings[a][b];
	buf[b] = '\0';

	c = 1;
	if (attributes && (attributes->valuemask & XpmInfos)) {
	    e = 0;
	    for (b = 0; b < attributes->ncolors; b++) {
		if (b == attributes->mask_pixel) {
		    e = 1;
		    continue;
		}
		if (attributes->pixels[b - e] == attrib->xcolors[a].pixel)
		    break;
	    }
	    if (b != attributes->ncolors) {
		c = 0;
		for (key = 1; key < NKEYS + 1; key++) {
		    if (attributes->colorTable[b][key])
			sprintf(&buf[strlen(buf)], "\t%s %s",
				xpmColorKeys[key - 1],
				attributes->colorTable[b][key]);
		}
	    }
	}
	if (c) {
	    colorname = NULL;
	    if (rgbn_max)
		colorname = xpmGetRgbName(rgbn, rgbn_max,
					  attrib->xcolors[a].red,
					  attrib->xcolors[a].green,
					  attrib->xcolors[a].blue);
	    if (colorname)
		sprintf(&buf[strlen(buf)], "\tc %s", colorname);
	    else
		sprintf(&buf[strlen(buf)], "\tc #%04X%04X%04X",
			attrib->xcolors[a].red,
			attrib->xcolors[a].green,
			attrib->xcolors[a].blue);
	}
	header[1 + a] = (char *) malloc(strlen(buf) + 1);
	if (!header[1 + a])
	    RETURN(XpmNoMemory);
	header_size += strlen(buf) + 1;
	strcpy(header[1 + a], buf);
    }

    /*
     * now we know the size needed, alloc the data and copy the header lines 
     */
    data_size = header_size + attrib->height * sizeof(char *)
	+ attrib->height * (attrib->width * attrib->cpp + 1);

    *data_return = (char **) malloc(data_size);
    if (!*data_return)
	RETURN(XpmNoMemory);

    data_nlines = header_nlines + attrib->height;
    (*data_return)[0] = (char *) (*data_return + data_nlines);
    for (a = 0; a < 1 + attrib->ncolors; a++) {
	strcpy((*data_return)[a], header[a]);
	(*data_return)[a + 1] = (*data_return)[a] + strlen(header[a]) + 1;
    }

    /*
     * print pixels 
     */
    (*data_return)[header_nlines] = (char *) *data_return +
	header_size + attrib->height * sizeof(char *);

    iptr = attrib->pixelindex;

    for (y = 0; y < attrib->height; y++) {

	for (x = 0; x < attrib->width; x++, iptr++)
	    for (b = 0; b < attrib->cpp; b++)
		(*data_return)[header_nlines + y][x * attrib->cpp + b] =
		    attrib->colorStrings[*iptr][b];

	(*data_return)[header_nlines + y][attrib->width * attrib->cpp] = '\0';

	if (y < attrib->height - 1)
	    (*data_return)[header_nlines + y + 1] =
		(*data_return)[header_nlines + y] +
		attrib->width * attrib->cpp + 1;
    }

    xpmFreeRgbNames(rgbn, rgbn_max);

    RETURN(XpmSuccess);
}