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.
- libvips v7.40.0+ (7.42.0+ recommended)
- C compatible compiler such as gcc 4.6+ or clang 3.0+
- Go 1.3+
go get -u gopkg.in/h2non/bimg.v0Run 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-openslideThe install script requires curl and pkg-config
For platform specific installations, see Mac OS tips or Windows tips
- 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...)
libvips is probably the faster open source solution for image processing. Here you can see some performance test comparisons for multiple scenarios:
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
import (
"fmt""os""gopkg.in/h2non/bimg.v0"
)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)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)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")
}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")
}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")
}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)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)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)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 constHasMagickSupport=int(C.VIPS_MAGICK_SUPPORT) ==1constVersion="0.1.20"constWATERMARK_FONT="sans 10"funcColourspaceIsSupported(buf []byte) (bool, error)Check in the image colourspace is supported by libvips
funcDetermineImageTypeName(buf []byte) stringDetermines the image type format by name (jpeg, png, webp or tiff)
funcInitialize()Explicit thread-safe start of libvips. Only call this function if you've previously shutdown libvips
funcIsTypeNameSupported(tstring) boolCheck if a given image type name is supported
funcIsTypeSupported(tImageType) boolCheck if a given image type is supported
funcRead(pathstring) ([]byte, error)funcResize(buf []byte, oOptions) ([]byte, error)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
funcVipsDebugInfo()Output to stdout vips collected data. Useful for debugging
funcWrite(pathstring, buf []byte) errortypeAngleintconst (
D0Angle=0D90Angle=90D180Angle=180D270Angle=270
)typeColorstruct {
R, G, Buint8
}Color represents a traditional RGB color scheme
typeDirectionintconst (
HORIZONTALDirection=C.VIPS_DIRECTION_HORIZONTALVERTICALDirection=C.VIPS_DIRECTION_VERTICAL
)typeGaussianBlurstruct {
Sigmafloat64MinAmplfloat64
}typeGravityintconst (
CENTREGravity=iotaNORTHEASTSOUTHWEST
)typeImagestruct {
}funcNewImage(buf []byte) *ImageCreates a new image
func (i*Image) Colourspace(cInterpretation) ([]byte, error)Colour space conversion
func (i*Image) ColourspaceIsSupported() (bool, error)Check if the current image has a valid colourspace
func (i*Image) Convert(tImageType) ([]byte, error)Convert image to another format
func (i*Image) Crop(width, heightint, gravityGravity) ([]byte, error)Crop the image to the exact size specified
func (i*Image) CropByHeight(heightint) ([]byte, error)Crop an image by height (auto width)
func (i*Image) CropByWidth(widthint) ([]byte, error)Crop an image by width (auto height)
func (i*Image) Enlarge(width, heightint) ([]byte, error)Enlarge the image by width and height. Aspect ratio is maintained
func (i*Image) EnlargeAndCrop(width, heightint) ([]byte, error)Enlarge the image by width and height with additional crop transformation
func (i*Image) Extract(top, left, width, heightint) ([]byte, error)Extract area from the by X/Y axis
func (i*Image) Flip() ([]byte, error)Flip the image about the vertical Y axis
func (i*Image) Flop() ([]byte, error)Flop the image about the horizontal X axis
func (i*Image) ForceResize(width, heightint) ([]byte, error)Force resize with custom size (aspect ratio won't be maintained)
func (i*Image) Image() []byteGet image buffer
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 (i*Image) Metadata() (ImageMetadata, error)Get image metadata (size, alpha channel, profile, EXIF rotation)
func (i*Image) Process(oOptions) ([]byte, error)Transform the image by custom options
func (i*Image) Resize(width, heightint) ([]byte, error)Resize the image to fixed width and height
func (i*Image) ResizeAndCrop(width, heightint) ([]byte, error)Resize the image to fixed width and height with additional crop transformation
func (i*Image) Rotate(aAngle) ([]byte, error)Rotate the image by given angle degrees (0, 90, 180 or 270)
func (i*Image) Size() (ImageSize, error)Get image size
func (i*Image) Thumbnail(pixelsint) ([]byte, error)Thumbnail the image by the a given width by aspect ratio 4:4
func (i*Image) Type() stringGet image type format (jpeg, png, webp, tiff)
func (i*Image) Watermark(wWatermark) ([]byte, error)Add text as watermark on the given image
func (i*Image) Zoom(factorint) ([]byte, error)Zoom the image by the given factor. You should probably call Extract() before
typeImageMetadatastruct {
OrientationintChannelsintAlphaboolProfileboolTypestringSpacestringColourspacestringSizeImageSize
}funcMetadata(buf []byte) (ImageMetadata, error)Extract the image metadata (size, type, alpha channel, profile, EXIF orientation...)
typeImageSizestruct {
WidthintHeightint
}funcSize(buf []byte) (ImageSize, error)Get the image size by width and height pixels
typeImageTypeintconst (
UNKNOWNImageType=iotaJPEGWEBPPNGTIFFMAGICK
)funcDetermineImageType(buf []byte) ImageTypeDetermines the image type format (jpeg, png, webp or tiff)
typeInterpolatorintconst (
BICUBICInterpolator=iotaBILINEARNOHALO
)func (iInterpolator) String() stringtypeInterpretationintImage 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
)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
typeOptionsstruct {
HeightintWidthintAreaHeightintAreaWidthintTopintLeftintExtendintQualityintCompressionintZoomintCropboolEnlargeboolEmbedboolFlipboolFlopboolForceboolNoAutoRotateboolNoProfileboolInterlaceboolRotateAngleGravityGravityWatermarkWatermarkTypeImageTypeInterpolatorInterpolatorInterpretationInterpretationGaussianBlurGaussianBlur
}typeVipsMemoryInfostruct {
Memoryint64MemoryHighwaterint64Allocationsint64
}funcVipsMemory() VipsMemoryInfoGet memory info stats from vips (cache size, memory allocs...)
typeWatermarkstruct {
WidthintDPIintMarginintOpacityfloat32NoReplicateboolTextstringFontstringBackgroundColor
}Special thanks to people who freely contributed to improve bimg in some or other way.
MIT - Tomas Aparicio
