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 #include <errno.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <fcntl.h>
15 #include <unistd.h>
16 
17 #include "bitmfile.h"
18 
19 /* --- (X) IMG-Implementation ----------------- */
20 
21 #define IMG_COMPRESSED
22 
23 typedef struct
24 	{
25 	UWORD img_version;
26 	UWORD img_headlen;
27 	UWORD img_nplanes;
28 	UWORD img_patlen;
29 	UWORD img_pixw;
30 	UWORD img_pixh;
31 	UWORD img_w;
32 	UWORD img_h;
33 	} IMG_HEADER;
34 
35 typedef enum {NONE, SOLID0, SOLID1, PATRUN, BITSTR} IMG_MODE;
36 
37 typedef UBYTE IMG_SOLID;
38 
39 typedef enum { RGB=0, CMY=1, Pantone=2 } XIMG_COLMODEL;
40 
41 typedef struct
42 	{
43 	ULONG img_ximg;
44 	XIMG_COLMODEL img_colmodel;
45 	} XIMG_HEADER;
46 
47 typedef struct RGB XIMG_RGB;
48 
49 
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))50 int bitmap_to_img(FILE_TYP typ,	int ww, int wh,
51 									unsigned int pixw, unsigned int pixh,
52 									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 += (UWORD)(sizeof(xheader)+colors*sizeof(xrgb))/2;
74 
75 	header.img_nplanes	= planes;
76 	header.img_patlen		= 2;
77 	header.img_pixw			= pixw;
78 	header.img_pixh			= pixh;
79 	header.img_w				= ww;
80 	header.img_h				= wh;
81 
82 	xheader.img_ximg		= XIMG_MAGIC;
83 	xheader.img_colmodel= RGB;
84 
85 	/* calculate linelength, allocate buffer. */
86 
87 	line_len 	= (ww+7)/8;
88 
89 	line_buf 	= malloc((size_t)planes*line_len);
90 	if (line_buf == NULL)
91 		return(ENOMEM);
92 
93 	/* Worst case: the bufferd line could grow to max. 3 times the length */
94 	/* of the original!																	*/
95 
96 	write_buf = malloc((size_t)3*line_len);
97 	if (write_buf == NULL)
98 		{
99 		free(line_buf);
100 		return(ENOMEM);
101 		};
102 
103 	/* open file */
104 
105 	file = open(filename, O_WRONLY | O_CREAT | O_TRUNC);
106 	if (file<0)
107 		{
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 &&	write (file, &xheader, sizeof(xheader) ) != sizeof(xheader)))
118 			{
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 		{
131 		get_color(cnt,&xrgb);
132 		if (write(file,&xrgb,sizeof(xrgb)) != sizeof(xrgb))
133 			{
134 			error = errno;
135 			close(file);
136 			free(line_buf);
137 			free(write_buf);
138 			return(error);
139 			};
140 		};
141 
142 	/* And now line by line ... */
143 
144 	for (line=0; line<wh; line++)
145 		{
146 		/* get pixel, split it up and */
147 		/* store it as planes in buffer */
148 
149 		for (byte=0; byte<line_len; byte++)
150 			{
151 			for (cnt=0; cnt<planes; cnt++)
152 				line_buf[cnt*line_len+byte] = 0x00;
153 
154 			for (bit=0; bit<8; bit++)
155 				{
156 				if (8*byte+bit < ww)
157 					get_pixel(8*byte+bit, line, &colind);
158 
159 				for (cnt=0; cnt<planes; cnt++)
160 					{
161 					line_buf[cnt*line_len+byte] <<= 1;
162 					line_buf[cnt*line_len+byte]  |= colind & 0x01;
163 					colind >>= 1;
164 					};
165 				};
166 			};
167 
168 		/* compress bitstrings in buffer */
169 		/* and write it to file        */
170 
171 		for (cnt=0; cnt<planes; cnt++)
172 			{
173 			/* Bitstringpointer to start of plane */
174 
175 			startpnt = &line_buf[cnt*line_len];
176 			bufpnt = write_buf;
177 
178 			while (startpnt < &line_buf[(cnt+1)*line_len])
179 				{
180 				/*********************************************/
181 				/* Which _new_ compression-mode "fits" the	*/
182 				/* the current byte?									*/
183 				/* Note: the compressing modes get choosen	*/
184 				/* "positive". The non compressing BITSTR-	*/
185 				/* mode is choosen only if nothing else 		*/
186 				/* "fits" ...											*/
187 				/*********************************************/
188 
189 				switch (*startpnt)
190 					{
191 					case 0x00:
192 						mode = SOLID0;
193 						break;
194 					case 0xFF:
195 						mode = SOLID1;
196 						break;
197 					default:
198 						if ( startpnt	<  &line_buf[(cnt+1)*line_len-3] &&
199 								*(startpnt)   == *(startpnt+2)						 &&
200 								*(startpnt+1) == *(startpnt+3)						 )
201 							mode = PATRUN;
202 						else
203 							mode = BITSTR;
204 					};
205 
206 				/************************************************/
207 				/* The mode is choosen, now work with it.			*/
208 				/* The compressing modi stay current as long as	*/
209 				/* possible.												*/
210 				/************************************************/
211 
212 				count = 0;
213 
214 				switch (mode)
215 					{
216 					case SOLID0:
217 						while (	(startpnt < &line_buf[(cnt+1)*line_len])	&&
218 									 	(*(startpnt)==0x00)											&&
219 									 	(count < 0x7F) 				 										)
220 									{
221 									startpnt++;
222 									count++;
223 									};
224 						*(bufpnt++) = count;
225 						break;
226 
227 					case SOLID1:
228 						while (	(startpnt < &line_buf[(cnt+1)*line_len])	&&
229 									 	(*(startpnt)==0xFF)											&&
230 									 	(count < 0x7F) 				 										)
231 									{
232 									startpnt++;
233 									count++;
234 									};
235 						*(bufpnt++) = 0x80 | count;
236 						break;
237 
238 					case PATRUN:
239 						*(bufpnt++) = 0x00;
240 						startpnt += 2;
241 						count = 1;
242 						while (	startpnt < &line_buf[(cnt+1)*line_len-1]	&&
243 										*(startpnt)		== *(startpnt-2)						&&
244 										*(startpnt+1)	== *(startpnt-1)						&&
245 										(count < 0xFF)														)
246 									{
247 									count++;
248 									startpnt += 2;
249 									};
250 						*(bufpnt++) = count;
251 						*(bufpnt++) = *(startpnt-2);
252 						*(bufpnt++) = *(startpnt-1);
253 						break;
254 
255 					/************************************************/
256 					/* The while Condition is ment as follows:		*/
257 					/*																							*/
258 					/* while ( NOT(2-Byte-Solidrun possible)	&&		*/
259 					/*			 NOT(6-Byte-Patternrun possible)	&&		*/
260 					/*				 count < 0xFF										&&		*/
261 					/*			 still Bytes remaining			)			*/
262 					/*																							*/
263 					/* As soon as a _compressing_ alternative	shows	*/
264 					/* up, BITSTR gets cancelled!							*/
265 					/************************************************/
266 
267 					case BITSTR:
268 						*(bufpnt++) = 0x80;
269 						while ( !(((startpnt+count)<&line_buf[(cnt+1)*line_len-1])&&
270 											(((*(startpnt+count)==0xFF) && (*(startpnt+count+1)==0xFF))||
271 											 ((*(startpnt+count)==0x00) && (*(startpnt+count+1)==0x00))))		&&
272 										!(((startpnt+count)<&line_buf[(cnt+1)*line_len-5])&&
273 											(*(startpnt+count)   == *(startpnt+count+2))&&
274 											(*(startpnt+count+1) == *(startpnt+count+3))&&
275 											(*(startpnt+count)   == *(startpnt+count+4))&&
276 											(*(startpnt+count+1) == *(startpnt+count+5)))												&&
277 										(count < 0xFF)																												&&
278 										((startpnt+count) < &line_buf[(cnt+1)*line_len]) 											)
279 										count++;
280 						*(bufpnt++) = count;
281 						for(; count>0; count--)
282 							*(bufpnt++) = *(startpnt++);
283 						break;
284 					};
285 				};
286 
287 			if (write(file,write_buf,bufpnt-write_buf) != (bufpnt-write_buf))
288 				{
289 				error = errno;
290 				close(file);
291 				free(line_buf);
292 				free(write_buf);
293 				return(error);
294 				};
295 
296 			};
297 		};
298 
299 	/*close file, free buffer. */
300 
301 	close(file);
302 	free(line_buf);
303 	free(write_buf);
304 	return(0);
305 
306 }
307 
308 /*---filetype-dispatcher--------------------*/
309 
get_file_ext(FILE_TYP typ)310 const char *get_file_ext(FILE_TYP typ)
311 	{
312 	switch (typ)
313 		{
314 		case IMG:
315 		case XIMG:
316 			return("IMG");
317 		default:
318 			return("");
319 		};
320 }
321 
322 
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))323 int bitmap_to_file(FILE_TYP typ, int ww, int wh,
324 									 unsigned int pwx, unsigned int pwy,
325 									 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 
331 	switch (typ)
332 		{
333 		case IMG:
334 		case XIMG:
335 			return(bitmap_to_img(typ,ww,wh,pwx,pwy,planes,colors,filename,get_color,get_pixel));
336 		default:
337 			return(-1);
338 		};
339 }
340 
341