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