1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
open Images
type ppm_magic_number = | P1 | P2 | P3 | P4 | P5 | P6
let magic_number_of_string = function
| "P1" -> P1
| "P2" -> P2
| "P3" -> P3
| "P4" -> P4
| "P5" -> P5
| "P6" -> P6
| s -> invalid_arg ("Unknown magic number for PPM image: " ^ s)
let read_ppm_magic_number ic = magic_number_of_string (input_line ic)
let string_of_magic_number = function
| P1 -> "P1"
| P2 -> "P2"
| P3 -> "P3"
| P4 -> "P4"
| P5 -> "P5"
| P6 -> "P6"
let ic =
let rec r0 () =
match input_char ic with
| '#' -> r1 ()
| ' ' -> r0 ()
| '\n' -> r0 ()
| c -> c
and r1 () =
match input_char ic with
| '\n' -> r0 ()
| _ -> r1 () in
r0 ()
let read_int_accu accu ic =
let rec read accu =
match input_char ic with
| '0' .. '9' as c -> read1 (10 * accu + int_of_char c - 48)
| ' ' -> read accu
| '\n' -> read accu
| _ -> invalid_arg "read_int"
and read1 accu =
match input_char ic with
| '0' .. '9' as c -> read1 (10 * accu + int_of_char c - 48)
| _ -> accu in
read accu
let read_int ic = read_int_accu 0 ic
let read_dims c ic =
let cols = read_int_accu (int_of_char c - 48) ic in
let lines = read_int ic in
cols, lines
let read_max ic = read_int ic
let ic =
let mn = read_ppm_magic_number ic in
let char = skip_comment ic in
let c, l = read_dims char ic in
mn, l, c
let filename =
let ic = open_in_bin filename in
try
let _mn, l, c = read_ppm_header ic in
close_in ic;
{ header_width = c;
header_height = l;
header_infos = [] }
with
| _ ->
close_in ic;
raise Wrong_file_type
let read_raw_pixel24 ic =
let r = input_byte ic in
let g = input_byte ic in
let b = input_byte ic in
{r = r; g = g; b = b}
let read_ascii_pixel24 ic =
let r = read_int ic in
let g = read_int ic in
let b = read_int ic in
{r = r; g = g; b = b}
let read_raw_ppm_ic ic l c _max =
let img = Rgb24.create c l in
for i = 0 to l - 1 do
for j = 0 to c - 1 do
Rgb24.set img j i (read_raw_pixel24 ic)
done
done;
img
let read_ascii_ppm_ic ic l c _max =
let img = Rgb24.create c l in
for i = 0 to l - 1 do
for j = 0 to c - 1 do
Rgb24.set img j i (read_ascii_pixel24 ic)
done
done;
img
let read_raw_grey = input_byte
let read_ascii_grey = read_int
let read_raw_gen_ic read_pixel ic l c max =
let img = Index8.create c l in
let greymap =
{ Color.max = max;
Color.map =
let make_grey i = {r = i; g = i; b = i} in
Array.init (max + 1) make_grey} in
img.Index8.colormap <- greymap;
for i = 0 to l - 1 do
for j = 0 to c - 1 do
Index8.set img j i (read_pixel ic)
done
done;
img
let read_raw_pgm_ic ic = read_raw_gen_ic read_raw_grey ic
let read_ascii_pgm_ic ic = read_raw_gen_ic read_ascii_grey ic
let black = 0 and white = 255
let max_byte = 255
let read_raw_pbm_ic ic l c =
let img = Index8.create c l in
let greymap =
{ Color.max = max_byte;
Color.map =
let make_grey i = {r = i; g = i; b = i} in
Array.init (max_byte + 1) make_grey} in
img.Index8.colormap <- greymap;
for i = 0 to l - 1 do
let rec loop j bn byte =
if j = c then () else
if bn = 8 then loop j 0 (input_byte ic) else
let color =
match byte land 0x80 with
| 0 -> white
| _ -> black in
Index8.set img j i color;
let new_byte = byte lsl 1 in
loop (j + 1) (bn + 1) new_byte
in
loop 0 0 (input_byte ic)
done;
img
let rec read_ascii_bit ic =
match input_char ic with
| '0' -> white
| ' ' -> read_ascii_bit ic
| '\n' -> read_ascii_bit ic
| _ -> black
let read_ascii_pbm_ic ic l c = read_raw_gen_ic read_ascii_bit ic l c max_byte
let read_ppm_ic ic =
let mn, l, c = read_ppm_header ic in
let img =
match mn with
| P1 -> Index8 (read_ascii_pbm_ic ic l c)
| P4 -> Index8 (read_raw_pbm_ic ic l c)
| P2 | P3 | P5 | P6 ->
let max = read_max ic in
match mn with
| P2 -> Index8 (read_ascii_pgm_ic ic l c max)
| P3 -> Rgb24 (read_ascii_ppm_ic ic l c max)
| P5 -> Index8 (read_raw_pgm_ic ic l c max)
| _ -> Rgb24 (read_raw_ppm_ic ic l c max) in
img
let read_ppm s =
let ic = open_in_bin s in
try
let img = read_ppm_ic ic in
close_in ic;
img
with End_of_file ->
close_in ic; invalid_arg "read_ppm: premature end of file"
let load_ppm s =
match read_ppm s with
| Rgb24 img -> img
| _ -> invalid_arg (s ^ " is not a ppm file.")
let _img mn oc l c =
output_string oc (Printf.sprintf "%s\n" (string_of_magic_number mn));
output_string oc "# CREATOR: CamlImages package\n";
output_string oc (Printf.sprintf "%d %d\n" c l);
if mn <> P1 && mn <> P4 then output_string oc (Printf.sprintf "%d\n" 255)
let bit_set = 1 and bit_cleared = 0
let gen_save_raw_pbm_oc is_white img oc l c =
save_ppm_header img P4 oc l c;
for i = 0 to l - 1 do
let rec loop j bn byte =
if j = c then
if bn = 0 then () else
let byte = byte lsl (8 - bn) in
output_byte oc byte else
if bn = 8 then (output_byte oc byte; loop j 0 0) else
let color =
if is_white (Index8.get_rgb img j i) then bit_set else bit_cleared in
let new_byte = (byte lsl 1) lor color in
loop (j + 1) (bn + 1) new_byte
in
loop 0 0 0
done
let save_raw_pbm_oc =
gen_save_raw_pbm_oc (fun c -> c.r = 255 && c.g = 255 && c.b = 255)
let save_raw_ppm_oc img oc l c =
save_ppm_header img P6 oc l c;
for i = 0 to l - 1 do
for j = 0 to c - 1 do
let color = Rgb24.get img j i in
output_byte oc color.r;
output_byte oc color.g;
output_byte oc color.b
done
done
let save_ppm_oc img oc =
let l = img.Rgb24.height in
if l = 0 then invalid_arg "save_ppm: invalid null line number";
let c = img.Rgb24.width in
if c = 0 then invalid_arg "save_ppm: invalid null column number";
save_raw_ppm_oc img oc l c
let save_ppm s img =
let oc = open_out_bin s in
save_ppm_oc img oc;
close_out oc
let save_bitmap_oc img oc =
let l = img.Index8.height in
if l = 0 then invalid_arg "save_ppm: invalid null line number";
let c = img.Index8.width in
if c = 0 then invalid_arg "save_ppm: invalid null column number";
save_raw_pbm_oc img oc l c
let save_bitmap s img =
let oc = open_out_bin s in
save_bitmap_oc img oc;
close_out oc
let load s _ = read_ppm s
let load_bitmap s =
match load s [] with
| Index8 t -> t
| _ -> invalid_arg "Not a pbm file."
let save s _ = function
| Index8 t -> save_bitmap s t
| Rgb24 t -> save_ppm s t
| _ -> invalid_arg "Ppm.save"
let () = add_methods Ppm
{ check_header = check_header;
load = Some load;
save = Some save;
load_sequence = None;
save_sequence = None}