NHDT->ANH, nethack->anethack, nhdat->anhdat
[aNetHack.git] / win / gem / bitmfile.c
blobf46d7264319ad251225e4c0d43eab9a54d6e296e
1 /****************************\
2 * Bitmap mit Farbtabelle als *
3 * Graphik-Datei speichern *
4 * Autor: Gabriel Schmidt *
5 * (c) 1992 by MAXON-Computer *
6 * Modifiziert von Sebastian *
7 * Bieber, Dez. 1994 *
8 * -> Programmcode *
9 \****************************/
11 * $ANH-Date: 1432512809 2015/05/25 00:13:29 $ $ANH-Branch: master $:$ANH-Revision: 1.4 $
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <fcntl.h>
18 #include <unistd.h>
20 #include "bitmfile.h"
22 /* --- (X) IMG-Implementation ----------------- */
24 #define IMG_COMPRESSED
26 typedef struct {
27 UWORD img_version;
28 UWORD img_headlen;
29 UWORD img_nplanes;
30 UWORD img_patlen;
31 UWORD img_pixw;
32 UWORD img_pixh;
33 UWORD img_w;
34 UWORD img_h;
35 } IMG_HEADER;
37 typedef enum { NONE, SOLID0, SOLID1, PATRUN, BITSTR } IMG_MODE;
39 typedef UBYTE IMG_SOLID;
41 typedef enum { RGB = 0, CMY = 1, Pantone = 2 } XIMG_COLMODEL;
43 typedef struct {
44 ULONG img_ximg;
45 XIMG_COLMODEL img_colmodel;
46 } XIMG_HEADER;
48 typedef struct RGB XIMG_RGB;
50 int
51 bitmap_to_img(FILE_TYP typ, int ww, int wh, unsigned int pixw,
52 unsigned int pixh, unsigned int planes, unsigned int colors,
53 const char *filename,
54 void (*get_color)(unsigned int colind, struct RGB *rgb),
55 void (*get_pixel)(int x, int y, unsigned int *colind))
57 int file, error, cnt;
58 IMG_HEADER header;
59 XIMG_HEADER xheader;
60 XIMG_RGB xrgb;
61 IMG_MODE mode;
62 UBYTE *line_buf, *write_buf;
63 register UBYTE *startpnt, *bufpnt;
64 unsigned int colind, line_len, line, bit;
65 register unsigned int byte;
66 register UBYTE count;
68 /* fill in (X) IMG-Header */
70 header.img_version = 1;
71 header.img_headlen = (UWORD) sizeof(header) / 2;
72 if (typ == XIMG)
73 header.img_headlen +=
74 (UWORD)(sizeof(xheader) + colors * sizeof(xrgb)) / 2;
76 header.img_nplanes = planes;
77 header.img_patlen = 2;
78 header.img_pixw = pixw;
79 header.img_pixh = pixh;
80 header.img_w = ww;
81 header.img_h = wh;
83 xheader.img_ximg = XIMG_MAGIC;
84 xheader.img_colmodel = RGB;
86 /* calculate linelength, allocate buffer. */
88 line_len = (ww + 7) / 8;
90 line_buf = malloc((size_t) planes * line_len);
91 if (line_buf == NULL)
92 return (ENOMEM);
94 /* Worst case: the bufferd line could grow to max. 3 times the length */
95 /* of the original!
98 write_buf = malloc((size_t) 3 * line_len);
99 if (write_buf == NULL) {
100 free(line_buf);
101 return (ENOMEM);
104 /* open file */
106 file = open(filename, O_WRONLY | O_CREAT | O_TRUNC);
107 if (file < 0) {
108 error = errno;
109 free(line_buf);
110 free(write_buf);
111 return (error);
114 /* write Header */
116 if (write(file, &header, sizeof(header)) != sizeof(header)
117 || (typ == XIMG
118 && write(file, &xheader, sizeof(xheader)) != sizeof(xheader))) {
119 error = errno;
120 close(file);
121 free(line_buf);
122 free(write_buf);
123 return (error);
126 /* save the colortable if possible */
128 if (typ == XIMG)
129 for (cnt = 0; cnt < colors; cnt++) {
130 get_color(cnt, &xrgb);
131 if (write(file, &xrgb, sizeof(xrgb)) != sizeof(xrgb)) {
132 error = errno;
133 close(file);
134 free(line_buf);
135 free(write_buf);
136 return (error);
140 /* And now line by line ... */
142 for (line = 0; line < wh; line++) {
143 /* get pixel, split it up and */
144 /* store it as planes in buffer */
146 for (byte = 0; byte < line_len; byte++) {
147 for (cnt = 0; cnt < planes; cnt++)
148 line_buf[cnt * line_len + byte] = 0x00;
150 for (bit = 0; bit < 8; bit++) {
151 if (8 * byte + bit < ww)
152 get_pixel(8 * byte + bit, line, &colind);
154 for (cnt = 0; cnt < planes; cnt++) {
155 line_buf[cnt * line_len + byte] <<= 1;
156 line_buf[cnt * line_len + byte] |= colind & 0x01;
157 colind >>= 1;
162 /* compress bitstrings in buffer */
163 /* and write it to file */
165 for (cnt = 0; cnt < planes; cnt++) {
166 /* Bitstringpointer to start of plane */
168 startpnt = &line_buf[cnt * line_len];
169 bufpnt = write_buf;
171 while (startpnt < &line_buf[(cnt + 1) * line_len]) {
172 /*********************************************/
173 /* Which _new_ compression-mode "fits" the */
174 /* the current byte?
176 /* Note: the compressing modes get choosen */
177 /* "positive". The non compressing BITSTR- */
178 /* mode is choosen only if nothing else */
179 /* "fits" ...
181 /*********************************************/
183 switch (*startpnt) {
184 case 0x00:
185 mode = SOLID0;
186 break;
187 case 0xFF:
188 mode = SOLID1;
189 break;
190 default:
191 if (startpnt < &line_buf[(cnt + 1) * line_len - 3]
192 && *(startpnt) == *(startpnt + 2)
193 && *(startpnt + 1) == *(startpnt + 3))
194 mode = PATRUN;
195 else
196 mode = BITSTR;
199 /************************************************/
200 /* The mode is choosen, now work with it.
202 /* The compressing modi stay current as long as */
203 /* possible.
205 /************************************************/
207 count = 0;
209 switch (mode) {
210 case SOLID0:
211 while ((startpnt < &line_buf[(cnt + 1) * line_len])
212 && (*(startpnt) == 0x00) && (count < 0x7F)) {
213 startpnt++;
214 count++;
216 *(bufpnt++) = count;
217 break;
219 case SOLID1:
220 while ((startpnt < &line_buf[(cnt + 1) * line_len])
221 && (*(startpnt) == 0xFF) && (count < 0x7F)) {
222 startpnt++;
223 count++;
225 *(bufpnt++) = 0x80 | count;
226 break;
228 case PATRUN:
229 *(bufpnt++) = 0x00;
230 startpnt += 2;
231 count = 1;
232 while (startpnt < &line_buf[(cnt + 1) * line_len - 1]
233 && *(startpnt) == *(startpnt - 2)
234 && *(startpnt + 1) == *(startpnt - 1)
235 && (count < 0xFF)) {
236 count++;
237 startpnt += 2;
239 *(bufpnt++) = count;
240 *(bufpnt++) = *(startpnt - 2);
241 *(bufpnt++) = *(startpnt - 1);
242 break;
244 /************************************************/
245 /* The while Condition is ment as follows: */
246 /* */
247 /* while ( NOT(2-Byte-Solidrun possible) &&
249 /* NOT(6-Byte-Patternrun possible) &&
251 /* count < 0xFF
252 * && */
253 /* still Bytes remaining )
255 /* */
256 /* As soon as a _compressing_ alternative shows */
257 /* up, BITSTR gets cancelled!
259 /************************************************/
261 case BITSTR:
262 *(bufpnt++) = 0x80;
263 while (!(((startpnt + count)
264 < &line_buf[(cnt + 1) * line_len - 1])
265 && (((*(startpnt + count) == 0xFF)
266 && (*(startpnt + count + 1) == 0xFF))
267 || ((*(startpnt + count) == 0x00)
268 && (*(startpnt + count + 1) == 0x00))))
269 && !(((startpnt + count)
270 < &line_buf[(cnt + 1) * line_len - 5])
271 && (*(startpnt + count)
272 == *(startpnt + count + 2))
273 && (*(startpnt + count + 1)
274 == *(startpnt + count + 3))
275 && (*(startpnt + count)
276 == *(startpnt + count + 4))
277 && (*(startpnt + count + 1)
278 == *(startpnt + count + 5)))
279 && (count < 0xFF)
280 && ((startpnt + count)
281 < &line_buf[(cnt + 1) * line_len]))
282 count++;
283 *(bufpnt++) = count;
284 for (; count > 0; count--)
285 *(bufpnt++) = *(startpnt++);
286 break;
290 if (write(file, write_buf, bufpnt - write_buf)
291 != (bufpnt - write_buf)) {
292 error = errno;
293 close(file);
294 free(line_buf);
295 free(write_buf);
296 return (error);
301 /*close file, free buffer. */
303 close(file);
304 free(line_buf);
305 free(write_buf);
306 return (0);
309 /*---filetype-dispatcher--------------------*/
311 const char *
312 get_file_ext(FILE_TYP typ)
314 switch (typ) {
315 case IMG:
316 case XIMG:
317 return ("IMG");
318 default:
319 return ("");
324 bitmap_to_file(FILE_TYP typ, int ww, int wh, unsigned int pwx,
325 unsigned int pwy, unsigned int planes, unsigned int colors,
326 const char *filename,
327 void (*get_color)(unsigned int colind, struct RGB *rgb),
328 void (*get_pixel)(int x, int y, unsigned int *colind))
330 switch (typ) {
331 case IMG:
332 case XIMG:
333 return (bitmap_to_img(typ, ww, wh, pwx, pwy, planes, colors, filename,
334 get_color, get_pixel));
335 default:
336 return (-1);