lilliput

package module
v0.0.0-...-24268aa Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 22, 2022 License: MIT Imports: 9 Imported by: 0

README

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.

Documentation

Overview

Package lilliput resizes and encodes images from compressed images

Index

Constants

View Source
const (
	JpegQuality    = int(C.CV_IMWRITE_JPEG_QUALITY)
	PngCompression = int(C.CV_IMWRITE_PNG_COMPRESSION)
	WebpQuality    = int(C.CV_IMWRITE_WEBP_QUALITY)

	JpegProgressive = int(C.CV_IMWRITE_JPEG_PROGRESSIVE)

	OrientationTopLeft     = ImageOrientation(C.CV_IMAGE_ORIENTATION_TL)
	OrientationTopRight    = ImageOrientation(C.CV_IMAGE_ORIENTATION_TR)
	OrientationBottomRight = ImageOrientation(C.CV_IMAGE_ORIENTATION_BR)
	OrientationBottomLeft  = ImageOrientation(C.CV_IMAGE_ORIENTATION_BL)
	OrientationLeftTop     = ImageOrientation(C.CV_IMAGE_ORIENTATION_LT)
	OrientationRightTop    = ImageOrientation(C.CV_IMAGE_ORIENTATION_RT)
	OrientationRightBottom = ImageOrientation(C.CV_IMAGE_ORIENTATION_RB)
	OrientationLeftBottom  = ImageOrientation(C.CV_IMAGE_ORIENTATION_LB)
)

Variables

View Source
var (
	ErrInvalidImage     = errors.New("unrecognized image format")
	ErrDecodingFailed   = errors.New("failed to decode image")
	ErrBufTooSmall      = errors.New("buffer too small to hold image")
	ErrFrameBufNoPixels = errors.New("Framebuffer contains no pixels")
	ErrSkipNotSupported = errors.New("skip operation not supported by this decoder")
)
View Source
var (
	ErrGifEncoderNeedsDecoder = errors.New("GIF encoder needs decoder used to create image")
)

Functions

func SetGIFMaxFrameDimension

func SetGIFMaxFrameDimension(dim uint64)

SetGIFMaxFrameDimension sets the largest GIF width/height that can be decoded

Types

type Decoder

type Decoder interface {
	// Header returns basic image metadata from the image.
	// This is done lazily, reading only the first part of the image and not
	// a full decode.
	Header() (*ImageHeader, error)

	// Close releases any resources associated with the Decoder
	Close()

	// Description returns a string description of the image type, such as
	// "PNG"
	Description() string

	// Duration returns the duration of the content. This property is 0 for
	// static images and animated GIFs.
	Duration() time.Duration

	// DecodeTo fully decodes the image pixel data into f. Generally users should
	// prefer instead using the ImageOps object to decode images.
	DecodeTo(f *Framebuffer) error

	// SkipFrame skips a frame if the decoder supports multiple frames
	// and returns io.EOF if the last frame has been reached
	SkipFrame() error
}

A Decoder decompresses compressed image data.

func NewDecoder

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

NewDecoder returns a Decoder which can be used to decode image data provided in buf. If the first few bytes of buf do not point to a valid magic string, an error will be returned.

type Encoder

type Encoder interface {
	// Encode encodes the pixel data in f into the dst provided to NewEncoder. Encode quality
	// options can be passed into opt, such as map[int]int{lilliput.JpegQuality: 80}
	Encode(f *Framebuffer, opt map[int]int) ([]byte, error)

	// Close releases any resources associated with the Encoder
	Close()
}

An Encoder compresses raw pixel data into a well-known image type.

func NewEncoder

func NewEncoder(ext string, decodedBy Decoder, dst []byte) (Encoder, error)

NewEncoder returns an Encode which can be used to encode Framebuffer into compressed image data. ext should be a string like ".jpeg" or ".png". decodedBy is optional and can be the Decoder used to make the Framebuffer. dst is where an encoded image will be written.

type Framebuffer

type Framebuffer struct {
	// contains filtered or unexported fields
}

Framebuffer contains an array of raw, decoded pixel data.

func NewFramebuffer

func NewFramebuffer(width, height int) *Framebuffer

NewFramebuffer creates the backing store for a pixel frame buffer.

func (*Framebuffer) Clear

func (f *Framebuffer) Clear()

Clear resets all of the pixel data in Framebuffer.

func (*Framebuffer) Close

func (f *Framebuffer) Close()

Close releases the resources associated with Framebuffer.

func (*Framebuffer) Duration

func (f *Framebuffer) Duration() time.Duration

Duration returns the length of time this frame plays out in an animated image

func (*Framebuffer) Fit

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

