• Stars
    star
    1,923
  • Rank 23,135 (Top 0.5 %)
  • Language
    C++
  • License
    Other
  • Created about 7 years ago
  • Updated about 1 month ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Resize images and animated GIFs in Go

lilliput

lilliput resizes images in Go.

Lilliput relies on mature, high-performance C libraries to do most of the work of decompressing, resizing and compressing images. It aims to do as little memory allocation as possible and especially not to create garbage in Go. As a result, it is suitable for very high throughput image resizing services.

Lilliput supports resizing JPEG, PNG, WEBP and animated GIFs. It can also convert formats. Lilliput also has some support for getting the first frame from MOV and WEBM videos.

Lilliput presently only supports OSX and Linux.

Example

Lilliput comes with a fully working example that runs on the command line. The example takes a user supplied filename and prints some basic info about the file. It then resizes and transcodes the image (if flags are supplied) and saves the resulting file.

To use the example, go get github.com/discord/lilliput and then run go build from the examples/ directory.

License

Lilliput is released under MIT license (see LICENSE). Additionally, lilliput ships with other libraries, each provided under its own license. See third-party-licenses for more info.

Usage

First, import "github.com/discord/lilliput".

Decoder

Lilliput is concerned with in-memory images, so the decoder requires image data to be in a []byte buffer.

func lilliput.NewDecoder([]byte buf) (lilliput.Decoder, error)

Create a new Decoder object from the compressed image contained by buf. This will return an error when the magic bytes of the buffer don't match one of the supported image types.

func (d lilliput.Decoder) Header() (lilliput.ImageHeader, error)

Read and return the image's header. The header contains the image's metadata. Returns error if the image has a malformed header. An image with a malformed header cannot be decoded.

func (d lilliput.Decoder) Description() string

Returns a string describing the image's type, e.g. "JPEG" or "PNG".

func (h lilliput.Decoder) Duration() time.Duration

Returns the length of the content. Returns 0 for static images and animated GIFs.

func (d lilliput.Decoder) DecodeTo(f *lilliput.Framebuffer) error

Fully decodes the image and writes its pixel data to f. Returns an error if the decoding process fails. If the image contains multiple frames, then each call returns a subsequent frame. io.EOF is returned when the image does not contain any more data to be decoded.

Users of lilliput generally should not call DecodeTo and should instead use an ImageOps object.

func (d lilliput.Decoder) Close()

Closes the decoder and releases resources. The Decoder object must have .Close() called when it is no longer in use.

ImageOps

Lilliput provides a convenience object to handle image resizing and encoding from an open Decoder object. The ImageOps object can be created and then reused, which reduces memory allocations. Generally, users should prefer the ImageOps object over manually controlling the resize and encode process.

func lilliput.NewImageOps(dimension int) *lilliput.ImageOps

Create an ImageOps object that can operate on images up to dimension x dimension pixels in size. This object can be reused for multiple operations.

func (o *lilliput.ImageOps) Transform(decoder lilliput.Decoder, opts *lilliput.ImageOptions, dst []byte) ([]byte, error)

Transform the compressed image contained in a Decoder object into the desired output type. The decoder must not have DecodeTo() called on it already. However, it is ok to call decoder.Header() if you would like to check image properties before transforming the image. Returns an error if the resize or encoding process fails.

The resulting compressed image will be written into dst. The returned []byte slice will point to the same region as dst but with a different length, so that you can tell where the image ends.

Fields for lilliput.ImageOptions are as follows

  • FileType: file extension type, e.g. ".jpeg"

  • Width: number of pixels of width of output image

  • Height: number of pixels of height of output image

  • ResizeMethod: one of lilliput.ImageOpsNoResize or lilliput.ImageOpsFit. Fit behavior is the same as Framebuffer.Fit() -- it performs a cropping resize that does not stretch the image.

  • NormalizeOrientation: If true, Transform() will inspect the image orientation and normalize the output so that it is facing in the standard orientation. This will undo JPEG EXIF-based orientation.

  • EncodeOptions: Of type map[int]int, same options accepted as Encoder.Encode(). This controls output encode quality.

func (o *lilliput.ImageOps) Clear()

Clear out all pixel data contained in ImageOps object from any previous operations. This function does not need to be called between Transform() calls. The user may choose to do this if they want to remove image data from memory.

func (o *lilliput.ImageOps) Close()

Close the ImageOps object and release resources. The ImageOps object must have .Close() called when it is no longer in use.

ImageHeader

This interface returns basic metadata about an image. It is created by calling Decoder.Header().

func (h lilliput.ImageHeader) Width() int

Returns the image's width in number of pixels.

func (h lilliput.ImageHeader) Height() int

Returns the image's height in number of pixels.

func (h lilliput.ImageHeader) PixelType() lilliput.PixelType

Returns the basic pixel type for the image's pixels.

func (h lilliput.ImageHeader) Orientation() lilliput.ImageOrientation

Returns the metadata-based orientation of the image. This function can be called on all image types but presently only detects orientation in JPEG images. An orientation value of 1 indicates default orientation. All other values indicate some kind of rotation or mirroring.

PixelType

func (p lilliput.PixelType) Depth() int

Returns the number of bits per pixel.

func (p lilliput.PixelType) Channels() int

Returns the number of channels per pixel, e.g. 3 for RGB or 4 for RGBA.

Framebuffer

This type contains a raw array of pixels, decompressed from an image. In general, you will want to use the ImageOps object instead of operating on Framebuffers manually.

func lilliput.NewFramebuffer(width, height int) *lilliput.Framebuffer

Create a new Framebuffer with given dimensions without any pixel data.

func (f *lilliput.Framebuffer) Clear()

Set contents of framebuffer to 0, clearing out any previous pixel data.

func (f *lilliput.Framebuffer) Width() int

Returns the width in number of pixels of the contained pixel data, if any. This does not return the capacity of the buffer.

func (f *lilliput.Framebuffer) Height() int

Returns the height in number of pixels of the contained pixel data, if any. This does not return the capacity of the buffer.

func (f *lilliput.Framebuffer) PixelType() lilliput.PixelType

Returns the PixelType of the contained pixel data, if any.

func (f *lilliput.Framebuffer) OrientationTransform(orientation lilliput.ImageOrientation)

Rotate and/or mirror framebuffer according to orientation value. If you pass the orientation value given by the image's ImageHeader, then the resulting image has its orientation normalized to the default orientation.

func (f *lilliput.Framebuffer) ResizeTo(width, height int, dst *lilliput.Framebuffer) error

Perform a resize into dst of f according to given dimensions. This function does not preserve the source's aspect ratio if the new dimensions have a different ratio. The resize can fail if the destination is not large enough to hold the new image.

func (f *lilliput.Framebuffer) Fit(width, height int, dst *lilliput.Framebuffer) error

Perform a cropping resize into dst of f according to given dimensions. This function does preserve the source's aspect ratio. The image will be cropped along one axis if the new dimensions have a different ratio than the source. The cropping will occur equally on the edges, e.g. if the source image is too tall for the new ratio, then the destination will have rows of pixels from the top and bottom removed. Returns error if the destination is not large enough to contain the resized image.

func (f *lilliput.Framebuffer) Close()

Closes the framebuffer and releases resources. The Framebuffer object must have .Close() called when it is no longer in use.

Encoder

The Encoder takes a Framebuffer and writes the pixels into a compressed format.

func lilliput.NewEncoder(extension string, decodedBy lilliput.Decoder, dst []byte) (lilliput.Encoder, error)

Create a new Encoder object that writes to dst. extension should be a file extension-like string, e.g. ".jpeg" or ".png". decodedBy should be the Decoder used to decompress the image, if any. decodedBy may be left as nil in most cases but is required when creating a .gif encoder. That is, .gif outputs can only be created from source GIFs.

func (e lilliput.Encoder) Encode(buffer lilliput.Framebuffer, opts map[int]int) ([]byte, error)

Encodes the Framebuffer supplied into the output dst given when the Encoder was created. The returned []byte will point to the same buffer as dst but can be a shorter slice, so that if dst has 50MB of capacity but the image only occupies 30KB, you can tell where the image data ends. This function returns an error if the encoding process fails.

opts is optional and may be left nil. It is used to control encoder behavior e.g. map[int]int{lilliput.JpegQuality: 80} to set JPEG outputquality to 80.

Valid keys/values for opts are

  • JpegQuality (1 - 100)
  • PngCompression (0 - 9)
  • WebpQuality (0 - 100).
func (e lilliput.Encoder) Close()

Close the Encoder and release resources. The Encoder object must have .Close() called when it is no longer in use.

Building Dependencies

Go does not provide any mechanism for arbitrary building of dependencies, e.g. invoking make or cmake. In order to make lilliput usable as a standard Go package, prebuilt static libraries have been provided for all of lilliput's dependencies on Linux and OSX. In order to automate this process, lilliput ships with build scripts alongside compressed archives of the sources of its dependencies. These build scripts are provided for OSX and Linux.

More Repositories

1

discord-api-docs

Official Discord API Documentation
Markdown
5,543
star
2

manifold

Fast batch message passing between nodes for Erlang/Elixir.
Elixir
1,618
star
3

sorted_set_nif

Elixir SortedSet backed by a Rust-based NIF
Elixir
1,532
star
4

discord-open-source

List of open source communities living on Discord
JavaScript
1,319
star
5

focus-rings

A centralized system for displaying and stylizing focus indicators anywhere on a webpage.
TypeScript
1,120
star
6

fastglobal

Fast no copy globals for Elixir & Erlang.
Elixir
1,097
star
7

discord-rpc

C++
983
star
8

airhornbot

The only bot for Discord you'll ever need.
TypeScript
851
star
9

semaphore

Fast semaphore using ETS.
Elixir
718
star
10

react-dnd-accessible-backend

An add-on backend for `react-dnd` that provides support for keyboards and screenreaders by default.
TypeScript
576
star
11

ex_hash_ring

A fast consistent hash ring implementation in Elixir.
Elixir
475
star
12

discord-example-app

Basic Discord app with examples
JavaScript
434
star
13

OverlappingPanels

Overlapping Panels is a gestures-driven navigation UI library for Android
Kotlin
420
star
14

SimpleAST

Extensible Android library for both parsing text into Abstract Syntax Trees and rendering those trees as rich text.
Kotlin
360
star
15

discord-interactions-js

JS/Node helpers for Discord Interactions
TypeScript
345
star
16

instruments

Simple and Fast metrics for Elixir
Elixir
295
star
17

focus-layers

Tiny React hooks for isolating focus within subsections of the DOM.
TypeScript
292
star
18

discord-api-spec

OpenAPI specification for Discord APIs
237
star
19

discord-oauth2-example

Discord OAuth2 Example
Python
225
star
20

loqui

RPC Transport Layer - with minimal bullshit.
Rust
220
star
21

erlpack

High Performance Erlang Term Format Packer
Cython
211
star
22

cloudflare-sample-app

Example discord bot using Cloudflare Workers
JavaScript
197
star
23

access

Access, a centralized portal for employees to transparently discover, request, and manage their access for all internal systems needed to do their jobs
Python
190
star
24

use-memo-value

Reuse the previous version of a value unless it has changed
TypeScript
170
star
25

zen_monitor

Efficient Process.monitor replacement
Elixir
167
star
26

deque

Fast bounded deque using two rotating lists.
Elixir
141
star
27

avatar-remix-bot

TypeScript
127
star
28

linked-roles-sample

JavaScript
119
star
29

punt

Punt is a tiny and lightweight daemon which helps ship logs to Elasticsearch.
Go
113
star
30

embedded-app-sdk

🚀 The Discord Embedded App SDK lets you build rich, multiplayer experiences as Activities inside Discord.
TypeScript
109
star
31

sample-game-integration

An example using Discord's API and local RPC socket to add Voice and Text chat to an instance or match based multiplayer game.
JavaScript
105
star
32

endanger

Build Dangerfiles with ease.
TypeScript
96
star
33

discord-interactions-python

Useful tools for building interactions in Python
Python
93
star
34

react-base-hooks

Basic utility React hooks
TypeScript
77
star
35

dynamic-pool

a lock-free, thread-safe, dynamically-sized object pool.
Rust
76
star
36

itsdangerous-rs

A rust port of itsdangerous!
Rust
72
star
37

gen_registry

Simple and efficient local Process Registry
Elixir
71
star
38

confetti-cannon

Launch Confetti
TypeScript
45
star
39

discord-react-forms

Forms... in React
JavaScript
43
star
40

discord-interactions-php

PHP utilities for building Discord Interaction webhooks
PHP
40
star
41

babel-plugin-define-patterns

Create constants that replace various expressions at build-time
JavaScript
39
star
42

eslint-traverse

Create a sub-traversal of an AST node in your ESLint plugin
JavaScript
30
star
43

rapidxml

Mirror of rapidxml from http://rapidxml.sourceforge.net/
C++
29
star
44

memory_size

Elixir
29
star
45

gamesdk-and-dispatch

Public issue tracker for the Discord Game SDK and Dispatch
22
star
46

dispenser

Elixir library to buffer and send events to subscribers.
Elixir
17
star
47

eslint-plugin-discord

Custom ESLint rules for Discord
JavaScript
16
star
48

chromium-build

Python
15
star
49

hash_ring

hash_ring
C
14
star
50

limited_queue

Simple Elixir queue, with a constant-time `size/1` and a maximum capacity
Elixir
13
star
51

perceptual

A smarter volume slider scale
TypeScript
13
star
52

discord_vigilante

12
star
53

heroku-sample-app

Example discord bot using Heroku
JavaScript
11
star
54

postcss-theme-shorthand

Converts `light-` and `dark-` prefixed CSS properties into corresponding light/dark theme globals
JavaScript
11
star
55

babel-plugin-strip-object-freeze

Replace all instances of Object.freeze(value) with value
JavaScript
10
star
56

libyuv

our fork of libyuv for webrtc
C++
10
star
57

lilliput-rs

Lilliput, in Rust!
Rust
9
star
58

lilliput-bench

Benchmarker for lilliput
Python
8
star
59

sqlite3

Mirror of sqlite amalgamation from https://www.sqlite.org/
C
7
star
60

openh264

C++
6
star
61

slate-react-package-fork

TypeScript
6
star
62

rlottiebinding-ios

rlottie ios submodule
Starlark
5
star
63

jemalloc_info

A small library for exporting jemalloc allocation data in Elixir
Elixir
5
star
64

libnice

Fork of https://nice.freedesktop.org/wiki/
C
5
star
65

libvpx

C
4
star
66

libsrtp

Fork of libsrtp
C
4
star
67

RLottieAndroid

C++
4
star
68

opentelemetry-rust-datadog

Rust
4
star
69

slate-package-fork

JavaScript
4
star
70

lilliput-dep-source

Convenient source repo for Lilliput's dependencies
3
star
71

slate-hotkeys-package-fork

3
star
72

rules_ios

Bazel rules for building iOS applications and frameworks
Starlark
2
star
73

cocoapods-bazel

A Cocoapods plugin for automatically generating Bazel BUILD files
Ruby
2
star
74

eslint-plugin-react-discord

Fork of eslint-plugin-react
JavaScript
1
star