Top Related Projects
A fast image processing library with low memory needs.
Fast, simple, scalable, Docker-ready HTTP microservice for high-level image processing
Fast and secure standalone server for resizing, processing, and converting images on the fly
thumbor is an open-source photo thumbnail service by globo.com
A caching, resizing image proxy written in Go
An image resizing server written in Go
Quick Overview
govips is a Go binding for libvips, a fast image processing library. It provides a high-performance, thread-safe image processing solution for Go applications, allowing developers to efficiently manipulate images with minimal memory usage.
Pros
- High performance and low memory usage
- Thread-safe operations for concurrent image processing
- Supports a wide range of image formats and operations
- Easy-to-use API for Go developers
Cons
- Requires libvips to be installed on the system
- Limited documentation compared to some other image processing libraries
- May have a steeper learning curve for developers unfamiliar with libvips
Code Examples
- Resizing an image:
import "github.com/davidbyttow/govips/v2/vips"
func resizeImage(inputPath, outputPath string) error {
image, err := vips.NewImageFromFile(inputPath)
if err != nil {
return err
}
defer image.Close()
err = image.Resize(0.5, vips.KernelAuto)
if err != nil {
return err
}
return image.ExportJpeg(outputPath, vips.NewJpegExportParams())
}
- Applying a blur effect:
import "github.com/davidbyttow/govips/v2/vips"
func blurImage(inputPath, outputPath string) error {
image, err := vips.NewImageFromFile(inputPath)
if err != nil {
return err
}
defer image.Close()
err = image.Gaussblur(5.0)
if err != nil {
return err
}
return image.ExportPng(outputPath, vips.NewPngExportParams())
}
- Converting image format:
import "github.com/davidbyttow/govips/v2/vips"
func convertToPNG(inputPath, outputPath string) error {
image, err := vips.NewImageFromFile(inputPath)
if err != nil {
return err
}
defer image.Close()
return image.ExportPng(outputPath, vips.NewPngExportParams())
}
Getting Started
To use govips in your Go project, follow these steps:
- Install libvips on your system (refer to the project's README for installation instructions).
- Add govips to your Go module:
go get github.com/davidbyttow/govips/v2 - Import and use govips in your Go code:
import "github.com/davidbyttow/govips/v2/vips" func main() { vips.Startup(nil) defer vips.Shutdown() // Your image processing code here }
Remember to call vips.Startup() before using any govips functions and vips.Shutdown() when you're done to properly initialize and clean up resources.
Competitor Comparisons
A fast image processing library with low memory needs.
Pros of libvips
- Written in C, offering potentially better performance for low-level image processing operations
- More extensive feature set and broader image format support
- Longer development history and larger community, potentially leading to better stability and support
Cons of libvips
- Requires C knowledge for direct usage or contribution
- More complex setup and integration compared to a Go-native solution
- Potential overhead when used with Go due to CGo bindings
Code Comparison
libvips (C):
VipsImage *in, *out;
vips_jpegload("input.jpg", &in, NULL);
vips_resize(in, &out, 0.5, NULL);
vips_jpegsave(out, "output.jpg", NULL);
govips (Go):
image, _ := vips.NewImageFromFile("input.jpg")
image.Resize(0.5, vips.KernelAuto)
image.WriteToFile("output.jpg")
Summary
libvips is a powerful, mature C library for image processing, offering extensive features and potentially better performance. govips provides a Go-native wrapper around libvips, simplifying usage for Go developers but potentially introducing some overhead. The choice between them depends on specific project requirements, language preferences, and performance needs.
Fast, simple, scalable, Docker-ready HTTP microservice for high-level image processing
Pros of Imaginary
- Provides a complete HTTP microservice for image processing
- Supports a wide range of image operations and transformations
- Offers Docker support for easy deployment and scaling
Cons of Imaginary
- Larger codebase and potentially more complex setup
- May have higher resource requirements due to its microservice architecture
Code Comparison
Imaginary (HTTP handler):
func ImageHandler(o ServerOptions, fn func(*ImageOptions, http.ResponseWriter) error) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" && r.Method != "POST" {
ErrorReply(w, ErrUnsupportedMethod, o)
return
}
// ... (additional code)
}
}
Govips (image processing):
func Resize(image *C.VipsImage, scale float64, kernel Kernel) (*C.VipsImage, error) {
var out *C.VipsImage
err := C.vips_resize_bridge(image, &out, C.double(scale), C.int(kernel))
return out, handleImageError(err)
}
Imaginary provides a full-featured HTTP microservice for image processing, while Govips focuses on providing Go bindings for the libvips image processing library. Imaginary offers more out-of-the-box functionality and easier deployment, but may have higher resource requirements. Govips provides lower-level access to image processing functions, allowing for more fine-grained control and potentially better performance in specific use cases.
Fast and secure standalone server for resizing, processing, and converting images on the fly
Pros of imgproxy
- Ready-to-use image processing server with a wide range of features
- Supports multiple image formats and processing operations out of the box
- Designed for high performance and scalability in production environments
Cons of imgproxy
- Less flexible for custom image processing workflows
- Requires running as a separate service, which may increase infrastructure complexity
- Limited to predefined image processing operations
Code Comparison
imgproxy (configuration example):
IMGPROXY_BIND=:8080
IMGPROXY_LOCAL_FILESYSTEM_ROOT=/mnt/images
IMGPROXY_USE_ETAG=true
IMGPROXY_QUALITY=80
IMGPROXY_MAX_SRC_RESOLUTION=50
govips (Go code example):
import "github.com/davidbyttow/govips/v2/vips"
image, err := vips.NewImageFromBuffer(buffer)
err = image.Resize(0.5, vips.KernelAuto)
buffer, err = image.WriteToBuffer(".jpg", vips.NewJpegExportParams())
govips is a Go library for image processing using libvips, offering more flexibility for custom image processing workflows. It's suitable for embedding within Go applications but requires more development effort. imgproxy, on the other hand, is a standalone image processing server that's easier to deploy and use out of the box, but with less customization options.
thumbor is an open-source photo thumbnail service by globo.com
Pros of Thumbor
- Written in Python, making it accessible to a wider range of developers
- Extensive feature set, including face detection and smart cropping
- Large and active community with frequent updates and contributions
Cons of Thumbor
- Generally slower performance compared to Go-based solutions
- Higher resource consumption, especially for memory-intensive operations
- More complex setup and configuration process
Code Comparison
Thumbor (Python):
from thumbor.handlers.imaging import ImagingHandler
class MyHandler(ImagingHandler):
def get(self):
# Custom image processing logic
super(MyHandler, self).get()
Govips (Go):
import "github.com/davidbyttow/govips/v2/vips"
func processImage(buffer []byte) ([]byte, error) {
image, err := vips.NewImageFromBuffer(buffer)
// Custom image processing logic
return image.ExportJpeg(vips.NewJpegExportParams())
}
Summary
Thumbor offers a feature-rich solution with a large community, making it suitable for projects requiring advanced image processing capabilities. Govips, on the other hand, provides better performance and resource efficiency, making it ideal for high-throughput applications. The choice between the two depends on specific project requirements, development team expertise, and performance needs.
A caching, resizing image proxy written in Go
Pros of imageproxy
- Designed specifically as an image proxy server, offering more specialized features for this use case
- Supports a wider range of image transformations and manipulations out-of-the-box
- Includes caching mechanisms for improved performance in high-traffic scenarios
Cons of imageproxy
- Less flexible for general-purpose image processing tasks outside of proxy use cases
- May have higher resource usage due to its comprehensive feature set
- Written in Go, which might be less familiar to some developers compared to C-based libraries
Code Comparison
imageproxy:
func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/favicon.ico" {
http.Error(w, "404 Not Found", http.StatusNotFound)
return
}
// ... (additional code)
}
govips:
func Resize(image *C.VipsImage, scale float64) (*C.VipsImage, error) {
var out *C.VipsImage
err := C.vips_resize_bridge(image, &out, C.double(scale))
return out, handleImageError(err)
}
Both projects serve different purposes: imageproxy is a full-fledged image proxy server, while govips is a low-level binding to the libvips image processing library. The choice between them depends on specific project requirements and use cases.
An image resizing server written in Go
Pros of picfit
- More comprehensive image processing solution with built-in HTTP server and caching
- Supports multiple storage backends (e.g., S3, Google Cloud Storage)
- Offers a wider range of image manipulation operations out-of-the-box
Cons of picfit
- Less actively maintained (last commit over 2 years ago)
- Fewer stars and contributors on GitHub
- More complex setup and configuration compared to govips
Code Comparison
picfit (main.go):
engine := picfit.NewEngine()
engine.AddProcessor(processor.NewImageProcessor())
engine.AddStorage(storage.NewFileSystemStorage("/path/to/images"))
server := http.NewServer(engine)
server.Run(":8080")
govips (example.go):
image, err := vips.NewImageFromBuffer(buffer)
err = image.Resize(0.5, vips.KernelAuto)
buffer, err = image.ExportJpeg(vips.NewJpegExportParams())
Both libraries offer image processing capabilities, but picfit provides a more complete solution with an HTTP server and storage options, while govips focuses on low-level image operations with high performance.
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
govips
A lightning fast image processing and resizing library for Go
This package wraps the core functionality of libvips image processing library by exposing all image operations on first-class types in Go.
Libvips is generally 4-8x faster than other graphics processors such as GraphicsMagick and ImageMagick. Check the benchmark: Speed and Memory Use
The intent for this is to enable developers to build extremely fast image processors in Go, which is suited well for concurrent requests.
Project Status
govips now includes a built-in code generator (cmd/vipsgen/) that uses libvips GObject introspection to auto-generate type-safe Go bindings. This covers 193+ operations across 9 categories (arithmetic, colour, conversion, convolution, create, freqfilt, histogram, morphology, resample), while complex operations like image I/O remain as hand-written bindings for full control.
Requirements
- libvips 8.14+
- C compatible compiler such as gcc 4.6+ or clang 3.0+
- Go 1.23+
Dependencies
MacOS
Use homebrew to install vips and pkg-config:
brew install vips pkg-config
Windows
The recommended approach on Windows is to use Govips via WSL and Ubuntu.
If you need to run Govips natively on Windows, it's not difficult but will require some effort. We don't have a recommended environment or setup at the moment. Windows is also not in our list of CI/CD targets so Govips is not regularly tested for compatibility. If you would be willing to setup and maintain a robust CI/CD Windows environment, please open a PR, we would be pleased to accept your contribution and support Windows as a platform.
Installation
go get -u github.com/davidbyttow/govips/v2/vips
MacOS note
On MacOS, govips may not compile without first setting an environment variable:
export CGO_CFLAGS_ALLOW="-Xpreprocessor"
Examples
Every example below assumes this setup:
package main
import (
"fmt"
"os"
"github.com/davidbyttow/govips/v2/vips"
)
func main() {
vips.Startup(nil)
defer vips.Shutdown()
// ... example code goes here
}
1. Load an image and export as JPEG
The basics: load from a file, auto-rotate based on EXIF data, and write it back out.
image, err := vips.NewImageFromFile("input.jpg")
if err != nil {
log.Fatal(err)
}
// Fix orientation from EXIF metadata
if err := image.AutoRotate(); err != nil {
log.Fatal(err)
}
buf, _, err := image.ExportJpeg(vips.NewJpegExportParams())
if err != nil {
log.Fatal(err)
}
os.WriteFile("output.jpg", buf, 0644)
2. Resize an image
Scale an image down by 50% using the Lanczos3 kernel (the sharpest option).
image, err := vips.NewImageFromFile("photo.jpg")
if err != nil {
log.Fatal(err)
}
// Scale to 50%
if err := image.Resize(0.5, vips.KernelLanczos3); err != nil {
log.Fatal(err)
}
buf, _, err := image.ExportJpeg(&vips.JpegExportParams{Quality: 85})
if err != nil {
log.Fatal(err)
}
os.WriteFile("resized.jpg", buf, 0644)
3. Create a thumbnail with smart crop
NewThumbnailFromFile is the fastest way to generate thumbnails. It decodes only the pixels it needs.
// Load and shrink to fit within 200x200, cropping to the most interesting region
image, err := vips.NewThumbnailFromFile("photo.jpg", 200, 200, vips.InterestingAttention)
if err != nil {
log.Fatal(err)
}
buf, _, err := image.ExportJpeg(&vips.JpegExportParams{Quality: 80})
if err != nil {
log.Fatal(err)
}
os.WriteFile("thumb.jpg", buf, 0644)
4. Convert between formats
Load a JPEG and export it as WebP and PNG.
image, err := vips.NewImageFromFile("photo.jpg")
if err != nil {
log.Fatal(err)
}
// Export as WebP (lossy)
webpBuf, _, err := image.ExportWebp(&vips.WebpExportParams{Quality: 75})
if err != nil {
log.Fatal(err)
}
os.WriteFile("photo.webp", webpBuf, 0644)
// Export as PNG
pngBuf, _, err := image.ExportPng(&vips.PngExportParams{Compression: 6})
if err != nil {
log.Fatal(err)
}
os.WriteFile("photo.png", pngBuf, 0644)
5. Crop and extract a region
Pull out a specific rectangle from an image.
image, err := vips.NewImageFromFile("photo.jpg")
if err != nil {
log.Fatal(err)
}
// Extract a 300x300 region starting at (50, 100)
if err := image.ExtractArea(50, 100, 300, 300); err != nil {
log.Fatal(err)
}
buf, _, err := image.ExportPng(vips.NewPngExportParams())
if err != nil {
log.Fatal(err)
}
os.WriteFile("cropped.png", buf, 0644)
6. Blur and sharpen
Apply a Gaussian blur or sharpen an image.
image, err := vips.NewImageFromFile("photo.jpg")
if err != nil {
log.Fatal(err)
}
// Gaussian blur with sigma=3.0
if err := image.GaussianBlur(3.0); err != nil {
log.Fatal(err)
}
buf, _, err := image.ExportJpeg(vips.NewJpegExportParams())
if err != nil {
log.Fatal(err)
}
os.WriteFile("blurred.jpg", buf, 0644)
// Or sharpen instead: sigma=1.0, x1=2.0, m2=3.0
image2, _ := vips.NewImageFromFile("photo.jpg")
if err := image2.Sharpen(1.0, 2.0, 3.0); err != nil {
log.Fatal(err)
}
buf2, _, _ := image2.ExportJpeg(vips.NewJpegExportParams())
os.WriteFile("sharpened.jpg", buf2, 0644)
7. Rotate and flip
Rotate by fixed angles and flip along an axis.
image, err := vips.NewImageFromFile("photo.jpg")
if err != nil {
log.Fatal(err)
}
// Rotate 90 degrees clockwise
if err := image.Rotate(vips.Angle90); err != nil {
log.Fatal(err)
}
// Flip horizontally
if err := image.Flip(vips.DirectionHorizontal); err != nil {
log.Fatal(err)
}
buf, _, err := image.ExportJpeg(vips.NewJpegExportParams())
if err != nil {
log.Fatal(err)
}
os.WriteFile("rotated.jpg", buf, 0644)
8. Adjust brightness, saturation, and hue
Modulate works in the LCH color space. Brightness and saturation are multipliers (1.0 = no change), hue is an angle shift in degrees.
image, err := vips.NewImageFromFile("photo.jpg")
if err != nil {
log.Fatal(err)
}
// Bump brightness by 20%, desaturate by 30%, shift hue by 45 degrees
if err := image.Modulate(1.2, 0.7, 45); err != nil {
log.Fatal(err)
}
buf, _, err := image.ExportJpeg(&vips.JpegExportParams{Quality: 90})
if err != nil {
log.Fatal(err)
}
os.WriteFile("adjusted.jpg", buf, 0644)
9. Composite two images (watermark overlay)
Layer one image on top of another using Porter-Duff blending.
base, err := vips.NewImageFromFile("photo.jpg")
if err != nil {
log.Fatal(err)
}
overlay, err := vips.NewImageFromFile("watermark.png")
if err != nil {
log.Fatal(err)
}
// Place the watermark at position (20, 20) using "over" blending
if err := base.Composite(overlay, vips.BlendModeOver, 20, 20); err != nil {
log.Fatal(err)
}
buf, _, err := base.ExportJpeg(&vips.JpegExportParams{Quality: 90})
if err != nil {
log.Fatal(err)
}
os.WriteFile("watermarked.jpg", buf, 0644)
10. Add a text label
Overlay text directly onto an image.
image, err := vips.NewImageFromFile("photo.jpg")
if err != nil {
log.Fatal(err)
}
err = image.Label(&vips.LabelParams{
Text: "govips",
Font: "sans bold 16",
OffsetX: vips.ValueOf(20),
OffsetY: vips.ValueOf(20),
Opacity: 0.8,
Color: vips.Color{R: 255, G: 255, B: 255},
Alignment: vips.AlignLow,
Width: vips.ValueOf(200),
Height: vips.ValueOf(40),
})
if err != nil {
log.Fatal(err)
}
buf, _, err := image.ExportPng(vips.NewPngExportParams())
if err != nil {
log.Fatal(err)
}
os.WriteFile("labeled.png", buf, 0644)
11. Flatten transparency onto a background color
Remove the alpha channel by compositing onto a solid color.
image, err := vips.NewImageFromFile("logo.png")
if err != nil {
log.Fatal(err)
}
// Flatten alpha onto white
if err := image.Flatten(&vips.Color{R: 255, G: 255, B: 255}); err != nil {
log.Fatal(err)
}
buf, _, err := image.ExportJpeg(&vips.JpegExportParams{Quality: 90})
if err != nil {
log.Fatal(err)
}
os.WriteFile("flattened.jpg", buf, 0644)
12. Embed an image in a larger canvas
Center an image inside a larger canvas with a colored background.
image, err := vips.NewImageFromFile("icon.png")
if err != nil {
log.Fatal(err)
}
w, h := image.Width(), image.Height()
// Center the image inside a 800x600 canvas with a dark background
if err := image.EmbedBackgroundRGBA(
(800-w)/2, (600-h)/2, 800, 600,
&vips.ColorRGBA{R: 30, G: 30, B: 30, A: 255},
); err != nil {
log.Fatal(err)
}
buf, _, err := image.ExportPng(vips.NewPngExportParams())
if err != nil {
log.Fatal(err)
}
os.WriteFile("embedded.png", buf, 0644)
13. Load from a byte buffer and strip metadata
Useful when you're reading images from HTTP requests or databases.
inputBytes, err := os.ReadFile("photo.jpg")
if err != nil {
log.Fatal(err)
}
image, err := vips.NewImageFromBuffer(inputBytes)
if err != nil {
log.Fatal(err)
}
// Strip all EXIF/metadata for privacy
if err := image.RemoveMetadata(); err != nil {
log.Fatal(err)
}
buf, _, err := image.ExportJpeg(&vips.JpegExportParams{
Quality: 80,
StripMetadata: true,
})
if err != nil {
log.Fatal(err)
}
os.WriteFile("clean.jpg", buf, 0644)
14. Build a pipeline: thumbnail, sharpen, and export as AVIF
Chain multiple operations together. Each method mutates the image in place, so you can pipeline them naturally.
image, err := vips.NewThumbnailFromFile("photo.jpg", 800, 600, vips.InterestingCentre)
if err != nil {
log.Fatal(err)
}
if err := image.Sharpen(0.7, 1.0, 2.0); err != nil {
log.Fatal(err)
}
buf, _, err := image.ExportAvif(&vips.AvifExportParams{
Quality: 50,
Effort: 4,
})
if err != nil {
log.Fatal(err)
}
os.WriteFile("output.avif", buf, 0644)
15. Stream images with io.Reader and io.Writer
Load directly from any io.Reader (HTTP body, S3 stream, file handle) and save directly to any io.Writer â without buffering the full compressed input or output in Go memory. If the reader also implements io.Seeker (like os.File), libvips uses random access for efficient loading of formats like HEIF. One exception on the save side: TIFF requires seekable output, so it is encoded in memory and written to w in a single chunk (bytes identical to ExportTiff).
// Stream-load: no full-file buffer in Go memory
f, err := os.Open("input.heic")
if err != nil {
log.Fatal(err)
}
defer f.Close()
image, err := vips.LoadImageFromReader(f, nil)
if err != nil {
log.Fatal(err)
}
defer image.Close()
// Process as usual
if err := image.AutoRotate(); err != nil {
log.Fatal(err)
}
// Stream-save: encoded chunks written directly to the output
out, err := os.Create("output.jpg")
if err != nil {
log.Fatal(err)
}
defer out.Close()
err = image.SaveToWriter(out, vips.ImageTypeJPEG, &vips.ExportParams{
Quality: 85,
})
if err != nil {
log.Fatal(err)
}
For the full set of format-specific export options (PNG palette, WebP near-lossless/target size, TIFF compression, HEIF bit depth, ...), use the typed variants: SaveToWriterJpeg, SaveToWriterPng, SaveToWriterWebp, SaveToWriterTiff, SaveToWriterHeif, SaveToWriterGif.
For non-seekable readers (e.g. http.Request.Body), libvips buffers header data up to ~1 GB by default. Lower the limit to bound memory usage:
vips.Startup(nil)
vips.SetPipeReadLimit(100 * 1024 * 1024) // 100 MB
16. End-to-end streaming transcode
TranscodeStream runs reader â decode â transform â encode â writer as one pipeline, picking the cheapest decode strategy automatically:
// Upload handler: stream the request body through a JPEG transcode into
// content-addressed storage, hashing the output while writing.
hasher := sha256.New()
err := vips.TranscodeStream(req.Body, io.MultiWriter(hasher, storage), &vips.TranscodeOptions{
Format: vips.ImageTypeJPEG,
AutoRotate: true,
ExportParams: &vips.ExportParams{Quality: 85, Interlaced: false},
})
Two decode strategies:
- Sequential fast path â when no random-access transform is needed, pixels flow from reader to writer in one pass. Peak RAM is bounded by libvips line caches, independent of file size and pixel count. Available directly via
LoadImageFromReaderwithparams.Access.Set(vips.AccessSequential); the source then stays connected (keep the reader open) untilClose. - Materialized path â when random access is required (e.g. EXIF rotation), the decoded frame is rendered in one streaming pass to memory or, above a threshold, to an unlinked scratch file on disc. RAM stays bounded either way; the source is released as soon as materialization finishes.
vips.SetStreamDiscThreshold(64 << 20) // decoded frames >64 MB go to scratch disc (default 100 MB, or VIPS_DISC_THRESHOLD)
vips.SetStreamScratchDir("/var/scratch") // default os.TempDir()
Which operations keep the sequential fast path? Sequential images may only be read top-to-bottom, once. Safe: resize/thumbnail (shrink), crop, flatten, colorspace conversion, sharpen/blur (line kernels), horizontal flip, format conversion. Forcing materialization: rotation (90°/180°/270°), vertical flip, AutoRotate for EXIF orientations 3â8 (TranscodeStream detects this from the header automatically), FindTrim, SmartCrop, and anything else that reads pixels out of order. Attempting a random-access operation on a sequential image fails with an "out of order read" error from libvips.
Codec caveats. True end-to-end streaming also depends on the codec: progressive (interlaced) JPEG and interlaced PNG cannot stream â on decode the codec buffers all input before emitting rows, and on encode (govips' default JPEG params set Interlace: true) it buffers the whole image before writing the first byte. Pass Interlaced: false for streaming output. HEIF/HEIC decodes whole-frame inside libheif regardless of access mode, and TIFF output is encoded in memory (seekable-output requirement). Non-seekable inputs additionally accumulate compressed bytes read so far (bounded by SetPipeReadLimit).
Where errors surface. On the default (materialized) load, truncated or erroring streams fail inside LoadImageFromReader/TranscodeStream during materialization. On the sequential path the load only reads the header, so the same failures surface from the operation that first consumes pixels â typically SaveToWriter â wrapped with the original reader error (errors.Is works).
See the examples/ folder for more.
Running tests
$ make test
Code Generation
The built-in generator lives in cmd/vipsgen/ and uses libvips GObject introspection to discover operations and their arguments at build time. To regenerate the bindings:
go generate ./vips/
This produces the generated files in vips/gen_*.{c,h,go}. You should not need to regenerate unless you are adding support for new libvips operations.
Memory usage note
MALLOC_ARENA_MAX
libvips uses GLib for memory management, and it brings GLib memory fragmentation
issues to heavily multi-threaded programs. First thing you can try if you noticed
constantly growing RSS usage without Go's sys memory growth is set MALLOC_ARENA_MAX:
MALLOC_ARENA_MAX=2 application
This will reduce GLib memory appetites by reducing the number of malloc arenas that it can create. By default GLib creates one are per thread, and this would follow to memory fragmentation.
Jemalloc
If the arena option doesn't help, you can try replacing the standard allocator with jemalloc,
which emphasizes fragmentation avoidance and scalable concurrency support.
To do this, you need to install the libjemalloc-dev package.
And pass the following flags for build command:
CGO_CFLAGS="-fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free" CGO_LDFLAGS="-ljemalloc" go build
Contributing
Feel free to file issues or create pull requests. See this guide on contributing for more information.
Credits
Thanks to:
- John Cupitt for creating and maintaining libvips
- Toni Melisma for pushing to a 2.x release
- wix.com for the govips logo and lots of great functionality
- All of our fantastic contributors
License
MIT
Top Related Projects
A fast image processing library with low memory needs.
Fast, simple, scalable, Docker-ready HTTP microservice for high-level image processing
Fast and secure standalone server for resizing, processing, and converting images on the fly
thumbor is an open-source photo thumbnail service by globo.com
A caching, resizing image proxy written in Go
An image resizing server written in Go
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot