Fast, Docker-ready image processing server written in Go and libvips, with Thumbor URL syntax

Imagor

Imagor is a fast, Docker-ready image processing server written in Go.

Imagor uses one of the most efficient image processing library libvips (with govips). It is typically 4-8x faster than using the quickest ImageMagick and GraphicsMagick settings.

Imagor is a Go library that is easily extensible, ready to be installed and used in any Unix environment, and ready to be containerized using Docker.

Imagor adopts the Thumbor URL syntax and covers most of the web image processing use cases. If these fit your requirements, Imagor would be a lightweight, high performance drop-in replacement.

Quick Start

docker run -p 8000:8000 shumc/imagor -imagor-unsafe

Try out the following image URLs:

# original images
https://raw.githubusercontent.com/golang-samples/gopher-vector/master/gopher.png
https://raw.githubusercontent.com/golang-samples/gopher-vector/master/gopher-front.png

http://localhost:8000/unsafe/500x500/top/https://raw.githubusercontent.com/golang-samples/gopher-vector/master/gopher.png
http://localhost:8000/unsafe/fit-in/500x500/filters:fill(white):format(jpeg)/raw.githubusercontent.com/golang-samples/gopher-vector/master/gopher.png
http://localhost:8000/unsafe/fit-in/-500x500/10x10/filters:hue(290):saturation(100):fill(yellow):format(jpeg):quality(80)/raw.githubusercontent.com/golang-samples/gopher-vector/master/gopher.png
http://localhost:8000/unsafe/fit-in/800x800/filters:fill(white):watermark(raw.githubusercontent.com/golang-samples/gopher-vector/master/gopher-front.png,repeat,bottom,10):format(jpeg)/raw.githubusercontent.com/golang-samples/gopher-vector/master/gopher.png

Docker Compose Example

Imagor with File Loader and Storage using mounted volume:

version: "3"
services:
  imagor:
    image: shumc/imagor:latest
    volumes:
      - ./:/mnt/data
    environment:
      PORT: 8000
      IMAGOR_UNSAFE: 1 # unsafe URL for testing
      FILE_LOADER_BASE_DIR: /mnt/data # enable file loader by specifying base dir
      FILE_STORAGE_BASE_DIR: /mnt/data # enable file storage by specifying base dir
    ports:
      - "8000:8000"

Imagor with AWS S3 Loader and Storage:

version: "3"
services:
  imagor:
    image: shumc/imagor:latest
    environment:
      PORT: 8000
      IMAGOR_SECRET: mysecret # secret key for URL signature
      AWS_ACCESS_KEY_ID: ...
      AWS_SECRET_ACCESS_KEY: ...
      AWS_REGION: ...
      S3_LOADER_BUCKET: mybucket # enable S3 loader by specifying loader bucket
      S3_LOADER_BASE_DIR: images # optional
      S3_STORAGE_BUCKET: mybucket # enable S3 storage by specifying storage bucket
      S3_STORAGE_BASE_DIR: images # optional
    ports:
      - "8000:8000"

Imagor Endpoint

Imagor endpoint is a series of URL parts which defines the image operations, followed by the image URI:

/HASH|unsafe/trim/AxB:CxD/fit-in/stretch/-Ex-F/GxH/HALIGN/VALIGN/smart/filters:NAME(ARGS):NAME(ARGS):.../IMAGE
  • HASH is the URL Signature hash, or unsafe if unsafe mode is used
  • trim removes surrounding space in images using top-left pixel color
  • AxB:CxD means manually crop the image at left-top point AxB and right-bottom point CxD
  • fit-in means that the generated image should not be auto-cropped and otherwise just fit in an imaginary box specified by ExF
  • stretch means resize the image to ExF without keeping its aspect ratios
  • -Ex-F means resize the image to be ExF of width per height size. The minus signs mean flip horizontally and vertically
  • GxH add horizontal padding G and vertical padding H under fit-in
  • HALIGN is horizontal alignment of crop. Accepts left, right or center, defaults to center
  • VALIGN is vertical alignment of crop. Accepts top, bottom or middle, defaults to middle
  • smart means using smart detection of focal points
  • filters a pipeline of image filter operations to be applied, see filters section
  • IMAGE is the image URI

Imagor provides utilities for previewing and generating Imagor endpoint URI:

GET /params

Prepending /params to the existing endpoint returns the endpoint attributes in JSON form, useful for preview:

curl http://localhost:8000/params/g5bMqZvxaQK65qFPaP1qlJOTuLM=/fit-in/500x400/0x20/filters:fill(white)/raw.githubusercontent.com/golang-samples/gopher-vector/master/gopher.png

{
  "path": "fit-in/500x400/0x20/filters:fill(white)/raw.githubusercontent.com/golang-samples/gopher-vector/master/gopher.png",
  "image": "raw.githubusercontent.com/golang-samples/gopher-vector/master/gopher.png",
  "hash": "g5bMqZvxaQK65qFPaP1qlJOTuLM=",
  "fit_in": true,
  "width": 500,
  "height": 400,
  "v_padding": 20,
  "filters": [
    {
      "name": "fill",
      "args": "white"
    }
  ]
}

imagorpath package

Imagor Go library provides a imagorpath package which allows you to parse and generate Imagor endpoint using the Params struct:

import "github.com/cshum/imagor/imagorpath"

...

func Test(t *testing.T) {
	params := imagorpath.Params{
		Image:    "raw.githubusercontent.com/golang-samples/gopher-vector/master/gopher.png",
		FitIn:    true,
		Width:    500,
		Height:   400,
		VPadding: 20,
		Filters: imagorpath.Filters{
			{
				Name: "fill",
				Args: "white",
			},
		},
	}

	// generate signed Imagor endpoint from Params struct with secret
	path := imagorpath.Generate(params, "mysecret")

	assert.Equal(t, path, "g5bMqZvxaQK65qFPaP1qlJOTuLM=/fit-in/500x400/0x20/filters:fill(white)/raw.githubusercontent.com/golang-samples/gopher-vector/master/gopher.png")
}

URL Signature

In production environment, it is highly recommended turning off IMAGOR_UNSAFE and setup IMAGOR_SECRET to avoid DDoS attacks that abuse multiple image operations.

The hash is based on HMAC digest, created by taking the URL path (excluding /unsafe/) with secret. The hash is then base64url-encoded. An example in Go:

func SignPath(path, secret string) string {
	h := hmac.New(sha1.New, []byte(secret))
	h.Write([]byte(strings.TrimPrefix(path, "/")))
	hash := base64.URLEncoding.EncodeToString(h.Sum(nil))
	return hash + "/" + path
}

func main() {
	fmt.Println(SignPath("500x500/top/raw.githubusercontent.com/golang-samples/gopher-vector/master/gopher.png", "mysecret"))
	// RArq3FZw_bqxLcpKo1WI0aX_q7s=/fit-in/500x500/filters:fill(white):format(jpeg)/raw.githubusercontent.com/golang-samples/gopher-vector/master/gopher.png
}

Filters

Filters /filters:NAME(ARGS):NAME(ARGS):.../ is a pipeline of image operations that will be sequentially applied to the image. Examples:

