Home My Page Projects Code Snippets Project Openings 3D graphics for Standard ML
Summary Activity SCM

SCM Repository

[sml3d] Annotation of /trunk/sml3d/src/image-io/tga-file-io.sml
ViewVC logotype

Annotation of /trunk/sml3d/src/image-io/tga-file-io.sml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 318 - (view) (download)
Original Path: trunk/sml3d/src/image/tga-file-io.sml

1 : jhr 314 (* tga-file-io.sml
2 : jhr 274 *
3 :     * COPYRIGHT (c) 2008 John Reppy (http://cs.uchicago.edu/~jhr)
4 :     * All rights reserved.
5 :     *)
6 :    
7 : jhr 314 structure TGAFileIO : sig
8 : jhr 273
9 : jhr 315 type ubyte = GLTypes.glubyte
10 :     type 'a image = 'a Image.image2D
11 :    
12 : jhr 273 (* the native formats that a TGA file can hold (at least those that
13 :     * we handle!)
14 :     *)
15 : jhr 315 datatype tga_data
16 :     = TGAData1 of ubyte DataBuffer.buffer
17 :     | TGAData2 of ubyte DataBuffer.buffer2
18 :     | TGAData3 of ubyte DataBuffer.buffer3
19 :     | TGAData4 of ubyte DataBuffer.buffer4
20 :    
21 : jhr 274 datatype tga_image
22 : jhr 315 = Gray of ubyte image
23 :     | GrayAlpha of (ubyte * ubyte) image
24 :     | RGB of (ubyte * ubyte * ubyte) image
25 :     | RGBA of (ubyte * ubyte * ubyte * ubyte) image
26 : jhr 273
27 : jhr 318 val readFile : {file : string, flip : bool} -> {wid : int, ht : int, data : tga_data}
28 :     val readImage : {file : string, flip : bool} -> tga_image
29 : jhr 273
30 : jhr 318 (* TODO: writeFile and writeImage *)
31 :    
32 : jhr 273 end = struct
33 :    
34 :     structure W8V = Word8Vector
35 :    
36 : jhr 274 (* need to do something sensible about error reporting *)
37 :     fun error msg = raise Fail msg
38 :    
39 : jhr 315
40 :     type ubyte = GLTypes.glubyte
41 :     type 'a image = 'a Image.image2D
42 :    
43 : jhr 273 (* the native formats that a TGA file can hold (at least those that
44 :     * we handle!)
45 :     *)
46 : jhr 315 datatype tga_data
47 :     = TGAData1 of ubyte DataBuffer.buffer
48 :     | TGAData2 of ubyte DataBuffer.buffer2
49 :     | TGAData3 of ubyte DataBuffer.buffer3
50 :     | TGAData4 of ubyte DataBuffer.buffer4
51 :    
52 : jhr 274 datatype tga_image
53 : jhr 315 = Gray of ubyte image
54 :     | GrayAlpha of (ubyte * ubyte) image
55 :     | RGB of (ubyte * ubyte * ubyte) image
56 :     | RGBA of (ubyte * ubyte * ubyte * ubyte) image
57 : jhr 273
58 :     (* TGA file-header layout *)
59 :     val hdrSz = 18
60 :     val offIDLength = 0
61 :     val offCMapType = 1
62 :     val offImageType = 2
63 :     val offCMapSpec = 3
64 :     val offWid = 12
65 :     val offHt = 14
66 :     val offBPP = 16
67 :     val offImgDesc = 17
68 :    
69 : jhr 274 fun getByte (vec, i) = Word.fromLargeWord(Word8.toLargeWordX(W8V.sub(vec, i)))
70 :     fun getShort (vec, i) = Word.toIntX(Word.orb(
71 : jhr 273 Word.<< (getByte(vec, i+1), 0w8),
72 :     getByte(vec, i)))
73 :    
74 :     (* read the file header *)
75 :     fun readHdr inS = let
76 :     val vec = BinIO.inputN (inS, hdrSz)
77 :     in
78 :     if (W8V.length vec <> hdrSz)
79 : jhr 274 then error "bogus TGA file"
80 : jhr 273 else let
81 :     val idLen = getByte(vec, offIDLength)
82 :     val cmapTy = getByte(vec, offCMapType)
83 : jhr 274 val (color, rle) = (case getByte(vec, offImageType)
84 :     of 0w2 => (true, false)
85 :     | 0w3 => (false, false)
86 :     | 0w10 => (true, true)
87 :     | 0w11 => (false, true)
88 :     | n => error "unsupported image type"
89 : jhr 273 (* end case *))
90 :     val wid = getShort(vec, offWid)
91 :     val ht = getShort(vec, offHt)
92 : jhr 274 val bytesPP = Word.toIntX(getByte(vec, offBPP) div 0w8)
93 : jhr 273 val imageDesc = getByte(vec, offImgDesc)
94 : jhr 274 val alpha = (Word.andb(imageDesc, 0wxF) <> 0w0)
95 : jhr 273 in
96 :     (* do some sanity checking *)
97 : jhr 274 if (cmapTy <> 0w0) then error "ill-formed TGA header" else ();
98 : jhr 273 case (color, alpha, bytesPP)
99 :     of (true, true, 4) => () (* RGBA data *)
100 :     | (true, false, 3) => () (* RGB data *)
101 :     | (false, false, 1) => () (* 8-bit gray-scale *)
102 : jhr 274 | _ => error "unsupported format"
103 : jhr 273 (* end case *);
104 :     (* skip the ID field, if present *)
105 :     if (idLen <> 0w0)
106 : jhr 274 then ignore(BinIO.inputN(inS, Word.toIntX idLen))
107 : jhr 273 else ();
108 :     (* return the header information *)
109 :     { wid = wid,
110 :     ht = ht,
111 :     bytesPerPixel = bytesPP,
112 : jhr 274 size = wid * ht * bytesPP,
113 : jhr 273 compressed = rle
114 :     }
115 :     end
116 :     end
117 :    
118 :     (* parse a packet header in a RLE image *)
119 :     fun parsePacketHdr ub = let
120 : jhr 274 val np = Word8.andb(ub, 0wx7f)
121 : jhr 273 in
122 :     {raw = (ub = np), nPixels = Word8.toInt np + 1}
123 :     end
124 :    
125 : jhr 274 local
126 :     fun getGrayPixel (v, i) = W8V.sub(v, i)
127 :     fun getGrayAlphaPixel (v, i) = (W8V.sub(v, i), W8V.sub(v, i+1))
128 :     fun getRGBPixel (v, i) = (W8V.sub(v, i), W8V.sub(v, i+1), W8V.sub(v, i+2))
129 :     fun getRGBAPixel (v, i) = (W8V.sub(v, i), W8V.sub(v, i+1), W8V.sub(v, i+2), W8V.sub(v, i+3))
130 :     fun readRow (bpp, get, put) (inS, buf, i, wid) = let
131 :     val n = bpp*wid
132 :     val v = BinIO.inputN (inS, n)
133 :     fun lp j = if (j < wid)
134 :     then (put(buf, i+j, get(v, j)); lp j)
135 :     else i+wid
136 :     in
137 :     if (W8V.length v <> n)
138 :     then error "error reading file"
139 :     else lp 0
140 :     end
141 :     in
142 :     val readGrayRow = readRow (1, getGrayPixel, DataBuffer.setub)
143 :     val readGrayAlphaRow = readRow (2, getGrayAlphaPixel, DataBuffer.set2ub)
144 :     val readRGBRow = readRow (3, getRGBPixel, DataBuffer.set3ub)
145 :     val readRGBARow = readRow (3, getRGBAPixel, DataBuffer.set4ub)
146 :     end
147 : jhr 273
148 : jhr 274 local
149 :     fun getGrayPixel inS = valOf(BinIO.input1 inS)
150 :     fun getGrayAlphaPixel inS = let
151 :     val v = BinIO.inputN(inS, 2)
152 :     in
153 :     (W8V.sub(v, 0), W8V.sub(v, 1))
154 :     end
155 :     fun getRGBPixel inS = let
156 :     val v = BinIO.inputN(inS, 3)
157 :     in
158 :     (W8V.sub(v, 0), W8V.sub(v, 1), W8V.sub(v, 2))
159 :     end
160 :     fun getRGBAPixel inS = let
161 :     val v = BinIO.inputN(inS, 4)
162 :     in
163 :     (W8V.sub(v, 0), W8V.sub(v, 1), W8V.sub(v, 2), W8V.sub(v, 3))
164 :     end
165 :    
166 :     (* read and uncompress a row of an REL encoded image *)
167 :     fun readRLERow (get, put) (inS, buf, i, wid) = let
168 :     val stop = i + wid
169 :     fun lp i = if (i < stop)
170 :     then let
171 :     val {raw, nPixels} = parsePacketHdr(valOf(BinIO.input1 inS))
172 :     in
173 :     if raw
174 :     then let
175 :     fun read (i, 0) = lp i
176 :     | read (i, n) = (put(buf, i, get inS); read(i+1, n-1))
177 :     in
178 :     read (i, nPixels)
179 :     end
180 :     else let
181 :     val pix = get inS
182 :     fun repeat (i, 0) = lp i
183 :     | repeat (i, n) = (put(buf, i, pix); repeat(i+1, n-1))
184 :     in
185 :     repeat (i, nPixels)
186 :     end
187 :     end
188 :     else i
189 :     in
190 :     lp i
191 :     end
192 :     in
193 : jhr 273 val readGrayRLERow = readRLERow (getGrayPixel, DataBuffer.setub)
194 :     val readGrayAlphaRLERow = readRLERow (getGrayAlphaPixel, DataBuffer.set2ub)
195 :     val readRGBRLERow = readRLERow (getRGBPixel, DataBuffer.set3ub)
196 :     val readRGBARLERow = readRLERow (getRGBAPixel, DataBuffer.set4ub)
197 : jhr 274 end
198 : jhr 273
199 : jhr 318 (* read an image row by row *)
200 :     fun readRaster readRow (inS, wid, ht, buf) = let
201 : jhr 273 val stop = wid * ht
202 :     fun lp i = if (i < stop)
203 :     then lp (readRow (inS, buf, i, wid))
204 :     else ()
205 :     in
206 :     lp 0
207 :     end
208 :    
209 :     (* read an image while flipping the Y axis *)
210 : jhr 318 fun flipRaster readRow (inS, wid, ht, buf) = let
211 : jhr 273 val start = (ht - 1) * wid
212 :     fun lp i = if (i < 0)
213 :     then ()
214 :     else (ignore (readRow (inS, buf, i, wid)); lp(i-wid))
215 :     in
216 :     lp ((ht - 1) * wid)
217 :     end
218 :    
219 : jhr 318 fun readFile {file, flip} = ImageIOUtil.withBinIn (file, fn inS => let
220 : jhr 273 fun load () = let
221 : jhr 274 val {wid, ht, size, bytesPerPixel, compressed} = readHdr inS
222 : jhr 273 in
223 : jhr 274 case bytesPerPixel
224 :     of 1 => let
225 :     val buf = DataBuffer.new (DataBuffer.sizeub, size)
226 :     in
227 :     case (flip, compressed)
228 : jhr 318 of (false, false) => readRaster readGrayRow (inS, wid, ht, buf)
229 :     | (false, true) => readRaster readGrayRLERow (inS, wid, ht, buf)
230 :     | (true, false) => flipRaster readGrayRow (inS, wid, ht, buf)
231 :     | (true, true) => flipRaster readGrayRLERow (inS, wid, ht, buf)
232 : jhr 274 (* end case *);
233 : jhr 315 {wid=wid, ht=ht, data=TGAData1 buf}
234 : jhr 274 end
235 :     | 2 => let
236 :     val buf = DataBuffer.new (DataBuffer.size2ub, size)
237 :     in
238 :     case (flip, compressed)
239 : jhr 318 of (false, false) => readRaster readGrayAlphaRow (inS, wid, ht, buf)
240 :     | (false, true) => readRaster readGrayAlphaRLERow (inS, wid, ht, buf)
241 :     | (true, false) => flipRaster readGrayAlphaRow (inS, wid, ht, buf)
242 :     | (true, true) => flipRaster readGrayAlphaRLERow (inS, wid, ht, buf)
243 : jhr 274 (* end case *);
244 : jhr 315 {wid=wid, ht=ht, data=TGAData2 buf}
245 : jhr 274 end
246 :     | 3 => let
247 :     val buf = DataBuffer.new (DataBuffer.size3ub, size)
248 :     in
249 :     case (flip, compressed)
250 : jhr 318 of (false, false) => readRaster readRGBRow (inS, wid, ht, buf)
251 :     | (false, true) => readRaster readRGBRLERow (inS, wid, ht, buf)
252 :     | (true, false) => flipRaster readRGBRow (inS, wid, ht, buf)
253 :     | (true, true) => flipRaster readRGBRLERow (inS, wid, ht, buf)
254 : jhr 274 (* end case *);
255 : jhr 315 {wid=wid, ht=ht, data=TGAData3 buf}
256 : jhr 274 end
257 :     | 4 => let
258 :     val buf = DataBuffer.new (DataBuffer.size4ub, size)
259 :     in
260 :     case (flip, compressed)
261 : jhr 318 of (false, false) => readRaster readRGBARow (inS, wid, ht, buf)
262 :     | (false, true) => readRaster readRGBARLERow (inS, wid, ht, buf)
263 :     | (true, false) => flipRaster readRGBARow (inS, wid, ht, buf)
264 :     | (true, true) => flipRaster readRGBARLERow (inS, wid, ht, buf)
265 : jhr 274 (* end case *);
266 : jhr 315 {wid=wid, ht=ht, data=TGAData4 buf}
267 : jhr 274 end
268 :     (* end case *)
269 : jhr 273 end
270 :     in
271 : jhr 318 load ()
272 :     end)
273 : jhr 273
274 : jhr 318 fun readImage arg = let
275 :     val {wid, ht, data} = readFile arg
276 : jhr 315 in
277 :     case data
278 :     of TGAData1 buf => Gray(Image.image2D{wid=wid, ht=ht, data=buf})
279 :     | TGAData2 buf => GrayAlpha(Image.image2D{wid=wid, ht=ht, data=buf})
280 :     | TGAData3 buf => RGB(Image.image2D{wid=wid, ht=ht, data=buf})
281 :     | TGAData4 buf => RGBA(Image.image2D{wid=wid, ht=ht, data=buf})
282 :     (* end case *)
283 :     end
284 :    
285 : jhr 273 end
286 :    

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0