Fit performs a resizing and cropping transform on the Framebuffer and puts the result in the provided destination Framebuffer. This function does preserve aspect ratio but will crop columns or rows from the edges of the image as necessary in order to keep from stretching the image content. Returns an error if the destination is not large enough to hold the given dimensions.

func (*Framebuffer) Height

func (f *Framebuffer) Height() int

Height returns the height of the contained pixel data in number of pixels. This may differ from the capacity of the framebuffer.

func (*Framebuffer) OrientationTransform

func (f *Framebuffer) OrientationTransform(orientation ImageOrientation)

OrientationTransform rotates and/or mirrors the Framebuffer. Passing the orientation given by the ImageHeader will normalize the orientation of the Framebuffer.

func (*Framebuffer) PixelType

func (f *Framebuffer) PixelType() PixelType

PixelType returns the PixelType information of the contained pixel data, if any.

func (*Framebuffer) ResizeTo

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

ResizeTo performs a resizing transform on the Framebuffer and puts the result in the provided destination Framebuffer. This function does not preserve aspect ratio if the given dimensions differ in ratio from the source. Returns an error if the destination is not large enough to hold the given dimensions.

func (*Framebuffer) Width

func (f *Framebuffer) Width() int

Width returns the width of the contained pixel data in number of pixels. This may differ from the capacity of the framebuffer.

type ImageHeader

type ImageHeader struct {
	// contains filtered or unexported fields
}

ImageHeader contains basic decoded image metadata.

func (*ImageHeader) Height

func (h *ImageHeader) Height() int

Height returns the height of the image in number of pixels.

func (*ImageHeader) IsAnimated

func (h *ImageHeader) IsAnimated() bool

func (*ImageHeader) Orientation

func (h *ImageHeader) Orientation() ImageOrientation

ImageOrientation returns the metadata-based image orientation.

func (*ImageHeader) PixelType

func (h *ImageHeader) PixelType() PixelType

PixelType returns a PixelType describing the image's pixels.

func (*ImageHeader) Width

func (h *ImageHeader) Width() int

Width returns the width of the image in number of pixels.

type ImageOps

type ImageOps struct {
	// contains filtered or unexported fields
}

ImageOps is a reusable object that can resize and encode images.

func NewImageOps

func NewImageOps(maxSize int) *ImageOps

NewImageOps creates a new ImageOps object that will operate on images up to maxSize on each axis.

func (*ImageOps) Clear

func (o *ImageOps) Clear()

Clear resets all pixel data in ImageOps. This need not be called between calls to Transform. You may choose to call this to remove image data from memory.

func (*ImageOps) Close

func (o *ImageOps) Close()

Close releases resources associated with ImageOps

func (*ImageOps) Transform

func (o *ImageOps) Transform(d Decoder, opt *ImageOptions, dst []byte) ([]byte, error)

Transform performs the requested transform operations on the Decoder specified by d. The result is written into the output buffer dst. A new slice pointing to dst is returned with its length set to the length of the resulting image. Errors may occur if the decoded image is too large for ImageOps or if Encoding fails.

It is important that .Decode() not have been called already on d.

type ImageOpsSizeMethod

type ImageOpsSizeMethod int
const (
	ImageOpsNoResize ImageOpsSizeMethod = iota
	ImageOpsFit
	ImageOpsResize
)

type ImageOptions

type ImageOptions struct {
	// FileType should be a string starting with '.', e.g.
	// ".jpeg"
	FileType string

	// Width controls the width of the output image
	Width int

	// Height controls the height of the output image
	Height int

	// ResizeMethod controls how the image will be transformed to
	// its output size. Notably, ImageOpsFit will do a cropping
	// resize, while ImageOpsResize will stretch the image.
	ResizeMethod ImageOpsSizeMethod

	// NormalizeOrientation will flip and rotate the image as necessary
	// in order to undo EXIF-based orientation
	NormalizeOrientation bool

	// EncodeOptions controls the encode quality options
	EncodeOptions map[int]int

	// MaxEncodeFrames controls the maximum number of frames that will be resized
	MaxEncodeFrames int

	// MaxEncodeDuration controls the maximum duration of animated image that will be resized
	MaxEncodeDuration time.Duration
}

ImageOptions controls how ImageOps resizes and encodes the pixel data decoded from a Decoder

type ImageOrientation

type ImageOrientation int

ImageOrientation describes how the decoded image is oriented according to its metadata.

type PixelType

type PixelType int

PixelType describes the base pixel type of the image.

func (PixelType) Channels

func (p PixelType) Channels() int

Channels returns the number of channels in the PixelType.

func (PixelType) Depth

func (p PixelType) Depth() int

Depth returns the number of bits in the PixelType.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL