1 ! Copyright (C) 2009 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays byte-arrays combinators
4 compression.run-length fry grouping images images.loader io
5 io.binary io.encodings.8-bit io.encodings.binary
6 io.encodings.string io.streams.limited kernel math math.bitwise
7 sequences specialized-arrays summary ;
8 QUALIFIED-WITH: bitstreams b
9 SPECIALIZED-ARRAY: ushort
10 IN: images.bitmap.loading
12 SINGLETON: bitmap-image
13 "bmp" bitmap-image register-image-class
15 ! http://www.fileformat.info/format/bmp/egff.htm
16 ! http://www.digicamsoft.com/bmp/bmp.html
18 ERROR: unknown-component-order bitmap ;
19 ERROR: unknown-bitmap-header n ;
21 : read2 ( -- n ) 2 read le> ;
22 : read4 ( -- n ) 4 read le> ;
26 color-palette color-index bitfields ;
29 { magic initial: "BM" }
31 { reserved1 initial: 0 }
32 { reserved2 initial: 0 }
40 { bit-count initial: 0 }
41 { compression initial: 0 }
42 { image-size initial: 0 }
43 { x-resolution initial: 0 }
44 { y-resolution initial: 0 }
45 { colors-used initial: 0 }
46 { colors-important initial: 0 } ;
48 TUPLE: v4-header < v3-header
49 { red-mask initial: 0 }
50 { green-mask initial: 0 }
51 { blue-mask initial: 0 }
52 { alpha-mask initial: 0 }
53 { cs-type initial: 0 }
54 { end-points initial: 0 }
55 { gamma-red initial: 0 }
56 { gamma-green initial: 0 }
57 { gamma-blue initial: 0 } ;
59 TUPLE: v5-header < v4-header
61 { profile-data initial: 0 }
62 { profile-size initial: 0 }
63 { reserved3 initial: 0 } ;
69 { bit-count initial: 0 } ;
71 TUPLE: os2v2-header < os2v1-header
72 { compression initial: 0 }
73 { image-size initial: 0 }
74 { x-resolution initial: 0 }
75 { y-resolution initial: 0 }
76 { colors-used initial: 0 }
77 { colors-important initial: 0 }
79 { reserved initial: 0 }
80 { recording initial: 0 }
81 { rendering initial: 0 }
84 { color-encoding initial: 0 }
85 { identifier initial: 0 } ;
87 UNION: v-header v3-header v4-header v5-header ;
88 UNION: os2-header os2v1-header os2v2-header ;
90 : parse-file-header ( -- file-header )
92 2 read latin1 decode >>magic
97 read4 >>header-length ;
99 : read-v3-header-data ( header -- header )
101 read4 32 >signed >>height
109 read4 >>colors-important ;
111 : read-v3-header ( -- header )
113 read-v3-header-data ;
115 : read-v4-header-data ( header -- header )
121 read4 read4 read4 3array >>end-points
126 : read-v4-header ( -- v4-header )
129 read-v4-header-data ;
131 : read-v5-header-data ( v5-header -- v5-header )
137 : read-v5-header ( -- loading-bitmap )
141 read-v5-header-data ;
143 : read-os2v1-header ( -- os2v1-header )
146 read2 16 >signed >>height
150 : read-os2v2-header-data ( os2v2-header -- os2v2-header )
152 read4 32 >signed >>height
160 read4 >>colors-important
167 read4 >>color-encoding
170 : read-os2v2-header ( -- os2v2-header )
172 read-os2v2-header-data ;
174 : parse-header ( n -- header )
176 { 12 [ read-os2v1-header ] }
177 { 64 [ read-os2v2-header ] }
178 { 40 [ read-v3-header ] }
179 { 108 [ read-v4-header ] }
180 { 124 [ read-v5-header ] }
181 [ unknown-bitmap-header ]
184 : color-index-length ( header -- n )
188 [ bit-count>> * 31 + 32 /i 4 * ]
192 : color-palette-length ( loading-bitmap -- n )
194 [ offset>> 14 - ] [ header-length>> ] bi - ;
196 : parse-color-palette ( loading-bitmap -- loading-bitmap )
197 dup color-palette-length read >>color-palette ;
199 GENERIC: parse-color-data* ( loading-bitmap header -- loading-bitmap )
201 : parse-color-data ( loading-bitmap -- loading-bitmap )
202 dup header>> parse-color-data* ;
204 M: os2v1-header parse-color-data* ( loading-bitmap header -- loading-bitmap )
205 color-index-length read >>color-index ;
207 M: object parse-color-data* ( loading-bitmap header -- loading-bitmap )
208 dup image-size>> [ 0 ] unless* dup 0 >
209 [ nip ] [ drop color-index-length ] if read >>color-index ;
211 : alpha-used? ( loading-bitmap -- ? )
212 color-index>> 4 <sliced-groups> [ fourth 0 = ] all? not ;
214 GENERIC: bitmap>component-order* ( loading-bitmap header -- object )
216 : bitmap>component-order ( loading-bitmap -- object )
217 dup header>> bitmap>component-order* ;
219 : simple-bitmap>component-order ( loading-bitamp -- object )
220 header>> bit-count>> {
227 [ unknown-component-order ]
230 : advanced-bitmap>component-order ( loading-bitmap -- object )
231 [ ] [ header>> bit-count>> ] [ alpha-used? ] tri 2array {
232 { { 32 t } [ drop BGRA ] }
233 { { 32 f } [ drop BGRX ] }
234 [ drop simple-bitmap>component-order ]
237 : color-lookup3 ( loading-bitmap -- seq )
238 [ color-index>> >array ]
239 [ color-palette>> 3 <sliced-groups> ] bi
240 '[ _ nth ] map concat ;
242 : color-lookup4 ( loading-bitmap -- seq )
243 [ color-index>> >array ]
244 [ color-palette>> 4 <sliced-groups> [ 3 head-slice ] map ] bi
245 '[ _ nth ] map concat ;
247 ! os2v1 is 3bytes each, all others are 3 + 1 unused
248 : color-lookup ( loading-bitmap -- seq )
249 dup file-header>> header-length>> {
250 { 12 [ color-lookup3 ] }
251 { 64 [ color-lookup4 ] }
252 { 40 [ color-lookup4 ] }
253 { 108 [ color-lookup4 ] }
254 { 124 [ color-lookup4 ] }
257 M: os2v1-header bitmap>component-order* drop simple-bitmap>component-order ;
258 M: os2v2-header bitmap>component-order* drop simple-bitmap>component-order ;
259 M: v3-header bitmap>component-order* drop simple-bitmap>component-order ;
260 M: v4-header bitmap>component-order* drop advanced-bitmap>component-order ;
261 M: v5-header bitmap>component-order* drop advanced-bitmap>component-order ;
263 : uncompress-bitfield ( seq masks -- bytes' )
266 [ bitand ] [ bit-count ] [ log2 ] tri - shift
268 ] { } map-as B{ } concat-as ;
270 ERROR: bmp-not-supported n ;
272 : bitmap>bytes ( loading-bitmap -- byte-array )
273 dup header>> bit-count>>
275 { 32 [ color-index>> ] }
276 { 24 [ color-index>> ] }
279 ! byte-array>ushort-array
282 ! { HEX: f800 HEX: 7e0 HEX: 1f } uncompress-bitfield
284 { HEX: 7c00 HEX: 3e0 HEX: 1f } uncompress-bitfield
288 { 8 [ color-lookup ] }
289 { 4 [ [ 4 b:byte-array-n>seq ] change-color-index color-lookup ] }
290 { 1 [ [ 1 b:byte-array-n>seq ] change-color-index color-lookup ] }
291 [ bmp-not-supported ]
294 : set-bitfield-widths ( loading-bitmap -- loading-bitmap' )
295 dup header>> bit-count>> {
296 { 16 [ dup color-palette>> 4 group [ le> ] map ] }
297 { 32 [ { HEX: ff0000 HEX: ff00 HEX: ff } ] }
298 } case reverse >>bitfields ;
300 ERROR: unsupported-bitfield-widths n ;
302 M: unsupported-bitfield-widths summary
303 drop "Bitmaps only support bitfield compression in 16/32bit images" ;
305 : uncompress-bitfield-widths ( loading-bitmap -- loading-bitmap' )
307 dup header>> bit-count>> {
310 byte-array>ushort-array _ uncompress-bitfield
314 [ unsupported-bitfield-widths ]
317 ERROR: unsupported-bitmap-compression compression ;
319 GENERIC: uncompress-bitmap* ( loading-bitmap header -- loading-bitmap )
321 : uncompress-bitmap ( loading-bitmap -- loading-bitmap )
322 dup header>> uncompress-bitmap* ;
324 M: os2-header uncompress-bitmap* ( loading-bitmap header -- loading-bitmap' )
327 : do-run-length-uncompress ( loading-bitmap word -- loading-bitmap )
329 _ header>> [ width>> ] [ height>> ] bi
331 ] change-color-index ; inline
333 M: v-header uncompress-bitmap* ( loading-bitmap header -- loading-bitmap' )
337 { 1 [ \ run-length-uncompress-bitmap8 do-run-length-uncompress ] }
338 { 2 [ \ run-length-uncompress-bitmap4 do-run-length-uncompress ] }
339 { 3 [ uncompress-bitfield-widths ] }
340 { 4 [ "jpeg" unsupported-bitmap-compression ] }
341 { 5 [ "png" unsupported-bitmap-compression ] }
344 ERROR: unsupported-bitmap-file magic ;
346 : load-bitmap ( stream -- loading-bitmap )
349 parse-file-header [ >>file-header ] [ ] bi magic>> {
351 dup file-header>> header-length>> parse-header >>header
355 ! { "BA" [ parse-os2-bitmap-array ] }
356 ! { "CI" [ parse-os2-color-icon ] }
357 ! { "CP" [ parse-os2-color-pointer ] }
358 ! { "IC" [ parse-os2-icon ] }
359 ! { "PT" [ parse-os2-pointer ] }
360 [ unsupported-bitmap-file ]
362 ] with-input-stream ;
364 : loading-bitmap>bytes ( loading-bitmap -- byte-array )
365 uncompress-bitmap bitmap>bytes ;
367 M: bitmap-image stream>image ( stream bitmap-image -- bitmap )
371 [ loading-bitmap>bytes >>bitmap ]
372 [ header>> [ width>> ] [ height>> abs ] bi 2array >>dim ]
373 [ header>> height>> 0 < not >>upside-down? ]
374 [ bitmap>component-order >>component-order ubyte-components >>component-type ]