1 /*
2 * xvpm.c - load routine for 'pm' format pictures
3 *
4 * LoadPM();
5 * WritePM(fp, pic, ptype, w, h, r,g,b, numcols, style, comment)
6 */
7
8 #include "copyright.h"
9
10 #include "xv.h"
11
12
13 /**** PM.H ******/
14 #define PM_MAGICNO 0x56494557 /* Hex for VIEW */
15 #define PM_A 0x8000
16 #define PM_C 0x8001
17 #define PM_S 0x8002
18 #define PM_I 0x8004
19 #define PM_F 0xc004
20
21 #define PM_IOHDR_SIZE (sizeof(pmpic)-(2*sizeof(char*)))
22
23 typedef struct {
24 int pm_id; /* Magic number for pm format files. */
25 int pm_np; /* Number of planes. Normally 1. */
26 int pm_nrow; /* Number of rows. 1 - MAXNELM. */
27 int pm_ncol; /* Number of columns. 1 - MAXNELM. */
28 int pm_nband; /* Number of bands. */
29 int pm_form; /* Pixel format. */
30 int pm_cmtsize; /* Number comment bytes. Includes NULL. */
31 char *pm_image; /* The image itself. */
32 char *pm_cmt; /* Transforms performed. */
33 } pmpic;
34
35
36 #define pm_nelm(p) ((p)->pm_ncol * (p)->pm_nrow)
37 #define pm_nbelm(p) (pm_nelm(p) * (p)->pm_nband)
38 #define pm_psize(p) (pm_nbelm(p) * (((p)->pm_form)&0xff))
39 #define pm_isize(p) ((p)->pm_np * pm_psize(p))
40 #define pm_npix(p) (pm_nbelm(p) * (p)->pm_np)
41
42 /***** end PM.H *****/
43
44
45 static pmpic thePic;
46
47 static int pmError PARM((const char *, const char *));
48 static int flip4 PARM((int));
49 static int getint32 PARM((FILE *));
50 static void putint32 PARM((int, FILE *));
51
52
53 /*******************************************/
LoadPM(fname,pinfo)54 int LoadPM(fname, pinfo)
55 char *fname;
56 PICINFO *pinfo;
57 /*******************************************/
58 {
59 /* returns '1' on success */
60
61 FILE *fp;
62 byte *pic8;
63 int isize,i,flipit,w,h,npixels,nRGBbytes;
64 const char *bname;
65
66 bname = BaseName(fname);
67 thePic.pm_image = (char *) NULL;
68 thePic.pm_cmt = (char *) NULL;
69
70 pinfo->pic = (byte *) NULL;
71 pinfo->comment = (char *) NULL;
72
73
74 fp = xv_fopen(fname,"r");
75 if (!fp) return( pmError(bname, "unable to open file") );
76
77 /* read in the pmpic struct, one byte at a time */
78 thePic.pm_id = getint32(fp);
79 thePic.pm_np = getint32(fp);
80 thePic.pm_nrow = getint32(fp);
81 thePic.pm_ncol = getint32(fp);
82 thePic.pm_nband = getint32(fp);
83 thePic.pm_form = getint32(fp);
84 thePic.pm_cmtsize = getint32(fp);
85
86 if (ferror(fp) || feof(fp)) return(pmError(bname, "error reading header"));
87
88 flipit = 0;
89
90 if (thePic.pm_id != PM_MAGICNO) {
91 thePic.pm_id = flip4(thePic.pm_id);
92 if (thePic.pm_id == PM_MAGICNO) flipit = 1;
93 else thePic.pm_id = flip4(thePic.pm_id);
94 }
95 if (thePic.pm_id != PM_MAGICNO) return( pmError(bname, "not a PM file") );
96
97 if (flipit) {
98 thePic.pm_np = flip4(thePic.pm_np);
99 thePic.pm_nrow = flip4(thePic.pm_nrow);
100 thePic.pm_ncol = flip4(thePic.pm_ncol);
101 thePic.pm_nband = flip4(thePic.pm_nband);
102 thePic.pm_form = flip4(thePic.pm_form);
103 thePic.pm_cmtsize = flip4(thePic.pm_cmtsize);
104 }
105
106 w = thePic.pm_ncol;
107 h = thePic.pm_nrow;
108
109 /* make sure that the input picture can be dealt with */
110 if ( thePic.pm_nband!=1 ||
111 (thePic.pm_form!=PM_I && thePic.pm_form!=PM_C) ||
112 (thePic.pm_form==PM_I && thePic.pm_np>1) ||
113 (thePic.pm_form==PM_C && (thePic.pm_np==2 || thePic.pm_np>4)) ) {
114 fprintf(stderr,"PM picture not in a displayable format.\n");
115 fprintf(stderr,"(ie, 1-plane PM_I, or 1-, 3-, or 4-plane PM_C)\n");
116
117 return pmError(bname, "PM file in unsupported format");
118 }
119
120
121 isize = pm_isize(&thePic);
122 npixels = w*h;
123 nRGBbytes = 3*npixels;
124
125 /* make sure image is more-or-less valid (and no overflows) */
126 if (isize <= 0 || w <= 0 || h <= 0 || npixels/w < h ||
127 nRGBbytes/3 < npixels || thePic.pm_cmtsize < 0)
128 return pmError(bname, "Bogus PM file!!");
129
130 if (DEBUG)
131 fprintf(stderr,"%s: LoadPM() - loading a %dx%d %s pic, %d planes\n",
132 cmd, w, h, (thePic.pm_form==PM_I) ? "PM_I" : "PM_C",
133 thePic.pm_np);
134
135
136 /* allocate memory for picture and read it in */
137 thePic.pm_image = (char *) malloc((size_t) isize);
138 if (thePic.pm_image == NULL)
139 return( pmError(bname, "unable to malloc PM picture") );
140
141 if (fread(thePic.pm_image, (size_t) isize, (size_t) 1, fp) != 1) {
142 free(thePic.pm_image);
143 return( pmError(bname, "file read error") );
144 }
145
146
147 /* alloc and read in comment, if any */
148 if (thePic.pm_cmtsize>0) {
149 thePic.pm_cmt = (char *) malloc((size_t) thePic.pm_cmtsize+1);
150 if (thePic.pm_cmt) {
151 thePic.pm_cmt[thePic.pm_cmtsize] = '\0'; /* to be safe */
152 if (fread(thePic.pm_cmt,(size_t) thePic.pm_cmtsize,(size_t) 1,fp) != 1) {
153 free(thePic.pm_cmt);
154 thePic.pm_cmt = (char *) NULL;
155 }
156 }
157 }
158
159 fclose(fp);
160
161
162 if (thePic.pm_form == PM_I) {
163 int *intptr;
164 byte *pic24, *picptr;
165
166 if ((pic24 = (byte *) malloc((size_t) nRGBbytes))==NULL) {
167 if (thePic.pm_cmt) free(thePic.pm_cmt);
168 return( pmError(bname, "unable to malloc 24-bit picture") );
169 }
170
171 intptr = (int *) thePic.pm_image;
172 picptr = pic24;
173
174 if (flipit) { /* if flipit, integer is RRGGBBAA instead of AABBGGRR */
175 for (i=w*h; i>0; i--, intptr++) {
176 if ((i & 0x3fff) == 0) WaitCursor();
177 *picptr++ = (*intptr>>24) & 0xff;
178 *picptr++ = (*intptr>>16) & 0xff;
179 *picptr++ = (*intptr>>8) & 0xff;
180 }
181 }
182 else {
183 for (i=w*h; i>0; i--, intptr++) {
184 if ((i & 0x3fff) == 0) WaitCursor();
185 *picptr++ = (*intptr) & 0xff;
186 *picptr++ = (*intptr>>8) & 0xff;
187 *picptr++ = (*intptr>>16) & 0xff;
188 }
189 }
190
191 free(thePic.pm_image);
192
193 pinfo->pic = pic24;
194 pinfo->type = PIC24;
195 }
196
197
198 else if (thePic.pm_form == PM_C && thePic.pm_np>1) {
199 byte *pic24, *picptr, *rptr, *gptr, *bptr;
200
201 if ((pic24 = (byte *) malloc((size_t) nRGBbytes))==NULL) {
202 if (thePic.pm_cmt) free(thePic.pm_cmt);
203 return( pmError(bname, "unable to malloc 24-bit picture") );
204 }
205
206 rptr = (byte *) thePic.pm_image;
207 gptr = rptr + w*h;
208 bptr = rptr + w*h*2;
209 picptr = pic24;
210 for (i=w*h; i>0; i--) {
211 if ((i & 0x3fff) == 0) WaitCursor();
212 *picptr++ = *rptr++;
213 *picptr++ = *gptr++;
214 *picptr++ = *bptr++;
215 }
216 free(thePic.pm_image);
217
218 pinfo->pic = pic24;
219 pinfo->type = PIC24;
220 }
221
222
223 else if (thePic.pm_form == PM_C && thePic.pm_np==1) {
224 /* don't have to convert, just point pic at thePic.pm_image */
225 pic8 = (byte *) thePic.pm_image;
226 for (i=0; i<256; i++)
227 pinfo->r[i] = pinfo->g[i] = pinfo->b[i] = i; /* build mono cmap */
228
229 pinfo->pic = pic8;
230 pinfo->type = PIC8;
231 }
232
233
234 /* load up remaining pinfo fields */
235 pinfo->w = thePic.pm_ncol; pinfo->h = thePic.pm_nrow;
236 pinfo->normw = pinfo->w; pinfo->normh = pinfo->h;
237
238 pinfo->frmType = F_PM;
239 pinfo->colType = (thePic.pm_form==PM_I || thePic.pm_np>1)
240 ? F_FULLCOLOR : F_GREYSCALE;
241 sprintf(pinfo->fullInfo,"PM, %s. (%d plane %s) (%d bytes)",
242 (thePic.pm_form==PM_I || thePic.pm_np>1)
243 ? "24-bit color" : "8-bit greyscale",
244 thePic.pm_np, (thePic.pm_form==PM_I) ? "PM_I" : "PM_C",
245 isize + (int)PM_IOHDR_SIZE + thePic.pm_cmtsize);
246
247 sprintf(pinfo->shrtInfo, "%dx%d PM.", w,h);
248 pinfo->comment = thePic.pm_cmt;
249
250 return 1;
251 }
252
253
254 /*******************************************/
WritePM(fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,comment)255 int WritePM(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle,
256 comment)
257 FILE *fp;
258 byte *pic;
259 int ptype,w,h;
260 byte *rmap, *gmap, *bmap;
261 int numcols, colorstyle;
262 char *comment;
263 {
264 /* writes a PM file to the already open stream
265 'colorstyle' single-handedly determines the type of PM pic written
266 if colorstyle==0, (Full Color) a 3-plane PM_C pic is written
267 if colorstyle==1, (Greyscal) a 1-plane PM_C pic is written
268 if colorstyle==0, (B/W stipple) a 1-plane PM_C pic is written */
269
270 char foo[256];
271 int i;
272 byte *p;
273
274 /* create 'comment' field */
275 sprintf(foo,"CREATOR: XV %s\n", REVDATE);
276
277 /* fill in fields of a pmheader */
278 thePic.pm_id = PM_MAGICNO;
279 thePic.pm_np = (colorstyle==0) ? 3 : 1;
280 thePic.pm_ncol = w;
281 thePic.pm_nrow = h;
282 thePic.pm_nband = 1;
283 thePic.pm_form = PM_C;
284 thePic.pm_cmtsize = (strlen(foo) + 1); /* +1 to write trailing '\0' */
285 if (comment) thePic.pm_cmtsize += (strlen(comment) + 1);
286
287 putint32(thePic.pm_id, fp);
288 putint32(thePic.pm_np, fp);
289 putint32(thePic.pm_nrow, fp);
290 putint32(thePic.pm_ncol, fp);
291 putint32(thePic.pm_nband, fp);
292 putint32(thePic.pm_form, fp);
293 putint32(thePic.pm_cmtsize, fp);
294
295 /* write the picture data */
296 if (colorstyle == 0) { /* 24bit RGB, organized as 3 8bit planes */
297
298 if (ptype == PIC8) {
299 WaitCursor();
300 for (i=0,p=pic; i<w*h; i++, p++) putc(rmap[*p], fp);
301
302 WaitCursor();
303 for (i=0,p=pic; i<w*h; i++, p++) putc(gmap[*p], fp);
304
305 WaitCursor();
306 for (i=0,p=pic; i<w*h; i++, p++) putc(bmap[*p], fp);
307 }
308
309 else { /* PIC24 */
310 WaitCursor();
311 for (i=0,p=pic; i<w*h; i++, p+=3) putc(*p, fp);
312
313 WaitCursor();
314 for (i=0,p=pic+1; i<w*h; i++, p+=3) putc(*p, fp);
315
316 WaitCursor();
317 for (i=0,p=pic+2; i<w*h; i++, p+=3) putc(*p, fp);
318 }
319 }
320
321
322 else if (colorstyle == 1) { /* GreyScale: 8 bits per pixel */
323 byte rgb[256];
324
325 if (ptype == PIC8) {
326 for (i=0; i<numcols; i++) rgb[i] = MONO(rmap[i],gmap[i],bmap[i]);
327 for (i=0, p=pic; i<w*h; i++, p++) {
328 if ((i & 0x3fff) == 0) WaitCursor();
329 putc(rgb[*p],fp);
330 }
331 }
332 else { /* PIC24 */
333 for (i=0, p=pic; i<w*h; i++, p+=3) {
334 if ((i & 0x3fff) == 0) WaitCursor();
335 putc( MONO(p[0],p[1],p[2]), fp);
336 }
337 }
338 }
339
340 else /* (colorstyle == 2) */ { /* B/W stipple. pic is 1's and 0's */
341 /* note: pic has already been dithered into 8-bit image */
342 for (i=0, p=pic; i<w*h; i++, p++) {
343 if ((i & 0x3fff) == 0) WaitCursor();
344 putc(*p ? 255 : 0,fp);
345 }
346 }
347
348 if (comment) {
349 fwrite(comment, (size_t) strlen(comment), (size_t) 1, fp);
350 fwrite("\n", (size_t) 1, (size_t) 1, fp);
351 }
352 fwrite(foo, strlen(foo) + 1, (size_t) 1, fp); /* +1 for trailing '\0' */
353
354 if (ferror(fp)) return -1;
355
356 return 0;
357 }
358
359
360 /*****************************/
pmError(fname,st)361 static int pmError(fname, st)
362 const char *fname, *st;
363 {
364 SetISTR(ISTR_WARNING,"%s: %s", fname, st);
365 if (thePic.pm_image != NULL) free(thePic.pm_image);
366 return 0;
367 }
368
369
370 /*****************************/
flip4(i)371 static int flip4(i)
372 int i;
373 {
374 /* flips low-order 4 bytes around in integer */
375
376 byte b0, b1, b2, b3;
377 int rv;
378
379 b0 = (((u_long) i)) & 0xff;
380 b1 = (((u_long) i) >> 8) & 0xff;
381 b2 = (((u_long) i) >> 16) & 0xff;
382 b3 = (((u_long) i) >> 24) & 0xff;
383
384 rv = (((u_long) b0) << 24) |
385 (((u_long) b1) << 16) |
386 (((u_long) b2) << 8) |
387 (((u_long) b3));
388
389 return rv;
390 }
391
392
393
getint32(fp)394 static int getint32(fp)
395 FILE *fp;
396 {
397 int i;
398
399 i = (getc(fp) & 0xff) << 24;
400 i |= (getc(fp) & 0xff) << 16;
401 i |= (getc(fp) & 0xff) << 8;
402 i |= (getc(fp) & 0xff);
403
404 return i;
405 }
406
407
408
putint32(i,fp)409 static void putint32(i, fp)
410 int i;
411 FILE *fp;
412 {
413 putc( ((i>>24) & 0xff), fp);
414 putc( ((i>>16) & 0xff), fp);
415 putc( ((i>> 8) & 0xff), fp);
416 putc( ((i) & 0xff), fp);
417 }
418
419
420
421