Skip to content

Image Converter — Zig source

Convert images between PNG, JPEG and WebP entirely in your browser. Batch-friendly with quality control and a before/after size delta — nothing is uploaded.

This is the Zig implementation — the same logic the interactive tool runs, in a shareable, citable form.

//! Image converter — Zig port of the image-converter tool.
//!
//! Codec work (PNG/JPEG/WebP encode) is environment-specific; this port
//! keeps the tool's pure pipeline logic: the format table, quality
//! clamping, and the alpha flatten JPEG requires before encoding.

const std = @import("std");

pub const Format = enum { png, jpeg, webp };

pub const Image = struct {
    width: usize,
    height: usize,
    /// RGBA8, tightly packed: len == width * height * 4.
    pixels: []u8,

    /// JPEG has no alpha channel: composite every pixel over opaque
    /// white, or transparency renders black in the encoded file.
    pub fn flattenOntoWhite(self: *Image) void {
        var i: usize = 0;
        while (i < self.pixels.len) : (i += 4) {
            const a: u32 = self.pixels[i + 3];
            for (0..3) |c| {
                const v: u32 = self.pixels[i + c];
                self.pixels[i + c] = @intCast((v * a + 255 * (255 - a) + 127) / 255);
            }
            self.pixels[i + 3] = 255;
        }
    }
};

/// Mirrors the web tool's `image/${target}` MIME lookup.
pub fn mimeType(format: Format) []const u8 {
    return switch (format) {
        .png => "image/png",
        .jpeg => "image/jpeg",
        .webp => "image/webp",
    };
}

/// canvas.toBlob takes 0..1; clamp like the web tool's quality slider.
pub fn clampQuality(q: f32) f32 {
    return std.math.clamp(q, 0.0, 1.0);
}

pub fn main() !void {
    var pixels = [_]u8{ 255, 0, 0, 128, 0, 128, 255, 0 };
    var img = Image{ .width = 2, .height = 1, .pixels = &pixels };

    const out = std.io.getStdOut().writer();
    try out.print("mime: {s}\n", .{mimeType(.jpeg)});
    try out.print("quality: {d:.2}\n", .{clampQuality(0.85)});

    img.flattenOntoWhite();
    try out.print("flattened rgba: {any}\n", .{img.pixels});
}

Also available in 8 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →