1 /* niff.c:
2  *
3  * xloadimage native image format.  This is used for loading and dumping
4  * xloadimage images.
5  *
6  * jim frost 10.29.91
7  *
8  * this is in the public domain.
9  */
10 
11 #include "image.h"
12 #ifdef HAVE_UNISTD_H
13 #include <unistd.h>
14 #endif
15 #include "niff.h"
16 
babble(name,header,title)17 static void babble(name, header, title)
18      char *name;
19      struct niff_header *header;
20      char *title;
21 {
22   printf("%s is a %ldx%ld ", name,
23 	 memToVal(header->width, 4),
24 	 memToVal(header->height, 4));
25   if (memToVal(header->version, 4) != NIFF_VERSION)
26     printf("version %ld ", memToVal(header->version, 4));
27   printf("NIFF ");
28   switch (header->type) {
29   case NIFF_BITMAP:
30     printf("bitmap image");
31     break;
32   case NIFF_RGB:
33     printf("%ld-bit RGB image with %ld colors",
34 	   memToVal(header->depth, 4), memToVal(header->cmap_size, 4));
35     break;
36   case NIFF_TRUE:
37     printf("%ld-bit true color image", memToVal(header->depth, 4));
38     break;
39   default:
40     printf("image with an unknown type");
41   }
42   if (title && title[0])
43     printf(" entitled \"%s\"", title);
44   printf("\n");
45 }
46 
readHeader(zf,header,rtitle)47 static int readHeader(zf, header, rtitle)
48      ZFILE *zf;
49      struct niff_header *header;
50      char **rtitle;
51 { unsigned int title_len;
52   char *title = NULL;
53 
54   /* read in header
55    */
56   if (zread(zf, (byte *)header, sizeof(struct niff_header)) !=
57       sizeof(struct niff_header)) {
58     zclose(zf);
59     return(0);
60   }
61 
62   /* check magic number to see if this is a NIFF image
63    */
64   if (memToVal(header->magic, 4) != NIFF_MAGIC)
65     return(0);
66 
67   /* read in title if there is one
68    */
69   title_len= memToVal(header->title_len, 4);
70   if (title_len != 0) {
71     title= (char *)lmalloc(title_len + 1);
72     if (zread(zf, (byte *)title, title_len) != title_len) {
73       lfree((byte *)title);
74       return(0);
75     }
76     title[title_len]= '\0';
77   }
78   if (rtitle)
79     *rtitle= title;
80   else
81     lfree((byte *)title);
82   return(1);
83 }
84 
niffIdent(fullname,name)85 int niffIdent(fullname, name)
86      char *fullname, *name;
87 { ZFILE *zf;
88   struct niff_header header;
89   char *title;
90 
91   if (! (zf= zopen(fullname)))
92     return(0);
93 
94   if (!readHeader(zf, &header, &title))
95     return(0);
96   zclose(zf);
97   babble(name, &header, title);
98   lfree((byte *)title);
99   return(1);
100 }
101 
readColormap(zf,image)102 static int readColormap(zf, image)
103      ZFILE *zf;
104      Image *image;
105 { unsigned int a;
106   struct niff_cmap cmap;
107 
108   for (a= 0; a < image->rgb.used; a++) {
109     if (zread(zf, (byte *)&cmap, sizeof(struct niff_cmap)) != sizeof(struct niff_cmap)) {
110       fprintf(stderr, "niffLoad: short read in colormap!\n");
111       return(0);
112     }
113     image->rgb.red[a]= memToVal(cmap.red, 2);
114     image->rgb.green[a]= memToVal(cmap.green, 2);
115     image->rgb.blue[a]= memToVal(cmap.blue, 2);
116   }
117   return(1);
118 }
119 
niffLoad(fullname,name,verbose)120 Image *niffLoad(fullname, name, verbose)
121      char *fullname, *name;
122      unsigned int verbose;
123 { ZFILE *zf;
124   struct niff_header header;
125   char *title;
126   unsigned int width, height, depth;
127   Image *image = NULL;
128   unsigned int data_size = 0;
129 
130   if (! (zf= zopen(fullname)))
131     return(NULL);
132 
133   if (!readHeader(zf, &header, &title)) {
134     zclose(zf);
135     return(NULL);
136   }
137   if (verbose)
138     babble(name, &header, title);
139   znocache(zf);
140 
141   width= memToVal(header.width, 4);
142   height= memToVal(header.height, 4);
143   depth= memToVal(header.depth, 4);
144   switch (header.type) {
145   case NIFF_BITMAP:
146     image= newBitImage(width, height);
147     if (memToVal(header.cmap_size, 4) != 2)
148       fprintf(stderr, "niffLoad: bitmap image has wrong number of colormap entries!\n");
149     if (!readColormap(zf, image)) {
150       freeImage(image);
151       zclose(zf);
152       return(NULL);
153     }
154     data_size= ((image->width / 8) + (image->width % 8 ? 1 : 0)) * image->height;
155     break;
156   case NIFF_RGB:
157     image= newRGBImage(width, height, depth);
158     image->rgb.used= memToVal(header.cmap_size, 4);
159     if (image->rgb.used > image->rgb.size) {
160       fprintf(stderr, "niffLoad: too many colormap entries!\n");
161       image->rgb.used= image->rgb.size;
162     }
163     if (!readColormap(zf, image)) {
164       freeImage(image);
165       zclose(zf);
166       return(NULL);
167     }
168     data_size= image->width * image->height * image->pixlen;
169     break;
170   case NIFF_TRUE:
171     image= newTrueImage(width, height);
172     data_size= image->width * image->height * 3;
173   }
174   image->title= title;
175 
176   /* read in image data
177    */
178 
179   if (zread(zf, image->data, data_size) != data_size)
180     fprintf(stderr, "Short read on image data\n");
181   zclose(zf);
182   return(image);
183 }
184 
185 /* this takes an Image and dumps it into a file in NIFF format.  returns
186  * zero if successful.
187  */
niffDump(image,options,filename,verbose)188 void niffDump(image, options, filename, verbose)
189      Image *image;
190      char *options; /* ignored */
191      char *filename;
192      int verbose;
193 { FILE *f;
194   unsigned int a;
195   struct niff_header header;
196   struct niff_cmap cmap;
197   unsigned int data_size = 0;
198 
199   if (verbose)
200     printf("Dumping NIFF image to %s.\n", filename);
201 
202   if (!(f= fopen(filename, "w"))) {
203     perror(filename);
204     return;
205   }
206 
207   valToMem(NIFF_MAGIC, header.magic, 4);
208   valToMem(NIFF_VERSION, header.version, 4);
209   valToMem(image->width, header.width, 4);
210   valToMem(image->height, header.height, 4);
211   valToMem(image->depth, header.depth, 4);
212   switch (image->type) {
213   case IBITMAP:
214     header.type= NIFF_BITMAP;
215     valToMem(image->rgb.used, header.cmap_size, 4);
216     data_size= ((image->width / 8) + (image->width % 8 ? 1 : 0)) * image->height;
217     break;
218   case IRGB:
219     header.type= NIFF_RGB;
220     valToMem(image->rgb.used, header.cmap_size, 4);
221     data_size= image->width * image->height * image->pixlen;
222     break;
223   case ITRUE:
224     header.type= NIFF_TRUE;
225     valToMem(0, header.cmap_size, 4);
226     data_size= image->width * image->height * 3;
227     break;
228   }
229   valToMem((image->title ? strlen(image->title) : 0), header.title_len, 4);
230 
231   /* write header
232    */
233   if (fwrite(&header, sizeof(struct niff_header), 1, f) != 1) {
234     perror(filename);
235     unlink(filename);
236     return;
237   }
238 
239   /* write title if there is one
240    */
241   if (image->title && (strlen(image->title) > 0)) {
242     if (fwrite(image->title, strlen(image->title), 1, f) != 1) {
243       perror(filename);
244       unlink(filename);
245       return;
246     }
247   }
248 
249   /* write cmap if we need one
250    */
251   switch (image->type) {
252   case IBITMAP:
253   case IRGB:
254     for (a= 0; a < image->rgb.used; a++) {
255       valToMem(image->rgb.red[a], cmap.red, 2);
256       valToMem(image->rgb.green[a], cmap.green, 2);
257       valToMem(image->rgb.blue[a], cmap.blue, 2);
258       if (fwrite(&cmap, sizeof(struct niff_cmap), 1, f) != 1) {
259 	perror(filename);
260 	unlink(filename);
261 	return;
262       }
263     }
264   }
265 
266   /* write image data
267    */
268 
269   if (fwrite(image->data, data_size, 1, f) != 1) {
270     perror(filename);
271     unlink(filename);
272     return;
273   }
274   return;
275 }
276