moonexr

    MoonBit OpenEXR scanline, tiled and flat multipart HDR interchange with PIZ

    openexr
    hdr
    image
    Download zip
    Version
    0.2.0
    License
    Apache-2.0
    Last updated
    8 hours ago
    Downloads
    32

    #MoonEXR

    MoonBit 原生 OpenEXR 读写库,支持 HDR 多通道 scanline、tiled、普通 multipart 和无损 PIZ。Native、JavaScript、Wasm、Wasm-GC 共用格式解析与编解码逻辑,核心无需加载 OpenEXR C++ 或 Python。

    本文对应 0.2.0。源码与安装包见 GitHub 与 Mooncakes。

    #生态价值与场景

    • 多视图与渲染交付。以命名部件封装左右视图、深度、对象 ID 等数据,分别选择通道、窗口、压缩和 scanline / tiled 存储。
    • HDR 纹理与局部取图。按 mipmap 或 ripmap 层选择分辨率,按绝对坐标仅读取相交 tile。对象 ID 可构建保留 UINT32 原始位的最近邻金字塔。
    • 资产提取与转码。把选中部件、分辨率、区域和通道导出为独立 EXR,或统一重压缩整个容器并保留全部层、部件和原始样本位。

    运行 moon run examples/storage --target native 复现混合部件、PIZ、分辨率选择、局部提取和转码。独立互操作、边界及算法说明见 存储能力文档。

    #安装与复现

    使用 官方 MoonBit 工具链;本机验证版本 moonc 0.10.16,符合赛事最低版本要求0.10.16;CI固定使用0.10.16+b1a0e846e。固定依赖见 moon.mod。

    moon version --all moon check --target all --deny-warn moon build --target all --deny-warn moon test --target all --deny-warn moon run examples/render_assets moon run examples/scientific_imaging moon run examples/offline_preview --target js moon run examples/scale --target native --release moon run examples/storage --target native

    在已有 MoonBit 工程中安装 0.2.0 以使用本文的格式能力。

    moon add FikaRomantic/moonexr@0.2.0

    在使用方的 moon.pkg 中配置 import { "FikaRomantic/moonexr" @exr, },即可运行下方最小示例;本仓库的示例目录已配置导入。

    Windows 的 Moon20261016 OCaml 子工具可能不接受驱动传入的 \\?\ 长路径;可用随项目的进程参数适配器(首次构建需要 MSVC Build Tools):

    .\tools\windows\moon.ps1 check --target all --deny-warn .\tools\windows\moon.ps1 test --target all --deny-warn .\tools\windows\moon.ps1 run examples/render_assets

    适配器只生成 _build 内容,保留官方编译器,不修改全局环境;其他平台直接使用标准 moon。

    #最小示例

    fn main raise {
    let w = @exr.Window::new(-1, 2, 1, 3)
    let ids = @exr.Plane::from_values(
    { name: "id", kind: U32, linear: true }, w,
    [0.0, 1.0, 16777217.0, 4294967295.0, 42.0, 7.0],
    )
    let image = @exr.Image::new(w, [ids])
    let file = @exr.ExrFile::open(@exr.encode(image))
    let roi = file.read(region=Some(@exr.Window::new(0, 2, 1, 3)))
    assert_eq(roi.plane("id").bits_at(1, 2), 16777217U)
    }

    窗口是包含两端的绝对图像坐标。区域请求与 dataWindow 相交后裁剪;完全不相交会报错。displayWindow 保留原画布,不随 crop 缩小。通道按 UTF-8 字节顺序规范排列,接口返回的目录/元数据数组是副本。

    #格式兼容边界

    项目已支持明确不支持/不承诺
    存储EXR v2 flat scanline、tiled ONE_LEVEL/MIPMAP/RIPMAP、命名 multipart、tile 随机块顺序deep、未知 flags、缺失块恢复
    通道UINT32、IEEE HALF16、FLOAT32,单位采样,命名层、长UTF-8名字子采样、自动合成Y/RY/BY、任意像素类型
    压缩NONE、RLE、ZIPS、ZIP、PIZ;压缩无收益时回退原始块PXR24、B44/B44A、DWA 等其他 codec
    元数据标准窗口/屏幕/像素比例,未知可选属性原始保留;string/int/float/chromaticities辅助接口任意可选属性的领域解释、ICC变换、设备校准
    读写单文件/多部件编码、按层及区域读、scanline 原子批次写、提取与转码文件IO流式读取、零复制、物理字节完全一致重写
    处理crop/select/rename/translate、层选择/合并、显式类型转换、有限值统计/直方图、RGBA预览合成器、滤镜引擎、渲染器、完整色彩管理

    原始 Plane::from_bits/sample_bits/bits_at 路径不经过数值算术,保持 UINT32、NaN payload、正负零、Infinity。from_values 和 map_values 是数值路径,浮点转类型可能舍入/溢出;HALF数值输入先转换为Float32再按最近偶数舍入。UINT数值输入/转换必须是0..2^32-1内整数,拒绝分数/非有限值,不自动饱和。

    convert 同类型保持全部位;HALF↔FLOAT通过位操作转换,窄化只保留高payload位。UINT→FLOAT可能失去整数精度,必须由调用方显式请求。linear 对应EXR pLinear编码提示,不代表通道已做色彩变换。

    未知可选属性按名称/类型/原始payload保留;编码会重建结构、排序元数据并选择压缩,所以保留支持范围内的样本位和属性语义,不承诺原始header排列、压缩字节或物理chunk顺序。重写输出统一增序。文件入口/目录在open校验,压缩内容在读取选中块时校验;不会替调用方检查未选中的坏块。

    #扫描与增量写入

    ExrFile::scan(region=...,channels=...,batch_rows=...) 按绝对y增序返回 Image,最多 batch_rows 行。每个选中块只解压一次,tiled 模式缓存当前 tile 行;错误后scanner永久失败,重试不会跳过坏数据。read_with_stats 返回本次块数和逻辑解码字节;plan 返回精确编码块范围。

    EXR压缩块将通道混合压缩,因此选择少量通道可以减少保留输出,不会免去解压所选块中的其他通道。区域可以跳过无交集块;完整输入Bytes仍在内存,plan本身不是远程range下载器。扫描返回批量不等于峰值工作内存只占这一批。

    Writer::new(window,channels,metadata=...) 固定全局头;push 接受下一个全宽、连续、相同通道集合的行批次。批次不得含可选元数据,防止隐式丢弃。writer只取批次样本,display/screen等全局几何由构造器定义为默认屏幕设置和指定display。不支持借push改变header。失败push保留此前状态;未收到全部行时finish可重试,成功后关闭并释放保留输出。它保留压缩结果及最多一个未满块,不写磁盘。

    #预览与统计

    preview_rgba 明确选择RGB/alpha名字、曝光、Clamp/Reinhard和gamma。输入应已处于调用方要求的线性色彩空间;此诊断预览不解析chromaticities做变换,不声称精确显示校准。premultiplied_alpha=true会在alpha>0时除以alpha,零alpha颜色输出0;未设置则直接映射颜色。NaN/非正值映射0,正Infinity映射1,alpha夹到0..1。原始平面始终保留。

    统计分别报告NaN、正负Infinity、负零,有限值使用Welford算法求总体方差。没有有限样本时mean/min/max/variance为None;浮点溢出时不伪造有限结果。直方图含两端点,范围外和非有限值单独计数。

    #CLI 与独立互操作

    moon run cmd/main --target native -- inspect INPUT.exr moon run cmd/main --target native -- bits INPUT.exr moon run cmd/main --target native -- demo NEW.exr moon run cmd/main --target native -- rewrite INPUT.exr NEW.exr zip moon run cmd/main --target native -- transcode INPUT.exr NEW.exr piz moon run cmd/main --target native -- extract-part INPUT.exr depth NEW.exr piz moon run cmd/main --target native -- level-bits INPUT.exr 0 2 2 Z python -m venv _local/venv # 激活环境后安装;Windows也可直接使用_local/venv/Scripts/python.exe python -m pip install -r scripts/requirements-interop.txt moon build --target native --deny-warn python scripts/interop.py verify _build/native/debug/build/cmd/main/main.exe

    CLI写入使用CreateNew,拒绝覆盖已有文件;bits输出原始unsigned位数组,限100万样本,只作小文件检查。rewrite 处理单部件文件并保留已有的 tiled 层。transcode 可重编码全部部件。Python环境仅供开发验证,官方OpenEXR3.4.2和numpy2.3.4不是核心运行依赖。

    独立 OpenEXR 3.4.2 对照覆盖五种 codec 的双向位级互操作、实际压缩的 PIZ、混合部件及各类存储边界。五份官方现有样本完成重编码与位级对照,包含 PIZ tiled、10 个命名部件、10 个 mipmap 层和 121 个 ripmap 层。样本来源、校验和与复现命令见 存储能力文档。

    #工程验证与资源边界

    已配置GitHub Actions的四后端check/build/test、fmt/API一致性、三个场景、规模负载、官方互操作和本地打包卫生检查。可在 Actions 查看远端执行记录;工程检查不等于正式赛事验收。

    默认上限:文件256MiB、header1MiB、像素16,777,216、通道64、属性1024、chunk65,536、逻辑解码256MiB。文件/长度乘加和窗口维度受检;重复属性/通道、重叠chunk、错误解压长度、Adler32、缺失字段和不支持模式明确拒绝。Limits不是进程精确峰值内存;输入、压缩块、临时数组、防御性复制和输出会同时存在,不适合无额外隔离地接收任意规模不可信内容。

    若 C 为 chunk 数,打开目录约 O(C log C),按已选定层的几何规划区域为 O(K),K 为命中块数。PIZ 的小波与重排按样本线性处理,Huffman 另计频次排序和编码位数。复杂度和额外内存详见 存储能力文档。

    examples/scale 验证98,304像素24块、区域4096像素只解码1块。它是可复现正确性负载,没有与OpenEXR的速度比较结论。

    #许可证与维护

    Apache-2.0,见 LICENSE、NOTICE、THIRD_PARTY.md。依据 OpenEXR官方格式 独立实现;测试对照使用 官方Python API。AI辅助设计与开发;独立测试不替代对生产文件变体的兼容评估。

    术语见CONTEXT.md,重要边界见docs/adr,公共接口见pkg.generated.mbti。申报书可保存在项目本地目录;申报书、审查/AI/汇总报告通过gitignore及历史/打包检查排除,不属于开源交付包。

    #十一月新增功能

    位级样本差异与数值误差(Plane::compare_samples);对象掩膜下的有限值统计(Plane::masked_statistics)。详见功能、用途和边界,运行 moon run examples/november --target native --deny-warn。本功能包含于0.1.0,安装方式见上文。

    #0.2.0 的图像处理接口

    新增 原始位级区域粘贴、有限样本经验分位数,用途、限制和复杂度见 功能文档。 从本仓库源码运行 moon run examples/expansion --target native --deny-warn。 本节 API 自 0.2.0 提供。

    ExrError

    pub suberror ExrError {
    Invalid(String, Int)
    Unsupported(String)
    Limit(String)
    } derive(
    Debug
    )

    ExrError::to_repr

    Attribute

    pub(all) struct Attribute {
    name : String
    kind : String
    value : Bytes
    } derive(Eq,
    Debug
    )

    Attribute::as_chromaticities

    fn Attribute::as_chromaticities(self : Attribute) -> Array[Double] raise ExrError

    Attribute::as_integer

    fn Attribute::as_integer(self : Attribute) -> Int raise ExrError

    Attribute::as_real

    fn Attribute::as_real(self : Attribute) -> Double raise ExrError

    Attribute::as_text

    fn Attribute::as_text(self : Attribute) -> String raise ExrError

    Attribute::chromaticities

    fn Attribute::chromaticities(values : Array[Double]) -> Attribute raise ExrError

    Eight xy coordinates: red, green, blue and white, in that order.

    Attribute::equal

    fn Attribute::equal(Attribute, Attribute) -> Bool

    Attribute::integer

    fn Attribute::integer(name : String, value : Int) -> Attribute raise ExrError

    Attribute::not_equal

    fn Attribute::not_equal(x : Attribute, y : Attribute) -> Bool

    Attribute::real

    fn Attribute::real(name : String, value : Double) -> Attribute raise ExrError

    Attribute::text

    fn Attribute::text(name : String, text : String) -> Attribute raise ExrError

    Channel

    pub(all) struct Channel {
    name : String
    kind : PixelType
    linear : Bool
    } derive(Eq,
    Debug
    )

    Channel::equal

    fn Channel::equal(Channel, Channel) -> Bool

    Channel::layer

    fn Channel::layer(self : Channel) -> String

    A layer is the name prefix before the last dot, excluding the final component.

    Channel::not_equal

    fn Channel::not_equal(x : Channel, y : Channel) -> Bool

    Channel::to_repr

    ChunkInfo

    pub(all) struct ChunkInfo {
    y : Int
    rows : Int
    offset : Int
    encoded_bytes : Int
    decoded_bytes : Int
    } derive(Eq,
    Debug
    )

    ChunkInfo::equal

    fn ChunkInfo::equal(ChunkInfo, ChunkInfo) -> Bool

    ChunkInfo::not_equal

    fn ChunkInfo::not_equal(x : ChunkInfo, y : ChunkInfo) -> Bool

    Compression

    pub(all) enum Compression {
    None
    Rle
    Zips
    Zip
    Piz
    } derive(Eq,
    Debug
    )

    Compression::equal

    fn Compression::equal(Compression, Compression) -> Bool

    Compression::not_equal

    fn Compression::not_equal(x : Compression, y : Compression) -> Bool

    Compression::scanlines

    fn Compression::scanlines(self : Compression) -> Int

    ExrDocument

    pub struct ExrDocument {
    // private fields
    }

    ExrDocument::is_multipart

    fn ExrDocument::is_multipart(self : ExrDocument) -> Bool

    ExrDocument::named_part

    fn ExrDocument::named_part(self : ExrDocument, name : String) -> ExrFile raise ExrError

    ExrDocument::open

    fn ExrDocument::open(bytes : Bytes, limits? : Limits) -> ExrDocument raise ExrError

    Parse all headers and offset tables once; compressed pixels remain in the input.

    ExrDocument::part

    fn ExrDocument::part(self : ExrDocument, index : Int) -> ExrFile raise ExrError

    ExrDocument::part_count

    fn ExrDocument::part_count(self : ExrDocument) -> Int

    ExrDocument::transcode

    fn ExrDocument::transcode(self : ExrDocument, compression : Compression) -> Bytes raise ExrError

    Recompress all parts and resolutions, preserving storage layout, names and sample bits.

    ExrFile

    pub struct ExrFile {
    // private fields
    }

    ExrFile::chunks

    fn ExrFile::chunks(self : ExrFile) -> Array[ChunkInfo]

    ExrFile::extract

    fn ExrFile::extract(self : ExrFile, level_x? : Int, level_y? : Int, region? : Window?, channels? : Array[String]?, tiles? : TileDescription?, compression? : Compression) -> Bytes raise ExrError

    Extract a part or resolution to an ordinary single-part file, with optional region and channel selection. Tiled output contains one level.

    ExrFile::header

    fn ExrFile::header(self : ExrFile) -> Header

    ExrFile::levels

    fn ExrFile::levels(self : ExrFile) -> Array[LevelInfo]

    ExrFile::open

    fn ExrFile::open(bytes : Bytes, limits? : Limits) -> ExrFile raise ExrError

    Open a single-part scanline or tiled file.

    ExrFile::plan

    fn ExrFile::plan(self : ExrFile, region : Window) -> Array[ChunkInfo]

    Exact encoded chunks needed for a region of the base level.

    ExrFile::plan_level

    fn ExrFile::plan_level(self : ExrFile, x : Int, y : Int, region : Window) -> Array[ChunkInfo] raise ExrError

    ExrFile::read

    fn ExrFile::read(self : ExrFile, region? : Window?, channels? : Array[String]?) -> Image raise ExrError

    ExrFile::read_level

    fn ExrFile::read_level(self : ExrFile, x : Int, y : Int, region? : Window?, channels? : Array[String]?) -> Image raise ExrError

    Decode only the blocks intersecting the region of the requested resolution.

    ExrFile::read_with_stats

    fn ExrFile::read_with_stats(self : ExrFile, region? : Window?, channels? : Array[String]?) -> ReadResult raise ExrError

    ExrFile::scan

    fn ExrFile::scan(self : ExrFile, region? : Window?, channels? : Array[String]?, batch_rows? : Int) -> Scan raise ExrError

    Iterate selected rows in increasing absolute y, independent of physical order. One selected block row stays decoded until consumed. This does not stream file IO.
    pub struct Header {
    // private fields
    }

    Header::attribute

    fn Header::attribute(self : Header, name : String) -> Attribute?

    Header::channels

    fn Header::channels(self : Header) -> Array[Channel]

    Header::compression

    fn Header::compression(self : Header) -> Compression

    Header::data_window

    fn Header::data_window(self : Header) -> Window

    Header::display_window

    fn Header::display_window(self : Header) -> Window

    Header::line_order

    fn Header::line_order(self : Header) -> Int

    Header::metadata

    fn Header::metadata(self : Header) -> Array[Attribute]

    Header::name

    fn Header::name(self : Header) -> String?

    Header::tiles

    fn Header::tiles(self : Header) -> TileDescription?

    Histogram

    pub(all) struct Histogram {
    lower : Double
    upper : Double
    bins : Array[Int]
    below : Int
    above : Int
    nonfinite : Int
    }

    Image

    pub struct Image {
    // private fields
    }

    Image::channels

    fn Image::channels(self : Image) -> Array[Channel]

    Image::crop

    fn Image::crop(self : Image, region : Window, limits? : Limits) -> Image raise ExrError

    Crop by absolute coordinates; reject disjoint requests, clip partial overlap.

    Image::display_window

    fn Image::display_window(self : Image) -> Window

    Image::layers

    fn Image::layers(self : Image) -> Array[String]

    Image::metadata

    fn Image::metadata(self : Image) -> Array[Attribute]

    Image::nearest_levels

    fn Image::nearest_levels(self : Image, tiles : TileDescription, limits? : Limits) -> Array[Image] raise ExrError

    Build a tiled pyramid using nearest samples on the base image's pixel grid. Every stored sample keeps its exact bits, including UINT IDs and float payloads. For filtered color pyramids, supply your own levels to encode_tiled.

    Image::new

    fn Image::new(window : Window, planes : Array[Plane], display? : Window, metadata? : Array[Attribute], pixel_aspect? : Double, screen_center? : (Double, Double), screen_width? : Double, limits? : Limits) -> Image raise ExrError

    Image::paste_region

    fn Image::paste_region(self : Image, patch : Image, limits? : Limits) -> Image raise ExrError

    Paste absolute-coordinate channel samples without converting their bits. The patch must fit completely; only matching channels are replaced.

    Image::pixel_aspect

    fn Image::pixel_aspect(self : Image) -> Double

    Image::plane

    fn Image::plane(self : Image, name : String) -> Plane raise ExrError

    Image::preview_rgba

    fn Image::preview_rgba(self : Image, rgb? : Array[String], alpha? : String?, options? : PreviewOptions, limits? : Limits) -> Bytes raise ExrError

    RGBA8 diagnostic preview. Assumes input channels already share the desired linear colour space; no ICC/chromaticity conversion or display calibration.

    Image::rename

    fn Image::rename(self : Image, mapping : Map[String, String], limits? : Limits) -> Image raise ExrError

    Image::replace_plane

    fn Image::replace_plane(self : Image, replacement : Plane, limits? : Limits) -> Image raise ExrError

    Image::screen

    fn Image::screen(self : Image) -> (Double, Double, Double)

    Image::select

    fn Image::select(self : Image, names : Array[String], limits? : Limits) -> Image raise ExrError

    Image::select_layer

    fn Image::select_layer(self : Image, layer : String, limits? : Limits) -> Image raise ExrError

    Image::translate

    fn Image::translate(self : Image, dx : Int, dy : Int, limits? : Limits) -> Image raise ExrError

    Translate both windows without resampling or changing any sample bits.

    Image::window

    fn Image::window(self : Image) -> Window

    Image::with_metadata

    fn Image::with_metadata(self : Image, attrs : Array[Attribute], limits? : Limits) -> Image raise ExrError

    LevelInfo

    pub(all) struct LevelInfo {
    x : Int
    y : Int
    window : Window
    columns : Int
    rows : Int
    } derive(Eq,
    Debug
    )

    LevelInfo::equal

    fn LevelInfo::equal(LevelInfo, LevelInfo) -> Bool

    LevelInfo::not_equal

    fn LevelInfo::not_equal(x : LevelInfo, y : LevelInfo) -> Bool

    LevelMode

    pub(all) enum LevelMode {
    OneLevel
    Mipmap
    Ripmap
    } derive(Eq,
    Debug
    )

    LevelMode::equal

    fn LevelMode::equal(LevelMode, LevelMode) -> Bool

    LevelMode::not_equal

    fn LevelMode::not_equal(x : LevelMode, y : LevelMode) -> Bool

    Limits

    pub(all) struct Limits {
    max_file_bytes : Int
    max_header_bytes : Int
    max_pixels : Int
    max_channels : Int
    max_attributes : Int
    max_chunks : Int
    max_decoded_bytes : Int
    } derive(Eq,
    Debug
    )

    Limits::default

    fn Limits::default() -> Limits

    Limits::equal

    fn Limits::equal(Limits, Limits) -> Bool

    Limits::not_equal

    fn Limits::not_equal(x : Limits, y : Limits) -> Bool

    Limits::to_repr

    MaskedStatistics

    pub(all) struct MaskedStatistics {
    selected : Int
    finite_samples : Int
    nonfinite_samples : Int
    minimum : Double?
    maximum : Double?
    mean : Double?
    } derive(
    Debug
    )

    PartSource

    pub(all) struct PartSource {
    name : String
    compression : Compression
    tiles : TileDescription?
    images : Array[Image]
    }

    Supply images in TileDescription::levels order. Scanline sources have one image.

    PixelType

    pub(all) enum PixelType {
    U32
    F16
    F32
    } derive(Eq,
    Debug
    )

    PixelType::bytes

    fn PixelType::bytes(self : PixelType) -> Int

    PixelType::equal

    fn PixelType::equal(PixelType, PixelType) -> Bool

    PixelType::not_equal

    fn PixelType::not_equal(x : PixelType, y : PixelType) -> Bool

    Plane

    pub struct Plane {
    // private fields
    }

    Plane::bits_at

    fn Plane::bits_at(self : Plane, x : Int, y : Int) -> UInt raise ExrError

    Plane::channel

    fn Plane::channel(self : Plane) -> Channel

    Plane::compare_samples

    fn Plane::compare_samples(self : Plane, other : Plane) -> SampleDifference raise ExrError

    Compare identical channel types/windows, keeping NaN payload and signed-zero differences.

    Plane::convert

    fn Plane::convert(self : Plane, kind : PixelType, limits? : Limits) -> Plane raise ExrError

    Explicit numerical conversion. Identity conversion retains every source bit. Float->UINT rejects fractions and nonfinite values; no implicit saturation.

    Plane::from_bits

    fn Plane::from_bits(channel : Channel, window : Window, bits : Bytes, limits? : Limits) -> Plane raise ExrError

    Plane::from_values

    fn Plane::from_values(channel : Channel, window : Window, values : Array[Double], limits? : Limits) -> Plane raise ExrError

    Plane::histogram

    fn Plane::histogram(self : Plane, lower : Double, upper : Double, bins : Int) -> Histogram raise ExrError

    Plane::map_values

    fn Plane::map_values(self : Plane, function : (Double) -> Double, output_type? : PixelType, limits? : Limits) -> Plane raise ExrError

    Map sample values to a new plane; never mutates the input. F16/F32 conversion follows round-to-nearest. UINT validation is strict.

    Plane::masked_statistics

    fn Plane::masked_statistics(self : Plane, mask : Plane) -> MaskedStatistics raise ExrError

    Nonzero UINT32 mask selects samples. No thresholding or modification of stored planes.

    Plane::quantiles

    fn Plane::quantiles(self : Plane, probabilities : Array[Double], limits? : Limits) -> Quantiles raise ExrError

    Finite-only nearest-rank empirical quantiles, in caller probability order. p=0 selects the minimum. Empty finite populations produce None.

    Plane::sample_bits

    fn Plane::sample_bits(self : Plane) -> Bytes

    Plane::statistics

    fn Plane::statistics(self : Plane) -> PlaneStatistics raise ExrError

    Welford's online finite-only moments. Extreme values can overflow variance; in that case variance is None, rather than an apparently valid infinity.

    Plane::value_at

    fn Plane::value_at(self : Plane, x : Int, y : Int) -> Double raise ExrError

    Plane::window

    fn Plane::window(self : Plane) -> Window

    PlaneStatistics

    pub(all) struct PlaneStatistics {
    samples : Int
    finite_samples : Int
    nan_samples : Int
    positive_infinities : Int
    negative_infinities : Int
    negative_zeros : Int
    minimum : Double?
    maximum : Double?
    mean : Double?
    population_variance : Double?
    } derive(
    Debug
    )

    PreviewOptions

    pub(all) struct PreviewOptions {
    exposure_stops : Double
    gamma : Double
    tone_map : ToneMap
    premultiplied_alpha : Bool
    } derive(
    Debug
    )

    PreviewOptions::default

    Quantiles

    pub(all) struct Quantiles {
    finite_samples : Int
    nonfinite_samples : Int
    values : Array[Double?]
    }

    ReadResult

    pub struct ReadResult {
    image : Image
    chunks_decoded : Int
    bytes_decoded : Int
    }

    SampleDifference

    pub(all) struct SampleDifference {
    samples : Int
    changed_bits : Int
    finite_pairs : Int
    maximum_absolute_error : Double?
    } derive(
    Debug
    )

    Scan

    pub struct Scan {
    // private fields
    }

    Scan::chunks_decoded

    fn Scan::chunks_decoded(self : Scan) -> Int

    Scan::next

    fn Scan::next(self : Scan) -> Image? raise ExrError

    TileDescription

    pub(all) struct TileDescription {
    width : Int
    height : Int
    mode : LevelMode
    round_up : Bool
    } derive(Eq,
    Debug
    )

    TileDescription::equal

    TileDescription::levels

    fn TileDescription::levels(self : TileDescription, base : Window) -> Array[LevelInfo] raise ExrError

    Levels in offset-table order. The base data window's origin applies to all levels.

    TileDescription::not_equal

    fn TileDescription::not_equal(x : TileDescription, y : TileDescription) -> Bool

    ToneMap

    pub(all) enum ToneMap {
    Clamp
    Reinhard
    } derive(Eq,
    Debug
    )

    ToneMap::equal

    fn ToneMap::equal(ToneMap, ToneMap) -> Bool

    ToneMap::not_equal

    fn ToneMap::not_equal(x : ToneMap, y : ToneMap) -> Bool

    ToneMap::to_repr

    Window

    pub struct Window {
    // private fields
    } derive(Eq,
    Debug
    )

    Window::bounds

    fn Window::bounds(self : Window) -> (Int, Int, Int, Int)

    Window::contains

    fn Window::contains(self : Window, x : Int, y : Int) -> Bool

    Window::equal

    fn Window::equal(Window, Window) -> Bool

    Window::height

    fn Window::height(self : Window) -> Int

    Window::intersection

    fn Window::intersection(self : Window, other : Window) -> Window?

    Window::new

    fn Window::new(x0 : Int, y0 : Int, x1 : Int, y1 : Int) -> Window raise ExrError

    Window::not_equal

    fn Window::not_equal(x : Window, y : Window) -> Bool

    Window::pixels

    fn Window::pixels(self : Window) -> Int raise ExrError

    Window::to_repr

    Window::width

    fn Window::width(self : Window) -> Int

    Writer

    pub struct Writer {
    // private fields
    }

    Writer::finish

    fn Writer::finish(self : Writer) -> Bytes raise ExrError

    Writer::new

    fn Writer::new(window : Window, channels : Array[Channel], display? : Window, metadata? : Array[Attribute], compression? : Compression, limits? : Limits) -> Writer raise ExrError

    Receive contiguous row batches, retain encoded output and at most one pending chunk of raw samples. Does not write to a filesystem and does not retain inputs. Global metadata/geometry are fixed here; batches carry samples, not new headers.

    Writer::push

    fn Writer::push(self : Writer, batch : Image) -> Unit raise ExrError

    Atomic push: validation/encoding failures leave existing content unchanged. A batch must have no optional metadata to avoid silently dropping attributes.

    Writer::rows_received

    fn Writer::rows_received(self : Writer) -> Int

    encode

    fn encode(image : Image, compression? : Compression, limits? : Limits) -> Bytes raise ExrError

    Deterministic scanline output; compression is lossless on sample bits.

    encode_multipart

    fn encode_multipart(parts : Array[PartSource], limits? : Limits) -> Bytes raise ExrError

    Encode named flat scanline and tiled parts, each with its own compression.

    encode_tiled

    fn encode_tiled(images : Array[Image], tiles : TileDescription, compression? : Compression, limits? : Limits) -> Bytes raise ExrError

    Encode single-part tiled data, including caller-supplied mipmap or ripmap levels.

    float_bits_to_half

    fn float_bits_to_half(bits : UInt) -> Int

    Round IEEE binary32 to binary16, round-to-nearest with ties to even. Sign and the high payload bits survive NaNs; a truncated payload stays nonzero.

    half_to_float_bits

    fn half_to_float_bits(bits : Int) -> UInt

    IEEE binary16 expansion without arithmetic on NaN payloads.

    half_value

    fn half_value(bits : Int) -> Double

    merge

    fn merge(images : Array[Image], limits? : Limits) -> Image raise ExrError

    Merge distinct channels only when all geometry, screen settings and metadata agree.