Skip to content

Repository files navigation

bimg Build StatusGitHub releaseGoDoc

Small Go package for fast high-level image processing using libvips via C bindings. Provides 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 between 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.

To get started you could take a look to the examples and API documentation.

If you're looking for a HTTP based image processing solution, see imaginary. bimg was heavily inspired in sharp, its homologous package built for node.js.

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

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-based)
  • Gaussian blur effect
  • Custom output color space (RGB, grayscale...)
  • Format conversion (with additional quality/compression settings)
  • EXIF metadata (size, alpha channel, profile, orientation...)

Performance

libvips is probably the faster open source solution for image processing. Here you can see some performance test comparisons for multiple scenarios:

Benchmarks

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

API

Examples

import (
"fmt""os""gopkg.in/h2non/bimg.v0"
)

Resize

buffer, err:=bimg.Read("image.jpg")
iferr!=nil {
fmt.Fprintln(os.Stderr, err)
}
newImage, err:=bimg.NewImage(buffer).Resize(800, 600)
iferr!=nil {
fmt.Fprintln(os.Stderr, err)
}
size, err:=bimg.NewImage(newImage).Size()
ifsize.Width==400&&size.Height==300 {
fmt.Println("The image size is valid")
}
bimg.Write("new.jpg", newImage)

Rotate

buffer, err:=bimg.Read("image.jpg")
iferr!=nil {
fmt.Fprintln(os.Stderr, err)
}
newImage, err:=bimg.NewImage(buffer).Rotate(90)
iferr!=nil {
fmt.Fprintln(os.Stderr, err)
}
bimg.Write("new.jpg", newImage)

Convert

buffer, err:=bimg.Read("image.jpg")
iferr!=nil {
fmt.Fprintln(os.Stderr, err)
}
newImage, err:=bimg.NewImage(buffer).Convert(bimg.PNG)
iferr!=nil {
fmt.Fprintln(os.Stderr, err)
}
ifbimg.NewImage(newImage).Type() =="png" {
fmt.Fprintln(os.Stderr, "The image was converted into png")
}

Force resize

buffer, err:=bimg.Read("image.jpg")
iferr!=nil {
fmt.Fprintln(os.Stderr, err)
}
newImage, err:=bimg.NewImage(buffer).ForceResize(1000, 500)
iferr!=nil {
fmt.Fprintln(os.Stderr, err)
}
size:=bimg.Size(newImage)
ifsize.Width!=1000||size.Height!=500 {
fmt.Fprintln(os.Stderr, "Incorrect image size")
}

Custom colour space (black & white)

buffer, err:=bimg.Read("image.jpg")
iferr!=nil {
fmt.Fprintln(os.Stderr, err)
}
newImage, err:=bimg.NewImage(buffer).Colourspace(bimg.INTERPRETATION_B_W)
iferr!=nil {
fmt.Fprintln(os.Stderr, err)
}
colourSpace, _:=bimg.ImageInterpretation(newImage)
ifcolourSpace!=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")
iferr!=nil {
fmt.Fprintln(os.Stderr, err)
}
newImage, err:=bimg.NewImage(buffer).Process(options)
iferr!=nil {
fmt.Fprintln(os.Stderr, err)
}
bimg.Write("new.jpg", newImage)

Watermark

buffer, err:=bimg.Read("image.jpg")
iferr!=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)
iferr!=nil {
fmt.Fprintln(os.Stderr, err)
}
bimg.Write("new.jpg", newImage)

Fluent interface

buffer, err:=bimg.Read("image.jpg")
iferr!=nil {
fmt.Fprintln(os.Stderr, err)
}
image:=bimg.NewImage(buffer)
// first crop image_, err:=image.CropByWidth(300)
iferr!=nil {
fmt.Fprintln(os.Stderr, err)
}
// then flip itnewImage, err:=image.Flip()
iferr!=nil {
fmt.Fprintln(os.Stderr, err)
}
// save the cropped and flipped imagebimg.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 

Programmatic API

constHasMagickSupport=int(C.VIPS_MAGICK_SUPPORT) ==1
constVersion="0.1.20"
constWATERMARK_FONT="sans 10"

func ColourspaceIsSupported

funcColourspaceIsSupported(buf []byte) (bool, error)