/filters:fill(white):format(jpeg)/
/filters:hue(290):saturation(100):fill(yellow):format(jpeg):quality(80)/
/filters:fill(white):watermark(raw.githubusercontent.com/golang-samples/gopher-vector/master/gopher-front.png,repeat,bottom,10):format(jpeg)/

Imagor supports the following filters:

  • background_color(color) sets the background color of a transparent image
    • color the color name or hexadecimal rgb expression without the “#” character
  • blur(sigma) applies gaussian blur to the image
  • brightness(amount) increases or decreases the image brightness
    • amount -100 to 100, the amount in % to increase or decrease the image brightness
  • contrast(amount) increases or decreases the image contrast
    • amount -100 to 100, the amount in % to increase or decrease the image contrast
  • fill(color) fill the missing area or transparent image with the specified color:
    • color - color name or hexadecimal rgb expression without the “#” character
      • If color is "blur" - missing parts are filled with blurred original image.
      • If color is "auto" - the top left image pixel will be chosen as the filling color
  • format(format) specifies the output format of the image
    • format accepts jpeg, png, webp, gif, jp2, tiff
  • grayscale() changes the image to grayscale
  • hue(angle) increases or decreases the image hue
    • angle the angle in degree to increase or decrease the hue rotation
  • quality(amount) changes the overall quality of the image, does nothing for png
    • amount 0 to 100, the quality level in %
  • rgb(r,g,b) amount of color in each of the rgb channels in %. Can range from -100 to 100
  • rotate(angle) rotates the given image according to the angle value passed
    • angle accepts 0, 90, 180, 270
  • round_corner(rx [, ry [, color]]) adds rounded corners to the image with the specified color as background
    • rx, ry amount of pixel to use as radius. ry = rx if ry is not provided
    • color the color name or hexadecimal rgb expression without the “#” character
  • saturation(amount) increases or decreases the image saturation
    • amount -100 to 100, the amount in % to increase or decrease the image saturation
  • sharpen(sigma) sharpens the image
  • trim([tolerance [, position]]) apply trim operation as part of the filter pipeline
    • tolerance the euclidean distance between the colors to get trimmed within the tolerance, default 1
    • position default using top-left pixel color unless specified bottom-right
  • upscale() upscale the image if fit-in is used
  • watermark(image, x, y, alpha [, w_ratio [, h_ratio]]) adds a watermark to the image. It can be positioned inside the image with the alpha channel specified and optionally resized based on the image size by specifying the ratio
    • image watermark image URI, using the same image loader configured for Imagor
    • x horizontal position that the watermark will be in:
      • Positive numbers indicate position from the left and negative numbers indicate position from the right.
      • Number followed by a p e.g. 20p means calculating the value from the image width as percentage
      • left,right,center positioned left, right or centered respectively
      • repeat the watermark will be repeated horizontally
    • y vertical position that the watermark will be in:
      • Positive numbers indicate position from the top and negative numbers indicate position from the bottom.
      • Number followed by a p e.g. 20p means calculating the value from the image height as percentage
      • top,bottom,center positioned top, bottom or centered respectively
      • repeat the watermark will be repeated vertically
    • alpha watermark image transparency, a number between 0 (fully opaque) and 100 (fully transparent).
    • w_ratio percentage of the width of the image the watermark should fit-in
    • h_ratio percentage of the height of the image the watermark should fit-in

Configurations

Imagor supports command-line arguments, see available options imagor -h. You may check main.go for better understanding the initialization sequences.

Imagor also supports environment variables or .env file for the arguments equivalent in capitalized snake case. For instances -imagor-secret would become IMAGOR_SECRET:

# both are equivalent

imagor -debug -imagor-secret=1234

DEBUG=1 IMAGOR_SECRET=1234 imagor

Available options:

imagor -h
Usage of imagor:
  -debug
        Debug mode
  -port int
        Sever port (default 8000)

  -imagor-secret string
        Secret key for signing Imagor URL
  -imagor-unsafe
        Unsafe Imagor that does not require URL signature. Prone to URL tampering
  -imagor-version
        Imagor version
  -imagor-cache-header-ttl duration
        Imagor HTTP cache header ttl for successful image response (default 24h0m0s)
  -imagor-request-timeout duration
        Timeout for performing imagor request (default 30s)
  -imagor-load-timeout duration
        Timeout for Imagor Loader request, should be smaller than imagor-request-timeout (default 20s)
  -imagor-save-timeout duration
        Timeout for saving image for storage (default 1m0s)

  -server-address string
        Server address
  -server-cors
        Enable CORS
  -server-strip-query-string
        Enable strip query string redirection
  -server-path-prefix string
        Server path prefix

  -vips-concurrency-level int
        VIPS concurrency level. Default to the number of CPU cores.
  -vips-disable-blur
        VIPS disable blur operations for vips processor
  -vips-disable-filters string
        VIPS disable filters by csv e.g. blur,watermark,rgb
  -vips-max-filter-ops int
        VIPS maximum number of filter operations allowed (default 10)

  -http-loader-allowed-sources string
        HTTP Loader allowed hosts whitelist to load images from if set. Accept csv wth glob pattern e.g. *.google.com,*.github.com.
  -http-loader-default-scheme string
        HTTP Loader default scheme if not specified by image path. Set "nil" to disable default scheme. (default "https")
  -http-loader-forward-headers string
        Forward request header to HTTP Loader request by csv e.g. User-Agent,Accept
  -http-loader-forward-all-headers
        Forward all request headers to HTTP Loader request
  -http-loader-insecure-skip-verify-transport
        HTTP Loader to use HTTP transport with InsecureSkipVerify true
  -http-loader-max-allowed-size int
        HTTP Loader maximum allowed size in bytes for loading images if set
  -http-loader-disable
        Disable HTTP Loader

  -file-loader-base-dir string
        Base directory for File Loader. Will activate File Loader only if this value present
  -file-loader-path-prefix string
        Base path prefix for File Loader

  -file-storage-base-dir string
        Base directory for File Storage. Will activate File Storage only if this value present
  -file-storage-path-prefix string
        Base path prefix for File Storage
  -file-storage-mkdir-permission string
        File Storage mkdir permission (default "0755")
  -file-storage-write-permission string
        File Storage write permission (default "0666")

  -aws-access-key-id string
        AWS Access Key ID. Required if using S3 Loader or S3 Storage
  -aws-region string
        AWS Region. Required if using S3 Loader or S3 Storage
  -aws-secret-access-key string
        AWS Secret Access Key. Required if using S3 Loader or S3 Storage

  -s3-loader-base-dir string
        Base directory for S3 Loader (default "/")
  -s3-loader-bucket string
        S3 Bucket for S3 Loader. Will activate S3 Loader only if this value present
  -s3-loader-path-prefix string
        Base path prefix for S3 Loader (default "/")

  -s3-storage-base-dir string
        Base directory for S3 Storage
  -s3-storage-bucket string
        S3 Bucket for S3 Storage. Will activate S3 Storage only if this value present
  -s3-storage-path-prefix string
        Base path prefix for S3 Storage
  -s3-storage-acl string
        Upload ACL for S3 Storage (default "public-read")

