~ubuntu-branches/debian/squeeze/camlimages/squeeze

« back to all changes in this revision

Viewing changes to src/ppm.ml

  • Committer: Bazaar Package Importer
  • Author(s): Sylvain Le Gall, Ralf Treinen, Sylvain Le Gall
  • Date: 2009-03-05 00:19:32 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20090305001932-f0hstlmun8hxvs0r
Tags: 1:3.0.1-1
[ Ralf Treinen ]
* Updated debian/watch.

[ Sylvain Le Gall ]
* New upstream version:
  * Remove useless patches
  * Adapt debian/rules and other debhelper files
  * Add debian/patches/fix_3_0_1 to fix various problem (probably due to
    OCaml 3.11 migration)
* Depends on version 2.12 of lablgtk2
* Add dh-ocaml build-dependency (rules/ocaml.mk)
* Add ${misc:Depends} to dependencies
* Update Homepage field into debian/control and debian/copyright
* Add license version for debian packaging
* Directly use eng.html rather than creating a linked index.html file

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
(***********************************************************************)
 
2
(*                                                                     *)
 
3
(*                           Objective Caml                            *)
 
4
(*                                                                     *)
 
5
(*            Fran�ois Pessaux, projet Cristal, INRIA Rocquencourt     *)
 
6
(*            Pierre Weis, projet Cristal, INRIA Rocquencourt          *)
 
7
(*            Jun Furuse, projet Cristal, INRIA Rocquencourt           *)
 
8
(*                                                                     *)
 
9
(*  Copyright 1999, 2004                                               *)
 
10
(*  Institut National de Recherche en Informatique et en Automatique.  *)
 
11
(*  Distributed only by permission.                                    *)
 
12
(*                                                                     *)
 
13
(***********************************************************************)
 
14
 
 
15
(* $Id: ppm.ml,v 1.1 2007/01/18 10:29:57 rousse Exp $ *)
 
16
 
 
17
(* Manipulating images in portable format: PPM, PGM, and PBM.
 
18
 
 
19
PPM: portable pixmap (pixels (picture element) map).
 
20
PGM: portable greymap (grey scale map).
 
21
PBM: portable bitmap (binary digit map).
 
22
 
 
23
*)
 
24
 
 
25
open Images;;
 
26
 
 
27
(* Reading PPM images. *)
 
28
 
 
29
type ppm_magic_number = | P1 | P2 | P3 | P4 | P5 | P6;;
 
30
 (* Magic numbers for PPM images.
 
31
    P1 and P4 indicate bitmaps (P1 is ascii encoding, P4 is raw encoding).
 
32
    P2 and P5 indicate greymaps, in raw or ascii encoding.
 
33
    P3 and P6 indicate pixmaps (P3 is ascii encoding, P6 is raw encoding).
 
34
 
 
35
    The library systematically saves images in raw form (which is more compact).
 
36
 *)
 
37
 
 
38
let magic_number_of_string = function
 
39
  | "P1" (* BITMAP, ASCII form *) -> P1
 
40
  | "P2" (* BITMAP, ASCII form *) -> P2
 
41
  | "P3" (* PIXMAP, ASCII form *) -> P3
 
42
  | "P4" (* BITMAP, RAW form *) -> P4
 
43
  | "P5" (* BITMAP, ASCII form *) -> P5
 
44
  | "P6" (* PIXMAP, RAW form *) -> P6
 
45
  | s -> invalid_arg ("Unknown magic number for PPM image: " ^ s);;
 
46
 
 
47
let read_ppm_magic_number ic = magic_number_of_string (input_line ic);;
 
48
 
 
49
let string_of_magic_number = function
 
50
  | P1 -> "P1"
 
51
  | P2 -> "P2"
 
52
  | P3 -> "P3"
 
53
  | P4 -> "P4"
 
54
  | P5 -> "P5"
 
55
  | P6 -> "P6";;
 
56
 
 
57
(* Auxiliaries: skipping comments and reading numbers into strings. *)
 
58
let rec skip_comment ic =
 
