Skip to content

Instantly share code, notes, and snippets.

@igm
Created June 1, 2026 16:16
Show Gist options
  • Select an option

  • Save igm/161b47cf89a5bed71d381c40333822c0 to your computer and use it in GitHub Desktop.

Select an option

Save igm/161b47cf89a5bed71d381c40333822c0 to your computer and use it in GitHub Desktop.
import Foundation
import CoreGraphics
import ImageIO
import UniformTypeIdentifiers
// Usage: swift pdf2jpeg.swift <input.pdf> <outdir> <dpi> <quality>
let args = CommandLine.arguments
guard args.count >= 3 else {
FileHandle.standardError.write("usage: pdf2jpeg <input.pdf> <outdir> [dpi] [quality]\n".data(using: .utf8)!)
exit(1)
}
let inputPath = args[1]
let outDir = args[2]
let dpi: CGFloat = args.count > 3 ? CGFloat(Double(args[3]) ?? 150) : 150
let quality: CGFloat = args.count > 4 ? CGFloat(Double(args[4]) ?? 0.9) : 0.9
let scale = dpi / 72.0
let url = URL(fileURLWithPath: inputPath)
guard let doc = CGPDFDocument(url as CFURL) else {
FileHandle.standardError.write("error: could not open PDF\n".data(using: .utf8)!)
exit(1)
}
try? FileManager.default.createDirectory(atPath: outDir, withIntermediateDirectories: true)
let pageCount = doc.numberOfPages
let pad = String(pageCount).count
for i in 1...pageCount {
guard let page = doc.page(at: i) else { continue }
let box = page.getBoxRect(.cropBox)
let w = Int((box.width * scale).rounded())
let h = Int((box.height * scale).rounded())
let cs = CGColorSpaceCreateDeviceRGB()
guard let ctx = CGContext(data: nil, width: w, height: h, bitsPerComponent: 8,
bytesPerRow: 0, space: cs,
bitmapInfo: CGImageAlphaInfo.noneSkipLast.rawValue) else { continue }
// white background
ctx.setFillColor(red: 1, green: 1, blue: 1, alpha: 1)
ctx.fill(CGRect(x: 0, y: 0, width: w, height: h))
ctx.scaleBy(x: scale, y: scale)
ctx.translateBy(x: -box.origin.x, y: -box.origin.y)
ctx.drawPDFPage(page)
guard let image = ctx.makeImage() else { continue }
let num = String(format: "%0\(pad)d", i)
let outURL = URL(fileURLWithPath: outDir).appendingPathComponent("page-\(num).jpg")
guard let dest = CGImageDestinationCreateWithURL(outURL as CFURL, UTType.jpeg.identifier as CFString, 1, nil) else { continue }
let opts: [CFString: Any] = [kCGImageDestinationLossyCompressionQuality: quality]
CGImageDestinationAddImage(dest, image, opts as CFDictionary)
if CGImageDestinationFinalize(dest) {
print("wrote \(outURL.path) (\(w)x\(h))")
} else {
FileHandle.standardError.write("failed to write page \(i)\n".data(using: .utf8)!)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment