bimg
Small Go package for fast high-level image processing using libvips via C bindings, providing a simple programmatic API.
bimg was designed to be a small and efficient library supporting common image operations such as crop, resize, rotate, zoom or watermark. It can read JPEG, PNG, WEBP natively, and optionally TIFF, PDF, GIF and SVG formats if libvips@8.3+ is compiled with proper library bindings.
bimg is able to output images as JPEG, PNG and WEBP formats, including transparent conversion across them.
bimg uses internally libvips, a powerful library written in C for image processing which requires a low memory footprint and it's typically 4x faster than using the quickest ImageMagick and GraphicsMagick settings or Go native image package, and in some cases it's even 8x faster processing JPEG images.
If you're looking for an HTTP based image processing solution, see imaginary.
bimg was heavily inspired in sharp, its homologous package built for node.js. bimg is used in production environments processing thousands of images per day.
v1 notice: bimg introduces some minor breaking changes in v1 release. If you're using gopkg.in, you can still rely in the v0 without worrying about API breaking changes.
Contents
Supported image operations
Resize
Enlarge
Crop (including smart crop support, libvips 8.5+)
Rotate (with auto-rotate based on EXIF orientation)
Flip (with auto-flip based on EXIF metadata)
Flop
Zoom
Thumbnail
Extract area
Watermark (using text or image)
Gaussian blur effect
Custom output color space (RGB, grayscale...)
Format conversion (with additional quality/compression settings)
EXIF metadata (size, alpha channel, profile, orientation...)
Trim (libvips 8.6+)
Prerequisites
libvips 8.3+ (8.8+ recommended)
C compatible compiler such as gcc 4.6+ or clang 3.0+
Go 1.3+
Note: libvips v8.3+ is required for GIF, PDF and SVG support.
Installation
go get -u github.com/h2non/bimg
libvips
Follow libvips installation instructions:
Installation script
Note: install script is officially deprecated, it might not work as expected. We recommend following libvips install instructions.
Run the following script as sudo (supports OSX, Debian/Ubuntu, Redhat, Fedora, Amazon Linux):
curl -s https://raw.githubusercontent.com/h2non/bimg/master/preinstall.sh | sudo bash -
If you want to take the advantage of OpenSlide, simply add --with-openslide to enable it:
curl -s https://raw.githubusercontent.com/h2non/bimg/master/preinstall.sh | sudo bash -s --with-openslide
The install script requires curl and pkg-config.
Performance
libvips is probably the fastest open source solution for image processing. Here you can see some performance test comparisons for multiple scenarios:
Benchmark
Tested using Go 1.5.1 and libvips-7.42.3 in OSX i7 2.7Ghz
BenchmarkRotateJpeg-8 20 64686945 ns/op
BenchmarkResizeLargeJpeg-8 20 63390416 ns/op
BenchmarkResizePng-8 100 18147294 ns/op
BenchmarkResizeWebP-8 100 20836741 ns/op
BenchmarkConvertToJpeg-8 100 12831812 ns/op
BenchmarkConvertToPng-8 10 128901422 ns/op
BenchmarkConvertToWebp-8 10 204027990 ns/op
BenchmarkCropJpeg-8 30 59068572 ns/op
BenchmarkCropPng-8 10 117303259 ns/op
BenchmarkCropWebP-8 10 107060659 ns/op
BenchmarkExtractJpeg-8 50 30708919 ns/op
BenchmarkExtractPng-8 3000 595546 ns/op
BenchmarkExtractWebp-8 3000 386379 ns/op
BenchmarkZoomJpeg-8 10 160005424 ns/op
BenchmarkZoomPng-8 30 44561047 ns/op
BenchmarkZoomWebp-8 10 126732678 ns/op
BenchmarkWatermarkJpeg-8 20 79006133 ns/op
BenchmarkWatermarPng-8 200 8197291 ns/op
BenchmarkWatermarWebp-8 30 49360369 ns/op
Examples
import (
"fmt"
"os"
"github.com/h2non/bimg"
)
Resize
buffer, err := bimg.Read("image.jpg")
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
newImage, err := bimg.NewImage(buffer).Resize(800, 600)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
size, err := bimg.NewImage(newImage).Size()
if size.Width == 800 && size.Height == 600 {
fmt.Println("The image size is valid")
}
bimg.Write("new.jpg", newImage)
Rotate
buffer, err := bimg.Read("image.jpg")
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
newImage, err := bimg.NewImage(buffer).Rotate(90)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
bimg.Write("new.jpg", newImage)
Convert
buffer, err := bimg.Read("image.jpg")
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
newImage, err := bimg.NewImage(buffer).Convert(bimg.PNG)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
if bimg.NewImage(newImage).Type() == "png" {
fmt.Fprintln(os.Stderr, "The image was converted into png")
}
Force resize
Force resize operation without perserving the aspect ratio:
buffer, err := bimg.Read("image.jpg")
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
newImage, err := bimg.NewImage(buffer).ForceResize(1000, 500)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
size := bimg.Size(newImage)
if size.Width != 1000 || size.Height != 500 {
fmt.Fprintln(os.Stderr, "Incorrect image size")
}
Custom colour space (black & white)
buffer, err := bimg.Read("image.jpg")
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
newImage, err := bimg.NewImage(buffer).Colourspace(bimg.INTERPRETATION_B_W)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
colourSpace, _ := bimg.ImageInterpretation(newImage)
if colourSpace != bimg.INTERPRETATION_B_W {
fmt.Fprintln(os.Stderr, "Invalid colour space")
}
Custom options
See Options struct to discover all the available fields
options := bimg.Options{
Width: 800,
Height: 600,
Crop: true,
Quality: 95,
Rotate: 180,
Interlace: true,
}
buffer, err := bimg.Read("image.jpg")
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
newImage, err := bimg.NewImage(buffer).Process(options)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
bimg.Write("new.jpg", newImage)
Watermark
buffer, err := bimg.Read("image.jpg")
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
watermark := bimg.Watermark{
Text: "Chuck Norris (c) 2315",
Opacity: 0.25,
Width: 200,
DPI: 100,
Margin: 150,
Font: "sans bold 12",
Background: bimg.Color{255, 255, 255},
}
newImage, err := bimg.NewImage(buffer).Watermark(watermark)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
bimg.Write("new.jpg", newImage)
Fluent interface
buffer, err := bimg.Read("image.jpg")
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
image := bimg.NewImage(buffer)
// first crop image
_, err := image.CropByWidth(300)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
// then flip it
newImage, err := image.Flip()
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
// save the cropped and flipped image
bimg.Write("new.jpg", newImage)
Debugging
Run the process passing the DEBUG environment variable
DEBUG=bimg ./app
Enable libvips traces (note that a lot of data will be written in stdout):
VIPS_TRACE=1 ./app
You can also dump a core on failure, as John Cuppit said:
g_log_set_always_fatal(
G_LOG_FLAG_RECURSION |
G_LOG_FLAG_FATAL |
G_LOG_LEVEL_ERROR |
G_LOG_LEVEL_CRITICAL |
G_LOG_LEVEL_WARNING );
Or set the G_DEBUG environment variable:
export G_DEBUG=fatal-warnings,fatal-criticals
API
See godoc reference for detailed API documentation.
Authors
Tomás Aparicio - Original author and architect.
Credits
People who recurrently contributed to improve bimg in some way.
Thank you!
License
MIT - Tomas Aparicio