59
 let rec r0 () =
 
60
  match input_char ic with
 
61
  | '#' -> r1 ()
 
62
  | ' ' -> r0 ()
 
63
  | '\n' -> r0 ()
 
64
  | c -> c
 
65
 and r1 () =
 
66
  match input_char ic with
 
67
  | '\n' -> r0 ()
 
68
  | _ -> r1 () in
 
69
 r0 ();;
 
70
 
 
71
(* Read a sequence of digits eventually followed by a single space. *)
 
72
let read_int_accu accu ic =
 
73
 let rec read accu =
 
74
 match input_char ic with
 
75
 | '0' .. '9' as c -> read1 (10 * accu + int_of_char c - 48)
 
76
 | ' ' -> read accu
 
77
 | '\n' -> read accu
 
78
 | _ -> invalid_arg "read_int"
 
79
 
 
80
 and read1 accu =
 
81
 match input_char ic with
 
82
 | '0' .. '9' as c -> read1 (10 * accu + int_of_char c - 48)
 
83
 | _ -> accu in
 
84
 read accu;;
 
85
 
 
86
let read_int ic = read_int_accu 0 ic;;
 
87
 
 
88
let read_dims c ic =
 
89
 let cols = read_int_accu (int_of_char c - 48) ic in
 
90
 let lines = read_int ic in
 
91
 cols, lines;;
 
92
 
 
93
let read_max ic = read_int ic;;
 
94
 
 
95
let read_ppm_header ic =
 
96
 (* Reads something like
 
97
    P6
 
98
    # CREATOR: XV Version 3.10  Rev: 12/16/94
 
99
    256 162
 
100
    255
 
101
 *)
 
102
 let mn = read_ppm_magic_number ic in
 
103
 let char = skip_comment ic in
 
104
 let c, l = read_dims char ic in
 
105
 mn, l, c;;
 
106
 
 
107
let check_header filename =
 
108
 let ic = open_in_bin filename in
 
109
 try
 
110
   let mn, l, c = read_ppm_header ic in
 
111
   close_in ic;
 
112
   { header_width = c;
 
113
     header_height = l;
 
114
     header_infos = [] }
 
115
 with
 
116
 | _ ->
 
117
   close_in ic;
 
118
   raise Wrong_file_type;;
 
119
 
 
120
(* Reading pixmaps. *)
 
121
let read_raw_pixel24 ic =
 
122
 let r = input_byte ic in
 
123
 let g = input_byte ic in
 
124
 let b = input_byte ic in
 
125
 {r = r; g = g; b = b};;
 
126
 
 
127
let read_ascii_pixel24 ic =
 
128
 let r = read_int ic in
 
129
 let g = read_int ic in
 
130
 let b = read_int ic in
 
131
 {r = r; g = g; b = b};;
 
132
 
 
133
let read_raw_ppm_ic ic l c max =
 
134
 let img = Rgb24.create c l in
 
135
 for i = 0 to l - 1 do
 
136
  for j = 0 to c - 1 do
 
137
   Rgb24.set img j i (read_raw_pixel24 ic)
 
138
  done
 
139
 done;
 
140
 img;;
 
141
 
 
142
let read_ascii_ppm_ic ic l c max =
 
143
 let img = Rgb24.create c l in
 
144
 for i = 0 to l - 1 do
 
145
  for j = 0 to c - 1 do
 
146
   Rgb24.set img j i (read_ascii_pixel24 ic)
 
147
  done
 
148
 done;
 
149
 img;;
 
150
 
 
151
(* Reading greymaps. *)
 
152
let read_raw_grey = input_byte;;
 
153
 
 
154
let read_ascii_grey = read_int;;
 
155
 
 
156
let read_raw_gen_ic read_pixel ic l c max =
 
157
 let img = Index8.create c l in
 
158
 let greymap =
 
159
   { Color.max = max;
 
160
     Color.map =
 
161
      let make_grey i = {r = i; g = i; b = i} in
 
162
      Array.init (max + 1) make_grey} in
 
163
 img.Index8.colormap <- greymap;
 
164
 for i = 0 to l - 1 do
 
165
  for j = 0 to c - 1 do
 
166
   Index8.set img j i (read_pixel ic)
 
167
  done
 
168
 done;
 
169
 img;;
 
170
 
 
171
let read_raw_pgm_ic ic = read_raw_gen_ic read_raw_grey ic;;
 
172
 
 
173
let read_ascii_pgm_ic ic = read_raw_gen_ic read_ascii_grey ic;;
 
174
 
 
175
let black = 0 and white = 255;;
 
176
let max_byte = 255;;
 
177
 
 
178
(* Reading bitmaps. *)
 
179
let read_raw_pbm_ic ic l c =
 
180
 let img = Index8.create c l in
 
181
 let greymap =
 
182
   { Color.max = max_byte;
 
183
     Color.map =
 
184
      let make_grey i = {r = i; g = i; b = i} in
 
185
      Array.init (max_byte + 1) make_grey} in
 
186
 img.Index8.colormap <- greymap;
 
187
 for i = 0 to l - 1 do
 
188
  let rec loop j bn byte =
 
189
    if j = c then () else
 
190
    if bn = 8 then loop j 0 (input_byte ic) else
 
191
    let color =
 
192
      match byte land 0x80 with
 
193
      | 0 -> white
 
194
      | _ -> black in
 
195
    Index8.set img j i color;
 
196
    let new_byte = byte lsl 1 in
 
197
    loop (j + 1) (bn + 1) new_byte
 
198
  in
 
199
  loop 0 0 (input_byte ic)
 
200
 done;
 
201
 img;;
 
202
 
 
203
let rec read_ascii_bit ic =
 
204
    match input_char ic with
 
205
    | '0' -> white
 
206
    | ' ' -> read_ascii_bit ic
 
207
    | '\n' -> read_ascii_bit ic
 
208
    | _ -> black;;
 
209
 
 
210
let read_ascii_pbm_ic ic l c = read_raw_gen_ic read_ascii_bit ic l c max_byte;;
 
211
 
 
212
let rec read_ppm_ic ic =
 
213
 let mn, l, c = read_ppm_header ic in
 
214
 let img =
 
215
   match mn with
 
216
   | P1 -> Index8 (read_ascii_pbm_ic ic l c)
 
217
   | P4 -> Index8 (read_raw_pbm_ic ic l c) 
 
218
   | P2 | P3 | P5 | P6 ->
 
219
       let max = read_max ic in
 
220
       match mn with
 
221
       | P2 -> Index8 (read_ascii_pgm_ic ic l c max)
 
222
       | P3 -> Rgb24 (read_ascii_ppm_ic ic l c max)
 
223
       | P5 -> Index8 (read_raw_pgm_ic ic l c max)
 
224
       | _ -> Rgb24 (read_raw_ppm_ic ic l c max) in
 
225
 img;;
 
226
 
 
227
let read_ppm s =
 
228
 let ic = open_in_bin s in
 
229
 try
 
230
  let img = read_ppm_ic ic in
 
231
  close_in ic;
 
232
  img
 
233
 with End_of_file ->
 
234
  close_in ic; invalid_arg "read_ppm: premature end of file";;
 
235
 
 
236
let load_ppm s = 
 
237
  match read_ppm s with
 
238
  | Rgb24 img -> img
 
239
  | _ -> invalid_arg (s ^ " is not a ppm file.");;
 
240
 
 
241
(* Saving images. *)
 
242
 
 
243
let save_ppm_header img mn oc l c =
 
244
 output_string oc (Printf.sprintf "%s\n" (string_of_magic_number mn));
 
245
 output_string oc "# CREATOR: CamlImages package\n";
 
246
 output_string oc (Printf.sprintf "%d %d\n" c l);
 
247
 if mn <> P1 && mn <> P4 then output_string oc (Printf.sprintf "%d\n" 255);;
 
248
 
 
249
let bit_set = 1 and bit_cleared = 0;;
 
