Skip to content

Image Converter — Swift 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 Swift implementation — the same logic the interactive tool runs, in a shareable, citable form.

// Image converter — Swift port of the image-converter tool.

import CoreGraphics
import Foundation
import ImageIO
import UniformTypeIdentifiers

enum ConversionError: Error {
    case decodeFailed
    case encodeFailed
}

/// Decode -> (JPEG only) flatten onto white -> encode at quality 0...1.
func convertImage(_ data: Data, to target: UTType, quality: CGFloat = 0.85) throws -> Data {
    guard
        let src = CGImageSourceCreateWithData(data as CFData, nil),
        let image = CGImageSourceCreateImageAtIndex(src, 0, nil)
    else { throw ConversionError.decodeFailed }

    // JPEG has no alpha channel: composite onto a white canvas first,
    // or transparent pixels render black in the encoded file.
    let out: CGImage
    if target == .jpeg, image.alphaInfo != .none {
        guard let ctx = CGContext(
            data: nil,
            width: image.width,
            height: image.height,
            bitsPerComponent: 8,
            bytesPerRow: 0,
            space: CGColorSpaceCreateDeviceRGB(),
            bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue
        ) else { throw ConversionError.encodeFailed }
        ctx.setFillColor(CGColor(gray: 1, alpha: 1))
        ctx.fill(CGRect(x: 0, y: 0, width: image.width, height: image.height))
        ctx.draw(image, in: CGRect(x: 0, y: 0, width: image.width, height: image.height))
        guard let composited = ctx.makeImage() else { throw ConversionError.encodeFailed }
        out = composited
    } else {
        out = image
    }

    let outData = NSMutableData()
    guard
        let dest = CGImageDestinationCreateWithData(
            outData, target.identifier as CFString, 1, nil)
    else { throw ConversionError.encodeFailed }
    // kCGImageDestinationLossyCompressionQuality takes 0...1 — the same
    // scale as the web tool's quality parameter.
    CGImageDestinationAddImage(
        dest, out,
        [kCGImageDestinationLossyCompressionQuality: quality] as CFDictionary)
    guard CGImageDestinationFinalize(dest) else { throw ConversionError.encodeFailed }
    return outData as Data
}

let input = try Data(contentsOf: URL(fileURLWithPath: "input.png"))
let jpeg = try convertImage(input, to: .jpeg, quality: 0.85)
try jpeg.write(to: URL(fileURLWithPath: "output.jpg"))

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 →