Check in the image colourspace is supported by libvips

func DetermineImageTypeName

funcDetermineImageTypeName(buf []byte) string

Determines the image type format by name (jpeg, png, webp or tiff)

func Initialize

funcInitialize()

Explicit thread-safe start of libvips. Only call this function if you've previously shutdown libvips

func IsTypeNameSupported

funcIsTypeNameSupported(tstring) bool

Check if a given image type name is supported

func IsTypeSupported

funcIsTypeSupported(tImageType) bool

Check if a given image type is supported

func Read

funcRead(pathstring) ([]byte, error)

func Resize

funcResize(buf []byte, oOptions) ([]byte, error)

func Shutdown

funcShutdown()

Thread-safe function to shutdown libvips. You can call this to drop caches as well. If libvips was already initialized, the function is no-op

func VipsDebugInfo

funcVipsDebugInfo()

Output to stdout vips collected data. Useful for debugging

func Write

funcWrite(pathstring, buf []byte) error

type Angle

typeAngleint
const (
D0Angle=0D90Angle=90D180Angle=180D270Angle=270
)

type Color

typeColorstruct {
R, G, Buint8
}

Color represents a traditional RGB color scheme

type Direction

typeDirectionint
const (
HORIZONTALDirection=C.VIPS_DIRECTION_HORIZONTALVERTICALDirection=C.VIPS_DIRECTION_VERTICAL
)

type GaussianBlur

typeGaussianBlurstruct {
Sigmafloat64MinAmplfloat64
}

type Gravity

typeGravityint
const (
CENTREGravity=iotaNORTHEASTSOUTHWEST
)

type Image

typeImagestruct {
}

func NewImage

funcNewImage(buf []byte) *Image

Creates a new image

func (*Image) Colourspace

func (i*Image) Colourspace(cInterpretation) ([]byte, error)

Colour space conversion

func (*Image) ColourspaceIsSupported

func (i*Image) ColourspaceIsSupported() (bool, error)

Check if the current image has a valid colourspace

func (*Image) Convert

func (i*Image) Convert(tImageType) ([]byte, error)

Convert image to another format

func (*Image) Crop

func (i*Image) Crop(width, heightint, gravityGravity) ([]byte, error)

Crop the image to the exact size specified

func (*Image) CropByHeight

func (i*Image) CropByHeight(heightint) ([]byte, error)

Crop an image by height (auto width)

func (*Image) CropByWidth

func (i*Image) CropByWidth(widthint) ([]byte, error)

Crop an image by width (auto height)

func (*Image) Enlarge

func (i*Image) Enlarge(width, heightint) ([]byte, error)

Enlarge the image by width and height. Aspect ratio is maintained

func (*Image) EnlargeAndCrop

func (i*Image) EnlargeAndCrop(width, heightint) ([]byte, error)

Enlarge the image by width and height with additional crop transformation

func (*Image) Extract

func (i*Image) Extract(top, left, width, heightint) ([]byte, error)

Extract area from the by X/Y axis

func (*Image) Flip

func (i*Image) Flip() ([]byte, error)

Flip the image about the vertical Y axis

func (*Image) Flop

func (i*Image) Flop() ([]byte, error)

Flop the image about the horizontal X axis

func (*Image) ForceResize

func (i*Image) ForceResize(width, heightint) ([]byte, error)