250
 
 
251
let gen_save_raw_pbm_oc is_white img oc l c =
 
252
  save_ppm_header img P4 oc l c;
 
253
  for i = 0 to l - 1 do
 
254
   let rec loop j bn byte =
 
255
    if j = c then
 
256
     if bn = 0 then () else
 
257
      let byte = byte lsl (8 - bn) in
 
258
      output_byte oc byte else
 
259
    if bn = 8 then (output_byte oc byte; loop j 0 0) else
 
260
    let color =
 
261
      if is_white (Index8.get_rgb img j i) then bit_set else bit_cleared in
 
262
    let new_byte = (byte lsl 1) lor color in
 
263
    loop (j + 1) (bn + 1) new_byte
 
264
   in
 
265
   loop 0 0 0
 
266
 done;;
 
267
 
 
268
(* Save a bitmap in raw form. *)
 
269
let save_raw_pbm_oc =
 
270
 gen_save_raw_pbm_oc (fun c -> c.r = 255 && c.g = 255 && c.b = 255);; 
 
271
 
 
272
(*
 
273
(* Save a transparency mask as a bitmap in raw form. *)
 
274
let save_mask = gen_save_raw_pbm_oc (fun c -> c = transp);;
 
275
*)
 
276
 
 
277
(* Save a pixmap in raw form. *)
 
278
let save_raw_ppm_oc img oc l c =
 
279
  save_ppm_header img P6 oc l c;
 
280
  let has_transp = ref false in
 
281
  for i = 0 to l - 1 do
 
282
   for j = 0 to c - 1 do
 
283
    let color = Rgb24.get img j i in
 
284
    output_byte oc color.r;
 
285
    output_byte oc color.g;
 
286
    output_byte oc color.b
 
287
   done
 
288
  done;
 
289
  !has_transp;;
 
290
 
 
291
let save_ppm_oc img oc =
 
292
  let l = img.Rgb24.height in
 
293
  if l = 0 then invalid_arg "save_ppm: invalid null line number";
 
294
  let c = img.Rgb24.width in
 
295
  if c = 0 then invalid_arg "save_ppm: invalid null column number";
 
296
  (*
 
297
  let has_transp = save_raw_ppm_oc img oc l c in
 
298
  if has_transp then
 
299
   begin
 
300
    (* Save the transparency mask *)
 
301
    output_char oc '\n';
 
302
    save_mask img oc l c;
 
303
    (* and correct the magic number *)
 
304
    seek_out oc 1;
 
305
    output_char oc '0';
 
306
   end*)
 
307
   ();;
 
308
 
 
309
let save_ppm s img =
 
310
 let oc = open_out_bin s in
 
311
 save_ppm_oc img oc;
 
312
 close_out oc;;
 
313
 
 
314
let save_bitmap_oc img oc =
 
315
 let l = img.Index8.height in
 
316
 if l = 0 then invalid_arg "save_ppm: invalid null line number";
 
317
 let c = img.Index8.width in
 
318
 if c = 0 then invalid_arg "save_ppm: invalid null column number";
 
319
 save_raw_pbm_oc img oc l c;;
 
320
 
 
321
let save_bitmap s img =
 
322
 let oc = open_out_bin s in
 
323
 save_bitmap_oc img oc;
 
324
 close_out oc;;
 
325
 
 
326
let load s _ = read_ppm s;;
 
327
 
 
328
let load_bitmap s =
 
329
 match load s [] with
 
330
 | Index8 t -> t
 
331
 | _ -> invalid_arg "Not a pbm file.";;
 
332
 
 
333
let save s _ = function
 
334
  | Index8 t -> save_bitmap s t
 
335
  | Rgb24 t -> save_ppm s t
 
336
  | _ -> invalid_arg "Ppm.save";;
 
337
 
 
338
add_methods Ppm
 
339
 { check_header = check_header;
 
340
   load = Some load;
 
341
   save = Some save;
 
342
   load_sequence = None;
 
343
   save_sequence = None};;