QoicQOI image codec.
Encodes and decodes QOI images.
See the limitations and an example.
val channel_count : channels -> intchannel_count c is the number of channels in c.
module Meta : sig ... endImage metadata.
module Bigbytes : sig ... endBigarrays of bytes.
type pixels = Bigbytes.tThe type for pixel data.
Pixels are stored in a linear buffer, line-by-line, from left to right and top to bottom in RGB or RGBA order with one byte per component.
val encode : Meta.t -> pixels -> Bigbytes.tencode m p is the encoding of pixels p described by m.
Raises Invalid_argument if Meta.pixels_byte_length m does not match p's length or if Meta.encodable m is false.
module Error : sig ... endDecoding errors.
val decode :
?channels:channels ->
Bigbytes.t ->
( Meta.t * pixels, Error.t ) Stdlib.resultdecode ~channels b decodes a QOI image from b.
If channels is Some c, forces the channels of the resulting metadata and pixels to be c. An `Rgb image forced to `Rgba gets a constant 0xFF alpha channel and an `Rgba image forced to `Rgb drops the alpha channel.
val decode' :
?channels:channels ->
Bigbytes.t ->
( Meta.t * pixels, string ) Stdlib.resultdecode' b is Result.map_error Error.to_string (decode b).
val decode_meta : Bigbytes.t -> ( Meta.t, Error.t ) Stdlib.resultdecode_meta b decodes QOI image metadata from b.
ints are used for the image size and indexing pixel components in bigarrays of bytes. On 32-bit platforms, this limits images to around 536 millions pixels (23k x 23k) for RGBA.The Stdlib (at least until 4.14) does not provide a simple interface to interface bigarrays with files. Assume we have a module with the following interface (see below for an implementation):
module Bigfile : sig
type fpath = string
type bigbytes =
(int, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
val read : fpath -> (bigbytes, string) result
val write : fpath -> bigbytes -> (unit, string) result
endThe following function recodes a QOI file with Qoic:
let recode ?channels file ~dst =
let ( let* ) = Result.bind in
let* bytes = Bigfile.read file in
let* meta, pixels = Qoic.decode' ?channels bytes in
Bigfile.write dst (Qoic.encode meta pixels)The Bigfile module can be implemented by:
module Bigfile = struct
type fpath = string
type bigbytes =
(int, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
let map_bytes ?(len = -1) ~write fd =
let t = Bigarray.int8_unsigned and l = Bigarray.C_layout in
Bigarray.array1_of_genarray (Unix.map_file fd t l write [|len|])
let error f e = Error (Printf.sprintf "%s: %s" f (Unix.error_message e))
let read file =
try
let fd = Unix.openfile file Unix.[O_RDONLY] 0x600 in
let finally () = try Unix.close fd with Unix.Unix_error _ -> () in
Fun.protect ~finally @@ fun () -> Ok (map_bytes ~write:false fd)
with
| Unix.Unix_error (e, _, _) -> error file e
let write file bytes =
try
let fd = Unix.openfile file Unix.[O_CREAT; O_RDWR; O_TRUNC] 0o644 in
let finally () = try Unix.close fd with Unix.Unix_error _ -> () in
Fun.protect ~finally @@ fun () ->
let dst = map_bytes ~len:(Bigarray.Array1.dim bytes) ~write:true fd in
Ok (Bigarray.Array1.blit bytes dst)
with
| Unix.Unix_error (e, _, _) -> error file e
end