You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
Tomás Aparicio a0fc602e69
fix(docs): minor typo
10 years ago
fixtures feat(test): add vertical image fixtures with multiple test cases 10 years ago
.editorconfig feat(#1): initial implementation 11 years ago
.gitignore refactor(resize) 11 years ago
.travis.yml feat(travis): use go 1.6 10 years ago
LICENSE feat(#1): initial implementation 11 years ago
README.md fix(docs): minor typo 10 years ago
debug.go feat(version): bump 11 years ago
file.go refactor(file) 11 years ago
file_test.go refactor(resize): extract 11 years ago
image.go feat(test): add vertical image fixtures with multiple test cases 10 years ago
image_test.go feat(#60): support zero top and left params in extract operation 10 years ago
metadata.go feat(test): add vertical image fixtures with multiple test cases 10 years ago
metadata_test.go refactor(#47): minor refactors, code normalization and test coverage 11 years ago
options.go fix(rotation) 10 years ago
resize.go fix(resize): auto rotate image before resize calculus 10 years ago
resize_test.go fix(resize): auto rotate image before resize calculus 10 years ago
type.go refactor(type): simplify image type matching 10 years ago
type_test.go refactor(type): simplify image type matching 10 years ago
version.go feat(version): bump 10 years ago
vips.go fix(resize): auto rotate image before resize calculus 10 years ago
vips.h Added interface and test for sharpen 10 years ago
vips_test.go fix(#46): transform to proper image size 11 years ago

README.md

bimg Build Status GoDoc Go Report Card Coverage Status

Small Go package for fast high-level image processing using libvips via C bindings, providing a simple, elegant and fluent programmatic API.

bimg was designed to be a small and efficient library supporting a common set of image operations such as crop, resize, rotate, zoom or watermark. It can read JPEG, PNG, WEBP and TIFF formats and output to JPEG, PNG and WEBP, including 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.

Contents

Supported image operations

  • Resize
  • Enlarge
  • Crop
  • Rotate (with auto-rotate based on EXIF orientation)
  • Flip (with auto-flip based on EXIF metadata)
  • Flop
  • Zoom
  • Thumbnail
  • Extract area
  • Watermark (text only)
  • Gaussian blur effect
  • Custom output color space (RGB, grayscale...)
  • Format conversion (with additional quality/compression settings)
  • EXIF metadata (size, alpha channel, profile, orientation...)

Prerequisites

  • libvips v7.40.0+ (7.42.0+ recommended)
  • C compatible compiler such as gcc 4.6+ or clang 3.0+
  • Go 1.3+

Installation

go get -u gopkg.in/h2non/bimg.v0

libvips

Run the following script as sudo (supports OSX, Debian/Ubuntu, Redhat, Fedora, Amazon Linux):

curl -s https://raw.githubusercontent.com/lovell/sharp/master/preinstall.sh | sudo bash -

If you wanna take the advantage of OpenSlide, simply add --with-openslide to enable it:

curl -s https://raw.githubusercontent.com/lovell/sharp/master/preinstall.sh | sudo bash -s --with-openslide

The install script requires curl and pkg-config

For platform specific installations, see Mac OS tips or Windows tips

Performance

libvips is probably the faster 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"
  "gopkg.in/h2non/bimg.v0"
)

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 == 400 && size.Height == 300 {
  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.

Credits

People who recurrently contributed to improve bimg in some way.

Thank you!

License

MIT - Tomas Aparicio

views