lilliput

repository·master·Indexed 24 days ago

https://github.com/discord/lilliput

A high-performance Go library for image resizing and transcoding that utilizes C libraries to minimize memory allocation and garbage collection overhead. It supports JPEG, PNG, WebP, AVIF, animated GIFs, and first-frame extraction from MOV and WEBM. Key features include the ImageOps API for efficient resizing, Framebuffer for manual pixel manipulation, and support for embedded ICC profiles (sRGB, Rec709, Rec2020, Rec601 PAL/NTSC). Compatible with OSX ARM64 and Linux.

Tokens
4.4K
Snippets
2
Records
34
Agent score
84%

What's inside lilliput

  1. Overview of lilliput

    master

    lilliput is a high-performance image resizing library for Go. It leverages mature C libraries to perform decompression, resizing, and compression with minimal memory allocation and Go garbage collection overhead, making it suitable for high-throughput services.

    Supported Formats:

    • JPEG
    • PNG
    • WebP (static and animated)
    • AVIF (static and animated)
    • Animated GIFs
    • MOV and WEBM (first frame extraction only)

    Platform Support:

    • OSX ARM64
    • Linux
  2. Understand libjpeg-turbo licensing coverage

    master

    libjpeg-turbo is covered by three compatible BSD-style open source licenses depending on which part of the project is being used:

    • IJG (Independent JPEG Group) License: Applies to the libjpeg API library and associated programs (including inherited code and modifications to it).
    • Modified (3-clause) BSD License: Covers the TurboJPEG API library and associated programs.
    • zlib License: Covers the libjpeg-turbo SIMD extensions.
  3. How to use embedded ICC profiles in Lilliput

    master
    Lilliput uses precomputed ICC profiles embedded as byte arrays in C++ header files. This allows the library to provide consistent color profiles without requiring runtime file I/O. This is especially useful for processing images extracted from video that reference a color-space but lack an embedded ICC profile.
  4. How ImageOps and Decoder work together for resizing

    master

    For most use cases, you should use ImageOps instead of manually calling Decoder.DecodeTo. ImageOps provides a high-level API for resizing and encoding that minimizes allocations by allowing object reuse.

    Workflow:

    1. Create an ImageOps object with lilliput.NewImageOps(dimension). This object can be reused for multiple operations.
    2. Use o.Transform(decoder, opts, dst) to perform the resize and transcode in one step.

    Important Constraints:

    • The Decoder must not have had DecodeTo() called on it before passing it to Transform().
    • You can call decoder.Header() before transforming if you need to inspect properties.
    • The dst slice provided to Transform will be returned as a slice pointing to the same underlying memory but with a length reflecting the actual encoded image size.
  5. Generate ICC profile C++ headers

    master

    If you need to regenerate or create new ICC profile headers, use the provided Python script. The script converts .icc files into C-style byte arrays saved as header files.

    Requirements

    • Python 3.x

    Steps

    1. Prepare the ICC Profile Files: Ensure you have the .icc files available in the same directory as the script or provide the correct path to each file.
    2. Run the Script: Execute the script to generate the headers.
    python3 icc_profile.py
  6. Comply with libjpeg-turbo licenses when distributing binaries or statically linked applications

    master

    If you are distributing only libjpeg-turbo binaries (without source) or an application that statically links with libjpeg-turbo, you must follow these documentation requirements:

    1. General Attribution: Your product documentation must include the following message: This software is based in part on the work of the Independent JPEG Group.
    2. TurboJPEG API Attribution: If your binary distribution includes or uses the TurboJPEG API, your product documentation must also include the full text of the Modified BSD License.
  7. How to use the lilliput example

    master

    Lilliput includes a command-line example that prints file information, resizes, and transcodes images. To run it:

    1. Install the package: go get github.com/discord/lilliput
    2. Navigate to the examples directory and build: go build from the examples/ directory.
    go get github.com/discord/lilliput
    # then run from the examples/ directory
    go build
  8. Comply with libjpeg-turbo licenses when distributing modified source

    master

    If you are distributing a modified version of the libjpeg-turbo source code, you must adhere to the following requirements:

    1. Preserve Notices: Do not alter or remove any existing copyright or license notices from the source.
    2. Add Your Own Notice: You must add your own copyright notice to the header of every source file you have modified. If the file lacks an existing copyright header, add a notice stating that you modified the file.
    3. Include IJG README: You must include the README.ijg file in your distribution and must not alter any of its copyright or license text.
  9. Decode media using avCodecDecoder

    master

    The avCodecDecoder (internal type, typically accessed via a constructor in the package) handles decoding of various video and image formats using FFmpeg's avcodec. You can use it to extract metadata, codec information, and decode frames from a byte buffer.

    To use a decoder, you must provide a byte buffer containing the media data. Note that HEVC and AV1 decoding support must be enabled at build time using specific -ldflags.

    Build Flags for Decoder Support:

    • HEVC: -ldflags="-X=github.com/discord/lilliput.hevcEnabled=true"
    • AV1: -ldflags="-X=github.com/discord/lilliput.av1Enabled=true"
  10. Configure ImageOptions for Transform

    master

    When using ImageOps.Transform, pass an *lilliput.ImageOptions to control the output:

    • FileType: The target file extension (e.g., ".jpeg", ".png").
    • Width: Target width in pixels.
    • Height: Target height in pixels.
    • ResizeMethod:
      • lilliput.ImageOpsNoResize: No resizing performed.
      • lilliput.ImageOpsFit: Performs a cropping resize that preserves aspect ratio (does not stretch).
    • NormalizeOrientation: If true, inspects orientation and normalizes the output (undoes JPEG EXIF orientation).
    • EncodeOptions: A map[int]int used to control output quality (see Encoder section for valid keys).
  11. Encode images with the Encoder

    master

    The Encoder writes pixels from a Framebuffer into a compressed format.

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

    • extension: e.g., ".jpeg" or ".png".
    • decodedBy: The Decoder used to decompress the image. This is required for .gif encoding (GIFs can only be created from source GIFs).
    • dst: The byte slice to write into.

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

    • opts: Optional map to control quality. Valid keys include:
      • lilliput.JpegQuality (1 - 100)
      • lilliput.PngCompression (0 - 9)
      • lilliput.WebpQuality (0 - 100)
      • lilliput.AvifQuality (0 - 100)

    Cleanup: Always call e.Close() to release resources.

  12. Use Framebuffer for manual pixel manipulation

    master

    A Framebuffer contains raw, decompressed pixel data. While ImageOps is preferred for general resizing, Framebuffer is useful for low-level operations.

    Key Methods:

    • lilliput.NewFramebuffer(width, height int) *lilliput.Framebuffer: Creates an empty buffer.
    • f.ResizeTo(width, height int, dst *lilliput.Framebuffer) error: Resizes f into dst. Does not preserve aspect ratio.
    • f.Fit(width, height int, dst *lilliput.Framebuffer) error: Performs a cropping resize into dst while preserving aspect ratio.
    • f.OrientationTransform(orientation lilliput.ImageOrientation): Rotates/mirrors the buffer. Passing the orientation from ImageHeader normalizes the image to default orientation.
    • f.Close(): Releases resources. Must be called when finished.