Force resize with custom size (aspect ratio won't be maintained)

func (*Image) Image

func (i*Image) Image() []byte

Get image buffer

func (*Image) Interpretation

func (i*Image) Interpretation() (Interpretation, error)

Get the image interpretation type See: http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/VipsImage.html#VipsInterpretation

func (*Image) Metadata

func (i*Image) Metadata() (ImageMetadata, error)

Get image metadata (size, alpha channel, profile, EXIF rotation)

func (*Image) Process

func (i*Image) Process(oOptions) ([]byte, error)

Transform the image by custom options

func (*Image) Resize

func (i*Image) Resize(width, heightint) ([]byte, error)

Resize the image to fixed width and height

func (*Image) ResizeAndCrop

func (i*Image) ResizeAndCrop(width, heightint) ([]byte, error)

Resize the image to fixed width and height with additional crop transformation

func (*Image) Rotate

func (i*Image) Rotate(aAngle) ([]byte, error)

Rotate the image by given angle degrees (0, 90, 180 or 270)

func (*Image) Size

func (i*Image) Size() (ImageSize, error)

Get image size

func (*Image) Thumbnail

func (i*Image) Thumbnail(pixelsint) ([]byte, error)

Thumbnail the image by the a given width by aspect ratio 4:4

func (*Image) Type

func (i*Image) Type() string

Get image type format (jpeg, png, webp, tiff)

func (*Image) Watermark

func (i*Image) Watermark(wWatermark) ([]byte, error)

Add text as watermark on the given image

func (*Image) Zoom

func (i*Image) Zoom(factorint) ([]byte, error)

Zoom the image by the given factor. You should probably call Extract() before

type ImageMetadata

typeImageMetadatastruct {
OrientationintChannelsintAlphaboolProfileboolTypestringSpacestringColourspacestringSizeImageSize
}

func Metadata

funcMetadata(buf []byte) (ImageMetadata, error)

Extract the image metadata (size, type, alpha channel, profile, EXIF orientation...)

type ImageSize

typeImageSizestruct {
WidthintHeightint
}

func Size

funcSize(buf []byte) (ImageSize, error)

Get the image size by width and height pixels

type ImageType

typeImageTypeint
const (
UNKNOWNImageType=iotaJPEGWEBPPNGTIFFMAGICK
)

func DetermineImageType

funcDetermineImageType(buf []byte) ImageType

Determines the image type format (jpeg, png, webp or tiff)

type Interpolator

typeInterpolatorint
const (
BICUBICInterpolator=iotaBILINEARNOHALO
)

func (Interpolator) String

func (iInterpolator) String() string

type Interpretation

typeInterpretationint

Image interpretation type See: http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/VipsImage.html#VipsInterpretation

const (
INTERPRETATION_ERRORInterpretation=C.VIPS_INTERPRETATION_ERRORINTERPRETATION_MULTIBANDInterpretation=C.VIPS_INTERPRETATION_MULTIBANDINTERPRETATION_B_WInterpretation=C.VIPS_INTERPRETATION_B_WINTERPRETATION_CMYKInterpretation=C.VIPS_INTERPRETATION_CMYKINTERPRETATION_RGBInterpretation=C.VIPS_INTERPRETATION_RGBINTERPRETATION_sRGBInterpretation=C.VIPS_INTERPRETATION_sRGBINTERPRETATION_RGB16Interpretation=C.VIPS_INTERPRETATION_RGB16INTERPRETATION_GREY16Interpretation=C.VIPS_INTERPRETATION_GREY16INTERPRETATION_scRGBInterpretation=C.VIPS_INTERPRETATION_scRGBINTERPRETATION_LABInterpretation=C.VIPS_INTERPRETATION_LABINTERPRETATION_XYZInterpretation=C.VIPS_INTERPRETATION_XYZ
)

func ImageInterpretation

funcImageInterpretation(buf []byte) (Interpretation, error)

Get the image interpretation type See: http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/VipsImage.html#VipsInterpretation

type Options

typeOptionsstruct {
HeightintWidthintAreaHeightintAreaWidthintTopintLeftintExtendintQualityintCompressionintZoomintCropboolEnlargeboolEmbedboolFlipboolFlopboolForceboolNoAutoRotateboolNoProfileboolInterlaceboolRotateAngleGravityGravityWatermarkWatermarkTypeImageTypeInterpolatorInterpolatorInterpretationInterpretationGaussianBlurGaussianBlur
}

type VipsMemoryInfo

typeVipsMemoryInfostruct {
Memoryint64MemoryHighwaterint64Allocationsint64
}

func VipsMemory

funcVipsMemory() VipsMemoryInfo

Get memory info stats from vips (cache size, memory allocs...)

type Watermark

typeWatermarkstruct {
WidthintDPIintMarginintOpacityfloat32NoReplicateboolTextstringFontstringBackgroundColor
}

Contributors

Special thanks to people who freely contributed to improve bimg in some or other way.

Special Thanks

License

MIT - Tomas Aparicio

views

About

Small Go package for fast high-level image processing using libvips via C bindings

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages