# Examples The snippets below show the main API shapes inline. For runnable end-to-end scripts, see the examples in [`examples/`](https://github.com/outskirtslabs/vips/tree/main/examples): * [`examples/create_thumbnail.clj`](https://github.com/outskirtslabs/vips/blob/main/examples/create_thumbnail.clj) creates a thumbnail from a local file and writes it back out. * [`examples/chain_transforms.clj`](https://github.com/outskirtslabs/vips/blob/main/examples/chain_transforms.clj) chains several image operations together with the threading style API. * [`examples/compose_images.clj`](https://github.com/outskirtslabs/vips/blob/main/examples/compose_images.clj) joins two images and builds a small grid with `join` and `arrayjoin`. * [`examples/bytes_and_streams.clj`](https://github.com/outskirtslabs/vips/blob/main/examples/bytes_and_streams.clj) reads image bytes into memory, streams them through libvips, and writes the result back out. * [`examples/http_stream_fetch.clj`](https://github.com/outskirtslabs/vips/blob/main/examples/http_stream_fetch.clj) streams an HTTP response body into libvips and saves a transformed result. * [`examples/image_diff.clj`](https://github.com/outskirtslabs/vips/blob/main/examples/image_diff.clj) compares two same-sized images, thresholds the absolute difference, and composites a red highlight overlay onto the changed pixels. * [`examples/palette_extractor.clj`](https://github.com/outskirtslabs/vips/blob/main/examples/palette_extractor.clj) extracts the top dominant colors from an image with `hist_find_ndim`, prints channel stats from `stats`, and renders a swatch strip below the source image. * [`examples/metadata_roundtrip.clj`](https://github.com/outskirtslabs/vips/blob/main/examples/metadata_roundtrip.clj) reads and writes metadata fields before saving an image. * [`examples/animated_gif.clj`](https://github.com/outskirtslabs/vips/blob/main/examples/animated_gif.clj) loads every GIF frame, transforms each page, and writes an animated result. ## File Input And Output Use the file helpers when your source and destination already live on disk and you want libvips to infer formats from the path or suffix. ```clojure (with-open [image (v/from-file "dev/rabbit.jpg" {:shrink 2})] (v/metadata image) (v/shape image) (v/write-to-file image "rabbit.png" {:compression 9}) (v/write-to-buffer image ".png" {:compression 9})) ``` ## Metadata `ol.vips` exposes a curated `v/metadata` summary and a generic header API for libvips metadata fields. ```clojure (with-open [image (v/from-file "dev/rabbit.jpg")] {:meta (v/metadata image) :width (v/field image "width") :fields (take 5 (v/field-names image))}) ;; => {:meta {:width 2490, :height 3084, :bands 3, :has-alpha? false} ;; :width 2490 ;; :fields ("width" "height" "bands" "format" "coding")} ``` Immutable metadata edits use `assoc`/`update`/`dissoc` style names. ```clojure (with-open [image (v/from-file "dev/rabbit.jpg") tagged (-> image (v/assoc-field "xres" 10.0) (v/update-field "yres" (constantly 10.0)))] (v/write-to-file tagged "rabbit-copy.jpg" {:strip false}) (select-keys (v/headers tagged) ["width" "height" "xres" "yres"])) ``` ## Animated Images Load every page or frame with a format-specific loader and `{:n -1}`. libvips represents animated and multipage images as one tall strip plus metadata such as `n-pages`, `page-height`, `loop`, and `delay`. ```clojure (require '[ol.vips :as v] '[ol.vips.operations :as ops]) (with-open [image (ops/gifload "test/fixtures/cogs.gif" {:n -1}) cropped (v/extract-area-pages image 10 7 50 50) turned (v/rot-pages cropped :d90) looped (v/assoc-loop-count turned 2)] (v/write-to-file looped "cogs-turned.gif") (v/metadata looped)) ;; => {:width 50, :height 250, :bands 4, :has-alpha? true, :pages 5, ...} ``` The dedicated animated helpers are: * `v/pages`, `v/page-height`, `v/page-delays`, and `v/loop-count` * `v/assoc-pages`, `v/assoc-page-height`, `v/assoc-page-delays`, and `v/assoc-loop-count` * `v/extract-area-pages`, `v/embed-pages`, `v/rot-pages`, and `v/assemble-pages` These helpers work best for uniform-height multipage inputs such as animated GIF/WebP strips and similarly-shaped TIFF/PDF inputs. For a deeper guide, see [Multipage and Animated Images](https://docs.outskirtslabs.com/ol.vips/next/multipage-and-animated-images). ## Image Loaders The generic loaders `v/from-file`, `v/from-buffer`, and `v/from-stream` auto-detect the input format and accept option maps that libvips forwards to the selected loader. When you need format-specific behavior, use the generated loader operations in `ol.vips.operations`, such as `ops/jpegload`. `ol.vips` blocks libvips operations marked as untrusted by default. This can block loaders with a larger attack surface, such as PDF or ImageMagick-backed formats. If you trust your input and need those operations, opt in explicitly before loading that data: ```clojure (require '[ol.vips :as v] '[ol.vips.operations :as ops]) (v/set-block-untrusted-operations! false) (with-open [image (ops/pdfload "document.pdf")] (v/metadata image)) ``` Use that override only for trusted inputs. See the upstream https://www.libvips.org/API/8.18/func.block_untrusted_set.html[`vips_block_untrusted_set` documentation]. In libvips terms this is equivalent to calling `vips_block_untrusted_set(FALSE)` after initialization. JPEG auto-rotation rotates the image according to its EXIF orientation at load time: ```clojure (require '[ol.vips :as v] '[ol.vips.operations :as ops]) (with-open [image (ops/jpegload "dev/rabbit.jpg" {:autorotate true})] (v/write-to-file image "rabbit-upright.jpg") (v/metadata image)) ``` ## Streaming Input And Output `from-stream` reads from any `java.io.InputStream`. `from-buffer` reads from a byte array already in memory. ```clojure (require '[babashka.http-client :as http] '[ol.vips :as v] '[ol.vips.operations :as ops]) (import '[java.io FileOutputStream]) (with-open [response-body (:body (http/get "https://casey.link/square-flask.png" {:as :stream})) image (v/from-stream response-body {:access :sequential :fail-on :error}) thumbnail (ops/thumbnail-image image 200) out (FileOutputStream. "square-flask-thumb.png")] (v/write-to-stream thumbnail out ".png") (v/metadata thumbnail)) ``` `write-to-stream` writes encoded bytes to any `java.io.OutputStream`. ```clojure (require '[babashka.fs :as fs] '[ol.vips :as v] '[ol.vips.operations :as ops]) (import '[java.io FileOutputStream]) (let [source-bytes (fs/read-all-bytes "dev/rabbit.jpg")] (with-open [image (v/from-buffer source-bytes) thumbnail (ops/thumbnail-image image 200) out (FileOutputStream. "rabbit-thumb.png")] (v/write-to-stream thumbnail out ".png") (v/metadata thumbnail))) ``` ## Autorotate And Inspect Outputs `autorot` returns a closeable result map. You can inspect `:angle` and `:flip`, and still use the same value anywhere an image is expected. ```clojure (with-open [image (v/from-file "dev/rabbit.jpg") autorot (ops/autorot image)] {:angle (:angle autorot) :flip (:flip autorot) :meta (v/metadata autorot)}) ;; => {:angle :d0, :flip false, :meta {:width 2490, :height 3084, :bands 3, :has-alpha? false}} ``` ## Resize And Crop Use these geometry operations when you want to rescale an image first and then work on a precise rectangular region. ```clojure (with-open [image (v/from-file "dev/rabbit.jpg") resized (ops/resize image 0.5) cropped (ops/extract-area resized 100 100 500 500)] (v/write-to-file resized "rabbit-resized.jpg") (v/write-to-file cropped "rabbit-cropped.jpg") {:resized (v/metadata resized) :cropped (v/metadata cropped)}) ``` ## Smart Thumbnailing `ops/thumbnail` exposes libvips’s higher-level thumbnail pipeline. Enum options such as `:size` and `:crop` are documented in `ol.vips.enums`. ```clojure (with-open [thumb (ops/thumbnail "dev/rabbit.jpg" 300 {:height 300 :size :down :crop :attention})] (v/write-to-file thumb "rabbit-smart-thumb.jpg") (v/metadata thumb)) ``` ## Transforming Images These operations are a good fit for orientation, color interpretation, and other structural changes you want to compose into one pipeline. ```clojure (with-open [image (v/from-file "dev/rabbit.jpg") rotated (ops/rotate image 90.0) flipped (ops/flip rotated :horizontal) bw (ops/colourspace flipped :b-w)] (v/write-to-file bw "rabbit-bw.jpg")) ``` ## Filters And Effects libvips includes a large set of convolution and enhancement operations, so common blur and sharpen passes can stay inside the same image pipeline. ```clojure (with-open [image (v/from-file "dev/rabbit.jpg") blurred (ops/gaussblur image 3.0) sharp (ops/sharpen image {:sigma 1.0})] (v/write-to-file blurred "rabbit-blur.jpg") (v/write-to-file sharp "rabbit-sharp.jpg") {:blurred (v/metadata blurred) :sharp (v/metadata sharp)}) ``` ## Composing Images Use the composition helpers when you need to join images, build contact sheets, or align multiple sources into one output image. ```clojure (with-open [left (v/from-file "dev/rabbit.jpg") right (v/from-file "dev/rabbit.jpg") joined (ops/join left right :horizontal) grid (ops/arrayjoin [left right left right] {:across 2 :shim 10 :halign :centre :valign :centre})] (v/write-to-file joined "rabbit-joined.jpg") (v/write-to-file grid "rabbit-grid.jpg")) ``` ## Web Optimization The save helpers accept format-specific encoder options, which makes it easy to produce smaller web-friendly JPEG and WebP outputs from the same source image. ```clojure (with-open [image (v/from-file "dev/rabbit.jpg")] (v/write-to-file image "rabbit-progressive.jpg" {:interlace true :strip true :Q 85}) (v/write-to-file image "rabbit.webp" {:Q 80 :effort 4})) ``` ## Calling Raw Operations Use `v/call` when you want access to the full libvips operation surface before a dedicated convenience wrapper exists. ```clojure (with-open [image (v/from-file "dev/rabbit.jpg") rotated (v/call "rotate" {:in image :angle 90.0})] (v/metadata rotated)) ``` Use `v/operations` to list available libvips operations and `v/operation-info` to inspect their inputs and outputs. ## Text Overlay Generated operation wrappers also cover image synthesis and compositing, so overlays like text labels can stay inside libvips rather than being rendered in a separate tool. ```clojure (with-open [image (v/from-file "dev/rabbit.jpg") label (ops/text "ol.vips" {:font "Sans Bold 48" :rgba true}) poster (ops/composite2 image label :over {:x 40 :y 40})] (v/write-to-file poster "rabbit-poster.png") (v/metadata poster)) ```