If an old port is resurrected to work with current version code, its files can be relocated to the appropriate sys or win folder as required. In the meantime, the burden of upkeep can be avoided for the stuff in the outdated folder for now.
339 lines
10 KiB
C
339 lines
10 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: 1432512809 2015/05/25 00:13:29 $ $NHDT-Branch: master $:$NHDT-Revision: 1.4 $
|
|
*/
|
|
|
|
#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);
|
|
};
|
|
}
|