1 /*
2  * xvtarga.c - load routine for 'targa' format pictures
3  *
4  * written and submitted by:
5  *     Derek Dongray    (dongray@genrad.com)
6  *
7  * The format read/written is actually Targa type 2 uncompressed as
8  * produced by POVray 1.0
9  *
10  * LoadTarga(fname, pinfo)
11  * WriteTarga(fp, pic, ptype, w,h, rmap,gmap,bmap,numcols, cstyle)
12  */
13 
14 
15 /*
16  * Targa Format (near as I can tell)
17  *   0:
18  *   1: colormap type
19  *   2: image type  (1=colmap RGB, 2=uncomp RGB, 3=uncomp gray)
20  *   3:
21  *   4:
22  *   5: colormap_length, low byte
23  *   6: colormap_length, high byte
24  *   7: bits per cmap entry     (8, 24, 32)
25  *
26  *  12: width, low byte
27  *  13: width, high byte
28  *  14: height, low byte
29  *  15: height, high byte
30  *  16: bits per pixel (8, 24)
31  *  17: flags
32  */
33 
34 
35 
36 #include "xv.h"
37 
38 static long filesize;
39 static const char *bname;
40 
41 
42 /*******************************************/
LoadTarga(fname,pinfo)43 int LoadTarga(fname, pinfo)
44      char    *fname;
45      PICINFO *pinfo;
46 /*******************************************/
47 {
48   /* returns '1' on success */
49 
50   FILE  *fp;
51   int    i, row, c, c1, w, h, npixels, bufsize, flags, intlace, topleft, trunc;
52   byte *pic24, *pp;
53 
54   bname = BaseName(fname);
55 
56   pinfo->pic     = (byte *) NULL;
57   pinfo->comment = (char *) NULL;
58 
59   fp=xv_fopen(fname,"r");
60   if (!fp) {
61      SetISTR(ISTR_WARNING,"%s:  %s", bname, "can't open file");
62      return 0;
63    }
64 
65   /* compute file length */
66   fseek(fp, 0L, 2);
67   filesize = ftell(fp);
68   fseek(fp, 0L, 0);
69 
70   if (filesize < 18) {
71      fclose(fp);
72      SetISTR(ISTR_WARNING,"%s:  %s", bname, "file is too short");
73      return 0;
74    }
75 
76   /* Discard the first few bytes of the file.
77      The format check has already been done or we wouldn't be here. */
78 
79   for (i=0; i<12; i++) {
80     c=getc(fp);
81   }
82 
83 
84   /* read in header information */
85   c=getc(fp); c1=getc(fp);
86   w = c1*256 + c;
87 
88   c=getc(fp); c1=getc(fp);
89   h = c1*256 + c;
90 
91   npixels = w * h;
92   bufsize = 3 * npixels;
93   if (w <= 0 || h <= 0 || npixels/w != h || bufsize/3 != npixels) {
94     fclose(fp);
95     SetISTR(ISTR_WARNING,"%s:  error in Targa header (bad image size)", bname);
96     return 0;
97   }
98 
99   c=getc(fp);
100   if (c!=24)  {
101     fclose(fp);
102     SetISTR(ISTR_WARNING,"%s:  unsupported type (not 24-bit)", bname);
103     return 0;
104   }
105 
106   flags   = getc(fp);
107   topleft = (flags & 0x20) >> 5;
108   intlace = (flags & 0xc0) >> 6;
109 
110 #ifdef FOO
111   if (c!=0x20)  {
112     fclose(fp);
113     SetISTR(ISTR_WARNING,"%s:  unsupported type (not top-down, noninterlaced)",
114 	    bname);
115     return 0;
116   }
117 #endif
118 
119 
120   pic24 = (byte *) calloc((size_t) bufsize, (size_t) 1);
121   if (!pic24) FatalError("couldn't malloc 'pic24'");
122 
123 
124   trunc = 0;
125 
126   /* read the data */
127   for (i=0; i<h; i++) {
128     if (intlace == 2) {        /* four pass interlace */
129       if      (i < (1*h) / 4) row = 4 * i;
130       else if (i < (2*h) / 4) row = 4 * (i - ((1*h)/4)) + 1;
131       else if (i < (3*h) / 4) row = 4 * (i - ((2*h)/4)) + 2;
132       else                    row = 4 * (i - ((3*h)/4)) + 3;
133     }
134 
135     else if (intlace == 1) {   /* two pass interlace */
136       if      (i < h / 2) row = 2 * i;
137       else                row = 2 * (i - h/2) + 1;
138     }
139 
140     else row = i;              /* no interlace */
141 
142 
143 
144     if (!topleft) row = (h - row - 1);     /* bottom-left origin: invert y */
145 
146 
147     c = fread(pic24 + (row*w*3), (size_t) 1, (size_t) w*3, fp);
148     if (c != w*3) trunc=1;
149   }
150 
151   if (trunc) SetISTR(ISTR_WARNING,"%s:  File appears to be truncated.",bname);
152 
153 
154   /* swap R,B values (file is in BGR, pic24 should be in RGB) */
155   for (i=0, pp=pic24; i<npixels; i++, pp+=3) {
156     c = pp[0];  pp[0] = pp[2];  pp[2] = c;
157   }
158 
159 
160   pinfo->pic     = pic24;
161   pinfo->type    = PIC24;
162   pinfo->w       = w;
163   pinfo->h       = h;
164   pinfo->normw = pinfo->w;   pinfo->normh = pinfo->h;
165   pinfo->frmType = F_TARGA;
166   sprintf(pinfo->fullInfo,"Targa, uncompressed RGB.  (%ld bytes)", filesize);
167   sprintf(pinfo->shrtInfo,"%dx%d Targa.", w,h);
168   pinfo->colType = F_FULLCOLOR;
169 
170   fclose(fp);
171 
172   return 1;
173 }
174 
175 
176 /*******************************************/
WriteTarga(fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle)177 int WriteTarga(fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle)
178      FILE *fp;
179      byte *pic;
180      int   ptype, w,h;
181      byte *rmap, *gmap, *bmap;
182      int   numcols, colorstyle;
183 /*******************************************/
184 {
185   int i, j;
186   byte *xpic;
187 
188   /* write the header */
189   for (i=0; i<12; i++) putc( (i==2) ? 2 : 0, fp);
190 
191   putc(w&0xff,     fp);
192   putc((w>>8)&0xff,fp);
193   putc(h&0xff,     fp);
194   putc((h>>8)&0xff,fp);
195 
196   putc(24,fp);
197   putc(0x20,fp);
198 
199   xpic = pic;
200 
201   for (i=0; i<h; i++) {
202     if ((i&63)==0) WaitCursor();
203 
204     for (j=0; j<w; j++) {
205       if (ptype==PIC8) {
206 	putc(bmap[*xpic],fp);  putc(gmap[*xpic],fp);  putc(rmap[*xpic],fp);
207 	xpic++;
208       }
209       else {  /* PIC24 */
210 	putc(xpic[2], fp);  /* b */
211 	putc(xpic[1], fp);  /* g */
212 	putc(xpic[0], fp);  /* r */
213 	xpic+=3;
214       }
215     }
216   }
217 
218   if (ferror(fp)) return -1;
219 
220   return 0;
221 }
222