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