package camlimages

  1. Overview
  2. Docs
Image processing library

Install

Dune Dependency

Authors

Maintainers

Sources

camlimages-5.0.4.tar.bz2
sha256=1c9a68bdc3d348c9f859d490dadf384926213e47a584159832f7fc4a20242865
md5=1ddba74d210b86a899b5d6565f45c2dc

doc/src/camlimages.core/color.ml.html

Source file color.ml

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
(***********************************************************************)
(*                                                                     *)
(*                           Objective Caml                            *)
(*                                                                     *)
(*            François Pessaux, projet Cristal, INRIA Rocquencourt     *)
(*            Pierre Weis, projet Cristal, INRIA Rocquencourt          *)
(*            Jun Furuse, projet Cristal, INRIA Rocquencourt           *)
(*                                                                     *)
(*  Copyright 1999-2004,                                               *)
(*  Institut National de Recherche en Informatique et en Automatique.  *)
(*  Distributed only by permission.                                    *)
(*                                                                     *)
(***********************************************************************)

(* $Id: color.ml,v 1.1.2.1 2010/05/16 01:45:54 furuse Exp $*)

exception Too_many_colors

module type COLORMODEL = sig
  type t
  val square_distance : t -> t -> int
end

(***************************************************************** color map *)

type 'a map = {
    mutable max: int;
    (* maximum color index allowed in the color map (-1 = unlimited) *)
    mutable map: 'a array;
  }

let size cmap = Array.length cmap.map

let find_exact cmap c =
  let found = ref 0 in
  let map = cmap.map in
  try
    for i = 0 to Array.length map - 1 do
      let c' = map.(i) in
      if c = c' then begin found := i; raise Exit end
    done;
    raise Not_found
  with Exit -> !found

let add_color cmap c1 =
  try
    find_exact cmap c1
  with
  | Not_found ->
    let len = size cmap in
    if cmap.max >= 0 && len = cmap.max then raise Too_many_colors;
    cmap.map <- Array.append cmap.map [|c1|];
    len

let add_colors cmap cs =
  let ret, not_exist =
    List.fold_right
      (fun c (ret, not_exist) ->
         try
           let found = find_exact cmap c in
           (Some found :: ret), not_exist
         with
         | Not_found -> (None :: ret), (c :: not_exist))
      cs ([],[]) in
  let len = size cmap in
  if cmap.max >= 0 && len + List.length not_exist > cmap.max
  then raise Too_many_colors;
  cmap.map <- Array.append cmap.map (Array.of_list not_exist);
  let cntr = ref len in
  List.map
    (function
     | Some x -> x
     | None -> let x = !cntr in incr cntr; x)
    ret

let copy cmap = {
  max = cmap.max;
  map = Array.copy cmap.map;
}

module type S = sig
  type t

  val square_distance : t -> t -> int
  val plus : t -> t -> t
  val minus : t -> t -> t
  val size : t map -> int
  val find_exact : t map -> t -> int
  val add_color : t map -> t -> int
  val add_colors : t map -> t list -> int list
  val find_nearest : t map -> t -> int
end
    
module MakeMap(CM:COLORMODEL) = struct
  let size = (size : CM.t map -> int)
  let find_exact = (find_exact : CM.t map -> CM.t -> int)
  let add_color = (add_color : CM.t map -> CM.t -> int)
  let add_colors = (add_colors : CM.t map -> CM.t list -> int list)

  let find_nearest cmap c =
    let found = ref (-1) in
    let diff = ref (-1) in
    let map = cmap.map in
    for i = 0 to Array.length map - 1 do
      let c' = map.(i) in
      let d = CM.square_distance c c' in
      if !diff < 0 || d < !diff then begin
          diff := d;
          found := i
      end
    done;
    if !found = -1 then raise Not_found else !found

end

