NB: On some platforms (OSes / Lisp implementations) it's necessary to
mask floating point traps, otherwise the lisp would crash (I mean it). It can
be done in a portable way with float-features:with-float-traps-masked.
Image decoding
This function decodes an image (in color) from a file and returns an array with 3 color components per pixel:
(serapeum:-> decode ((or pathname string))
(values (simple-array (unsigned-byte 8)(* * 3)) &optional))
(defun decode (name)
(with-libheif (+default-init-parameters+)
(with-context (ctx)
(context-read-from-file! ctx name)
(with-primary-image-handle (handle ctx)
(with-decode-image (image handle :rgb :interleaved-rgb +default-decoding-options+)
(image-plane-data image :interleaved))))))
The same for a grayscale image:
(serapeum:-> decode ((or pathname string))
(values (simple-array (unsigned-byte 8)(* * 1)) &optional))
(defun decode (name)
(with-libheif (+default-init-parameters+)
(with-context (ctx)
(context-read-from-file! ctx name)
(with-primary-image-handle (handle ctx)
(with-decode-image (image handle :monochrome :monochrome +default-decoding-options+)
(image-plane-data image :y))))))
The wrapper can also read from a stream:
(serapeum:-> decode (stream)
(values (simple-array (unsigned-byte 8)(* * 3)) &optional))
(defun decode (stream)
(with-libheif (+default-init-parameters+)
(with-context (ctx)
(with-stream-reader (reader stream)
(context-read-from-stream! ctx reader)
(with-primary-image-handle (handle ctx)
(with-decode-image (image handle :rgb :interleaved-rgb +default-decoding-options+)
(image-plane-data image :interleaved)))))))
(with-open-file (input "my-photo.heic" :element-type '(unsigned-byte 8))
(decode input))
You can obtain a preferred colorspace with
image-handle-preferred-decoding-colorspace.
Image encoding
Encode an image and write the result to a file.(serapeum:-> encode ((simple-array (unsigned-byte 8)(* * 3))(or pathname string))
(values &optional))
(defun encode (data name)
(let ((height (array-dimension data 0))
(width (array-dimension data 1)))
(with-libheif (+default-init-parameters+)
(with-context (ctx)
(with-image (image width height :rgb :interleaved-rgb)
(image-add-plane! image :interleaved width height 24)
(image-set-plane-data! image :interleaved data)
(with-encoder-for-format (encoder ctx :hevc)
(encoder-set-lossy-quality! encoder 90)
(context-encode-image! ctx image encoder
+default-encoding-options+)
(context-write-to-file! ctx name)))))))
Metadata
Read all metadata blocks in a list (each element is a simple array of octets):(serapeum:-> read-metadata ((or pathname string))
(values list &optional))
(defun read-metadata (name)
(with-libheif (+default-init-parameters+)
(with-context (ctx)
(context-read-from-file! ctx name)
(with-primary-image-handle (handle ctx)
(mapcar
(lambda (ref)
(image-handle-metadata handle ref))
(image-handle-metadata-refs handle))))))