GithubHelp home page GithubHelp logo

sudokai / imageresizer Goto Github PK

View Code? Open in Web Editor NEW
8.0 3.0 9.0 3.09 MB

libvips image resizing server

License: MIT License

Makefile 1.52% Go 90.87% C 4.12% Dockerfile 3.48%
libvips image-resizing thumbnails

imageresizer's Introduction

imageresizer

Warning: at an early stage of development, NOT suitable for production use.

Prototype of a image resizing server written in Go.

I decided to write this software after dealing with image thumbnailing at scale (15 million images, multiple thumbnail sizes, 500k new images per month) at work.

imageresizer attempts to address the image thumbnailing needs of a company such as the one I work for:

  • High volume of basic resize operations. Fast resizing is a must.
  • Caching of thumbnails and originals, to avoid hitting S3 continuously ($$$). Caches should use LRU or LFU with a maximum on-disk size.
  • Ease of deployment and maintenance. No supervisors or http servers.
  • New deployments should incur near-zero downtime.

Getting started

Building and running the code:

Install libvips (minimum required version is v8.5, due to the fact that we use vips_thumbnail_buffer and libvips' new sequential mode).

If you run an older version or another distro: just compile libvips following the official instructions (very easy to do, it takes 60 seconds):

Building libvips from a source tarball

Then:

This project uses Go 1.11's new go modules, if you don't have Go 1.11 yet, run make dep to get the dependencies first.

make
./imageresizer

URL format:

/{width:[0-9]+}x{height:[0-9]+}/crop/{gravity}/{path}
/{width:[0-9]+}x{height:[0-9]+}/fit/{extend}/{path}

Supported resize operations:

  • crop: resize cropping the edges.
  • fit: resize without cropping (make image smaller if needed).

At the moment, only two gravity settings are supported:

  • s: smart
  • c: center

Supported extend settings (fit then extend edges until target size):

  • 0: do not extend image
  • rrggbb: rgb color in hex format, e.g. ffdea5.

Features

  • Fast resizes using libvips through a cgo bridge (JPEG and PNG)
  • Local caching of originals and thumbnails with approximate LRU eviction based on file atimes.
  • Smart cropping.
  • Image uploads and deletions.
  • S3 storage support.
  • Graceful zero-downtime upgrades/restarts.
  • 304 Not Modified responses.

Examples

Photo Result
Original @samuelclara (2400x1600) Original
480x640/crop/s 480x640/crop/s
480x640/crop/c 480x640/crop/c
480x640/fit/0 480x640/fit/0
Original @natcatalyst (3456ร—5184) Original
300/crop/s 300x300 smart crop
500/fit/000000 500x500 fit

Configuration properties

Put your configuration properties inside a config.properties file in the same directory as the imageresizer executable. The config below contains the default values:

# Listen address
server.addr=:8080

# File storage settings
local.prefix=./images/originals

# S3 settings
s3.enable=false
s3.region={S3 region}
s3.bucket={bucketName}
s3.prefix="" # root path of original images

# Caches
cache.orig.enable=true
cache.orig.path=./images/cache
cache.orig.maxsize=1G
cache.orig.shards=256
cache.thumb.enable=true
cache.thumb.path=./images/thumbnails
cache.thumb.maxsize=1G
cache.thumb.shards=256
cache.loader.sleep=50
cache.loader.files=100
cache.loader.threshold=200

# Uploads
upload.maxsize=50M

# Etag cache size (num items)
etag.cache.enable=true
etag.cache.maxsize=50000

Roadmap

In order of priority:

  • Older libvips (<8.5) compatibility.
  • WEBP and GIF support?
  • Security controls for uploads and deletions?
  • Secure links?
  • Cache sharding.
  • LFU instead of LRU.

Acknowledgements

imageresizer's People

Contributors

asnelzin avatar jhernandezb avatar jskswamy avatar pr0gramista avatar ptisserand avatar sudokai avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

imageresizer's Issues

Current caching data structures do not scale well

Both the ETag cache and FileStore metadata rely on maps protected by a sync.RWMutex. This is probably enough for most users, but it does not scale well.

  • High concurrency will lead to lock contention.
  • Big maps will be slow to GC.

Some ideas:

  • Creating cache partitions and assigning one mutex to each partition will reduce lock contention.
  • Some interesting cache implementations:

Listen to file system modifications to update in-memory file metadata

Right now, we walk the file system once at startup to load the file access times needed for LRU eviction and update the metadata manually when an image is accessed/deleted/created through the API.

This has many drawbacks, such as the fact that the program will not be aware of outside file system modifications (modifications not made through the api) of subdirectories and files under the directory root of a store.FileStore. We should listen to file system modifications and keep the metadata in sync.

Check fsnotify/fsnotify and store.FileStore to get started.

Migrate S3 code to use minio-go

By migrating S3Store to use minio-go instead of aws-sdk-go, it is my understanding that we will be able to have a single storage codebase supporting Amazon S3, DigitalOcean Spaces, Scaleway Object Storage and Backblaze B2.

libvips resize operations should use a thread pool

Currently each request that requests a thumbnail creates a libvips thread to do the resizing. Goroutines are cheap but C threads not so much. We should use a thread pool of libvips threads to handle resize operations.

Some ideas:

  • Queue resize operations within a buffered channel, then have a pool of goroutines listen on the channel.
  • Resize results should be sent back with another channel.

Add top, right, bottom, left resize gravities

Currently we support center and smart resize gravities. Add support for top, right, bottom, left gravity types:

/{width}x{height}/crop/{gravity}/example.jpg

Resize gravity:

  • Top t: crop bottom
  • Right r: crop left
  • Bottom b: crop top
  • Left l: crop left

Check vips.go to get started.

Create a Docker image for the project

Create a Docker image for the project. It should integrate libvips 8.5+ and this program. Use a minimal base image such as alpine.

Expose the environment variables and the volumes you deem necessary.

Decouple file metadata from an in-memory map

Currently, the file metadata needed for operating the LRU caches is stored in a in-memory map structure. Since this map is non-persistent, each time the program is started it walks the entire cache directory tree to populate this map.

We should decouple the metadata from this data structure and offer Redis as an alternative metadata datastore.

Ability to resize remote images

Add the ability to resize remote images by specifying the remote url as the last parameter of the url:

/300x400/crop/s/{remoteUrl}

remoteUrl should be a full remote url: https://example.com/example.jpg

Given the example above, the original image should be cached locally as {originalCacheDir}/example.com/example.jpg and the thumbnail as {thumbnailCacheDir}/300x400/crop/s/example.com/example.jpg.

Expose a configuration property to enable remote image resizing.

Check net/http and api/routes.go to get started.

Allow resizing on only one axis

Currently, we resize images on both axis, e.g.

/400x300/crop/sm/example.jpg

This will generate a 400x300 image.

Implement resizing on only one axis, e.g.

/400x/crop/sm/example.jpg

Output a 400x{originalHeight} image.

/x300/crop/sm/example.jpg

Output a {originalWidth}x300 image.

Check routes.go and vips.go to get started.

Implement secure links

Add 2 config properties:

  • secure.links.enabled: true|false
  • secure.links.secret: a string that will be the secret used to create the secure hash.

Given an url to access an image, such as

/400x300/crop/s/example.jpg

If the secure.links.enabled config property is true and secure.links.secret is mysecret, the above url to the resource should be disabled (returning a http 403), instead the following url scheme should be used to access the image:

/{secureHash}/400x300/crop/s/example.jpg

where {secureHash} should be an MD5 hash of 400x300/crop/s/example.jpgmysecret.

Take a look at crypto/md5 and api/routes.go to get started.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.