1 /* $Header: /home/yav/xpx/RCS/mag.c,v 1.10 1996/04/23 10:58:05 yav Exp $
2  * xpx save load MAG format
3  * written by yav (UHD98984@pcvan.or.jp)
4  */
5 
6 #include <X11/Xlib.h>
7 
8 #include "xpx.h"
9 #include "headers.h"
10 #include "work.h"
11 #define PUBLIC_MAG_C
12 #include "extern.h"
13 
14 
15 char rcsid_mag[] = "$Id: mag.c,v 1.10 1996/04/23 10:58:05 yav Exp $";
16 static char mag_magic_number[] = "MAKI02  ";
17 static char mag_default_user[] = ">\x93\xe4<";
18 static struct {int x,y;} magpostbl[16]={
19   {0,0},{1,0},{2,0},{4,0},{0,1},{1,1},{0,2},{1,2},
20   {2,2},{0,4},{1,4},{2,4},{0,8},{1,8},{2,8},{0,16}};
21 static long flagAsize;
22 static long flagBsize;
23 static long pixelsize;
24 static unsigned char *pixelbuf = NULL;
25 static unsigned char *flaga = NULL;
26 static unsigned char *flagb = NULL;
27 
28 
29 /* store short integer to char buffer as little-endian
30  */
setleshort(p,n)31 void setleshort(p, n)
32      char *p;
33      int n;
34 {
35   *p++ = n;
36   *p = n >> 8;
37 }
38 
39 /* store long integer to char buffer as little-endian
40  */
setlelong(p,n)41 void setlelong(p, n)
42      char *p;
43      long n;
44 {
45   *p++ = n;
46   *p++ = n >> 8;
47   *p++ = n >> 16;
48   *p   = n >> 24;
49 }
50 
51 /* write MAG palette data
52  * Caution! Now supported only 16 colors format
53  */
write_mag_palette_section(fp)54 int write_mag_palette_section(fp)
55      FILE *fp;
56 {
57   int i;
58   COL *cp;
59   char buf[3*16], *p;
60 
61   cp = color_buf;
62   p = buf;
63   for (i = 0; i < 16; i++) {
64     *p++ = cp->rgb.green;
65     *p++ = cp->rgb.red;
66     *p++ = cp->rgb.blue;
67     cp++;
68   }
69   if (!fwrite(buf, 3*16, 1, fp))
70     return 1;
71   return 0;
72 }
73 
alloc_compress_work()74 int alloc_compress_work()
75 {
76   int w;
77 
78   w = (imgfilew+7)/8;
79   pixelbuf = (unsigned char *)malloc((imgfilew+1)/2*imgfileh);
80   flaga = (unsigned char *)malloc(w*imgfileh + 1);
81   flagb = (unsigned char *)malloc(w*imgfileh + 1);
82   return pixelbuf == NULL || flaga == NULL || flagb == NULL;
83 }
84 
free_compress_work()85 void free_compress_work()
86 {
87   if (pixelbuf != NULL) {
88     free(pixelbuf);
89     pixelbuf = NULL;
90   }
91   if (flaga != NULL) {
92     free(flaga);
93     flaga = NULL;
94   }
95   if (flagb != NULL) {
96     free(flagb);
97     flagb = NULL;
98   }
99 }
100 
is_same_pixel(x,y,dd)101 int is_same_pixel(x, y, dd)
102      int x;
103      int y;
104      int dd;
105 {
106   int dx, dy;
107 
108   dx = x - magpostbl[dd].x * 4;
109   dy = y - magpostbl[dd].y;
110   if (dx < 0 || dy < 0)
111     return 0;
112   return memcmp(imgdata+imgmaxw*y+x, imgdata+imgmaxw*dy+dx, 4) == 0;
113 }
114 
search_same_pixel(x,y)115 int search_same_pixel(x, y)
116      int x;
117      int y;
118 {
119   int i, n;
120   static int stbl[15] = {1,4,5,6,7,9,10,2,8,11,12,13,14,3,15};
121 
122   for (i = 0; i < 15; i++) {
123     n = stbl[i];
124     if (is_same_pixel(x, y, n))
125       return n;
126   }
127   return 0;			/* not found */
128 }
129 
130 /* compress MAG
131  * imgdata imgmaxw x imgmaxh
132  * effective area imgfilew x imgfileh
133  */
mag_compress()134 int mag_compress()
135 {
136   int x, y, n0, n1, w, bitpos;
137   unsigned char *flagbuf, *pf;
138   unsigned char *flagbuf2, *pf2; /* upper line flag cache */
139   unsigned char *pi, *pp;
140   unsigned char *pa, *pb;
141 
142   w = (imgfilew+7)/8;
143   pf = flagbuf = (unsigned char *)malloc(w*imgfileh);
144   if (flagbuf == NULL)
145     return 1;
146   flagbuf2 = (unsigned char *)malloc(w);
147   if (flagbuf2 == NULL) {
148     free(flagbuf);
149     return 1;
150   }
151   if (alloc_compress_work()) {
152     free(flagbuf);
153     free_compress_work();
154     return 1;
155   }
156   pp = pixelbuf;
157   bzero(flagbuf2, w);
158   for (y = 0; y < imgfileh; y++) {
159     pi = imgdata+imgmaxw*y;
160     pf2 = flagbuf2;
161     for (x = 0; x < imgfilew; x += 8) {
162       n0 = *pf2 >> 4;
163       if (!n0 || !is_same_pixel(x, y, n0))
164 	n0 = search_same_pixel(x, y);
165       if (!n0) {
166 	*pp++ = (*pi << 4) | *(pi+1);
167 	*pp++ = (*(pi+2) << 4) | *(pi+3);
168       }
169       pi += 4;
170       n1 = *pf2 & 0x0f;
171       if (!n1 || !is_same_pixel(x+4, y, n1))
172 	n1 = search_same_pixel(x+4, y);
173       if (!n1) {
174 	*pp++ = (*pi << 4) | *(pi+1);
175 	*pp++ = (*(pi+2) << 4) | *(pi+3);
176       }
177       pi += 4;
178       *pf2++ = *pf++ = (n0 << 4) | n1;
179     }
180   }
181   for (y = imgfileh-1; y > 0; y--) {
182     pf = flagbuf+w*y;
183     for (x = 0; x < w; x++)
184       *pf++ ^= *(pf-w);
185   }
186   bitpos = 0x80;
187   pf = flagbuf;
188   pa = flaga;
189   pb = flagb;
190   for (y = 0; y < imgfileh; y++) {
191     for (x = 0; x < w; x++) {
192       if (*pf) {
193 	*pb++ = *pf;
194 	*pa |= bitpos;
195       }
196       if (!(bitpos >>= 1)) {
197 	pa++;
198 	*pa = 0;
199 	bitpos = 0x80;
200       }
201       pf++;
202     }
203   }
204   if (bitpos != 0x80)
205     pa++;
206   flagAsize = pa - flaga;
207   if (flagAsize & 1)
208     flagAsize++;
209   flagBsize = pb - flagb;
210   if (flagBsize & 1)
211     flagBsize++;
212   pixelsize = pp - pixelbuf;
213   free(flagbuf);
214   free(flagbuf2);
215   return 0;			/* success */
216 }
217 
wr_mag(fp)218 int wr_mag(fp)
219      FILE *fp;
220 {
221   int i, x, y, comp;
222   unsigned char *p;
223   long l, flagAofs, flagBofs, pixelofs;
224   char *username, *comment;
225   char buf[512];
226 
227   if (!imgfiledepth)
228     imgfiledepth = 4;		/* If no depth info, treat 4 bit depth */
229   if (imgfiledepth > 4) {
230     message("!\n Supported only 16 color mag!\n");
231     return 1;
232   }
233   comp = 1;
234   username = (char *)getenv("USER");
235   if (username == NULL)
236     username = mag_default_user;
237   sprintf(buf, "%sxpx  %-18.18s ", mag_magic_number, username);
238   if (!fwrite(buf, strlen(buf), 1, fp))
239     return 1;
240   sprintf(buf, "Saved by %s %s", myname, xpx_version);
241   comment = buf;
242   if (!fwrite(comment, strlen(comment), 1, fp))
243     return 1;
244   if (!fwrite("\032", 1, 1, fp))
245     return 1;
246   if (comp) {
247     if (mag_compress())
248       comp = 0;		/* compression failed, select no compression */
249   }
250   if (!comp) {
251     flagAsize = ((imgfilew+3)/4+1)/2;
252     flagAsize *= imgfileh;
253     if (flagAsize & 1)
254       ++flagAsize;
255     flagBsize = 0;
256     pixelsize = ((imgfilew*imgfileh+3)/4) * 2;
257   }
258   flagAofs = 32 + 3*16;
259   flagBofs = flagAofs + flagAsize;
260   pixelofs = flagBofs + flagBsize;
261   /* write header */
262   bzero(buf, 32);
263   setleshort(buf+4, imgposx);
264   setleshort(buf+6, imgposy);
265   setleshort(buf+8, imgposx+imgfilew-1);
266   setleshort(buf+10, imgposy+imgfileh-1);
267   setlelong(buf+12, flagAofs);
268   setlelong(buf+16, flagBofs);
269   setlelong(buf+20, flagBsize);
270   setlelong(buf+24, pixelofs);
271   setlelong(buf+28, pixelsize);
272   fwrite(buf, 32, 1, fp);
273   write_mag_palette_section(fp);
274   if (comp) {
275     /* write flagA */
276     fwrite(flaga, 1, flagAsize, fp);
277     /* flagB */
278     fwrite(flagb, 1, flagBsize, fp);
279     /* write pixel */
280     fwrite(pixelbuf, 1, pixelsize, fp);
281     free_compress_work();
282   } else {
283     /* write flagA */
284     l = flagAsize;
285     bzero(buf, sizeof(buf));
286     while (l > 0) {
287       i = l < sizeof(buf) ? l : sizeof(buf);
288       fwrite(buf, i, 1, fp);
289       l -= i;
290     }
291     /* No need to save flagB */
292     /* write pixel */
293     for (y = 0; y < imgfileh; y++) {
294       p = imgdata+y*imgmaxw;
295       for (x = 0; x < imgfilew; x += 4) {
296 	buf[0] = (*p << 4) | *(p+1);
297 	buf[1] = (*(p+2) << 4) | *(p+3);
298 	p += 4;
299 	fwrite(buf, 2, 1, fp);
300       }
301     }
302   }
303   return ferror(fp);
304 }
305 
rd_mag(fp)306 int rd_mag(fp)
307      FILE *fp;
308 {
309   int w, h;
310 
311   free_color_all();
312   decode_mag(fp, "*noname*");
313   get_color(color_buf, mag_palcnt);
314   get_requested_colors();
315   w = mag_dataw;
316   h = mag_datah;
317   if (w > imgmaxw) {
318     w = imgmaxw;
319     message("!\nwidth %d trancate to %d.\n", mag_dataw, w);
320   }
321   if (h > imgmaxh) {
322     h = imgmaxh;
323     message("!\nheight %d trancate to %d.\n", mag_datah, h);
324   }
325   imgupdate(w, h);
326   return 0;
327 }
328 
329 /* End of file */
330