{"id":13413200,"url":"https://github.com/h2non/imaginary","last_synced_at":"2025-12-16T01:29:06.274Z","repository":{"id":28172549,"uuid":"31673858","full_name":"h2non/imaginary","owner":"h2non","description":"Fast, simple, scalable, Docker-ready HTTP microservice for high-level image processing","archived":false,"fork":false,"pushed_at":"2025-01-14T00:15:09.000Z","size":18542,"stargazers_count":5841,"open_issues_count":127,"forks_count":471,"subscribers_count":77,"default_branch":"master","last_synced_at":"2025-05-16T01:01:47.191Z","etag":null,"topics":["crop-image","docker","gif","image","image-processing","jpeg","libvips","microservice","png","resize-images","watermark","webp"],"latest_commit_sha":null,"homepage":"https://fly.io/docs/app-guides/run-a-global-image-service/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/h2non.png","metadata":{"files":{"readme":"README.md","changelog":"History.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"open_collective":"imaginary"}},"created_at":"2015-03-04T18:51:40.000Z","updated_at":"2025-05-14T22:20:13.000Z","dependencies_parsed_at":"2023-01-14T08:17:04.329Z","dependency_job_id":"951c6ad0-3f3c-4578-8c8e-0005640ebbaa","html_url":"https://github.com/h2non/imaginary","commit_stats":{"total_commits":539,"total_committers":58,"mean_commits":9.293103448275861,"dds":"0.25231910946196656","last_synced_commit":"6cd9edd1d3fb151eb773c14552886e4fc8e50138"},"previous_names":["h2non/imgine"],"tags_count":58,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/h2non%2Fimaginary","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/h2non%2Fimaginary/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/h2non%2Fimaginary/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/h2non%2Fimaginary/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/h2non","download_url":"https://codeload.github.com/h2non/imaginary/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254448579,"owners_count":22072764,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crop-image","docker","gif","image","image-processing","jpeg","libvips","microservice","png","resize-images","watermark","webp"],"created_at":"2024-07-30T20:01:35.017Z","updated_at":"2025-12-16T01:29:05.690Z","avatar_url":"https://github.com/h2non.png","language":"Go","readme":"# imaginary [![Docker](https://img.shields.io/badge/docker-h2non/imaginary-blue.svg)](https://hub.docker.com/r/h2non/imaginary/) [![Docker Registry](https://img.shields.io/docker/pulls/h2non/imaginary.svg)](https://hub.docker.com/r/h2non/imaginary/) [![Fly.io](https://img.shields.io/badge/deploy-fly.io-blue.svg)](https://fly.io/launch/github/h2non/imaginary)\n\n**[Fast](#benchmarks) HTTP [microservice](http://microservices.io/patterns/microservices.html)** written in Go **for high-level image processing** backed by [bimg](https://github.com/h2non/bimg) and [libvips](https://github.com/jcupitt/libvips). `imaginary` can be used as private or public HTTP service for massive image processing with first-class support for [Docker](#docker) \u0026 [Fly.io](#flyio).\nIt's almost dependency-free and only uses [`net/http`](http://golang.org/pkg/net/http/) native package without additional abstractions for better [performance](#performance).\n\nSupports multiple [image operations](#supported-image-operations) exposed as a simple [HTTP API](#http-api),\nwith additional optional features such as **API token authorization**, **URL signature protection**, **HTTP traffic throttle** strategy and **CORS support** for web clients.\n\n`imaginary` **can read** images **from HTTP POST payloads**, **server local path** or **remote HTTP servers**, supporting **JPEG**, **PNG**, **WEBP**, **HEIF**, and optionally **TIFF**, **PDF**, **GIF** and **SVG** formats if `libvips@8.3+` is compiled with proper library bindings.\n\n`imaginary` is able to output images as JPEG, PNG and WEBP formats, including transparent conversion across them.\n\n`imaginary` optionally **supports image placeholder fallback mechanism** in case of image processing error or server error of any nature, hence an image will be always returned by imaginary even in case of error, trying to match the requested image size and format type transparently. The error details will be provided in the response HTTP header `Error` field serialized as JSON.\n\n`imaginary` uses internally `libvips`, a powerful and efficient library written in C for fast image processing\nwhich requires a [low memory footprint](https://github.com/libvips/libvips/wiki/Benchmarks)\nand it's typically 4x faster than using the quickest ImageMagick and GraphicsMagick\nsettings or Go native `image` package, and in some cases it's even 8x faster processing JPEG images.\n\nTo get started, take a look the [installation](#installation) steps, [usage](#command-line-usage) cases and [API](#http-api) docs.\n\n## Contents\n\n- [Supported image operations](#supported-image-operations)\n- [Prerequisites](#prerequisites)\n- [Installation](#installation)\n  - [Docker](#docker)\n  - [Fly.io](#flyio)\n  - [Cloud Foundry](#cloudfoundry)\n  - [Google Cloud Run](#google-cloud-run)\n- [Recommended resources](#recommended-resources)\n- [Production notes](#production-notes)\n- [Scalability](#scalability)\n- [Clients](#clients)\n- [Performance](#performance)\n- [Benchmark](#benchmark)\n- [Command-line usage](#command-line-usage)\n- [HTTP API](#http-api)\n  - [Authorization](#authorization)\n  - [URL signature](#url-signature)\n  - [Errors](#errors)\n  - [Form data](#form-data)\n  - [Params](#params)\n  - [Endpoints](#get-)\n- [Logging](#logging)\n  - [Fluentd log ingestion](#fluentd-log-ingestion)\n- [Authors](#authors)\n- [License](#license)\n\n## Supported image operations\n\n- Resize\n- Enlarge\n- Crop\n- SmartCrop (based on [libvips built-in algorithm](https://github.com/jcupitt/libvips/blob/master/libvips/conversion/smartcrop.c))\n- Rotate (with auto-rotate based on EXIF orientation)\n- AutoRotate with further image transformations (based on EXIF metadata orientation)\n- Flip (with auto-flip based on EXIF metadata)\n- Flop\n- Zoom\n- Thumbnail\n- Fit\n- [Pipeline](#get--post-pipeline) of multiple independent image transformations in a single HTTP request.\n- Configurable image area extraction\n- Embed/Extend image, supporting multiple modes (white, black, mirror, copy or custom background color)\n- Watermark (customizable by text)\n- Watermark image\n- Custom output color space (RGB, black/white...)\n- Format conversion (with additional quality/compression settings)\n- Info (image size, format, orientation, alpha...)\n- Reply with default or custom placeholder image in case of error.\n- Blur\n\n## Prerequisites\n\n- [libvips](https://github.com/jcupitt/libvips) 8.8+ (8.9+ recommended)\n- C compatible compiler such as gcc 4.6+ or clang 3.0+\n- Go 1.12+\n\n## Installation\n\n```bash\ngo get -u github.com/h2non/imaginary\n```\n\nAlso, be sure you have the latest version of `bimg`:\n```bash\ngo get -u github.com/h2non/bimg\n```\n\n### libvips\n\nRun the following script as `sudo` (supports OSX, Debian/Ubuntu, Redhat, Fedora, Amazon Linux):\n```bash\ncurl -s https://raw.githubusercontent.com/h2non/bimg/master/preinstall.sh | sudo bash -\n```\n\nThe [install script](https://github.com/h2non/bimg/blob/master/preinstall.sh) requires `curl` and `pkg-config`\n\n### Docker\n\nSee [Dockerfile](https://github.com/h2non/imaginary/blob/master/Dockerfile) for image details.\n\nFetch the image (comes with latest stable Go and `libvips` versions)\n```\ndocker pull h2non/imaginary\n```\n\nStart the container with optional flags (default listening on port 9000)\n```\ndocker run -p 9000:9000 h2non/imaginary -cors\n```\n\nStart the container enabling remote URL source image processing via GET requests and `url` query param.\n```\ndocker run -p 9000:9000 h2non/imaginary -p 9000 -enable-url-source\n```\n\nStart the container enabling local directory image process via GET requests and `file` query param.\n```\ndocker run -p 9000:9000 h2non/imaginary -p 900 -mount /volume/images\n```\n\nStart the container in debug mode:\n```\ndocker run -p 9000:9000 -e \"DEBUG=*\" h2non/imaginary\n```\n\nEnter to the interactive shell in a running container\n```\nsudo docker exec -it \u003ccontainerIdOrName\u003e bash\n```\n\nStop the container\n```\ndocker stop h2non/imaginary\n```\n\nFor more usage examples, see the [command line usage](#command-line-usage).\n\nAll Docker images tags are available [here](https://hub.docker.com/r/h2non/imaginary/tags/).\n\n#### Docker Compose\n\nYou can add `imaginary` to your `docker-compose.yml` file:\n\n```yaml\nversion: \"3\"\nservices:\n  imaginary:\n    image: h2non/imaginary:latest\n    # optionally mount a volume as local image source\n    volumes:\n      - images:/mnt/data\n    environment:\n       PORT: 9000\n    command: -enable-url-source -mount /mnt/data\n    ports:\n      - \"9000:9000\"\n```\n\n### Fly.io\n\nDeploy imaginary in seconds close to your users in [Fly.io](https://fly.io) cloud by clicking on the button below:\n\n\u003ca href=\"https://fly.io/docs/app-guides/run-a-global-image-service/\"\u003e\n  \u003cimg src=\"testdata/flyio-button.svg?raw=true\" width=\"200\"\u003e\n\u003c/a\u003e\n\n#### About Fly.io\n\nFly is a platform for applications that need to run globally. It runs your code close to users and scales compute in cities where your app is busiest. Write your code, package it into a Docker image, deploy it to Fly's platform and let that do all the work to keep your app snappy.\n\nYou can [learn more](https://fly.io/docs/) about how Fly.io can reduce latency and provide a better experience by serving traffic close to your users location.\n\n#### Global image service tutorial\n\n[Learn more](https://fly.io/docs/app-guides/run-a-global-image-service/) about how to run a custom deployment of imaginary on the Fly.io cloud.\n\n### CloudFoundry\n\nAssuming you have cloudfoundry account, [bluemix](https://console.ng.bluemix.net/) or [pivotal](https://console.run.pivotal.io/) and [command line utility installed](https://github.com/cloudfoundry/cli).\n\nClone this repository:\n```\ngit clone https://github.com/h2non/imaginary.git\n```\n\nPush the application\n```\ncf push -b https://github.com/yacloud-io/go-buildpack-imaginary.git imaginary-inst01 --no-start\n```\n\nDefine the library path\n```\ncf set-env imaginary-inst01 LD_LIBRARY_PATH /home/vcap/app/vendor/vips/lib\n```\n\nStart the application\n```\ncf start imaginary-inst01\n```\n\n### Google Cloud Run\n\nClick to deploy on Google Cloud Run:\n\n[![Run on Google Cloud](https://deploy.cloud.run/button.svg)](https://deploy.cloud.run)\n\n### Recommended resources\n\nGiven the multithreaded native nature of Go, in terms of CPUs, most cores means more concurrency and therefore, a better performance can be achieved.\nFrom the other hand, in terms of memory, 512MB of RAM is usually enough for small services with low concurrency (\u003c5 requests/second).\nUp to 2GB for high-load HTTP service processing potentially large images or exposed to an eventual high concurrency.\n\nIf you need to expose `imaginary` as public HTTP server, it's highly recommended to protect the service against DDoS-like attacks.\n`imaginary` has built-in support for HTTP concurrency throttle strategy to deal with this in a more convenient way and mitigate possible issues limiting the number of concurrent requests per second and caching the awaiting requests, if necessary.\n\n### Production notes\n\nIn production focused environments it's highly recommended to enable the HTTP concurrency throttle strategy in your `imaginary` servers.\n\nThe recommended concurrency limit per server to guarantee a good performance is up to `20` requests per second.\n\nYou can enable it simply passing a flag to the binary:\n```\n$ imaginary -concurrency 20\n```\n\n### Memory issues\n\nIn case you are experiencing any persistent unreleased memory issues in your deployment, you can try passing this environment variables to `imaginary`:\n\n```\nMALLOC_ARENA_MAX=2 imaginary -p 9000 -enable-url-source\n```\n\n### Graceful shutdown\n\nWhen you use a cluster, it is necessary to control how the deployment is executed, and it is very useful to finish the containers in a controlled manner.\n\nYou can use the next command:\n\n```\n$ ps auxw | grep 'bin/imaginary' | awk 'NR\u003e1{print buf}{buf = $2}' | xargs kill -TERM \u003e /dev/null 2\u003e\u00261\n```\n\n### Scalability\n\nIf you're looking for a large scale solution for massive image processing, you should scale `imaginary` horizontally, distributing the HTTP load across a pool of imaginary servers.\n\nAssuming that you want to provide a high availability to deal efficiently with, let's say, 100 concurrent req/sec, a good approach would be using a front end balancer (e.g: HAProxy) to delegate the traffic control flow, ensure the quality of service and distribution the HTTP across a pool of servers:\n\n```\n        |==============|\n        |  Dark World  |\n        |==============|\n              ||||\n        |==============|\n        |   Balancer   |\n        |==============|\n           |       |\n          /         \\\n         /           \\\n        /             \\\n /-----------\\   /-----------\\\n | imaginary |   | imaginary | (*n)\n \\-----------/   \\-----------/\n```\n\n## Clients\n\n- [node.js](https://github.com/h2non/node-imaginary)\n\nFeel free to send a PR if you created a client for other language.\n\n## Performance\n\nlibvips is probably the faster open source solution for image processing.\nHere you can see some performance test comparisons for multiple scenarios:\n\n- [libvips speed and memory usage](https://github.com/libvips/libvips/wiki/Benchmarks)\n- [bimg](https://github.com/h2non/bimg#Performance) (Go library with C bindings to libvips)\n\n## Benchmark\n\nSee [benchmark.sh](https://github.com/h2non/imaginary/blob/master/benchmark.sh) for more details\n\nEnvironment: Go 1.4.2. libvips-7.42.3. OSX i7 2.7Ghz\n\n```\nRequests  [total]       200\nDuration  [total, attack, wait]   10.030639787s, 9.949499515s, 81.140272ms\nLatencies [mean, 50, 95, 99, max]   83.124471ms, 82.899435ms, 88.948008ms, 95.547765ms, 104.384977ms\nBytes In  [total, mean]     23443800, 117219.00\nBytes Out [total, mean]     175517000, 877585.00\nSuccess   [ratio]       100.00%\nStatus Codes  [code:count]      200:200\n```\n\n### Conclusions\n\n`imaginary` can deal efficiently with up to 20 request per second running in a multicore machine,\nwhere it crops a JPEG image of 5MB and spending per each request less than 100 ms\n\nThe most expensive image operation under high concurrency scenarios (\u003e 20 req/sec) is the image enlargement, which requires a considerable amount of math operations to scale the original image. In this kind of operation the required processing time usually grows over the time if you're stressing the server continuously. The advice here is as simple as taking care about the number of concurrent enlarge operations to avoid server performance bottlenecks.\n\n## Command-line usage\n\n```\nUsage:\n  imaginary -p 80\n  imaginary -cors\n  imaginary -concurrency 10\n  imaginary -path-prefix /api/v1\n  imaginary -enable-url-source\n  imaginary -disable-endpoints form,health,crop,rotate\n  imaginary -enable-url-source -allowed-origins http://localhost,http://server.com,http://*.example.org\n  imaginary -enable-url-source -enable-auth-forwarding\n  imaginary -enable-url-source -authorization \"Basic AwDJdL2DbwrD==\"\n  imaginary -enable-placeholder\n  imaginary -enable-url-source -placeholder ./placeholder.jpg\n  imaginary -enable-url-signature -url-signature-key 4f46feebafc4b5e988f131c4ff8b5997\n  imaginary -enable-url-source -forward-headers X-Custom,X-Token\n  imaginary -h | -help\n  imaginary -v | -version\n\nOptions:\n  -a \u003caddr\u003e                 Bind address [default: *]\n  -p \u003cport\u003e                 Bind port [default: 8088]\n  -h, -help                 Show help\n  -v, -version              Show version\n  -path-prefix \u003cvalue\u003e      Url path prefix to listen to [default: \"/\"]\n  -cors                     Enable CORS support [default: false]\n  -gzip                     Enable gzip compression (deprecated) [default: false]\n  -disable-endpoints        Comma separated endpoints to disable. E.g: form,crop,rotate,health [default: \"\"]\n  -key \u003ckey\u003e                Define API key for authorization\n  -mount \u003cpath\u003e             Mount server local directory\n  -http-cache-ttl \u003cnum\u003e     The TTL in seconds. Adds caching headers to locally served files.\n  -http-read-timeout \u003cnum\u003e  HTTP read timeout in seconds [default: 60]\n  -http-write-timeout \u003cnum\u003e HTTP write timeout in seconds [default: 60]\n  -enable-url-source        Enable remote HTTP URL image source processing (?url=http://..)\n  -enable-placeholder       Enable image response placeholder to be used in case of error [default: false]\n  -enable-auth-forwarding   Forwards X-Forward-Authorization or Authorization header to the image source server. -enable-url-source flag must be defined. Tip: secure your server from public access to prevent attack vectors\n  -forward-headers          Forwards custom headers to the image source server. -enable-url-source flag must be defined.\n  -enable-url-signature     Enable URL signature (URL-safe Base64-encoded HMAC digest) [default: false]\n  -url-signature-key        The URL signature key (32 characters minimum)\n  -allowed-origins \u003curls\u003e   Restrict remote image source processing to certain origins (separated by commas). Note: Origins are validated against host *AND* path.\n  -max-allowed-size \u003cbytes\u003e Restrict maximum size of http image source (in bytes)\n  -max-allowed-resolution \u003cmegapixels\u003e Restrict maximum resolution of the image [default: 18.0]\n  -certfile \u003cpath\u003e          TLS certificate file path\n  -keyfile \u003cpath\u003e           TLS private key file path\n  -authorization \u003cvalue\u003e    Defines a constant Authorization header value passed to all the image source servers. -enable-url-source flag must be defined. This overwrites authorization headers forwarding behavior via X-Forward-Authorization\n  -placeholder \u003cpath\u003e       Image path to image custom placeholder to be used in case of error. Recommended minimum image size is: 1200x1200\n  -concurrency \u003cnum\u003e        Throttle concurrency limit per second [default: disabled]\n  -burst \u003cnum\u003e              Throttle burst max cache size [default: 100]\n  -mrelease \u003cnum\u003e           OS memory release interval in seconds [default: 30]\n  -cpus \u003cnum\u003e               Number of used cpu cores.\n                            (default for current machine is 8 cores)\n  -log-level                Set log level for http-server. E.g: info,warning,error [default: info].\n                            Or can use the environment variable GOLANG_LOG=info.\n```\n\nStart the server in a custom port:\n```bash\nimaginary -p 8080\n```\n\nAlso, you can pass the port as environment variable:\n```bash\nPORT=8080 imaginary\n```\n\nEnable HTTP server throttle strategy (max 10 requests/second):\n```\nimaginary -p 8080 -concurrency 10\n```\n\nEnable remote URL image fetching (then you can do GET request passing the `url=http://server.com/image.jpg` query param):\n```\nimaginary -p 8080 -enable-url-source\n```\n\nMount local directory (then you can do GET request passing the `file=image.jpg` query param):\n```\nimaginary -p 8080 -mount ~/images\n```\n\nEnable authorization header forwarding to image origin server. `X-Forward-Authorization` or `Authorization` (by priority) header value will be forwarded as `Authorization` header to the target origin server, if one of those headers are present in the incoming HTTP request.\nSecurity tip: secure your server from public access to prevent attack vectors when enabling this option:\n```\nimaginary -p 8080 -enable-url-source -enable-auth-forwarding\n```\n\nOr alternatively you can manually define an constant Authorization header value that will be always sent when fetching images from remote image origins. If defined, `X-Forward-Authorization` or `Authorization` headers won't be forwarded, and therefore ignored, if present.\n**Note**:\n```\nimaginary -p 8080 -enable-url-source -authorization \"Bearer s3cr3t\"\n```\n\nSend fixed caching headers in the response. The headers can be set in either \"cache nothing\" or \"cache for N seconds\". By specifying `0` imaginary will send the \"don't cache\" headers, otherwise it sends headers with a TTL. The following example informs the client to cache the result for 1 year:\n```\nimaginary -p 8080 -enable-url-source -http-cache-ttl 31556926\n```\n\nEnable placeholder image HTTP responses in case of server error/bad request.\nThe placeholder image will be dynamically and transparently resized matching the expected image `width`x`height` define in the HTTP request params.\nAlso, the placeholder image will be also transparently converted to the desired image type defined in the HTTP request params, so the API contract should be maintained as much better as possible.\n\nThis feature is particularly useful when using `imaginary` as public HTTP service consumed by Web clients.\nIn case of error, the appropriate HTTP status code will be used to reflect the error, and the error details will be exposed serialized as JSON in the `Error` response HTTP header, for further inspection and convenience for API clients.\n```\nimaginary -p 8080 -enable-placeholder -enable-url-source\n```\n\nYou can optionally use a custom placeholder image.\nSince the placeholder image should fit a variety of different sizes, it's recommended to use a large image, such as `1200`x`1200`.\nSupported custom placeholder image types are: `JPEG`, `PNG` and `WEBP`.\n```\nimaginary -p 8080 -placeholder=placeholder.jpg -enable-url-source\n```\n\nEnable URL signature (URL-safe Base64-encoded HMAC digest).\n\nThis feature is particularly useful to protect against multiple image operations attacks and to verify the requester identity.\n```\nimaginary -p 8080 -enable-url-signature -url-signature-key 4f46feebafc4b5e988f131c4ff8b5997\n```\n\nIt is recommended to pass key as environment variables:\n```\nURL_SIGNATURE_KEY=4f46feebafc4b5e988f131c4ff8b5997 imaginary -p 8080 -enable-url-signature\n```\n\nIncrease libvips threads concurrency (experimental):\n```\nVIPS_CONCURRENCY=10 imaginary -p 8080 -concurrency 10\n```\n\nEnable debug mode:\n```\nDEBUG=* imaginary -p 8080\n```\n\nOr filter debug output by package:\n```\nDEBUG=imaginary imaginary -p 8080\n```\n\nDisable info logs:\n```\nGOLANG_LOG=error imaginary -p 8080\n```\n\n#### Examples\n\nReading a local image (you must pass the `-mount=\u003cdirectory\u003e` flag):\n```\ncurl -O \"http://localhost:8088/crop?width=500\u0026height=400\u0026file=foo/bar/image.jpg\"\n```\n\nFetching the image from a remote server (you must pass the `-enable-url-source` flag):\n```\ncurl -O \"http://localhost:8088/crop?width=500\u0026height=400\u0026url=https://raw.githubusercontent.com/h2non/imaginary/master/testdata/large.jpg\"\n```\n\nCrop behaviour can be influenced with the `gravity` parameter. You can specify a preference for a certain region (north, south, etc.). To enable Smart Crop you can specify the value \"smart\" to autodetect the most interesting section to consider as center point for the crop operation:\n```\ncurl -O \"http://localhost:8088/crop?width=500\u0026height=200\u0026gravity=smart\u0026url=https://raw.githubusercontent.com/h2non/imaginary/master/testdata/smart-crop.jpg\"\n```\n\n\n#### Playground\n\n`imaginary` exposes an ugly HTML form for playground purposes in: [`http://localhost:8088/form`](http://localhost:8088/form)\n\n## HTTP API\n\n### Allowed Origins\n\nimaginary can be configured to block all requests for images with a src URL this is not specified in the `allowed-origins` list. Imaginary will validate that the remote url matches the hostname and path of at least one origin in allowed list. Perhaps the easiest way to show how this works is to show some examples.\n\n| `allowed-origins` setting | image url | is valid |\n| ------------------------- | --------- | -------- |\n| `-allowed-origins https://s3.amazonaws.com/some-bucket/` | `s3.amazonaws.com/some-bucket/images/image.png` | VALID |\n| `-allowed-origins https://s3.amazonaws.com/some-bucket/` | `s3.amazonaws.com/images/image.png` | NOT VALID (no matching basepath) |\n| `-allowed-origins https://s3.amazonaws.com/some-*` | `s3.amazonaws.com/some-bucket/images/image.png` | VALID |\n| `-allowed-origins https://*.amazonaws.com/some-bucket/` | `anysubdomain.amazonaws.com/some-bucket/images/image.png` | VALID |\n| `-allowed-origins https://*.amazonaws.com` | `anysubdomain.amazonaws.comimages/image.png` | VALID |\n| `-allowed-origins https://*.amazonaws.com` | `www.notaws.comimages/image.png` | NOT VALID (no matching host) |\n| `-allowed-origins https://*.amazonaws.com, foo.amazonaws.com/some-bucket/` | `bar.amazonaws.com/some-other-bucket/image.png` | VALID (matches first condition but not second) |\n\n### Authorization\n\nimaginary supports a simple token-based API authorization.\nTo enable it, you should pass the `-key` flag to the binary.\n\nAPI token can be defined as HTTP header (`API-Key`) or query param (`key`).\n\nExample request with API key:\n```\nPOST /crop HTTP/1.1\nHost: localhost:8088\nAPI-Key: secret\n```\n\n### URL signature\n\nThe URL signature is provided by the `sign` request parameter.\n\nThe HMAC-SHA256 hash is created by taking the URL path (including the leading /), the request parameters (alphabetically-sorted and concatenated with \u0026 into a string). The hash is then base64url-encoded.\n\nHere an example in Go:\n```\nsignKey  := \"4f46feebafc4b5e988f131c4ff8b5997\"\nurlPath  := \"/resize\"\nurlQuery := \"file=image.jpg\u0026height=200\u0026type=jpeg\u0026width=300\"\n\nh := hmac.New(sha256.New, []byte(signKey))\nh.Write([]byte(urlPath))\nh.Write([]byte(urlQuery))\nbuf := h.Sum(nil)\n\nfmt.Println(\"sign=\" + base64.RawURLEncoding.EncodeToString(buf))\n```\n\n### Errors\n\n`imaginary` will always reply with the proper HTTP status code and JSON body with error details.\n\nHere an example response error when the payload is empty:\n```json\n{\n  \"message\": \"Cannot read payload: no such file\",\n  \"code\": 1\n}\n```\n\nSee all the predefined supported errors [here](https://github.com/h2non/imaginary/blob/master/error.go#L19-L28).\n\n#### Placeholder\n\nIf `-enable-placeholder` or `-placeholder \u003cimage path\u003e` flags are passed to `imaginary`, a placeholder image will be used in case of error or invalid request input.\n\nIf `-enable-placeholder` is passed, the default `imaginary` placeholder image will be used, however you can customized it via `-placeholder` flag, loading a custom compatible image from the file system.\n\nSince `imaginary` has been partially designed to be used as public HTTP service, including web pages, in certain scenarios the response MIME type must be respected,\nso the server will always reply with a placeholder image in case of error, such as image processing error, read error, payload error, request invalid request or any other.\n\nYou can customize the placeholder image passing the `-placeholder \u003cimage path\u003e` flag when starting `imaginary`.\n\nIn this scenarios, the error message details will be exposed in the `Error` response header field as JSON for further inspection from API clients.\n\nIn some edge cases the placeholder image resizing might fail, so a 400 Bad Request will be used as response status and the `Content-Type` will be `application/json` with the proper message info. Note that this scenario won't be common.\n\n### Form data\n\nIf you're pushing images to `imaginary` as `multipart/form-data` (you can do it as well as `image/*`), you must define at least one input field called `file` with the raw image data in order to be processed properly by imaginary.\n\n### Params\n\nComplete list of available params. Take a look to each specific endpoint to see which params are supported.\nImage measures are always in pixels, unless otherwise indicated.\n\n- **width**       `int`   - Width of image area to extract/resize\n- **height**      `int`   - Height of image area to extract/resize\n- **top**         `int`   - Top edge of area to extract. Example: `100`\n- **left**        `int`   - Left edge of area to extract. Example: `100`\n- **areawidth**   `int`   - Height area to extract. Example: `300`\n- **areaheight**  `int`   - Width area to extract. Example: `300`\n- **quality**     `int`   - JPEG image quality between 1-100. Defaults to `80`\n- **compression** `int`   - PNG compression level. Default: `6`\n- **palette**     `bool`  - Enable 8-bit quantisation. Works with only PNG images. Default: `false`\n- **rotate**      `int`   - Image rotation angle. Must be multiple of `90`. Example: `180`\n- **factor**      `int`   - Zoom factor level. Example: `2`\n- **margin**      `int`   - Text area margin for watermark. Example: `50`\n- **dpi**         `int`   - DPI value for watermark. Example: `150`\n- **textwidth**   `int`   - Text area width for watermark. Example: `200`\n- **opacity**     `float` - Opacity level for watermark text or watermark image. Default: `0.2`\n- **flip**        `bool`  - Transform the resultant image with flip operation. Default: `false`\n- **flop**        `bool`  - Transform the resultant image with flop operation. Default: `false`\n- **force**       `bool`  - Force image transformation size. Default: `false`\n- **nocrop**      `bool`  - Disable crop transformation. Defaults depend on the operation\n- **noreplicate** `bool`  - Disable text replication in watermark. Defaults to `false`\n- **norotation**  `bool`  - Disable auto rotation based on EXIF orientation. Defaults to `false`\n- **noprofile**   `bool`  - Disable adding ICC profile metadata. Defaults to `false`\n- **stripmeta**   `bool`  - Remove original image metadata, such as EXIF metadata. Defaults to `false`\n- **text**        `string` - Watermark text content. Example: `copyright (c) 2189`\n- **font**        `string` - Watermark text font type and format. Example: `sans bold 12`\n- **color**       `string` - Watermark text RGB decimal base color. Example: `255,200,150`\n- **image**       `string` - Watermark image URL pointing to the remote HTTP server.\n- **type**        `string` - Specify the image format to output. Possible values are: `jpeg`, `png`, `webp` and `auto`. `auto` will use the preferred format requested by the client in the HTTP Accept header. A client can provide multiple comma-separated choices in `Accept` with the best being the one picked.\n- **gravity**     `string` - Define the crop operation gravity. Supported values are: `north`, `south`, `centre`, `west`, `east` and `smart`. Defaults to `centre`.\n- **file**        `string` - Use image from server local file path. In order to use this you must pass the `-mount=\u003cdir\u003e` flag.\n- **url**         `string` - Fetch the image from a remote HTTP server. In order to use this you must pass the `-enable-url-source` flag.\n- **colorspace**  `string` - Use a custom color space for the output image. Allowed values are: `srgb` or `bw` (black\u0026white)\n- **field**       `string` - Custom image form field name if using `multipart/form`. Defaults to: `file`\n- **extend**      `string` - Extend represents the image extend mode used when the edges of an image are extended. Defaults to `mirror`. Allowed values are: `black`, `copy`, `mirror`, `white`, `lastpixel` and `background`. If `background` value is specified, you can define the desired extend RGB color via `background` param, such as `?extend=background\u0026background=250,20,10`. For more info, see [libvips docs](https://libvips.github.io/libvips/API/current/libvips-conversion.html#VIPS-EXTEND-BACKGROUND:CAPS).\n- **background**  `string` - Background RGB decimal base color to use when flattening transparent PNGs. Example: `255,200,150`\n- **sigma**       `float`  - Size of the gaussian mask to use when blurring an image. Example: `15.0`\n- **minampl**     `float`  - Minimum amplitude of the gaussian filter to use when blurring an image. Default: Example: `0.5`\n- **operations**  `json`   - Pipeline of image operation transformations defined as URL safe encoded JSON array. See [pipeline](#get--post-pipeline) endpoints for more details.\n- **sign**        `string` - URL signature (URL-safe Base64-encoded HMAC digest)\n- **interlace**   `bool`   - Use progressive / interlaced format of the image output. Defaults to `false`\n- **aspectratio** `string` - Apply aspect ratio by giving either image's height or width. Exampe: `16:9`\n\n#### GET /\nContent-Type: `application/json`\n\nServes as JSON the current `imaginary`, `bimg` and `libvips` versions.\n\nExample response:\n```json\n{\n  \"imaginary\": \"0.1.28\",\n  \"bimg\": \"1.0.5\",\n  \"libvips\": \"8.4.1\"\n}\n```\n\n#### GET /health\nContent-Type: `application/json`\n\nProvides some useful statistics about the server stats with the following structure:\n\n- **uptime** `number` - Server process uptime in seconds.\n- **allocatedMemory** `number` - Currently allocated memory in megabytes.\n- **totalAllocatedMemory** `number` - Total allocated memory over the time in megabytes.\n- **goroutines** `number` - Number of running goroutines.\n- **cpus** `number` - Number of used CPU cores.\n\nExample response:\n```json\n{\n  \"uptime\": 1293,\n  \"allocatedMemory\": 5.31,\n  \"totalAllocatedMemory\": 34.3,\n  \"goroutines\": 19,\n  \"cpus\": 8\n}\n```\n\n#### GET /form\nContent Type: `text/html`\n\nServes an ugly HTML form, just for testing/playground purposes\n\n#### GET | POST /info\nAccepts: `image/*, multipart/form-data`. Content-Type: `application/json`\n\nReturns the image metadata as JSON:\n```json\n{\n  \"width\": 550,\n  \"height\": 740,\n  \"type\": \"jpeg\",\n  \"space\": \"srgb\",\n  \"hasAlpha\": false,\n  \"hasProfile\": true,\n  \"channels\": 3,\n  \"orientation\": 1\n}\n```\n\n#### GET | POST /crop\nAccepts: `image/*, multipart/form-data`. Content-Type: `image/*`\n\nCrop the image by a given width or height. Image ratio is maintained\n\n##### Allowed params\n\n- width `int`\n- height `int`\n- quality `int` (JPEG-only)\n- compression `int` (PNG-only)\n- type `string`\n- file `string` - Only GET method and if the `-mount` flag is present\n- url `string` - Only GET method and if the `-enable-url-source` flag is present\n- force `bool`\n- rotate `int`\n- embed `bool`\n- norotation `bool`\n- noprofile `bool`\n- flip `bool`\n- flop `bool`\n- stripmeta `bool`\n- extend `string`\n- background `string` - Example: `?background=250,20,10`\n- colorspace `string`\n- sigma `float`\n- minampl `float`\n- gravity `string`\n- field `string` - Only POST and `multipart/form` payloads\n- interlace `bool`\n- aspectratio `string`\n\n#### GET | POST /smartcrop\nAccepts: `image/*, multipart/form-data`. Content-Type: `image/*`\n\nCrop the image by a given width or height using the [libvips](https://github.com/jcupitt/libvips/blob/master/libvips/conversion/smartcrop.c) built-in smart crop algorithm.\n\n##### Allowed params\n\n- width `int`\n- height `int`\n- quality `int` (JPEG-only)\n- compression `int` (PNG-only)\n- type `string`\n- file `string` - Only GET method and if the `-mount` flag is present\n- url `string` - Only GET method and if the `-enable-url-source` flag is present\n- force `bool`\n- rotate `int`\n- embed `bool`\n- norotation `bool`\n- noprofile `bool`\n- flip `bool`\n- flop `bool`\n- stripmeta `bool`\n- extend `string`\n- background `string` - Example: `?background=250,20,10`\n- colorspace `string`\n- sigma `float`\n- minampl `float`\n- gravity `string`\n- field `string` - Only POST and `multipart/form` payloads\n- interlace `bool`\n- aspectratio `string`\n\n#### GET | POST /resize\nAccepts: `image/*, multipart/form-data`. Content-Type: `image/*`\n\nResize an image by width or height. Image aspect ratio is maintained\n\n##### Allowed params\n\n- width `int` `required`\n- height `int`\n- quality `int` (JPEG-only)\n- compression `int` (PNG-only)\n- type `string`\n- file `string` - Only GET method and if the `-mount` flag is present\n- url `string` - Only GET method and if the `-enable-url-source` flag is present\n- embed `bool`\n- force `bool`\n- rotate `int`\n- nocrop `bool` - Defaults to `true`\n- norotation `bool`\n- noprofile `bool`\n- stripmeta `bool`\n- flip `bool`\n- flop `bool`\n- extend `string`\n- background `string` - Example: `?background=250,20,10`\n- colorspace `string`\n- sigma `float`\n- minampl `float`\n- field `string` - Only POST and `multipart/form` payloads\n- interlace `bool`\n- aspectratio `string`\n- palette `bool`\n\n#### GET | POST /enlarge\nAccepts: `image/*, multipart/form-data`. Content-Type: `image/*`\n\n##### Allowed params\n\n- width `int` `required`\n- height `int` `required`\n- quality `int` (JPEG-only)\n- compression `int` (PNG-only)\n- type `string`\n- file `string` - Only GET method and if the `-mount` flag is present\n- url `string` - Only GET method and if the `-enable-url-source` flag is present\n- embed `bool`\n- force `bool`\n- rotate `int`\n- nocrop `bool` - Defaults to `false`\n- norotation `bool`\n- noprofile `bool`\n- stripmeta `bool`\n- flip `bool`\n- flop `bool`\n- extend `string`\n- background `string` - Example: `?background=250,20,10`\n- colorspace `string`\n- sigma `float`\n- minampl `float`\n- field `string` - Only POST and `multipart/form` payloads\n- interlace `bool`\n- palette `bool`\n\n#### GET | POST /extract\nAccepts: `image/*, multipart/form-data`. Content-Type: `image/*`\n\n##### Allowed params\n\n- top `int` `required`\n- left `int`\n- areawidth `int` `required`\n- areaheight `int`\n- width `int`\n- height `int`\n- quality `int` (JPEG-only)\n- compression `int` (PNG-only)\n- type `string`\n- file `string` - Only GET method and if the `-mount` flag is present\n- url `string` - Only GET method and if the `-enable-url-source` flag is present\n- embed `bool`\n- force `bool`\n- rotate `int`\n- norotation `bool`\n- noprofile `bool`\n- stripmeta `bool`\n- flip `bool`\n- flop `bool`\n- extend `string`\n- background `string` - Example: `?background=250,20,10`\n- colorspace `string`\n- sigma `float`\n- minampl `float`\n- field `string` - Only POST and `multipart/form` payloads\n- interlace `bool`\n- aspectratio `string`\n- palette `bool`\n\n#### GET | POST /zoom\nAccepts: `image/*, multipart/form-data`. Content-Type: `image/*`\n\n##### Allowed params\n\n- factor `number` `required`\n- width `int`\n- height `int`\n- quality `int` (JPEG-only)\n- compression `int` (PNG-only)\n- type `string`\n- file `string` - Only GET method and if the `-mount` flag is present\n- url `string` - Only GET method and if the `-enable-url-source` flag is present\n- embed `bool`\n- force `bool`\n- rotate `int`\n- nocrop `bool` - Defaults to `true`\n- norotation `bool`\n- noprofile `bool`\n- stripmeta `bool`\n- flip `bool`\n- flop `bool`\n- extend `string`\n- background `string` - Example: `?background=250,20,10`\n- colorspace `string`\n- sigma `float`\n- minampl `float`\n- field `string` - Only POST and `multipart/form` payloads\n- interlace `bool`\n- aspectratio `string`\n- palette `bool`\n\n#### GET | POST /thumbnail\nAccepts: `image/*, multipart/form-data`. Content-Type: `image/*`\n\n##### Allowed params\n\n- width `int` `required`\n- height `int` `required`\n- quality `int` (JPEG-only)\n- compression `int` (PNG-only)\n- type `string`\n- file `string` - Only GET method and if the `-mount` flag is present\n- url `string` - Only GET method and if the `-enable-url-source` flag is present\n- embed `bool`\n- force `bool`\n- rotate `int`\n- norotation `bool`\n- noprofile `bool`\n- stripmeta `bool`\n- flip `bool`\n- flop `bool`\n- extend `string`\n- background `string` - Example: `?background=250,20,10`\n- colorspace `string`\n- sigma `float`\n- minampl `float`\n- field `string` - Only POST and `multipart/form` payloads\n- interlace `bool`\n- aspectratio `string`\n- palette `bool`\n\n#### GET | POST /fit\nAccepts: `image/*, multipart/form-data`. Content-Type: `image/*`\n\nResize an image to fit within width and height, without cropping. Image aspect ratio is maintained\nThe width and height specify a maximum bounding box for the image.\n\n##### Allowed params\n\n- width `int` `required`\n- height `int` `required`\n- quality `int` (JPEG-only)\n- compression `int` (PNG-only)\n- type `string`\n- file `string` - Only GET method and if the `-mount` flag is present\n- url `string` - Only GET method and if the `-enable-url-source` flag is present\n- embed `bool`\n- force `bool`\n- rotate `int`\n- norotation `bool`\n- noprofile `bool`\n- stripmeta `bool`\n- flip `bool`\n- flop `bool`\n- extend `string`\n- background `string` - Example: `?background=250,20,10`\n- colorspace `string`\n- sigma `float`\n- minampl `float`\n- field `string` - Only POST and `multipart/form` payloads\n- interlace `bool`\n- aspectratio `string`\n- palette `bool`\n\n#### GET | POST /rotate\nAccepts: `image/*, multipart/form-data`. Content-Type: `image/*`\n\n\n#### GET | POST /autorotate\nAccepts: `image/*, multipart/form-data`. Content-Type: `image/*`\n\nAutomatically rotate the image with no further image transformations based on EXIF orientation metadata.\n\nReturns a new image with the same size and format as the input image.\n\n##### Allowed params\n\n- rotate `int` `required`\n- width `int`\n- height `int`\n- quality `int` (JPEG-only)\n- compression `int` (PNG-only)\n- type `string`\n- file `string` - Only GET method and if the `-mount` flag is present\n- url `string` - Only GET method and if the `-enable-url-source` flag is present\n- embed `bool`\n- force `bool`\n- norotation `bool`\n- noprofile `bool`\n- stripmeta `bool`\n- flip `bool`\n- flop `bool`\n- extend `string`\n- background `string` - Example: `?background=250,20,10`\n- colorspace `string`\n- sigma `float`\n- minampl `float`\n- field `string` - Only POST and `multipart/form` payloads\n- interlace `bool`\n- aspectratio `string`\n- palette `bool`\n\n#### GET | POST /flip\nAccepts: `image/*, multipart/form-data`. Content-Type: `image/*`\n\n##### Allowed params\n\n- width `int`\n- height `int`\n- quality `int` (JPEG-only)\n- compression `int` (PNG-only)\n- type `string`\n- file `string` - Only GET method and if the `-mount` flag is present\n- url `string` - Only GET method and if the `-enable-url-source` flag is present\n- embed `bool`\n- force `bool`\n- norotation `bool`\n- noprofile `bool`\n- stripmeta `bool`\n- flip `bool`\n- flop `bool`\n- extend `string`\n- background `string` - Example: `?background=250,20,10`\n- colorspace `string`\n- sigma `float`\n- minampl `float`\n- field `string` - Only POST and `multipart/form` payloads\n- interlace `bool`\n- aspectratio `string`\n- palette `bool`\n\n#### GET | POST /flop\nAccepts: `image/*, multipart/form-data`. Content-Type: `image/*`\n\n##### Allowed params\n\n- width `int`\n- height `int`\n- quality `int` (JPEG-only)\n- compression `int` (PNG-only)\n- type `string`\n- file `string` - Only GET method and if the `-mount` flag is present\n- url `string` - Only GET method and if the `-enable-url-source` flag is present\n- embed `bool`\n- force `bool`\n- norotation `bool`\n- noprofile `bool`\n- stripmeta `bool`\n- flip `bool`\n- flop `bool`\n- extend `string`\n- background `string` - Example: `?background=250,20,10`\n- colorspace `string`\n- sigma `float`\n- minampl `float`\n- field `string` - Only POST and `multipart/form` payloads\n- interlace `bool`\n- aspectratio `string`\n- palette `bool`\n\n#### GET | POST /convert\nAccepts: `image/*, multipart/form-data`. Content-Type: `image/*`\n\n##### Allowed params\n\n- type `string` `required`\n- quality `int` (JPEG-only)\n- compression `int` (PNG-only)\n- file `string` - Only GET method and if the `-mount` flag is present\n- url `string` - Only GET method and if the `-enable-url-source` flag is present\n- embed `bool`\n- force `bool`\n- rotate `int`\n- norotation `bool`\n- noprofile `bool`\n- stripmeta `bool`\n- flip `bool`\n- flop `bool`\n- extend `string`\n- background `string` - Example: `?background=250,20,10`\n- colorspace `string`\n- sigma `float`\n- minampl `float`\n- field `string` - Only POST and `multipart/form` payloads\n- interlace `bool`\n- aspectratio `string`\n- palette `bool`\n\n#### GET | POST /pipeline\nAccepts: `image/*, multipart/form-data`. Content-Type: `image/*`\n\nThis endpoint allow the user to declare a pipeline of multiple independent image transformation operations all in a single HTTP request.\n\n**Note**: a maximum of 10 independent operations are current allowed within the same HTTP request.\n\nInternally, it operates pretty much as a sequential reducer pattern chain, where given an input image and a set of operations, for each independent image operation iteration, the output result image will be passed to the next one, as the accumulated result, until finishing all the operations.\n\nIn imperative programming, this would be pretty much analog to the following code:\n```js\nvar image\nfor operation in operations {\n  image = operation.Run(image, operation.Options)\n}\n```\n\n##### Allowed params\n\n- operations `json` `required` - URL safe encoded JSON with a list of operations. See below for interface details.\n- file `string` - Only GET method and if the `-mount` flag is present\n- url `string` - Only GET method and if the `-enable-url-source` flag is present\n\n##### Operations JSON specification\n\nSelf-documented JSON operation schema:\n```js\n[\n  {\n    \"operation\": string, // Operation name identifier. Required.\n    \"ignore_failure\": boolean, // Ignore error in case of failure and continue with the next operation. Optional.\n    \"params\": map[string]mixed, // Object defining operation specific image transformation params, same as supported URL query params per each endpoint.\n  }\n]\n```\n\n###### Supported operations names\n\n- **crop** - Same as [`/crop`](#get--post-crop) endpoint.\n- **smartcrop** - Same as [`/smartcrop`](#get--post-smartcrop) endpoint.\n- **resize** - Same as [`/resize`](#get--post-resize) endpoint.\n- **enlarge** - Same as [`/enlarge`](#get--post-enlarge) endpoint.\n- **extract** - Same as [`/extract`](#get--post-extract) endpoint.\n- **rotate** - Same as [`/rotate`](#get--post-rotate) endpoint.\n- **autorotate** - Same as [`/autorotate`](#get--post-autorotate) endpoint.\n- **flip** - Same as [`/flip`](#get--post-flip) endpoint.\n- **flop** - Same as [`/flop`](#get--post-flop) endpoint.\n- **thumbnail** - Same as [`/thumbnail`](#get--post-thumbnail) endpoint.\n- **zoom** - Same as [`/zoom`](#get--post-zoom) endpoint.\n- **convert** - Same as [`/convert`](#get--post-convert) endpoint.\n- **watermark** - Same as [`/watermark`](#get--post-watermark) endpoint.\n- **watermarkImage** - Same as [`/watermarkimage`](#get--post-watermarkimage) endpoint.\n- **blur** - Same as [`/blur`](#get--post-blur) endpoint.\n\n###### Example\n\n```json\n[\n  {\n    \"operation\": \"crop\",\n    \"params\": {\n      \"width\": 500,\n      \"height\": 300\n    }\n  },\n  {\n    \"operation\": \"watermark\",\n    \"params\": {\n      \"text\": \"I need some covfete\",\n      \"font\": \"Verdana\",\n      \"textwidth\": 100,\n      \"opacity\": 0.8\n    }\n  },\n  {\n    \"operation\": \"rotate\",\n    \"params\": {\n      \"rotate\": 180\n    }\n  },\n  {\n    \"operation\": \"convert\",\n    \"params\": {\n      \"type\": \"webp\"\n    }\n  }\n]\n```\n\n#### GET | POST /watermark\nAccepts: `image/*, multipart/form-data`. Content-Type: `image/*`\n\n##### Allowed params\n\n- text `string` `required`\n- margin `int`\n- dpi `int`\n- textwidth `int`\n- opacity `float`\n- noreplicate `bool`\n- font `string`\n- color `string`\n- quality `int` (JPEG-only)\n- compression `int` (PNG-only)\n- type `string`\n- file `string` - Only GET method and if the `-mount` flag is present\n- url `string` - Only GET method and if the `-enable-url-source` flag is present\n- embed `bool`\n- force `bool`\n- rotate `int`\n- norotation `bool`\n- noprofile `bool`\n- stripmeta `bool`\n- flip `bool`\n- flop `bool`\n- extend `string`\n- background `string` - Example: `?background=250,20,10`\n- colorspace `string`\n- sigma `float`\n- minampl `float`\n- field `string` - Only POST and `multipart/form` payloads\n- interlace `bool`\n- palette `bool`\n\n#### GET | POST /watermarkimage\nAccepts: `image/*, multipart/form-data`. Content-Type: `image/*`\n\n##### Allowed params\n\n- image `string` `required` - URL to watermark image, example: `?image=https://logo-server.com/logo.jpg`\n- top `int` - Top position of the watermark image\n- left `int` - Left position of the watermark image\n- opacity `float` - Opacity value of the watermark image\n- quality `int` (JPEG-only)\n- compression `int` (PNG-only)\n- type `string`\n- file `string` - Only GET method and if the `-mount` flag is present\n- url `string` - Only GET method and if the `-enable-url-source` flag is present\n- embed `bool`\n- force `bool`\n- rotate `int`\n- norotation `bool`\n- noprofile `bool`\n- stripmeta `bool`\n- flip `bool`\n- flop `bool`\n- extend `string`\n- background `string` - Example: `?background=250,20,10`\n- colorspace `string`\n- sigma `float`\n- minampl `float`\n- field `string` - Only POST and `multipart/form` payloads\n- interlace `bool`\n- palette `bool`\n\n#### GET | POST /blur\nAccepts: `image/*, multipart/form-data`. Content-Type: `image/*`\n\n##### Allowed params\n\n- sigma `float` `required`\n- minampl `float`\n- width `int`\n- height `int`\n- quality `int` (JPEG-only)\n- compression `int` (PNG-only)\n- type `string`\n- file `string` - Only GET method and if the `-mount` flag is present\n- url `string` - Only GET method and if the `-enable-url-source` flag is present\n- embed `bool`\n- force `bool`\n- norotation `bool`\n- noprofile `bool`\n- stripmeta `bool`\n- flip `bool`\n- flop `bool`\n- extend `string`\n- background `string` - Example: `?background=250,20,10`\n- colorspace `string`\n- field `string` - Only POST and `multipart/form` payloads\n- interlace `bool`\n- aspectratio `string`\n- palette `bool`\n\n## Logging\n\nImaginary uses an [apache compatible log format](/log.go).\n\n### Fluentd log ingestion\n\nYou can ingest Imaginary logs with fluentd using the following fluentd config :\n\n```\n# use your own tag name (*.imaginary for this example)\n\u003cfilter *.imaginary\u003e\n    @type parser\n    key_name log\n    reserve_data true\n\n    \u003cparse\u003e\n        @type multi_format\n        # access logs parser\n        \u003cpattern\u003e\n            format regexp\n            expression /^[^ ]* [^ ]* [^ ]* \\[(?\u003ctime\u003e[^\\]]*)\\] \"(?\u003cmethod\u003e\\S+)(?: +(?\u003cpath\u003e[^ ]*) +\\S*)?\" (?\u003ccode\u003e[^ ]*) (?\u003csize\u003e[^ ]*) (?\u003cresponse_time\u003e[^ ]*)$/\n            types code:integer,size:integer,response_time:float\n            time_key time\n            time_format %d/%b/%Y %H:%M:%S\n        \u003c/pattern\u003e\n        # warnings / error logs parser\n        \u003cpattern\u003e\n            format none\n            message_key message\n        \u003c/pattern\u003e\n    \u003c/parse\u003e\n\u003c/filter\u003e\n\n\u003cmatch *.imaginary\u003e\n    @type rewrite_tag_filter\n\n    # Logs with code field are access logs, and logs without are error logs\n    \u003crule\u003e\n        key code\n        pattern ^.+$\n        tag ${tag}.access\n    \u003c/rule\u003e\n    \u003crule\u003e\n        key code\n        pattern ^.+$\n        invert true\n        tag ${tag}.error\n    \u003c/rule\u003e\n\u003c/match\u003e\n```\n\nIn the end, access records are tagged with `*.imaginary.access`, and warning /\nerror records are tagged with `*.imaginary.error`.\n\n## Support\n\n### Backers\n\nSupport us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/imaginary#backer)]\n\n\u003ca href=\"https://opencollective.com/imaginary/backer/0/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/0/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/1/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/1/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/2/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/2/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/3/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/3/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/4/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/4/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/5/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/5/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/6/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/6/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/7/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/7/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/8/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/8/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/9/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/9/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/10/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/10/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/11/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/11/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/12/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/12/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/13/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/13/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/14/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/14/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/15/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/15/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/16/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/16/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/17/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/17/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/18/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/18/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/19/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/19/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/20/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/20/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/21/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/21/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/22/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/22/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/23/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/23/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/24/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/24/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/25/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/25/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/26/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/26/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/27/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/27/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/28/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/28/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/backer/29/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/backer/29/avatar.svg\"\u003e\u003c/a\u003e\n\n### Support this project\n\n[![OpenCollective](https://opencollective.com/imaginary/backers/badge.svg)](#backers)\n\n### Sponsors\n\nBecome a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/imaginary#sponsor)]\n\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/0/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/0/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/1/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/1/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/2/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/2/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/3/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/3/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/4/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/4/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/5/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/5/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/6/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/6/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/7/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/7/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/8/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/8/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/9/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/9/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/10/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/10/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/11/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/11/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/12/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/12/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/13/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/13/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/14/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/14/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/15/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/15/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/16/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/16/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/17/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/17/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/18/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/18/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/19/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/19/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/20/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/20/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/21/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/21/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/22/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/22/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/23/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/23/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/24/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/24/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/25/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/25/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/26/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/26/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/27/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/27/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/28/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/28/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/imaginary/sponsor/29/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/imaginary/sponsor/29/avatar.svg\"\u003e\u003c/a\u003e\n\n## Authors\n\n- [Tomás Aparicio](https://github.com/h2non) - Original author and maintainer.\n\n## License\n\nMIT - Tomas Aparicio\n\n[![views](https://sourcegraph.com/api/repos/github.com/h2non/imaginary/.counters/views.svg)](https://sourcegraph.com/github.com/h2non/imaginary)\n","funding_links":["https://opencollective.com/imaginary","https://opencollective.com/imaginary/backer/0/website","https://opencollective.com/imaginary/backer/1/website","https://opencollective.com/imaginary/backer/2/website","https://opencollective.com/imaginary/backer/3/website","https://opencollective.com/imaginary/backer/4/website","https://opencollective.com/imaginary/backer/5/website","https://opencollective.com/imaginary/backer/6/website","https://opencollective.com/imaginary/backer/7/website","https://opencollective.com/imaginary/backer/8/website","https://opencollective.com/imaginary/backer/9/website","https://opencollective.com/imaginary/backer/10/website","https://opencollective.com/imaginary/backer/11/website","https://opencollective.com/imaginary/backer/12/website","https://opencollective.com/imaginary/backer/13/website","https://opencollective.com/imaginary/backer/14/website","https://opencollective.com/imaginary/backer/15/website","https://opencollective.com/imaginary/backer/16/website","https://opencollective.com/imaginary/backer/17/website","https://opencollective.com/imaginary/backer/18/website","https://opencollective.com/imaginary/backer/19/website","https://opencollective.com/imaginary/backer/20/website","https://opencollective.com/imaginary/backer/21/website","https://opencollective.com/imaginary/backer/22/website","https://opencollective.com/imaginary/backer/23/website","https://opencollective.com/imaginary/backer/24/website","https://opencollective.com/imaginary/backer/25/website","https://opencollective.com/imaginary/backer/26/website","https://opencollective.com/imaginary/backer/27/website","https://opencollective.com/imaginary/backer/28/website","https://opencollective.com/imaginary/backer/29/website"],"categories":["Go","Images","开源类库","Image Processing","图片","Images 图像处理","Open source library","Relational Databases","Programming Languages","resize-images","webp","图像","圖象","\u003cspan id=\"图片-images\"\u003e图片 Images\u003c/span\u003e"],"sub_categories":["Advanced Console UIs","图形处理","Snippets Manager","检索及分析资料库","SQL 查询语句构建库","Graphics Processing","Search and Analytic Databases","Go","交流","高级控制台界面","高級控制台界面","\u003cspan id=\"高级控制台用户界面-advanced-console-uis\"\u003e高级控制台用户界面 Advanced Console UIs\u003c/span\u003e"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fh2non%2Fimaginary","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fh2non%2Fimaginary","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fh2non%2Fimaginary/lists"}