WebP

0.7.0

A thin Swift wrapper around libwebp, offering both encoding and decoding APIs
ainame/Swift-WebP

What's New

0.7.0

2026-09-28T18:51:20Z

Breaking

Source-compatible, but some calls now behave differently at runtime:

  • Encoder inputs must contain stride * originHeight bytes, including final-row padding, matching libwebp's documented contract. Compact padded buffers that the unchecked pointer API previously accepted now throw invalidParameter. (#66)
  • UIImage encoding no longer downscales @2x/@3x images to their point size; output now has the image's full pixel dimensions. To keep the previous size, pass width/height in points. (#68)

Added

  • WebPEncoder.encode(normalizing:config:resizeWidth:resizeHeight:) for CGImage, which converts premultiplied, BGRA, 16-bit, and other layouts to straight-alpha RGBA before encoding. The existing encode(_:format:config:resizeWidth:resizeHeight:) still encodes the backing bytes as-is. (#68)
  • Safe encoding entrypoints that accept pixels as [UInt8], Data, or a borrowed Span<UInt8>. (#66)
  • Decoding into a caller-provided MutableSpan<UInt8>. (#66)
  • WebPImageInspector.inspect(_:) overload for a borrowed Span<UInt8>. (#66)
  • WebPDecoderConfig.validate(), backed by libwebp's decoder configuration validation. (#65)

Changed

  • Raised the libwebp-Xcode dependency minimum to 1.6.0, picking up upstream lossless compression improvements and bug fixes. Projects that pin libwebp-Xcode below 1.6.0 need to relax that pin. (#65)
  • Invalid decoder settings are now rejected up front with WebPDecodingError.invalidParam, before any output buffer is allocated. (#65)

Fixed

  • NSImage and UIImage encoding no longer assumes straight RGBA, fixing darkened translucent colors and swapped red/blue channels for premultiplied, BGRA, or 16-bit images (e.g. from drawing or screen capture). Straight 8-bit layouts such as decoded PNGs and JPEGs are still encoded from their backing bytes without a copy. Thanks to macshot for documenting the workaround that exposed this issue. (#68)
  • Encoder input capacity, row stride, and dimensions are validated before pixel memory is read, including in the deprecated raw-pointer encoder. (#66)
  • CoreGraphics pixel storage is retained for the whole duration of encoding. (#66)
  • Partially written encoder output is freed on failure. (#66)
  • Decode buffer sizing when one scaled dimension is zero, including scaling after cropping and rounding up inferred dimensions. (#65)
  • Crop validation keeps exact origins for lossless images and snaps to even pixels only for lossy images. (#65)
  • Platform image helpers now use the resolved output dimensions for cropping and inferred scaling. (#65)

Performance

  • Decoding writes into an uninitialized allocation that is handed directly to Data on success, avoiding zero-filling and a duplicate layout inspection. (#66)
  • Bitstream feature inspection uses a stack-local C structure instead of a heap allocation. (#66)
  • Core Data APIs come from FoundationEssentials when available, and unused Foundation imports were removed, reducing Foundation dependencies on Linux. (#67)

Demo

  • Added a visual comparison of the old platform image encoding bugs against the corrected WebP output. (#68)

Swift-WebP

Swift-WebP provides Swift wrappers around libwebp for encoding, decoding, and bitstream inspection.

Encode pixels from arrays, Data, or spans, and decode into Data or reusable buffers. Swift-WebP handles buffer validation and memory cleanup for you, with efficient decoding that avoids unnecessary output copies.

Notice

0.7.0 contains behavior changes to encoder input validation and UIImage output size. See details in CHANGELOG.md

Support Versions

  • Minimum Swift version: 6.2 (swift-tools-version: 6.2 in Package.swift)
  • Swift language mode: 6
  • libwebp: 1.6.0+ (via libwebp-Xcode)
  • iOS deployment target: 13.0+
  • macOS deployment target: 11.0+

Features

  • Swift Package Manager support
  • Advanced encoding via WebPEncoder + WebPEncoderConfig
  • Advanced decoding via WebPDecoder + WebPDecoderOptions
  • WebP bitstream inspection via WebPImageInspector
  • Cross-platform core APIs (Apple platforms + Linux)

Installation

Add Swift-WebP in your Package.swift:

.package(url: "https://github.com/ainame/Swift-WebP.git", from: "0.7.0")

Usage

Encoding

import WebP

let encoder = WebPEncoder()
let data = try encoder.encode(
    rgbaBytes, // [UInt8], Data, or a borrowed Span<UInt8>
    format: .rgba,
    config: .preset(.picture, quality: 95),
    originWidth: width,
    originHeight: height,
    stride: width * 4
)

The encoder validates dimensions, stride, and input capacity. Provide at least stride * originHeight bytes, including padding after the final row. Borrowed spans avoid copying the input storage.

Encoding a CGImage

// Handles any bitmap layout: premultiplied, BGRA, and 16-bit images are converted first.
let data = try encoder.encode(normalizing: cgImage, config: .preset(.picture, quality: 95))

// Encodes the backing bytes as-is; `format` must match the image's layout with straight alpha.
let raw = try encoder.encode(cgImage, format: .rgba, config: .preset(.picture, quality: 95))

Images from drawing or screen capture are premultiplied, so use encode(normalizing:) for them. The NSImage and UIImage encoders use it too.

Decoding to raw pixel bytes

import WebP

let decoder = WebPDecoder()
var options = WebPDecoderOptions()
options.useScaling = true
options.scaledWidth = targetWidth
options.scaledHeight = targetHeight

let rgbaData = try decoder.decode(webPData, options: options, format: .rgba)

Set either scaled dimension to 0 to infer it while preserving the aspect ratio (after cropping, if enabled). Invalid decoder options throw WebPDecodingError.invalidParam.

Decoding into caller-owned memory

import WebP

let decoder = WebPDecoder()
var options = WebPDecoderOptions()
let required = try decoder.requiredOutputByteCount(for: webPData, options: options, format: .rgba)
var output = [UInt8](repeating: 0, count: required)
let written = try decoder.decode(webPData, into: &output, options: options, format: .rgba)
print("decoded bytes:", written)

Decoding to platform images

#if canImport(CoreGraphics)
let cgImage = try decoder.decodeCGImage(from: webPData, options: options)
#endif

#if canImport(UIKit)
let image = try decoder.decodeUIImage(from: webPData, options: options)
#endif

#if canImport(AppKit)
let image = try decoder.decodeNSImage(from: webPData, options: options)
#endif

Inspecting WebP metadata

let feature = try WebPImageInspector.inspect(webPData)
print(feature.width, feature.height, feature.hasAlpha, feature.hasAnimation)

Development

The local development toolchain is Swift 6.4.0, selected by .swift-version. This file does not define the minimum supported Swift version.

Common local commands:

make format
swift build
swift test

make format runs the SwiftFormat SPM plugin.

The library enables strict memory-safety checking. Intentional C operations are marked with unsafe at the interoperability boundary; pointer-based APIs and low-level buffer configuration remain unsafe interfaces. Array, Data, and Span entry points handle those requirements internally.

See the benchmark guide for reproducible version comparisons, pipeline benchmarks, metric definitions, and interpretation limits.

Resource benchmark + validation:

Scripts/benchmark-resource.sh
Scripts/validate-resource.sh
Scripts/compare-with-cwebp.sh

You can tune benchmark parameters with env vars such as: MODE=pipeline|source-decode-only|encode-only|decode-only, WIDTH, HEIGHT, ITERATIONS, WARMUP, QUALITY, THREADS_FLAG=off, INPUT=/absolute/path/to/image, SOURCE_DECODE_PER_ITERATION=on. Validation thresholds can be tuned with: MAX_SOURCE_DECODE_AVG_MS, MAX_ENCODE_AVG_MS, MAX_DECODE_AVG_MS, MAX_PIPELINE_ENCODE_AVG_MS, MAX_ENCODE_P95_MS, MAX_DECODE_P95_MS, MAX_STAGE_PEAK_RSS_MB, MAX_PIPELINE_PEAK_RSS_MB.

License

Swift-WebP is available under the MIT license. See LICENSE.

Description

  • Swift Tools 6.2.0
View More Packages from this Author

Dependencies

Last updated: Sun Oct 25 2026 13:51:30 GMT-0900 (Hawaii-Aleutian Daylight Time)