Files
nethack/win/gem/bitmfile.c

345 lines
8.0 KiB
C

/****************************\
* Bitmap mit Farbtabelle als *
* Graphik-Datei speichern *
* Autor: Gabriel Schmidt *
* (c) 1992 by MAXON-Computer *
* Modifiziert von Sebastian *
* Bieber, Dez. 1994 *
* -> Programmcode *
\****************************/
/*
* $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$
* $Date: 2002/01/05 21:06:00 $ $Revision: 1.1 $
*/
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include "bitmfile.h"
/* --- (X) IMG-Implementation ----------------- */
#define IMG_COMPRESSED
typedef struct
{
UWORD img_version;
UWORD img_headlen;
UWORD img_nplanes;
UWORD img_patlen;
UWORD img_pixw;
UWORD img_pixh;
UWORD img_w;
UWORD img_h;
} IMG_HEADER;
typedef enum {NONE, SOLID0, SOLID1, PATRUN, BITSTR} IMG_MODE;
typedef UBYTE IMG_SOLID;
typedef enum { RGB=0, CMY=1, Pantone=2 } XIMG_COLMODEL;
typedef struct
{
ULONG img_ximg;
XIMG_COLMODEL img_colmodel;
} XIMG_HEADER;
typedef struct RGB XIMG_RGB;
int bitmap_to_img(FILE_TYP typ, int ww, int wh,
unsigned int pixw, unsigned int pixh,
unsigned int planes, unsigned int colors,
const char *filename,
void(*get_color)(unsigned int colind, struct RGB *rgb),
void(*get_pixel)(int x, int y, unsigned int *colind) )
{
int file, error, cnt;
IMG_HEADER header;
XIMG_HEADER xheader;
XIMG_RGB xrgb;
IMG_MODE mode;
UBYTE *line_buf, *write_buf;
register UBYTE *startpnt, *bufpnt;
unsigned int colind, line_len, line, bit;
register unsigned int byte;
register UBYTE count;
/* fill in (X) IMG-Header */
header.img_version = 1;
header.img_headlen = (UWORD) sizeof(header) /2;
if (typ == XIMG)
header.img_headlen += (UWORD)(sizeof(xheader)+colors*sizeof(xrgb))/2;
header.img_nplanes = planes;
header.img_patlen = 2;
header.img_pixw = pixw;
header.img_pixh = pixh;
header.img_w = ww;
header.img_h = wh;
xheader.img_ximg = XIMG_MAGIC;
xheader.img_colmodel= RGB;
/* calculate linelength, allocate buffer. */
line_len = (ww+7)/8;
line_buf = malloc((size_t)planes*line_len);
if (line_buf == NULL)
return(ENOMEM);
/* Worst case: the bufferd line could grow to max. 3 times the length */
/* of the original! */
write_buf = malloc((size_t)3*line_len);
if (write_buf == NULL)
{
free(line_buf);
return(ENOMEM);
};
/* open file */
file = open(filename, O_WRONLY | O_CREAT | O_TRUNC);
if (file<0)
{
error = errno;
free(line_buf);
free(write_buf);
return(error);
};
/* write Header */
if (write (file, &header, sizeof(header)) != sizeof(header) ||
(typ == XIMG && write (file, &xheader, sizeof(xheader) ) != sizeof(xheader)))
{
error = errno;
close(file);
free(line_buf);
free(write_buf);
return(error);
};
/* save the colortable if possible */
if ( typ == XIMG )
for (cnt=0; cnt<colors; cnt++)
{
get_color(cnt,&xrgb);
if (write(file,&xrgb,sizeof(xrgb)) != sizeof(xrgb))
{
error = errno;
close(file);
free(line_buf);
free(write_buf);
return(error);
};
};
/* And now line by line ... */
for (line=0; line<wh; line++)
{
/* get pixel, split it up and */
/* store it as planes in buffer */
for (byte=0; byte<line_len; byte++)
{
for (cnt=0; cnt<planes; cnt++)
line_buf[cnt*line_len+byte] = 0x00;
for (bit=0; bit<8; bit++)
{
if (8*byte+bit < ww)
get_pixel(8*byte+bit, line, &colind);
for (cnt=0; cnt<planes; cnt++)
{
line_buf[cnt*line_len+byte] <<= 1;
line_buf[cnt*line_len+byte] |= colind & 0x01;
colind >>= 1;
};
};
};
/* compress bitstrings in buffer */
/* and write it to file */
for (cnt=0; cnt<planes; cnt++)
{
/* Bitstringpointer to start of plane */
startpnt = &line_buf[cnt*line_len];
bufpnt = write_buf;
while (startpnt < &line_buf[(cnt+1)*line_len])
{
/*********************************************/
/* Which _new_ compression-mode "fits" the */
/* the current byte? */
/* Note: the compressing modes get choosen */
/* "positive". The non compressing BITSTR- */
/* mode is choosen only if nothing else */
/* "fits" ... */
/*********************************************/
switch (*startpnt)
{
case 0x00:
mode = SOLID0;
break;
case 0xFF:
mode = SOLID1;
break;
default:
if ( startpnt < &line_buf[(cnt+1)*line_len-3] &&
*(startpnt) == *(startpnt+2) &&
*(startpnt+1) == *(startpnt+3) )
mode = PATRUN;
else
mode = BITSTR;
};
/************************************************/
/* The mode is choosen, now work with it. */
/* The compressing modi stay current as long as */
/* possible. */
/************************************************/
count = 0;
switch (mode)
{
case SOLID0:
while ( (startpnt < &line_buf[(cnt+1)*line_len]) &&
(*(startpnt)==0x00) &&
(count < 0x7F) )
{
startpnt++;
count++;
};
*(bufpnt++) = count;
break;
case SOLID1:
while ( (startpnt < &line_buf[(cnt+1)*line_len]) &&
(*(startpnt)==0xFF) &&
(count < 0x7F) )
{
startpnt++;
count++;
};
*(bufpnt++) = 0x80 | count;
break;
case PATRUN:
*(bufpnt++) = 0x00;
startpnt += 2;
count = 1;
while ( startpnt < &line_buf[(cnt+1)*line_len-1] &&
*(startpnt) == *(startpnt-2) &&
*(startpnt+1) == *(startpnt-1) &&
(count < 0xFF) )
{
count++;
startpnt += 2;
};
*(bufpnt++) = count;
*(bufpnt++) = *(startpnt-2);
*(bufpnt++) = *(startpnt-1);
break;
/************************************************/
/* The while Condition is ment as follows: */
/* */
/* while ( NOT(2-Byte-Solidrun possible) && */
/* NOT(6-Byte-Patternrun possible) && */
/* count < 0xFF && */
/* still Bytes remaining ) */
/* */
/* As soon as a _compressing_ alternative shows */
/* up, BITSTR gets cancelled! */
/************************************************/
case BITSTR:
*(bufpnt++) = 0x80;
while ( !(((startpnt+count)<&line_buf[(cnt+1)*line_len-1])&&
(((*(startpnt+count)==0xFF) && (*(startpnt+count+1)==0xFF))||
((*(startpnt+count)==0x00) && (*(startpnt+count+1)==0x00)))) &&
!(((startpnt+count)<&line_buf[(cnt+1)*line_len-5])&&
(*(startpnt+count) == *(startpnt+count+2))&&
(*(startpnt+count+1) == *(startpnt+count+3))&&
(*(startpnt+count) == *(startpnt+count+4))&&
(*(startpnt+count+1) == *(startpnt+count+5))) &&
(count < 0xFF) &&
((startpnt+count) < &line_buf[(cnt+1)*line_len]) )
count++;
*(bufpnt++) = count;
for(; count>0; count--)
*(bufpnt++) = *(startpnt++);
break;
};
};
if (write(file,write_buf,bufpnt-write_buf) != (bufpnt-write_buf))
{
error = errno;
close(file);
free(line_buf);
free(write_buf);
return(error);
};
};
};
/*close file, free buffer. */
close(file);
free(line_buf);
free(write_buf);
return(0);
}
/*---filetype-dispatcher--------------------*/
const char *get_file_ext(FILE_TYP typ)
{
switch (typ)
{
case IMG:
case XIMG:
return("IMG");
default:
return("");
};
}
int bitmap_to_file(FILE_TYP typ, int ww, int wh,
unsigned int pwx, unsigned int pwy,
unsigned int planes, unsigned int colors,
const char *filename,
void (*get_color)(unsigned int colind, struct RGB *rgb),
void (*get_pixel)(int x, int y, unsigned int *colind))
{
switch (typ)
{
case IMG:
case XIMG:
return(bitmap_to_img(typ,ww,wh,pwx,pwy,planes,colors,filename,get_color,get_pixel));
default:
return(-1);
};
}