Resize images and animated GIFs in Go

Overview

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.

Comments
  • New release build

    New release build

    Hi lilliput team!

    I was wondering when the next release version will be released? Currently, if I use go get..., my project works, but if I use dep ensure, it fails due to a C++ issue. I believe this was solved in one of the commits that got merged after v1.1. Could you release an update release to solve this?

    Thanks!

    opened by theRoughCode 10
  • Add range check to NewDecoder

    Add range check to NewDecoder

    The current code produces the following error on an empty buffer. The added range check prevents it from panicking, instead returning an error.

    panic: runtime error: index out of range
    
    goroutine 1 [running]:
    github.com/discordapp/lilliput.newOpenCVDecoder(0xc4200e6200, 0x0, 0x200, 0x0, 0x0, 0xc420130040)
            /home/alexrsagen/go/src/github.com/discordapp/lilliput/opencv.go:234 +0x16a
    github.com/discordapp/lilliput.NewDecoder(0xc4200e6200, 0x0, 0x200, 0x0, 0x200, 0x0, 0x0)
            /home/alexrsagen/go/src/github.com/discordapp/lilliput/lilliput.go:67 +0x72
    
    opened by alexrsagen 9
  • Libraries in deps/linux/lib/ can not be used when making a shared object

    Libraries in deps/linux/lib/ can not be used when making a shared object

    Numerous errors arise when building the example main.go, such as:

    /usr/bin/ld: src/github.com/discordapp/lilliput/deps/linux/lib/libavcodec.a(bsf.o): relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a shared object; recompile with -fPIC
    /usr/bin/ld: src/github.com/discordapp/lilliput/deps/linux/lib/libavcodec.a(vp8dsp_init.o): relocation R_X86_64_32S against hidden symbol `ff_put_vp8_pixels8_mmx' can not be used when making a shared object
    

    Tested environments:

    • go1.7.4 linux/amd64 + gcc version 6.3.0 20170516 (Debian 6.3.0-18)
    • go1.9.2 linux/amd64 + gcc version 6.4.0 (Gentoo Hardened 6.4.0 p1.1)

    Thanks.

    opened by mapx 8
  • Buffer too small

    Buffer too small

    Hi team,

    I've been encountering this issue when using the library: buffer too small to hold image. Is there a way to know how big of a buffer is needed or a way to bypass passing in a buffer?

    Thanks!

    opened by theRoughCode 7
  •  recompile with -fPIC in debian

    recompile with -fPIC in debian

    Using a golang docker image (which I believe is based on Debian), I get the errors described in #6. Presumably they are appearing again because of #45.

    16:12 $ docker run -it golang:1.11 /bin/bash
    [email protected]:/go# ls
    bin  src
    [email protected]:/go# go get github.com/discordapp/lilliput
    # github.com/discordapp/lilliput
    /usr/bin/ld: src/github.com/discordapp/lilliput/deps/linux/lib/libswscale.a(swscale.o): relocation R_X86_64_32 against `.rodata.str1.8' can not be used when making a shared object; recompile with -fPIC
    /usr/bin/ld: src/github.com/discordapp/lilliput/deps/linux/lib/libswscale.a(utils.o): relocation R_X86_64_32S against `.bss' can not be used when making a shared object; recompile with -fPIC
    

    Here's my thoughts: Things work fine in the latest centos docker image. After some research, it looks like recent versions of gcc (6+) provide a "-pie" option by default that requires shared libraries be compiled with "fPIC". I found that if I added -no-pie to all the #cgo linux LDFLAGS: lines (and added -no-pie to CGO_LDFLAGS_ALLOW) it would build just fine in the golang:1.11 image.

    I suppose we could also downgrade the version of gcc too.

    My question: What do you guys do? Do you have build recommendations? It would be nice to put some stuff in the README so that future users don't stumble like I did. Or am I missing something obvious?

    opened by dougnd 6
  • Memory management using Lilliput

    Memory management using Lilliput

    Hi,

    We are using lilliput as custom backend in picfit, it's a better way to handle gif than golang image standard library.

    Since Lilliput handles memory using buffer, the allocated memory of the image server is increasing over time with the following config:

    // DefaultMaxBufferSize is the maximum size of buffer for lilliput
    const DefaultMaxBufferSize = 8192
    
    // DefaultImageBufferSize is the default image buffer size for lilliput
    const DefaultImageBufferSize = 50 * 1024 * 1024
    

    memory

    What approach do you recommend in this case?

    Thank you

    opened by thoas 5
  • Can not build the lib

    Can not build the lib

    Hello there. I am stack for a couple of days

    can not build the lilliput under the alpine linux in docker

    here is the full error : https://pastebin.com/ZZrK12Xh

    this is what I fetching in container

    RUN apk add --no-cache --virtual .fetch-deps \ libtirpc-dev \ libtirpc \ procps \ imlib2 \ gcc \ ca-certificates \ curl \ nano \ file \ ffmpeg \ gawk \ build-base \ linux-headers \ autoconf \ nasm \ cmake \ libtool \ automake

    but still had no luck :(

    is there anything else I need to do ?

    opened by dubrovine 4
  • data races question

    data races question

    Hi, Is such global variables will be secure, if you will run e.g. tests in parallel, for code that using lilliput with -race flag? https://github.com/discordapp/lilliput/blob/master/opencv.go#L25 Cuz I'm afraid here is race condition thx.

    opened by mymtw 4
  • Strange distortion/artifacts

    Strange distortion/artifacts

    Hi, this lib is the best for generating thumbnails that I tested so far. Thanks for the great job! :)

    Unfortunately I have few files that give strange results. Probably it's my fault (file may be broken somehow) but in players it looks ok. Maybe it's worth to look at it?

    I tried turning on and off NormalizeOrientation and used all 3 ResizeMethod options in my code but that doesn't have any effect on this. As I tested - FFmpeg gets first frame correctly.

    My setup: Ubuntu Desktop 16.04 64bit go version go1.9.2 linux/amd64

    Steps to reproduce:

    1. Clone repo with commit c2b38847094c248c1dad51293c60bdbb9397a2a1 (latest when I'm writing this)
    2. Get example .webm file to reproduce and unzip it 0d2cfdb1b7e04d66f4e4bf712932a03591696bbf515eb03d4a1a0663b97637d0.webm.zip
    wget https://github.com/SystemZ/gotag/files/1514352/0d2cfdb1b7e04d66f4e4bf712932a03591696bbf515eb03d4a1a0663b97637d0.webm.zip
    
    1. Use examples/main.go to convert .webm to .png (or .jpg)
    go run main.go -input test.webm -output test.png
    
    1. Thumbnail is not looking correctly

    zxejh9d6cng5jl4c

    opened by SystemZ 4
  • go get error

    go get error

    go get -u github.com/discord/[email protected]
    # github.com/discord/lilliput
    ../../../../pkg/mod/github.com/discord/[email protected]/lilliput.go:31:13: undefined: ImageHeader
    ../../../../pkg/mod/github.com/discord/[email protected]/lilliput.go:46:14: undefined: Framebuffer
    ../../../../pkg/mod/github.com/discord/[email protected]/lilliput.go:57:12: undefined: Framebuffer
    ../../../../pkg/mod/github.com/discord/[email protected]/lilliput.go:87:10: undefined: newGifDecoder
    ../../../../pkg/mod/github.com/discord/[email protected]/lilliput.go:90:23: undefined: newOpenCVDecoder
    ../../../../pkg/mod/github.com/discord/[email protected]/lilliput.go:95:9: undefined: newAVCodecDecoder
    ../../../../pkg/mod/github.com/discord/[email protected]/ops.go:50:16: undefined: Framebuffer
    ../../../../pkg/mod/github.com/discord/[email protected]/ops.go:66:30: undefined: Framebuffer
    ../../../../pkg/mod/github.com/discord/[email protected]/ops.go:70:33: undefined: Framebuffer
    ../../../../pkg/mod/github.com/discord/[email protected]/ops.go:119:53: undefined: ImageOrientation
    ../../../../pkg/mod/github.com/discord/[email protected]/lilliput.go:95:9: too many errors
    
    opened by loeffel-io 3
  • on partial frame, allocate a transparency color

    on partial frame, allocate a transparency color

    The GIF spec is fun and allows the GIF itself to define a canvas/viewport size, and then each frame can define its own size. Frames can also define a starting coordinate, so for example a 400x400 gif might have a 30x20 frame that starts at (180, 100).

    I took a lazy approach to these partial frames. Rather than trying to figure out how to rescale the coordinates, e.g. what is 99% of (180, 100), I decided to just composite the new frame on top of the previous frame and then use standard resizing for the composited frame. In the encoder, we consider which color from the palette to use. The right color could be a transparency color if the color at (x, y) is close to the color at (x, y) in the previous frame. And so my intention was that we would turn these partial frames into full frames with a bunch of transparency everywhere.

    This almost worked except that sometimes frames don't have a transparency color. There's an extension block in the gif format that tells you which color is transparency, it's essentially just an override that tells you "if you see this color palette index, it /actually/ means transparency, ignore whatever color is there". This PR forces the gif to have a transparency color in the last index of the relevant color palette. We're essentially discarding one color. I chose the last index because I'm assuming the original gif encoder put the most common colors first, though I haven't validated that assumption. At the least, this will lose some color info, but the weird partial frame glitches will be gone.

    opened by brian-armstrong-discord 3
  • Add support for animated WebP images

    Add support for animated WebP images

    This PR adds support for resizing animated WebP images through the libwebpmux/demux sublibraries. It uses the WebPAnimEncoder/WebPAnimDecoder APIs to implement new Encoder/Decoder classes instead of relying on OpenCV, similar to the giflib codec.

    This does add an additional dependency on those two libraries, but since they're included with the already required libwebp library (just disabled by default), this shouldn't cause much more hassle beyond rebuilding dependencies.

    I've done some testing with animated WebPs I had on hand, as well as making sure that non-animated WebPs go through the normal OpenCV route, but it's probably a good idea to run it with other files as well (I only happen to have lossless files at the moment).

    I'm not quite sure what happened with the png headers - I guess they were turned into links when I updated the dependencies? I can revert those changes if necessary, but I expect they'll be reverted the moment someone else updates them again.

    Closes #97

    opened by MCJack123 8
  • Add support for APNG files (fix #101)

    Add support for APNG files (fix #101)

    Currently, lilliput removes all of the APNG-specific data when resizing an animated PNG file, causing it to only output the first frame of the animation. This pull request adds a new encoder and decoder type for animated PNG files that properly handles subsequent frames.

    GIF-to-APNG conversion currently does not work, since the number of frames in a GIF is not known until all frames have been read, while the total number of frames must be known before encoding the first frame of an animated PNG.

    This change also requires an update to the dependencies to include the patch adding APNG support to libpng. Since I'm not sure what the process for updating them is, I haven't touched the dependencies beyond updating build-deps-linux.sh.

    opened by commandblockguy 2
  • APNG support

    APNG support

    Currently, lilliput removes all of the APNG-specific data when resizing an animated PNG file, causing it to only output the first frame of the animation. Ideally, it should resize and output the remainder of the APNG file as well.

    opened by commandblockguy 0
  • Versions not picked up by pkg.go.dev

    Versions not picked up by pkg.go.dev

    https://pkg.go.dev/github.com/discord/lilliput

    I think it’s because this repository’s version tags are missing PATCH. e.g. v1.2 should instead be v1.2.0

    instead, pseudo version numbers are automatically getting picked up by the module proxy https://golang.org/doc/modules/version-numbers#pseudo-version-number

    it should be fairly easy to add new tags to existing releases which include PATCH

    opened by JeremyLoy 0
  • Apple M1 issues

    Apple M1 issues

    I'm having some problems with lilliput on my M1 machine.

    Running go get github.com/discord/lilliput returns me:

    # github.com/discord/lilliput
    ld: warning: ignoring file ../../go/pkg/mod/github.com/discord/[email protected]/deps/osx/lib/libswscale.a, building for macOS-arm64 but attempting to link with file built for macOS-x86_64
    ld: warning: ignoring file ../../go/pkg/mod/github.com/discord/[email protected]7514bd5f/deps/osx/lib/libavformat.a, building for macOS-arm64 but attempting to link with file built for macOS-x86_64
    ld: warning: ignoring file ../../go/pkg/mod/github.com/discord/[email protected]/deps/osx/lib/libavfilter.a, building for macOS-arm64 but attempting to link with file built for macOS-x86_64
    ld: warning: ignoring file ../../go/pkg/mod/github.com/discord/[email protected]/deps/osx/lib/libz.a, building for macOS-arm64 but attempting to link with file built for macOS-x86_64
    ld: warning: ignoring file ../../go/pkg/mod/github.com/discord/[email protected]/deps/osx/lib/libbz2.a, building for macOS-arm64 but attempting to link with file built for macOS-x86_64
    ld: warning: ignoring file ../../go/pkg/mod/github.com/discord/[email protected]/deps/osx/lib/libavutil.a, building for macOS-arm64 but attempting to link with file built for macOS-x86_64
    ld: warning: ignoring file ../../go/pkg/mod/github.com/discord/[email protected]/deps/osx/lib/libavcodec.a, building for macOS-arm64 but attempting to link with file built for macOS-x86_64
    ld: warning: ignoring file ../../go/pkg/mod/github.com/discord/[email protected]/deps/osx/lib/libopencv_core.a, building for macOS-arm64 but attempting to link with file built for macOS-x86_64
    ld: warning: ignoring file ../../go/pkg/mod/github.com/discord/[email protected]/deps/osx/lib/libwebp.a, building for macOS-arm64 but attempting to link with file built for macOS-x86_64
    ld: warning: ignoring file ../../go/pkg/mod/github.com/discord/[email protected]/deps/osx/share/OpenCV/3rdparty/lib/libippicv.a, missing required architecture arm64 in file ../../go/pkg/mod/github.com/discord/[email protected]/deps/osx/share/OpenCV/3rdparty/lib/libippicv.a (2 slices)
    ld: warning: ignoring file ../../go/pkg/mod/github.com/discord/[email protected]/deps/osx/lib/libpng.a, building for macOS-arm64 but attempting to link with file built for macOS-x86_64
    ld: warning: ignoring file ../../go/pkg/mod/github.com/discord/[email protected]/deps/osx/lib/libjpeg.a, building for macOS-arm64 but attempting to link with file built for macOS-x86_64
    ld: warning: ignoring file ../../go/pkg/mod/github.com/discord/[email protected]/deps/osx/lib/libgif.a, building for macOS-arm64 but attempting to link with file built for macOS-x86_64
    ld: warning: ignoring file ../../go/pkg/mod/github.com/discord/[email protected]/deps/osx/lib/libopencv_imgproc.a, building for macOS-arm64 but attempting to link with file built for macOS-x86_64
    ld: warning: ignoring file ../../go/pkg/mod/github.com/discord/[email protected]/deps/osx/lib/libopencv_imgcodecs.a, building for macOS-arm64 but attempting to link with file built for macOS-x86_64
    Undefined symbols for architecture arm64:
      "_DGifCloseFile", referenced from:
          _giflib_decoder_release in _x006.o
      "_DGifExtensionToGCB", referenced from:
          _giflib_decoder_decode_frame in _x006.o
          _giflib_encoder_encode_frame in _x006.o
      ...
      "_sws_scale", referenced from:
          _avcodec_decoder_decode in _x005.o
    ld: symbol(s) not found for architecture arm64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    

    My machine go version and arch is as follow:

    ❯ go version
    go version go1.17 darwin/arm64
    

    Is this a known issue? Is there any workaround?

    Cheers

    opened by jjoliveira 3
Releases(v1.2)
Owner
Discord
A new way to chat with your communities and friends. Discord is the easiest way to communicate over voice, video, and text.
Discord
Asset storage and on-the-fly image resize

air - Asset & Image Resize Asset storage and on-the-fly image resize powered by libvips. Uploading an asset $ http -f POST http://127.0.0.1:1323/uploa

Alexandre Ferland 0 Feb 5, 2022
go library for image programming (merge, crop, resize, watermark, animate, ease, transit)

Result Terminal Code mergi -t TT -i https://raw.githubusercontent.com/ashleymcnamara/gophers/master/Facepalm_Gopher.png -r "131 131" -i https://raw.gi

Noel Yahan 185 Sep 29, 2022
Content aware image resize library

Caire is a content aware image resize library based on Seam Carving for Content-Aware Image Resizing paper. How does it work An energy map (edge detec

Endre Simo 10k Sep 26, 2022
Fast and secure standalone server for resizing and converting remote images

imgproxy imgproxy is a fast and secure standalone server for resizing and converting remote images. The main principles of imgproxy are simplicity, sp

imgproxy 6.5k Oct 3, 2022
Read and write Netpbm images from Go programs

netpbm Introduction netpbm is a package for the Go programming language that implements image decoders and encoders for the Netpbm image formats. The

Scott Pakin 16 Jul 1, 2022
A go library for reading and creating ISO9660 images

iso9660 A package for reading and creating ISO9660, forked from https://github.com/kdomanski/iso9660. Requires Go 1.13 or newer. Joliet and Rock Ridge

Karpelès Lab Inc. 8 Mar 4, 2021
A cross-platform tool to convert images into ascii art and print them on the console

A cross-platform tool to convert images into ascii art and print them on the console

Zoraiz Hassan 1k Oct 2, 2022
Cloud function + website for resizing, cropping and bordering images for pragalicious.com

Cloud function + website for resizing, cropping and bordering images for pragalicious.com

Ard Scheirlynck 0 Jan 23, 2022
Pure Golang Library that allows simple LSB steganography on images

Steganography Lib Steganography is a library written in Pure go to allow simple LSB steganography on images. It is capable of both encoding and decodi

Rafael Passos 155 Sep 26, 2022
Reproducing images with geometric primitives.

Primitive Pictures Reproducing images with geometric primitives. How it Works A target image is provided as input. The algorithm tries to find the sin

Michael Fogleman 12k Oct 4, 2022
An iterative algorithm to generate high quality triangulated images.

Triangula uses a modified genetic algorithm to triangulate images. It works best with images smaller than 3000px and with fewer than 3000 points, typically producing an optimal result within a couple of minutes.

null 3.8k Sep 24, 2022
Generate high-quality triangulated art from images.

An iterative algorithm to generate high quality triangulated images.

null 53 May 26, 2021
Convert images to computer generated art using delaunay triangulation.

▲ Triangle is a tool for generating triangulated image using delaunay triangulation. It takes a source image and converts it to an abstract image comp

Endre Simo 2k Sep 19, 2022
Emoji images for Ebiten

Ebiten Emoji Alpha version: The API is not stable yet Package emoji provides Emoji images for Ebiten. Usage func (*YourGame) Draw(screen *ebiten.Image

Ebiten 17 Jul 26, 2022
An experiment in rendering images with Slack custom emojis.

emojimage An experiment in rendering images with Slack custom emojis. Example Usage 1. Initializing your workspace First, you'll need to upload 1,332

Caleb Denio 9 Mar 12, 2022
a tool to output images as RGB ANSI graphics on the terminal

imgcat Tool to output images in the terminal. Built with bubbletea install homebrew brew install trashhalo/homebrew-brews/imgcat prebuilt packages Pr

Stephen Solka 463 Sep 18, 2022
Image compression codec for 16 bit medical images

MIC - Medical Image Codec This library introduces a lossless medical image compression codec MIC for 16 bit images which provides compression ratio si

Kuldeep S 0 Dec 26, 2021
Small project to convert images to grayscale

This is a small http server that will read images from a provided path, convert the image to gray, and then serve back the converted image Usage You c

Wolfgang E Sanyer 0 Nov 5, 2021
Cryptseaside generates seaside images using Unix nanoseconds as the seed value.

Cryptseaside Welcome to the Cryptseaside project. Cryptseaside generates seaside images using Unix nanoseconds as the seed value.

Rhymof 1 Nov 12, 2021