Comments
  • Benchmarks

    Benchmarks

    Hi again :)

    I'm trying to run some simple benchmarks to compare thumbor performance to imagor. For some reason I'm not sure the VIPS_CONCURRENCY_LEVEL env has an effect? It seems like it's always using all available CPUs ... Also interesting is that whilst it seems to run faster compared it to a single-process thumbor, when I run it with concurrency of 4 against thumbor (with the same concurrency), thumbor out-performs imagor (without caching, only keeping the original image in file storage) ...

    Perhaps it's due to the way I've setup the benchmark? maybe it doesn't keep the original image in storage and always fetches it? or some other trivial misconfiguration? because otherwise I would expect libvips to outperform thumbor ...

    You can see the benchmark code I'm running at https://github.com/MinimalCompact/thumbor/tree/imagor-thumbor-benchmark/benchmarks/locust (it's based on an older benchmark I created for optimizing thumbor on a multi-proc environment, so it's a bit messy unfortunately, but hope it's still useful)

    I tested it on a DigitalOcean droplet with 4 cpus. Here's a sheet with the stats

  • Imagor crashes sometimes

    Imagor crashes sometimes

    Hi, from time to time (every day or every to days) imagor crashes and restarts.

    I cannot reproduce the error, I can see this traces in the log:

    {"log":"fatal error: unexpected signal during runtime execution\n","stream":"stderr","time":"2022-09-07T10:26:21.691272038Z"}
    {"log":"[signal SIGSEGV: segmentation violation code=0x1 addr=0x125 pc=0x7f749a91b3a0]\n","stream":"stderr","time":"2022-09-07T10:26:21.693398049Z"}
    {"log":"\n","stream":"stderr","time":"2022-09-07T10:26:21.69341131Z"}
    {"log":"runtime stack:\n","stream":"stderr","time":"2022-09-07T10:26:21.693413756Z"}
    {"log":"runtime.throw({0xf780d7?, 0x3?})\n","stream":"stderr","time":"2022-09-07T10:26:21.693730377Z"}
    {"log":"\u0009/usr/local/go/src/runtime/panic.go:1047 +0x5d fp=0x7f7332c75a60 sp=0x7f7332c75a30 pc=0x43b77d\n","stream":"stderr","time":"2022-09-07T10:26:21.693734236Z"}
    {"log":"runtime.sigpanic()\n","stream":"stderr","time":"2022-09-07T10:26:21.693737062Z"}
    {"log":"\u0009/usr/local/go/src/runtime/signal_unix.go:819 +0x369 fp=0x7f7332c75ab0 sp=0x7f7332c75a60 pc=0x451689\n","stream":"stderr","time":"2022-09-07T10:26:21.693739123Z"}
    {"log":"\n","stream":"stderr","time":"2022-09-07T10:26:21.693741245Z"}
    {"log":"goroutine 5715652 [syscall]:\n","stream":"stderr","time":"2022-09-07T10:26:21.693743343Z"}
    {"log":"runtime.cgocall(0xd0e560, 0xc000ff4f40)\n","stream":"stderr","time":"2022-09-07T10:26:21.693754002Z"}
    {"log":"\u0009/usr/local/go/src/runtime/cgocall.go:158 +0x5c fp=0xc000ff4f18 sp=0xc000ff4ee0 pc=0x4096dc\n","stream":"stderr","time":"2022-09-07T10:26:21.693757499Z"}
    {"log":"github.com/cshum/imagor/vips._Cfunc_thumbnail_source_with_option(0x7f7434207270, 0xc0013bc010, 0x1f4, 0x1388, 0x0, 0x2, 0x7f742d60d780)\n","stream":"stderr","time":"2022-09-07T10:26:21.694102171Z"}
    {"log":"\u0009_cgo_gotypes.go:1402 +0x4c fp=0xc000ff4f40 sp=0xc000ff4f18 pc=0xcfea0c\n","stream":"stderr","time":"2022-09-07T10:26:21.694106296Z"}
    {"log":"github.com/cshum/imagor/vips.vipsThumbnailFromSource.func2(0xc00184e020?, 0x9?, 0x1f4, 0x1388, 0x0, 0x2, 0x0?)\n","stream":"stderr","time":"2022-09-07T10:26:21.694108351Z"}
    {"log":"\u0009/go/src/github.com/cshum/imagor/vips/vips.go:99 +0xbc fp=0xc000ff4f98 sp=0xc000ff4f40 pc=0xd06e3c\n","stream":"stderr","time":"2022-09-07T10:26:21.694110387Z"}
    {"log":"github.com/cshum/imagor/vips.vipsThumbnailFromSource(0x7f7496d85d28?, 0x8?, 0xc001d1e400?, 0xc0013bc008?, 0x0?, 0xc000ff50b0)\n","stream":"stderr","time":"2022-09-07T10:26:21.694112449Z"}
    {"log":"\u0009/go/src/github.com/cshum/imagor/vips/vips.go:99 +0x155 fp=0xc000ff5058 sp=0xc000ff4f98 pc=0xd06bf5\n","stream":"stderr","time":"2022-09-07T10:26:21.694117436Z"}
    {"log":"github.com/cshum/imagor/vips.LoadThumbnailFromSource(0x1225d38?, 0xc000960420?, 0xc000ff51d8?, 0x41d46b?, 0x7f746f2b4100?, 0xc00042e8c0?)\n","stream":"stderr","time":"2022-09-07T10:26:21.69413578Z"}
    {"log":"\u0009/go/src/github.com/cshum/imagor/vips/image.go:137 +0x86 fp=0xc000ff5180 sp=0xc000ff5058 pc=0xd019e6\n","stream":"stderr","time":"2022-09-07T10:26:21.694139392Z"}
    {"log":"github.com/cshum/imagor/vips.(*Source).LoadThumbnail(...)\n","stream":"stderr","time":"2022-09-07T10:26:21.694503284Z"}
    {"log":"\u0009/go/src/github.com/cshum/imagor/vips/source.go:61\n","stream":"stderr","time":"2022-09-07T10:26:21.694507062Z"}
    {"log":"github.com/cshum/imagor/vips.newThumbnailFromBlob({0x1225d38, 0xc000960420}, 0xc000988200, 0x203000?, 0xc000960420?, 0xc0009603f0?, 0xc000753860?, 0x0?)\n","stream":"stderr","time":"2022-09-07T10:26:21.694509083Z"}
    {"log":"\u0009/go/src/github.com/cshum/imagor/vips/processor.go:174 +0x1a5 fp=0xc000ff5208 sp=0xc000ff5180 pc=0xcfa3c5\n","stream":"stderr","time":"2022-09-07T10:26:21.69451134Z"}
    {"log":"github.com/cshum/imagor/vips.(*Processor).NewThumbnail(0xdf86c0?, {0x1225d38, 0xc000960420}, 0xc000988200, 0xe12080?, 0xc0009603f0?, 0x0, 0x2, 0x1)\n","stream":"stderr","time":"2022-09-07T10:26:21.694513437Z"}
    {"log":"\u0009/go/src/github.com/cshum/imagor/vips/processor.go:219 +0x44f fp=0xc000ff5350 sp=0xc000ff5208 pc=0xcfa88f\n","stream":"stderr","time":"2022-09-07T10:26:21.694515589Z"}
    {"log":"github.com/cshum/imagor/vips.(*Processor).Process(_, {_, _}, _, {0x0, {0xc001b180a8, 0x91}, {0xc002050300, 0x51}, 0x1, ...}, ...)\n","stream":"stderr","time":"2022-09-07T10:26:21.694554902Z"}
    {"log":"\u0009/go/src/github.com/cshum/imagor/vips/process.go:119 +0x32f fp=0xc000ff5738 sp=0xc000ff5350 pc=0xcf4c2f\n","stream":"stderr","time":"2022-09-07T10:26:21.694570019Z"}
    {"log":"github.com/cshum/imagor.(*Imagor).Do.func2({0x1225d38, 0xc0022542d0}, 0xc001e02140)\n","stream":"stderr","time":"2022-09-07T10:26:21.694573673Z"}
    {"log":"\u0009/go/src/github.com/cshum/imagor/imagor.go:306 +0x10a3 fp=0xc000ff5e58 sp=0xc000ff5738 pc=0x7581a3\n","stream":"stderr","time":"2022-09-07T10:26:21.694576598Z"}
    {"log":"github.com/cshum/imagor.(*Imagor).suppress.func2()\n","stream":"stderr","time":"2022-09-07T10:26:21.694579764Z"}
    {"log":"\u0009/go/src/github.com/cshum/imagor/imagor.go:496 +0xc7 fp=0xc000ff5f00 sp=0xc000ff5e58 pc=0x75b207\n","stream":"stderr","time":"2022-09-07T10:26:21.69458286Z"}
    {"log":"golang.org/x/sync/singleflight.(*Group).doCall.func2(0xc000ff5f56, 0xc001152420, 0x0?)\n","stream":"stderr","time":"2022-09-07T10:26:21.694586323Z"}
    {"log":"\u0009/go/pkg/mod/golang.org/x/[email protected]/singleflight/singleflight.go:193 +0x6f fp=0xc000ff5f38 sp=0xc000ff5f00 pc=0x75158f\n","stream":"stderr","time":"2022-09-07T10:26:21.694596584Z"}
    {"log":"golang.org/x/sync/singleflight.(*Group).doCall(0xc000636480?, 0xc0011eefd0?, {0xc001b180a8?, 0xc0011ba060?}, 0x0?)\n","stream":"stderr","time":"2022-09-07T10:26:21.694603798Z"}
    {"log":"\u0009/go/pkg/mod/golang.org/x/[email protected]/singleflight/singleflight.go:195 +0xa5 fp=0xc000ff5fa8 sp=0xc000ff5f38 pc=0x7514a5\n","stream":"stderr","time":"2022-09-07T10:26:21.694605955Z"}
    {"log":"golang.org/x/sync/singleflight.(*Group).DoChan.func1()\n","stream":"stderr","time":"2022-09-07T10:26:21.694613684Z"}
    {"log":"\u0009/go/pkg/mod/golang.org/x/[email protected]/singleflight/singleflight.go:133 +0x36 fp=0xc000ff5fe0 sp=0xc000ff5fa8 pc=0x7513d6\n","stream":"stderr","time":"2022-09-07T10:26:21.694615979Z"}
    {"log":"runtime.goexit()\n","stream":"stderr","time":"2022-09-07T10:26:21.694618162Z"}
    {"log":"\u0009/usr/local/go/src/runtime/asm_amd64.s:1594 +0x1 fp=0xc000ff5fe8 sp=0xc000ff5fe0 pc=0x46cb81\n","stream":"stderr","time":"2022-09-07T10:26:21.694620142Z"}
    {"log":"created by golang.org/x/sync/singleflight.(*Group).DoChan\n","stream":"stderr","time":"2022-09-07T10:26:21.69462219Z"}
    {"log":"\u0009/go/pkg/mod/golang.org/x/[email protected]/singleflight/singleflight.go:133 +0x315\n","stream":"stderr","time":"2022-09-07T10:26:21.694624208Z"}
    {"log":"\n","stream":"stderr","time":"2022-09-07T10:26:21.694626248Z"}
    {"log":"goroutine 1 [chan receive, 861 minutes]:\n","stream":"stderr","time":"2022-09-07T10:26:21.694628117Z"}
    {"log":"runtime.gopark(0x30cc80c?, 0x1890060?, 0x0?, 0x0?, 0x0?)\n","stream":"stderr","time":"2022-09-07T10:26:21.694631229Z"}
    {"log":"\u0009/usr/local/go/src/runtime/proc.go:363 +0xd6 fp=0xc000a86d90 sp=0xc000a86d70 pc=0x43e456\n","stream":"stderr","time":"2022-09-07T10:26:21.694633251Z"}
    {"log":"runtime.chanrecv(0xc0000d84e0, 0x0, 0x1)\n","stream":"stderr","time":"2022-09-07T10:26:21.694635648Z"}
    {"log":"\u0009/usr/local/go/src/runtime/chan.go:583 +0x49b fp=0xc000a86e20 sp=0xc000a86d90 pc=0x40c6db\n","stream":"stderr","time":"2022-09-07T10:26:21.694638531Z"}
    {"log":"runtime.chanrecv1(0xc00019c420?, 0xf4ad58?)\n","stream":"stderr","time":"2022-09-07T10:26:21.694642103Z"}
    {"log":"\u0009/usr/local/go/src/runtime/chan.go:442 +0x18 fp=0xc000a86e48 sp=0xc000a86e20 pc=0x40c1d8\n","stream":"stderr","time":"2022-09-07T10:26:21.694645043Z"}
    {"log":"github.com/cshum/imagor/server.(*Server).RunContext(0xc00019c420, {0x12264e0, 0xc0001d0a40})\n","stream":"stderr","time":"2022-09-07T10:26:21.69464934Z"}
    {"log":"\u0009/go/src/github.com/cshum/imagor/server/server.go:83 +0x16b fp=0xc000a86ed0 sp=0xc000a86e48 pc=0x76548b\n","stream":"stderr","time":"2022-09-07T10:26:21.694652347Z"}
    {"log":"github.com/cshum/imagor/server.(*Server).Run(0xc000036240?)\n","stream":"stderr","time":"2022-09-07T10:26:21.694654428Z"}
    {"log":"\u0009/go/src/github.com/cshum/imagor/server/server.go:71 +0xa5 fp=0xc000a86f28 sp=0xc000a86ed0 pc=0x7652c5\n","stream":"stderr","time":"2022-09-07T10:26:21.694656349Z"}
    {"log":"main.main()\n","stream":"stderr","time":"2022-09-07T10:26:21.694658373Z"}
    {"log":"\u0009/go/src/github.com/cshum/imagor/cmd/imagor/main.go:19 +0xb7 fp=0xc000a86f80 sp=0xc000a86f28 pc=0xd0d6b7\n","stream":"stderr","time":"2022-09-07T10:26:21.694660416Z"}
    {"log":"runtime.main()\n","stream":"stderr","time":"2022-09-07T10:26:21.694663029Z"}
    {"log":"\u0009/usr/local/go/src/runtime/proc.go:250 +0x212 fp=0xc000a86fe0 sp=0xc000a86f80 pc=0x43e092\n","stream":"stderr","time":"2022-09-07T10:26:21.69466493Z"}
    {"log":"runtime.goexit()\n","stream":"stderr","time":"2022-09-07T10:26:21.694667047Z"}
    {"log":"\u0009/usr/local/go/src/runtime/asm_amd64.s:1594 +0x1 fp=0xc000a86fe8 sp=0xc000a86fe0 pc=0x46cb81\n","stream":"stderr","time":"2022-09-07T10:26:21.694669512Z"}
    {"log":"\n","stream":"stderr","time":"2022-09-07T10:26:21.694671574Z"}
    {"log":"goroutine 2 [force gc (idle), 861 minutes]:\n","stream":"stderr","time":"2022-09-07T10:26:21.694673803Z"}
    {"log":"runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)\n","stream":"stderr","time":"2022-09-07T10:26:21.6946842Z"}
    {"log":"\u0009/usr/local/go/src/runtime/proc.go:363 +0xd6 fp=0xc0000a0fb0 sp=0xc0000a0f90 pc=0x43e456\n","stream":"stderr","time":"2022-09-07T10:26:21.694692563Z"}
    {"log":"runtime.goparkunlock(...)\n","stream":"stderr","time":"2022-09-07T10:26:21.69469481Z"}
    {"log":"\u0009/usr/local/go/src/runtime/proc.go:369\n","stream":"stderr","time":"2022-09-07T10:26:21.694704646Z"}
    {"log":"runtime.forcegchelper()\n","stream":"stderr","time":"2022-09-07T10:26:21.694706723Z"}
    {"log":"\u0009/usr/local/go/src/runtime/proc.go:302 +0xad fp=0xc0000a0fe0 sp=0xc0000a0fb0 pc=0x43e2ed\n","stream":"stderr","time":"2022-09-07T10:26:21.694711758Z"}
    {"log":"runtime.goexit()\n","stream":"stderr","time":"2022-09-07T10:26:21.694715028Z"}
    {"log":"\u0009/usr/local/go/src/runtime/asm_amd64.s:1594 +0x1 fp=0xc0000a0fe8 sp=0xc0000a0fe0 pc=0x46cb81\n","stream":"stderr","time":"2022-09-07T10:26:21.694718055Z"}
    {"log":"created by runtime.init.6\n","stream":"stderr","time":"2022-09-07T10:26:21.694721206Z"}
    {"log":"\u0009/usr/local/go/src/runtime/proc.go:290 +0x25\n","stream":"stderr","time":"2022-09-07T10:26:21.694725907Z"}
    {"log":"\n","stream":"stderr","time":"2022-09-07T10:26:21.694728948Z"}
    {"log":"goroutine 3 [GC sweep wait]:\n","stream":"stderr","time":"2022-09-07T10:26:21.694730856Z"}
    {"log":"runtime.gopark(0x188fa01?, 0x0?, 0x0?, 0x0?, 0x0?)\n","stream":"stderr","time":"2022-09-07T10:26:21.694732793Z"}
    {"log":"\u0009/usr/local/go/src/runtime/proc.go:363 +0xd6 fp=0xc0000a1790 sp=0xc0000a1770 pc=0x43e456\n","stream":"stderr","time":"2022-09-07T10:26:21.694735235Z"}
    {"log":"runtime.goparkunlock(...)\n","stream":"stderr","time":"2022-09-07T10:26:21.694759617Z"}
    {"log":"\u0009/usr/local/go/src/runtime/proc.go:369\n","stream":"stderr","time":"2022-09-07T10:26:21.694767234Z"}
    {"log":"runtime.bgsweep(0x0?)\n","stream":"stderr","time":"2022-09-07T10:26:21.694770359Z"}
    {"log":"\u0009/usr/local/go/src/runtime/mgcsweep.go:297 +0xd7 fp=0xc0000a17c8 sp=0xc0000a1790 pc=0x42a897\n","stream":"stderr","time":"2022-09-07T10:26:21.694773261Z"}
    {"log":"runtime.gcenable.func1()\n","stream":"stderr","time":"2022-09-07T10:26:21.694776628Z"}
    {"log":"\u0009/usr/local/go/src/runtime/mgc.go:178 +0x26 fp=0xc0000a17e0 sp=0xc0000a17c8 pc=0x41f506\n","stream":"stderr","time":"2022-09-07T10:26:21.694779532Z"}
    {"log":"runtime.goexit()\n","stream":"stderr","time":"2022-09-07T10:26:21.694782534Z"}
    {"log":"\u0009/usr/local/go/src/runtime/asm_amd64.s:1594 +0x1 fp=0xc0000a17e8 sp=0xc0000a17e0 pc=0x46cb81\n","stream":"stderr","time":"2022-09-07T10:26:21.694785472Z"}
    {"log":"created by runtime.gcenable\n","stream":"stderr","time":"2022-09-07T10:26:21.694788725Z"}
    {"log":"\u0009/usr/local/go/src/runtime/mgc.go:178 +0x6b\n","stream":"stderr","time":"2022-09-07T10:26:21.694792508Z"}
    {"log":"\n","stream":"stderr","time":"2022-09-07T10:26:21.694795503Z"}
    {"log":"goroutine 4 [GC scavenge wait]:\n","stream":"stderr","time":"2022-09-07T10:26:21.694798322Z"}
    {"log":"runtime.gopark(0x1c9d63eb19ee6f?, 0x201f13?, 0x0?, 0x0?, 0x0?)\n","stream":"stderr","time":"2022-09-07T10:26:21.694801343Z"}
    {"log":"\u0009/usr/local/go/src/runtime/proc.go:363 +0xd6 fp=0xc0000a1f70 sp=0xc0000a1f50 pc=0x43e456\n","stream":"stderr","time":"2022-09-07T10:26:21.694804511Z"}
    {"log":"runtime.goparkunlock(...)\n","stream":"stderr","time":"2022-09-07T10:26:21.694807658Z"}
    {"log":"\u0009/usr/local/go/src/runtime/proc.go:369\n","stream":"stderr","time":"2022-09-07T10:26:21.694810682Z"}
    {"log":"runtime.(*scavengerState).park(0x18900e0)\n","stream":"stderr","time":"2022-09-07T10:26:21.694813669Z"}
    {"log":"\u0009/usr/local/go/src/runtime/mgcscavenge.go:389 +0x53 fp=0xc0000a1fa0 sp=0xc0000a1f70 pc=0x4288f3\n","stream":"stderr","time":"2022-09-07T10:26:21.694816562Z"}
    {"log":"runtime.bgscavenge(0x0?)\n","stream":"stderr","time":"2022-09-07T10:26:21.694819748Z"}
    {"log":"\u0009/usr/local/go/src/runtime/mgcscavenge.go:622 +0x65 fp=0xc0000a1fc8 sp=0xc0000a1fa0 pc=0x428ee5\n","stream":"stderr","time":"2022-09-07T10:26:21.694823288Z"}
    {"log":"runtime.gcenable.func2()\n","stream":"stderr","time":"2022-09-07T10:26:21.694827605Z"}
    {"log":"\u0009/usr/local/go/src/runtime/mgc.go:179 +0x26 fp=0xc0000a1fe0 sp=0xc0000a1fc8 pc=0x41f4a6\n","stream":"stderr","time":"2022-09-07T10:26:21.694830585Z"}
    {"log":"runtime.goexit()\n","stream":"stderr","time":"2022-09-07T10:26:21.69483364Z"}
    ...
    

    This is with 1.0.3. It was also happening in 0.9.7 (and others I guess). I think that it happens a bit more frequently in this version.

    I'm not sure about it, but I think that related to this crashes I get the result storage populated with truncated images, like this one: https://cdn4.travelconline.com/unsafe/fit-in/800x0/filters:quality(75):format(jpg)/https%3A%2F%2Fi.travelapi.com%2Fhotels%2F22000000%2F21540000%2F21537500%2F21537420%2F8a95c8cf_z.jpg

    (it looks fine in the browser but it's truncated and some utilities will crash when they read this image)

    If I delete the file from the result storage the image works fine again

  • Segmentation faults

    Segmentation faults

    Version: Imagor 1.3.2 Platform: Alpine Linux 3.17 Libvips: vips-8.13.3-r1 Libheif: libheif-1.14.0-r0 Golang: go-1.19.3-r0

    Formats: Web + AVIF Action: Resize Images

    We are getting at least 1 segmentation fault per day when using imagor to resize images to webp/avif (50/50 ratio).

    We are using the app.ServeBlob api from our golang program.

    fatal error: unexpected signal during runtime execution
    [signal SIGSEGV: segmentation violation code=0x80 addr=0x0 pc=0x7fa28db8f2dd]
    
    runtime stack:
    runtime.throw({0x125a02b?, 0x7fa28fdd1c56?})
    	/usr/lib/go/src/runtime/panic.go:1047 +0x5d fp=0x7fa252e35cb0 sp=0x7fa252e35c80 pc=0x46acbd
    runtime.sigpanic()
    	/usr/lib/go/src/runtime/signal_unix.go:819 +0x369 fp=0x7fa252e35d00 sp=0x7fa252e35cb0 pc=0x4815a9
    
    goroutine 146318102 [syscall]:
    runtime.cgocall(0xfffb70, 0xc2797c8000)
    	/usr/lib/go/src/runtime/cgocall.go:158 +0x5c fp=0xc2797c7fd8 sp=0xc2797c7fa0 pc=0x436b1c
    github.com/cshum/imagor/vips._Cfunc_thumbnail_image(0x22dee7eb840, 0xc034670ad8, 0x70, 0x70, 0x1, 0x0)
    	_cgo_gotypes.go:1365 +0x4c fp=0xc2797c8000 sp=0xc2797c7fd8 pc=0xb0252c
    github.com/cshum/imagor/vips.vipsThumbnail.func1(0x7fa28d0c71d8?, 0x4b635e?, 0x70, 0x70, 0x1, 0x0)
    	/code-go/go/src/github.com/cshum/imagor/vips/vips.go:142 +0xa7 fp=0xc2797c8048 sp=0xc2797c8000 pc=0xb0b267
    github.com/cshum/imagor/vips.vipsThumbnail(0x51aac5?, 0xc047f15a00?, 0xc179f02000?, 0x1d?, 0xc2797c8160?)
    	/code-go/go/src/github.com/cshum/imagor/vips/vips.go:142 +0x65 fp=0xc2797c80b8 sp=0xc2797c8048 pc=0xb0b145
    github.com/cshum/imagor/vips.(*Image).ThumbnailWithSize(0xc0d5537240, 0xc130412620?, 0xc047f15a00?, 0xc2797c8230?, 0xb059d7?)
    	/code-go/go/src/github.com/cshum/imagor/vips/image.go:618 +0x25 fp=0xc2797c80f0 sp=0xc2797c80b8 pc=0xb077e5
    github.com/cshum/imagor/vips.(*Processor).Thumbnail(0x22dee7eb840?, 0xc0d5537240?, 0x0?, 0xc2797c81b0?, 0x475611?, 0x0?)
    	/code-go/go/src/github.com/cshum/imagor/vips/processor.go:271 +0xad fp=0xc2797c8150 sp=0xc2797c80f0 pc=0xafed4d
    github.com/cshum/imagor/vips.(*Processor).process(_, {_, _}, _, {0x0, {0xc0588ca600, 0x3a}, {0x0, 0x0}, 0x1, ...}, ...)
    	/code-go/go/src/github.com/cshum/imagor/vips/process.go:441 +0xeb3 fp=0xc2797c8418 sp=0xc2797c8150 pc=0xafb5f3
    github.com/cshum/imagor/vips.(*Processor).Process(_, {_, _}, _, {0x0, {0xc0588ca600, 0x3a}, {0x0, 0x0}, 0x1, ...}, ...)
    	/code-go/go/src/github.com/cshum/imagor/vips/process.go:278 +0xfc8 fp=0xc2797c88c0 sp=0xc2797c8418 pc=0xaf9028
    github.com/cshum/imagor.(*Imagor).Do.func2({0x13cc688, 0xc051e62780}, 0x129a968)
    	/code-go/go/src/github.com/cshum/imagor/imagor.go:362 +0x1149 fp=0xc2797c9270 sp=0xc2797c88c0 pc=0xaec009
    github.com/cshum/imagor.(*Imagor).suppress(0x0?, {0x13cc688?, 0xc051e62780?}, {0x0?, 0x0?}, 0x1?)
    	/code-go/go/src/github.com/cshum/imagor/imagor.go:571 +0x60f fp=0xc2797c9410 sp=0xc2797c9270 pc=0xaef04f
    github.com/cshum/imagor.(*Imagor).Do(_, _, {0x0, {0x0, 0x0}, {0x0, 0x0}, 0x1, {0x0, 0x0}, ...})
    
  • How to activate file saving?

    How to activate file saving?

    Great tool! The only question I have is how to activate file saving: I have defined the FILE_STORAGE_BASE_DIR in the docker-compose.yml file yet nothing happens when triggering the image treatments from the browser.

  • S3 paths with url encoding not working

    S3 paths with url encoding not working

    I am currently testing locally imagor as a drop in replacement for our Thumbor implementation. We currently use an S3 loader and we're trying to emulate that with our local testing. However, we are getting errors when trying to implement it. I believe it has to do with url encoding special characters in the file path.

    Here is the url we are using:

    http://localhost:8888/unsafe/400x200/smart/photos/j/006b8bbe2c1baa8f2d12c06988a6efa7a15f048d.jpg
    

    Here is the result:

    {"message":"Get \"https://photos/j/006b8bbe2c1baa8f2d12c06988a6efa7a15f048d.jpg\": dial tcp: lookup photos on 127.0.0.11:53: no such host","status":500}
    

    If I url encode the path of the photo, then it works:

    photos%2Fj%2F006b8bbe2c1baa8f2d12c06988a6efa7a15f048d.jpg
    

    But if the url encoded path has special characters in the filename, such as { to %7B, it gets an error:

    photos%2F{1089856636549d026d369fb}.jpg
    

    to

    photos%2F%7B1089856636549d026d369fb%7D.jpg
    
    {"message":"Get \"https://photos/%7B1089856636549d026d369fb%7D.jpg\": dial tcp: lookup photos on 127.0.0.11:53: no such host","status":500}
    

    I'm assuming this is an issue because when querying s3 for the file, imagor is passing the url-encoded string instead of the actual filename. imagor should probably url-decode the string before making the request to s3. Thoughts?

  • Accept encoded reserved characters

    Accept encoded reserved characters

    Attempting to request images using encoded characters results in a Bad Request error: {"message":"invalid","status":400}

    Here is an example URL causing this, by encoding the :() characters:

    http://localhost:8000/unsafe/filters%3Afill%28red%29/https://raw.githubusercontent.com/cshum/imagor/master/testdata/gopher.png

    If using URL Signature, the error is instead {"message":"url signature mismatch","status":403}.

    I am aware the characters in question do not need to be encoded. I noticed this issue when some applications were unable to create a preview of the image. Checking the logs, I see the preview crawler encodes the parenthesis, hence failing the request.

  • About caching

    About caching

    Hi,

    How can turn on caching? I've tried

    ...
    IMAGOR_CACHE_HEADER_TTL: 10000h0m0s
    IMAGOR_CACHE_HEADER_SWR: 10000h0m0s
    IMAGOR_CACHE_HEADER_NO_CACHE: 0
    S3_STORAGE_EXPIRATION: 1000h
    S3_RESULT_STORAGE_EXPIRATION: 1000h
    ...
    

    but an image loaded(maybe render) every time.

    Response headers look like

    Status Code: 200 
    cache-control: public, s-maxage=36000000, max-age=36000000, no-transform
    content-disposition: inline
    content-length: 92576
    content-type: image/webp
    date: Sat, 15 Oct 2022 02:57:38 GMT
    expires: Tue, 05 Dec 2023 18:57:38 GMT
    
  • AWS S3: Default credentials

    AWS S3: Default credentials

    Hey there, I am a bit fan of this project thus far. Thank you for the work.

    I am attempting to run imagor on a fargate cluster, and I would like to use the ECS Task Role to handle the S3 permissions so that I don't need to manage a set of keys.

    It appears imagor wont attempt to initialize s3 unless the credentials are provided, which stops the aws sdk from trying to default credential provider chain.

    Creating this issue to see if theres any potential workaround, or simply bring this to attention.

    Thank you!

    Heres some documentation

    https://docs.aws.amazon.com/sdk-for-go/api/aws/defaults/#CredChain https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html

  • 406 VipsJpeg: Premature end of input file

    406 VipsJpeg: Premature end of input file

    Hi, I recently upgraded the imagor to v1.0.0 and I saw this error in docker container log many times for different images:

    {
        "level": "warn",
        "ts": 1660161069.1208205,
        "caller": "imagor/imagor.go:326",
        "msg": "process",
        "params": {
            "path": "fit-in/1280x720/filters:format(webp)/xxxx",
            "image": "xxxx",
            "hash": "xxxxx",
            "fit_in": true,
            "width": 1280,
            "height": 720,
            "filters": [
                {
                    "name": "format",
                    "args": "webp"
                }
            ]
        },
        "error": "imagor: 406 VipsJpeg: Premature end of input file"
    }
    
  • Access rights considerations in a docker installation

    Access rights considerations in a docker installation

    I have an image present at the right location (I checked), with the right authorizations, with a fairly standard name: IMG_20180408_153807553_HDR.jpg

    And yet it is not treated by the Imagor server with this error: {"Op":"Get","URL":"https://pho/tst/IMG_20180408_153807553_HDR.jpg","Err":{"Op":"dial","Net":"tcp","Source":null,"Addr":null,"Err":{"Err":"no such host","Name":"pho","Server":"127.0.0.11:53","IsTimeout":false,"IsTemporary":false,"IsNotFound":true}}}

    Other images with underscores or uppercase letters are being treated fine in the exact same environment. The only difference is that the image weighs 3MB but that should not be an issue and is not what the error reports anyway.

    Please let me know what I am doing wrong.

  • Feature request: Signature expiration

    Feature request: Signature expiration

    Hey there, big thanks again for this project.

    One use case my company is exploring is including an expiration time within the imagor signature, making links invalid after a certain timeframe.

    We are currently expirementing doing this with cloudfront however having it build directly into imagor would be ideal as it would avoid two signatures.

    I would be happy to discuss how we could support the development of this!

  • build(deps): bump github.com/rs/cors from 1.8.2 to 1.8.3

    build(deps): bump github.com/rs/cors from 1.8.2 to 1.8.3

    Bumps github.com/rs/cors from 1.8.2 to 1.8.3.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
  • build(deps): bump github.com/fsouza/fake-gcs-server from 1.42.2 to 1.43.0

    build(deps): bump github.com/fsouza/fake-gcs-server from 1.42.2 to 1.43.0

    Bumps github.com/fsouza/fake-gcs-server from 1.42.2 to 1.43.0.

    Release notes

    Sourced from github.com/fsouza/fake-gcs-server's releases.

    v1.43.0

    What's Changed

    New Contributors

    Full Changelog: https://github.com/fsouza/fake-gcs-server/compare/v1.42.2...v1.43.0

    Commits
    • e6f1413 Make resumable uploads work from browser with signed url (#1022)
    • 041da75 Do not escape the object name in the fs backend (#1017)
    • 23a976c Add ability to change log level (#1023)
    • a72af60 Custom metadata missing in Public and Signed URLs #1019 (#1020)
    • 514832f build(deps): bump actions/cache from 3.2.1 to 3.2.2 (#1021)
    • ef33501 build(deps): bump actions/cache from 3.2.0 to 3.2.1 (#1018)
    • 10234b0 build(deps): bump actions/cache from 3.0.11 to 3.2.0 (#1015)
    • 07968e5 build(deps): bump google.golang.org/api in /examples/go (#1011)
    • 8385d06 build(deps): bump google.golang.org/api from 0.104.0 to 0.105.0 (#1012)
    • 03a2199 build(deps): bump actions/setup-go from 3.4.0 to 3.5.0 (#1008)
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
  • build(deps): bump github.com/aws/aws-sdk-go from 1.44.153 to 1.44.171

    build(deps): bump github.com/aws/aws-sdk-go from 1.44.153 to 1.44.171

    Bumps github.com/aws/aws-sdk-go from 1.44.153 to 1.44.171.

    Release notes

    Sourced from github.com/aws/aws-sdk-go's releases.

    Release v1.44.171 (2022-12-30)

    Service Client Updates

    • service/cloudfront: Updates service API and documentation
      • Extend response headers policy to support removing headers from viewer responses
    • service/iotfleetwise: Updates service documentation

    Release v1.44.170 (2022-12-29)

    Service Client Updates

    • service/apigateway: Updates service documentation
      • Documentation updates for Amazon API Gateway
    • service/elasticmapreduce: Updates service API and documentation
      • Added GetClusterSessionCredentials API to allow Amazon SageMaker Studio to connect to EMR on EC2 clusters with runtime roles and AWS Lake Formation-based access control for Apache Spark, Apache Hive, and Presto queries.
    • service/secretsmanager: Updates service API and documentation
      • Added owning service filter, include planned deletion flag, and next rotation date response parameter in ListSecrets.
    • service/wisdom: Updates service API and documentation

    Release v1.44.169 (2022-12-28)

    Service Client Updates

    • service/elasticache: Updates service API and documentation
      • This release allows you to modify the encryption in transit setting, for existing Redis clusters. You can now change the TLS configuration of your Redis clusters without the need to re-build or re-provision the clusters or impact application availability.
    • service/network-firewall: Updates service API and documentation
    • service/rds: Updates service API, documentation, waiters, paginators, and examples
      • This release adds support for Custom Engine Version (CEV) on RDS Custom SQL Server.
    • service/route53-recovery-control-config: Updates service documentation and paginators

    Release v1.44.168 (2022-12-27)

    Service Client Updates

    • service/memorydb: Updates service API, documentation, and paginators
    • service/transfer: Updates service API
      • Add additional operations to throw ThrottlingExceptions

    Release v1.44.167 (2022-12-23)

    Service Client Updates

    • service/connect: Updates service API and documentation
    • service/connectparticipant: Updates service API and documentation
    • service/detective: Updates service API and documentation
    • service/fsx: Updates service API and documentation
    • service/inspector2: Updates service API

    Release v1.44.166 (2022-12-22)

    ... (truncated)

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
  • vips/pointer

    vips/pointer

    @cshum Can you tell me a little bit about what the vips/pointer stuff is doing in callback.go? Is this a defensive mechanism to ensure the buffer belongs to a known source and not some random location in memory?

  • Idea for better JPEG decoding

    Idea for better JPEG decoding

    Noticed this comment from user JyrkiAlakuijala on HN:

    Also good to know that Jpegli (a traditional jpeg codec within libjxl) allows for 16 bit input and 
    output for '8-bit jpegs' and can deliver about ~12 bits of dynamics for the slowest gradients
    and ~10.5 bits for the usual photographs.
    
    Jpegli improves existing jpeg images by about 8 % by doing decoding more precisely.
    
    [...]
    Jpegli is predicted to be production ready in April or so, but can be benchmarked already.
    

    And thought it might be interesting exploring (when Jpegli is production ready) the option of doing decoding with Jpegli before re-compressing images to squeeze out a little more image quality.

  • feat(server): Add optional Prometheus metrics server

    feat(server): Add optional Prometheus metrics server

    • Add optional --metrics flag to enable metrics
    • Additional configuration with --metrics-address, --metrics-port, --metrics-path
    • Rgenerate options list in README
Fast docker image distribution plugin for containerd, based on CRFS/stargz
Fast docker image distribution plugin for containerd, based on CRFS/stargz

[ ⬇️ Download] [ ?? Browse images] [ ☸ Quick Start (Kubernetes)] [ ?? Quick Start (nerdctl)] Stargz Snapshotter Read also introductory blog: Startup C

Dec 29, 2022
Putty-url-scheme - Open PuTTY as a url scheme

PuTTY URL Scheme Helper Open PuTTY as a url scheme Install download release bina

Apr 25, 2022
This image is primarily used to ping/call a URL on regular intervals using Kubernetes (k8s) CronJob.

A simple webhook caller This image is primarily used to ping/call a URL on regular intervals using Kubernetes (k8s) CronJob. A sample job would look s

Nov 30, 2021
A docker image and a launcher to run sasm on Windows and MacOS
A docker image and a launcher to run sasm on Windows and MacOS

Sasm-docker Sasm-docker simplifies the setup and use of SASM by running it inside a docker container and using x11 (X Window System) in order to displ

Nov 14, 2022
k8s-image-swapper Mirror images into your own registry and swap image references automatically.
k8s-image-swapper Mirror images into your own registry and swap image references automatically.

k8s-image-swapper Mirror images into your own registry and swap image references automatically. k8s-image-swapper is a mutating webhook for Kubernetes

Dec 27, 2022
Dockpin - A tool for pinning Docker image and apt package versions

Dockpin Install dockpin with: go install github.com/Jille/dockpin@latest Dockpin

Dec 20, 2022
This action prints "true" if image is required to update based on the base image update.

container-image-updater This action prints "true" if image is required to update based on the base image update. Inputs Name Type Description base-ima

Apr 15, 2022
Explore Docker registries and manipulate Docker images!
Explore Docker registries and manipulate Docker images!

L/S tags Utility and API to manipulate (analyze, synchronize and aggregate) images across different Docker registries. Example invocation $ lstags alp

Nov 25, 2022
Dotnet-appsettings-env - Convert .NET appsettings.json file to Kubernetes, Docker and Docker-Compose environment variables

dotnet-appsettings-env Convert .NET appsettings.json file to Kubernetes, Docker

Dec 30, 2022
Dotnet-appsettings-env - Convert .NET appsettings.json file to Kubernetes, Docker and Docker-Compose environment variables

dotnet-appsettings-env Convert .NET appsettings.json file to Kubernetes, Docker

Feb 16, 2022
A tool to restart a Docker container with a newer version of the image

repull A tool to restart a Docker container with a newer version of an image used by the container Often you may need to pull a newer version of an im

Nov 28, 2022
Triggers an update to a Koyeb app service to re-deploy the latest docker image

Triggers an update to a Koyeb app service to re-deploy the latest docker image

May 5, 2021
Docker image for setting up one or multiple TCP ports forwarding, using socat

Docker socat Port Forward Docker image for setting up one or multiple TCP ports forwarding, using socat. Getting started The ports mappings are set wi

Dec 20, 2022
A docker image for test redis HA

Guide 测试集群模式(Test Redis Cluster) redis-test --arch cluster 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 测试哨兵模式(TEST Redis Sentinel) redis-test --arc

Nov 30, 2021
A Docker image that allows you to use Hetzner DNS as a DynDNS Provider

Docker Hetzner DDNS This Docker image will allow you to use the Hetzner DNS Service as a Dynamic DNS Provider (DDNS). How does it work? The Go script

Dec 27, 2022
EdgeDB-Golang-Docker-Sample - The sample of connection between EdgeDB Server and Go Echo API Server

EdgeDB Golang Docker Sample 『Go + Docker Composeを使ってEdgeDBを動かしてみた』のサンプルコードです。 使い

Nov 2, 2022
A minimal Go project with user authentication ready out of the box. All frontend assets should be less than 100 kB on every page load

Golang Base Project A minimal Golang project with user authentication ready out of the box. All frontend assets should be less than 100 kB on every pa

Jan 1, 2023
Ready to deploy, distributed cryptocurrency trading bot
Ready to deploy, distributed cryptocurrency trading bot

HyperTrade Ready to deploy, distributed cryptocurrency trading bot. USE THIS SOFTWARE AT YOUR OWN RISK. THE AUTHOR ASSUMES NO LIABILITY FOR YOUR TRADI

Dec 28, 2022
Docker-based remote code runner / 基于 Docker 的远程代码运行器
Docker-based remote code runner / 基于 Docker 的远程代码运行器

Docker-based remote code runner / 基于 Docker 的远程代码运行器

Nov 9, 2022