Makes a smaller copy of a gain-map JPEG that is still an HDR photo.
An iPhone or Pixel JPEG is two JPEGs in one file: the picture (SDR) and a small gain map that says how much brighter each part is on an HDR screen, tied together by a Multi-Picture directory (and, for Android, a line of XMP naming the map's length). A plain resize keeps the picture and loses the map; this keeps both:
- the file is split into the picture and the gain map (
Hdr's directory); - each is resized with ImageMagick (
ImageProcessor.resize/5: pinned input, resource limits, a pixel budget), the map by the same ratio as the picture; - the metadata that describes the pictures (colour profile, EXIF, the XMP and
ISO 21496-1 parameters of the map) is carried over unchanged, because it
is about brightness and colour, not size. With
strip_metadata: truethe EXIF (device, time, position, maker notes) is dropped but for the orientation tag, and only the gain-map properties are kept in either picture's XMP; - what is about size is rewritten: the directory's sizes and offsets, and the map's byte length in the picture's XMP.
Nothing is decoded to HDR pixels, so nothing is tone-mapped or clipped: the map is the camera's own.
Only JPEGs whose map is a second picture are handled ({:error, :no_gain_map}
otherwise; a HEIC gain map is a different container). Anything that does not
parse as expected is an {:error, _}, and the caller keeps its ordinary SDR
rendition: an HDR rendition is a bonus, never a reason for a size to be missing.
Summary
Functions
Writes a width x height crop of the gain-map JPEG at source to dest, still an
HDR photo: the picture is cropped, and the gain map is cropped to the same part of
it (a map covers the whole picture, so cutting the picture alone would put the
brightness of one place over another).
Writes a copy of the gain-map JPEG at source to dest, width pixels wide
(never larger than the source), at JPEG :quality (default 85).
Types
@type result() :: {:ok, %{width: pos_integer(), height: pos_integer(), gain_map_bytes: pos_integer()}}
Functions
@spec crop(Path.t(), Path.t(), {pos_integer(), pos_integer()}, keyword()) :: result() | {:error, term()}
Writes a width x height crop of the gain-map JPEG at source to dest, still an
HDR photo: the picture is cropped, and the gain map is cropped to the same part of
it (a map covers the whole picture, so cutting the picture alone would put the
brightness of one place over another).
The box is cut as ImageProcessor.resize_and_crop_focus/6 cuts it: the largest
window of its shape, centered on :focal ({x, y}, fractions of the photo as it
is displayed; the middle by default) as far as the edges allow, then scaled to the
box, which shrinks to fit when the photo is smaller. A turned photo (EXIF
orientation) is cut where it is shown, and keeps its orientation tag, so its pixels
and its map stay as the camera stored them. Takes :quality and :strip_metadata
like resize/4.
Writes a copy of the gain-map JPEG at source to dest, width pixels wide
(never larger than the source), at JPEG :quality (default 85).
Width and the returned dimensions are measured as displayed, after EXIF orientation. The stored pixels retain the camera's orientation tag.