Go to file
Tom b29a573563
Merge pull request #368 from exaring/fix-shrinking-on-small-webp-images
Fix for blurry images from WEBP input and small output dimensions
2021-08-07 18:04:19 +02:00
testdata Use faster encoding setting in test 2020-10-14 14:23:56 +02:00
.editorconfig refactor(ci): disable verions matrix 2020-06-06 18:07:03 +02:00
.gitignore feat: add Gopkg manifests, move fixtures to testdata, add vendor dependencies 2017-10-30 09:41:13 +01:00
.travis.yml Since AVIF computation was awfully slow, this exposes the CPU effort setting "speed". 2020-10-14 13:43:37 +02:00
Dockerfile adds libaom 2020-10-11 22:13:23 +02:00
Gopkg.lock Remove go-debug usage 2017-12-22 16:31:43 +01:00
Gopkg.toml Remove go-debug usage 2017-12-22 16:31:43 +01:00
History.md Update History.md 2020-11-21 13:53:52 +01:00
LICENSE feat(#1): initial implementation 2015-03-29 22:55:04 +02:00
README.md adds section in README about libheif for AVIF en-/decoding 2020-10-26 16:51:27 +01:00
file.go feat(version): v1 release. see history for details 2016-04-21 16:44:50 +01:00
file_test.go feat: add Gopkg manifests, move fixtures to testdata, add vendor dependencies 2017-10-30 09:41:13 +01:00
image.go feat: autorotate 2020-08-04 19:40:07 +02:00
image_test.go Adds AVIF support 2020-10-10 15:25:53 +02:00
metadata.go goimports 2021-07-20 12:32:32 +09:00
metadata_test.go goimports 2021-07-20 12:32:32 +09:00
options.go fix typo in comments 2021-07-20 12:32:24 +09:00
preinstall.sh refactor(docs): add libvips install reference 2020-06-08 15:06:41 +02:00
resize.go fix build tag 2017-10-29 21:13:52 -07:00
resize_legacy.go fix build tag 2017-10-29 21:13:52 -07:00
resizer.go Remove debug output 2021-03-31 12:19:48 +02:00
resizer_test.go feat: add Dockerfile / Docker-driven CI job 2020-06-07 01:16:45 +02:00
type.go Adds AVIF support 2020-10-10 15:25:53 +02:00
type_test.go Adds AVIF support 2020-10-10 15:25:53 +02:00
version.go feat: bump version 2020-11-21 13:49:20 +01:00
vips.go Merge pull request #360 from jaberwoky/master 2021-08-07 18:02:47 +02:00
vips.h Vips: add VipsVectorSetEnabled 2021-07-06 14:59:12 +03:00
vips_test.go Merge pull request #360 from jaberwoky/master 2021-08-07 18:02:47 +02:00

README.md

bimg Build Status GoDoc Go Report Card Coverage Status License

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. Lastly AVIF is supported as of libvips@8.9+. For AVIF support libheif needs to be compiled with an applicable AVIF en-/decoder.

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.
  • libvips v8.9+ is required for AVIF support. libheif compiled with a AVIF en-/decoder also needs to be present.

Installation

go get -u github.com/h2non/bimg

libvips

Follow libvips installation instructions:

https://libvips.github.io/libvips/install.html

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

Credits

People who recurrently contributed to improve bimg in some way.

Thank you!

License

MIT - Tomas Aparicio

views