I’m currently learning OCaml and I’m trying to edit PNG images. My idea is to introduce the following type :
type image = (int * int * int) array array;;
(a matrix whose coefficients are pixels represented by three integers between 0 and 255)
However, when it comes to load a PNG image, I can’t figure out how. The only packages I found for that are camlimagesand imagelib. The documentation I found for these packages is really unhelpful : all I was able to find on the Internet is a list of types and functions, with no indications regarding what those actually do.
When trying to load a PNG with imagelibwith the following code
#use “topfind”;;
#require “imagelib”;;
open Image;;
open ImagePNG;;
open ImageUtil;;
let png = parsefile (chunk_reader_of_string “image.png”);;
I get the error : Exception: Image.Corrupted_image "Invalid PNG header...".
But the image isn’t corrupted (I get this same error with any PNG file). Actually I don’t even know how functions parsefile and chunk_reader_of_string work, as I couldn’t find any clear documentation on them. I just looked as the list of functions of modules Image, ImagePNG, and ImageUtil, and tried it. I can’t find any more information about how to use these modules.
I searched everywhere (I even asked AI, which wasn’t better) but was not able to find any solution to this problem. All I would like to do is to create functions load_png (file : string) : imageand write_png (img : image) (destination : string) : unit where image is the type described above, and where fileand destinationare string indicating a file location on my computer, from which to load / where to write a PNG image.
I also wasn’t able to install package camlimages: [ERROR] The compilation of camlimages.5.0.5 failed at "dune build -p camlimages -j 7 @install".
but I think this has more to do with opam.
I would really appreciate if somebody could help me understand all this.
Thank you very much.
#require "tsdl-image";;
open Tsdl;;
open Tsdl_image;;
Sdl.(init Init.video);;
let surf = match Image.load "image.png" with Ok s -> s | _ -> failwith "error loading file";;
Sdl.lock_surface surf;;
let data = Sdl.get_surface_pixels surf Bigarray.int8_unsigned;;
Then, data is a bigarray containing your image.
You can inspect the image format (eg: RGBA) with Sdl.get_surface_format_enum surf
#! /usr/bin/env -S thin-ocamlscript -package imagelib -linkpkg --
let load_png path =
In_channel.with_open_bin path (fun file ->
ImagePNG.parsefile
(ImageUtil.chunk_reader_of_string (In_channel.input_all file)))
let write_png img path =
Out_channel.with_open_bin path (fun file ->
let buf = Buffer.create 0 in
let writer = ImageUtil.chunk_writer_of_buffer buf in
ImagePNG.write_png writer img;
Out_channel.output_string file (Buffer.contents buf))
let grayscale = function
| Image.RGB (Pix8 ra, Pix8 ga, Pix8 ba) ->
let module A = Bigarray.Array2 in
let rows = A.dim1 ra in
let cols = A.dim2 ra in
let dst = A.create Bigarray.int8_unsigned Bigarray.c_layout rows cols in
for y = 0 to rows - 1 do
for x = 0 to cols - 1 do
let r, g, b = A.get ra y x, A.get ga y x, A.get ba y x in
let r, g, b = Float.of_int r, Float.of_int g, Float.of_int b in
A.set dst y x
(truncate ((0.2126 *. r) +. (0.7152 *. g) +. (0.0722 *. b)))
done
done;
Image.Grey (Pix8 dst)
| _ -> failwith "unsupported png"
let () =
let img = load_png Sys.argv.(1) in
let img = {img with pixels = grayscale img.pixels} in
write_png img Sys.argv.(2)
When there are no docs, there is still :MerlinLocateImpl , which reveals that you were getting a PNG format error because the string “image.png” is not a PNG.