module RgbModel = struct
  type t = { mutable r : int; mutable g : int; mutable b : int; }

  let square_distance c1 c2 =
    let dr = c1.r - c2.r
    and dg = c1.g - c2.g
    and db = c1.b - c2.b in
    dr * dr + dg * dg + db * db

  let plus rgb rgb' =
    { r = rgb.r + rgb'.r;
      g = rgb.g + rgb'.g;
      b = rgb.b + rgb'.b; }

  let minus rgb rgb' =
    { r = rgb.r - rgb'.r;
      g = rgb.g - rgb'.g;
      b = rgb.b - rgb'.b; }

end

module Rgb = struct
  include RgbModel
  include MakeMap(RgbModel)
end

type rgb = Rgb.t = { mutable r : int; mutable g : int; mutable b : int; }

module RgbaModel = struct
  type t = { color : rgb; mutable alpha : int; }

  let square_distance c1 c2 =
    let ds_rgb = Rgb.square_distance c1.color c2.color in
    let da = c1.alpha - c2.alpha in
    ds_rgb + da * da

  let plus c c' =
    { color = Rgb.plus c.color c'.color;
      alpha = c.alpha + c'.alpha; }

  let minus c c' =
    { color = Rgb.minus c.color c'.color;
      alpha = c.alpha - c'.alpha; }

  let merge src dst = (* I am not sure... *)
    let check v = if v < 0 then 0 else if v > 255 then 255 else v in
    if src.alpha = 0 then dst else
    if src.alpha = 255 then src else
      let alpha' = 255 - src.alpha in
      let c = {
        r = check ((alpha' * dst.color.r * dst.alpha / 255 +
                    src.color.r * src.alpha) / 255);
        g = check ((alpha' * dst.color.g * dst.alpha / 255 +
                    src.color.g * src.alpha) / 255);
        b = check ((alpha' * dst.color.b * dst.alpha / 255 +
                    src.color.b * src.alpha) / 255);
      } in

      { color = c; alpha = check (255 - alpha' * (255 - dst.alpha) / 255); }
end

module Rgba = struct
  include RgbaModel
  include MakeMap(RgbaModel)
end

type rgba = Rgba.t = { color : rgb; mutable alpha : int; }

module CmykModel = struct
  type t = {
    mutable c : int; mutable m : int; mutable y : int; mutable k : int;
  }
       
  let square_distance c1 c2 =
    let dc = c1.c - c2.c
    and dm = c1.m - c2.m
    and dy = c1.y - c2.y
    and dk = c1.k - c2.k in
    dc * dc + dm * dm + dy * dy + dk * dk

  let plus c c' =
    { c = c.c + c'.c; m = c.m + c'.m; y = c.y + c'.y; k = c.k + c'.k; }

  let minus c c' =
    { c = c.c - c'.c; m = c.m - c'.m; y = c.y - c'.y; k = c.k - c'.k; }
end

module Cmyk = struct
  include CmykModel
  include MakeMap(CmykModel)
end

type cmyk = Cmyk.t =
    { mutable c : int; mutable m : int; mutable y : int;
      mutable k : int; }

(************************************************* RGB specialized functions *)

let rgb_square_distance = Rgb.square_distance
let plus = Rgb.plus
let minus = Rgb.minus

(*
let brightness c = (c.r * 88 + c.g * 127 + c.b * 40) / 255

XV setting
*)

let brightness c = (c.r * 54 + c.g * 182 + c.b * 19) / 255
(*
  Y = 0.212671 * R + 0.715160 * G + 0.072169 * B;

ITU-R Recommendation BT.709, Basic Parameter Values for the HDTV
Standard for the Studio and for International Programme Exchange (1990),
[formerly CCIR Rec. 709], ITU, 1211 Geneva 20, Switzerland.
*)

(********************************************************* Color name parser *)

let color_name_table = ref None

(* CR jfuruse: path_rgb_txt may not exist *)
let color_table_load () =
  let table = Hashtbl.create 107 in
  match Camlimages.path_rgb_txt with
  | None -> table
  | Some path_rgb_txt ->
      let ic = open_in path_rgb_txt in
      try
        while true do
          let s = input_line ic in
          if s.[0] <> '!' then
            let tokens =
              Mstring.split_str (function ' ' | '\t' -> true | _ -> false) s in
            match tokens with
            | r :: g :: b :: rest ->
              Hashtbl.add table (Mstring.catenate_sep " " rest)
                {r = int_of_string r; g = int_of_string g; b = int_of_string b;}
            | _ -> assert false
        done;
        raise Exit
      with
      | End_of_file ->
        close_in ic;
        color_name_table := Some table;
        table

let color_name_query c =
  let table =
    match !color_name_table with
    | Some t -> t
    | None -> color_table_load () in
  Hashtbl.find table c

let color_parse c =
  try
    if c = "none" || c = "None" then {r = -1; g = -1; b = -1} else
    if c.[0] = '#' then
      match String.length c with
      | 7 ->
        let r = int_of_string ("0x" ^ String.sub c 1 2)
        and g = int_of_string ("0x" ^ String.sub c 3 2)
        and b = int_of_string ("0x" ^ String.sub c 5 2) in
        {r = r; g = g; b = b}
      | 13 ->
        let r = int_of_string ("0x" ^ String.sub c 1 4) / 256
        and g = int_of_string ("0x" ^ String.sub c 5 4) / 256
        and b = int_of_string ("0x" ^ String.sub c 9 4) / 256 in
        {r = r; g = g; b = b}
      | _ -> raise Exit
    else color_name_query c
  with
  | _ -> failwith (Printf.sprintf "Color parse %s failed" c)

let colormap_parse cmap =
  let transparent = ref (-1) in
  let cmap = Array.map color_parse cmap in
  for i = 0 to Array.length cmap - 1 do
    let c = cmap.(i) in
    if c.r < 0 then begin
      c.r <- 0; c.g <- 255; c.b <- 0;
      transparent := i;
      prerr_endline (Printf.sprintf "transparent= %d" i);
    end
  done;
  cmap, !transparent
OCaml

Innovation. Community. Security.