package tiny_libs
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
From-scratch libraries for teaching: graphics, audio, compression, crypto, networking and more
Install
dune-project
Dependency
Authors
Maintainers
Sources
0.3.6.tar.gz
md5=7c636383d146d30ac6f2fa234a6253c8
sha512=c79f3823c5f8f57e5038eb640d487c61168b84aa07c61999d6622ef9fd0c890e2b03b4c6a7cdbbe9352a49e25dda00ac7bb14693cee8e3d7beeed251351a2af0
doc/src/tiny_libs.graphics_core/Matting.ml.html
Source file Matting.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(* Claude Code * * Copyright (C) 2026 Yoann Padioleau * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License * (LGPL) as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. *) (* See Matting.mli. *) type rgba = (int, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t (* the channel at bit [shift] of a 0xRRGGBB color: 16 red, 8 green, 0 blue. * claude: at the top level, not inside premultiplied_rgba's loop, * where OCaml would allocate a closure for it at each of the million * pixels of a 1000x1000 image (~11ms of the first version's 64) *) let channel (rgb : int) (shift : int) : int = (rgb lsr shift) land 0xFF let premultiplied_rgba ~(width : int) ~(height : int) (draw : Framebuffer.t -> unit) : rgba = let over_black = Framebuffer.create ~width ~height in Framebuffer.clear over_black ~rgb:0x000000; draw over_black; let over_white = Framebuffer.create ~width ~height in Framebuffer.clear over_white ~rgb:0xFFFFFF; draw over_white; (* all transparent to start with: most pixels stay so (nothing drawn * there), and filling with zeros is fast *) let out = Bigarray.Array1.create Bigarray.int8_unsigned Bigarray.c_layout (width * height * 4) in Bigarray.Array1.fill out 0; for y = 0 to height - 1 do for x = 0 to width - 1 do let b = Framebuffer.get_rgb over_black ~x ~y and w = Framebuffer.get_rgb over_white ~x ~y in (* claude: only where something was drawn: black and white left * as they were is transparent, already in [out]. Skipping them * took a HUD of a few words on a 1000x1000 window from 27ms to * 20ms: they're nearly all the pixels. *) if not (b = 0x000000 && w = 0xFFFFFF) then begin (* a = 1 - (W - B)/255, from each channel; they agree up to * rounding, so their average *) let diff_sum = channel w 16 - channel b 16 + (channel w 8 - channel b 8) + (channel w 0 - channel b 0) in let alpha = 255 - ((diff_sum + 1) / 3) in let i = ((y * width) + x) * 4 in out.{i} <- channel b 16; out.{i + 1} <- channel b 8; out.{i + 2} <- channel b 0; (* claude: Int.max/Int.min, not max/min. The first version, * [max 0 (min 255 alpha)], took ~25ms of its 64 on the million * pixels of a 1000x1000 window, i.e. ~12ns per call, for what * should be one machine comparison. Why: Stdlib's [max] is * * let max a b = if a >= b then a else b (* 'a -> 'a -> 'a *) * * compiled once, for every type, so its [>=] can't know it's * comparing ints: it calls the C function caml_greaterequal, * which inspects both values at runtime (int? pointer? to a * string, a float, a tuple?) before comparing. ocamlopt * replaces a comparison by a single instruction only where the * types are known at that very spot, e.g. [alpha >= 0] written * here, with [alpha : int]; calling a polymorphic function hides * the type (unless the compiler inlines it first: flambda, an * optional optimizing variant of ocamlopt, can; the standard * one, used here, doesn't). Int.max/Int.min (OCaml >= 4.13) are the same code * with ints, so their comparisons are single instructions. The * same trap: [compare], [=], [<] passed around as values, or * used inside a function polymorphic in the compared values' * type (e.g. [List.sort compare] on ints: [Int.compare] is * faster). *) out.{i + 3} <- Int.max 0 (Int.min 255 alpha) end done done; out
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>