sirv/sirv-image-swift
A Swift package for building [Sirv](https://sirv.com) image transformation URLs using a fluent builder pattern.
Requirements
- Swift 5.7+
- Any platform supported by Swift (macOS, iOS, tvOS, watchOS, Linux)
Installation
Swift Package Manager
Add to your Package.swift:
dependencies: [
.package(url: "https://github.com/sirv/sirv-image-transformation.git", from: "1.0.0")
]Then add "SirvImage" to your target's dependencies.
Quick Start
import SirvImage
let url = SirvImage(url: "https://demo.sirv.com/photo.jpg")
.resize(width: 400, height: 300)
.format(.webp)
.quality(80)
.toUrl()
// https://demo.sirv.com/photo.jpg?w=400&h=300&format=webp&q=80Initialization
// From a full URL
let img = SirvImage(url: "https://demo.sirv.com/photo.jpg")
// From base URL + path
let img = SirvImage(baseUrl: "https://demo.sirv.com", path: "/photo.jpg")Existing query parameters are preserved:
let img = SirvImage(url: "https://demo.sirv.com/photo.jpg?profile=my-preset")
.width(400)
.toUrl()
// https://demo.sirv.com/photo.jpg?profile=my-preset&w=400URL Output
// Explicit
let url: String = img.toUrl()
// Via CustomStringConvertible
print("URL: \(img)")API Reference
Resize
.resize(width: 400, height: 300)
.resize(width: 400, height: 300, option: .fill)
.width(400)
.height(300)
.scaleByLongest(800)
.thumbnail(150)ResizeOption values: .fill, .fitWidth, .fitHeight, .force, .ignore
Crop
.crop(width: 200, height: 200, x: 50, y: 50)
.crop(width: 300, height: 300, type: .face)
.crop(width: 200, height: 200, type: .trim, padWidth: 10, padHeight: 10)
.clipPath("circle(50%)")CropType values: .fill, .face, .trim
Rotation
.rotate(90)
.flip() // vertical
.flop() // horizontalFormat
.format(.webp)
.quality(80)
.webpFallback("jpg")
.subsampling(.s420)
.pngOptimize()
.gifLossy(80)ImageFormat values: .jpg, .png, .webp, .gif, .bmp, .tiff, .original
Subsampling values: .s420, .s422, .s444
Color Adjustments
.brightness(10) // -100 to 100
.contrast(15) // -100 to 100
.exposure(5) // -100 to 100
.hue(30) // -360 to 360
.saturation(-20) // -100 to 100
.lightness(10) // -100 to 100
.shadows(20) // -100 to 100
.highlights(-10) // -100 to 100
.grayscale()
.colorLevel(black: 10, white: 245)
.histogram(.rgb)Color Effects
// Preset colortone
.colortone("sepia")
// Custom colortone
.colortone(color: "ff6600", level: 50, mode: .highlights)
// Colorize
.colorize(color: "ff0000", opacity: 50)ColortoneMode values: .solid, .highlights, .shadows
Effects
.blur(5)
.sharpen(3)
.vignette(value: 50, color: "000000")
.opacity(75)Text Overlays
.text("Hello World", options: TextOptions(
fontSize: 32,
fontFamily: "Arial",
fontWeight: .bold,
color: "ffffff",
position: .center
))Multiple text layers are supported -- each .text() call adds a new layer:
.text("Title", options: TextOptions(fontSize: 48, position: .north))
.text("Subtitle", options: TextOptions(fontSize: 24, position: .south))TextOptions fields:
| Field | Type | Description | |-------|------|-------------| | size | Int? | Text box size | | fontSize | Int? | Font size in pixels | | fontFamily | String? | Font family name | | fontStyle | FontStyle? | .normal, .italic | | fontWeight | FontWeight? | .normal, .bold, .w100....w900 | | color | String? | Text color (hex) | | opacity | Int? | Text opacity (0-100) | | outlineWidth | Int? | Outline width | | outlineColor | String? | Outline color (hex) | | outlineOpacity | Int? | Outline opacity (0-100) | | outlineBlur | Int? | Outline blur radius | | backgroundColor | String? | Background color (hex) | | backgroundOpacity | Int? | Background opacity (0-100) | | align | TextAlign? | .left, .center, .right | | position | Position? | Position preset | | positionX | Int? | Horizontal offset | | positionY | Int? | Vertical offset | | positionGravity | PositionGravity? | Gravity for position offset |
Watermarks
.watermark("/logo.png", options: WatermarkOptions(
position: .southEast,
opacity: 50,
scaleWidth: 200
))Multiple watermarks are supported -- each .watermark() call adds a new layer:
.watermark("/logo.png", options: WatermarkOptions(position: .northWest))
.watermark("/badge.png", options: WatermarkOptions(position: .southEast))WatermarkOptions fields:
| Field | Type | Description | |-------|------|-------------| | position | Position? | Position preset | | positionX | Int? | Horizontal offset | | positionY | Int? | Vertical offset | | positionGravity | PositionGravity? | Gravity for position offset | | scaleWidth | Int? | Scale to width | | scaleHeight | Int? | Scale to height | | scaleOption | WatermarkScaleOption? | .fit, .fill, .ignore, .noup | | rotate | Int? | Rotation angle | | opacity | Int? | Opacity (0-100) | | layer | WatermarkLayer? | .overlay, .background | | canvasColor | String? | Canvas color (hex) | | canvasOpacity | Int? | Canvas opacity (0-100) | | canvasWidth | Int? | Canvas width | | canvasHeight | Int? | Canvas height | | cropX | Int? | Crop X offset | | cropY | Int? | Crop Y offset | | cropWidth | Int? | Crop width | | cropHeight | Int? | Crop height |
Canvas
.canvas(CanvasOptions(
width: 500,
height: 400,
color: "f0f0f0",
position: .center
))CanvasOptions fields: width, height, color, opacity, position, positionX, positionY, positionGravity
Frame
.frame(FrameOptions(
style: "solid",
color: "333333",
width: 10
))FrameOptions fields: style, color, width, rimColor, rimWidth
Other
.page(3) // multi-page document page selection
.profile("srgb") // ICC profileMethod Chaining
All transformation methods return Self, enabling fluent chaining:
let url = SirvImage(url: "https://demo.sirv.com/photo.jpg")
.resize(width: 800, option: .fill)
.crop(width: 400, height: 400, type: .face)
.format(.webp)
.quality(85)
.brightness(5)
.sharpen(2)
.watermark("/logo.png", options: WatermarkOptions(
position: .southEast,
opacity: 30
))
.toUrl()Running Tests
cd swift
swift testLicense
MIT
Package Metadata
Repository: sirv/sirv-image-swift
Default branch: main
README: README.md