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 \****************************/
10 /*
11 * $NHDT-Date: 1432512809 2015/05/25 00:13:29 $ $NHDT-Branch: master $:$NHDT-Revision: 1.4 $
12 */
13
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <fcntl.h>
18 #include <unistd.h>
19
20 #include "bitmfile.h"
21
22 /* --- (X) IMG-Implementation ----------------- */
23
24 #define IMG_COMPRESSED
25
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;
36
37 typedef enum { NONE, SOLID0, SOLID1, PATRUN, BITSTR } IMG_MODE;
38
39 typedef UBYTE IMG_SOLID;
40
41 typedef enum { RGB = 0, CMY = 1, Pantone = 2 } XIMG_COLMODEL;
42
43 typedef struct {
44 ULONG img_ximg;
45 XIMG_COLMODEL img_colmodel;
46 } XIMG_HEADER;
47
48 typedef struct RGB XIMG_RGB;
49
50 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))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))
56 {
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;
67
68 /* fill in (X) IMG-Header */
69
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;
75
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;
82
83 xheader.img_ximg = XIMG_MAGIC;
84 xheader.img_colmodel = RGB;
85
86 /* calculate linelength, allocate buffer. */
87
88 line_len = (ww + 7) / 8;
89
90 line_buf = malloc((size_t) planes * line_len);
91 if (line_buf == NULL)
92 return (ENOMEM);
93
94 /* Worst case: the bufferd line could grow to max. 3 times the length */
95 /* of the original!
96 */
97
98 write_buf = malloc((size_t) 3 * line_len);
99 if (write_buf == NULL) {
100 free(line_buf);
101 return (ENOMEM);
102 };
103
104 /* open file */
105
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);
112 };
113
114 /* write Header */
115
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);
124 };
125
126 /* save the colortable if possible */
127
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);
137 };
138 };
139
140 /* And now line by line ... */
141
142 for (line = 0; line < wh; line++) {
143 /* get pixel, split it up and */
144 /* store it as planes in buffer */
145
146 for (byte = 0; byte < line_len; byte++) {
147 for (cnt = 0; cnt < planes; cnt++)
148 line_buf[cnt * line_len + byte] = 0x00;
149
150 for (bit = 0; bit < 8; bit++) {
151 if (8 * byte + bit < ww)
152 get_pixel(8 * byte + bit, line, &colind);
153
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;
158 };
159 };
160 };
161
162 /* compress bitstrings in buffer */
163 /* and write it to file */
164
165 for (cnt = 0; cnt < planes; cnt++) {
166 /* Bitstringpointer to start of plane */
167
168 startpnt = &line_buf[cnt * line_len];
169 bufpnt = write_buf;
170
171 while (startpnt < &line_buf[(cnt + 1) * line_len]) {
172 /*********************************************/
173 /* Which _new_ compression-mode "fits" the */
174 /* the current byte?
175 */
176 /* Note: the compressing modes get choosen */
177 /* "positive". The non compressing BITSTR- */
178 /* mode is choosen only if nothing else */
179 /* "fits" ...
180 */
181 /*********************************************/
182
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;
197 };
198
199 /************************************************/
200 /* The mode is choosen, now work with it.
201 */
202 /* The compressing modi stay current as long as */
203 /* possible.
204 */
205 /************************************************/
206
207 count = 0;
208
209 switch (mode) {
210 case SOLID0:
211 while ((startpnt < &line_buf[(cnt + 1) * line_len])
212 && (*(startpnt) == 0x00) && (count < 0x7F)) {
213 startpnt++;
214 count++;
215 };
216 *(bufpnt++) = count;
217 break;
218
219 case SOLID1:
220 while ((startpnt < &line_buf[(cnt + 1) * line_len])
221 && (*(startpnt) == 0xFF) && (count < 0x7F)) {
222 startpnt++;
223 count++;
224 };
225 *(bufpnt++) = 0x80 | count;
226 break;
227
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;
238 };
239 *(bufpnt++) = count;
240 *(bufpnt++) = *(startpnt - 2);
241 *(bufpnt++) = *(startpnt - 1);
242 break;
243
244 /************************************************/
245 /* The while Condition is ment as follows: */
246 /* */
247 /* while ( NOT(2-Byte-Solidrun possible) &&
248 */
249 /* NOT(6-Byte-Patternrun possible) &&
250 */
251 /* count < 0xFF
252 * && */
253 /* still Bytes remaining )
254 */
255 /* */
256 /* As soon as a _compressing_ alternative shows */
257 /* up, BITSTR gets cancelled!
258 */
259 /************************************************/
260
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;
287 };
288 };
289
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);
297 };
298 };
299 };
300
301 /*close file, free buffer. */
302
303 close(file);
304 free(line_buf);
305 free(write_buf);
306 return (0);
307 }
308
309 /*---filetype-dispatcher--------------------*/
310
311 const char *
get_file_ext(FILE_TYP typ)312 get_file_ext(FILE_TYP typ)
313 {
314 switch (typ) {
315 case IMG:
316 case XIMG:
317 return ("IMG");
318 default:
319 return ("");
320 };
321 }
322
323 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))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))
329 {
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);
337 };
338 }
339