PommaLabs.Thumbnailer.Client 5.1.0

The ID prefix of this package has been reserved for one of the owners of this package by NuGet.org. Prefix Reserved
.NET 6.0
This package has a SemVer 2.0.0 package version: 5.1.0+1aee6c5.
dotnet add package PommaLabs.Thumbnailer.Client --version 5.1.0
NuGet\Install-Package PommaLabs.Thumbnailer.Client -Version 5.1.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PommaLabs.Thumbnailer.Client" Version="5.1.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add PommaLabs.Thumbnailer.Client --version 5.1.0
#r "nuget: PommaLabs.Thumbnailer.Client, 5.1.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install PommaLabs.Thumbnailer.Client as a Cake Addin
#addin nuget:?package=PommaLabs.Thumbnailer.Client&version=5.1.0

// Install PommaLabs.Thumbnailer.Client as a Cake Tool
#tool nuget:?package=PommaLabs.Thumbnailer.Client&version=5.1.0


License: MIT Donate Docker Stars Docker Pulls Docs NuGet version NuGet downloads

standard-readme compliant GitLab pipeline status Quality gate Code coverage Renovate enabled

Web service which exposes endpoints to generate file thumbnails and to optimize media files.

Thumbnailer heavily relies on many open source command line tools. Just to name a few:

  • ffmpeg, used to generate video thumbnails and to optimize MP4 files.
  • GraphicsMagick, used to generate image thumbnails.
  • LibreOffice, used to convert Office files to images.
  • Firefox, used to convert HTML files to images.
  • pngquant, used to optimize PNG images and file thumbnails.

Web service runs on ASP.NET Core and this repository contains a .NET Standard client which can be used to interact with it.

Table of Contents


Thumbnailer web service is provided as a Docker image hosted on Docker Hub.

You can quickly start a local test instance with following command:

docker run -it --rm -e Security__AllowAnonymousAccess=true -p 8080:8080 pommalabs/thumbnailer:latest

Local test instance will be listening on port 8080 and it will accept unauthenticated requests. Please check the Configuration section to find further information about how the web service can be properly configured.

A .NET client, PommaLabs.Thumbnailer.Client, is available as a NuGet package:

dotnet add package PommaLabs.Thumbnailer.Client


Following tags are available:

  • latest, based on pommalabs/dotnet:7-aspnet, contains the code found in main branch.
  • azure-appsvc, based on pommalabs/dotnet:7-azure-appsvc, contains the code found in main branch. This tag is customized in order to support SSH connection exposed through Azure App Service.
  • preview, based on pommalabs/dotnet:7-aspnet, contains the code found in preview branch.

Each tag is rebuilt every week.


Docker image can be configured using the following environment variables:

Environment variable Notes Default value
Database__CacheLifetime How long each cache entry will live. 20 minutes
Database__ConnectionString Connection string of a SQL database.
Database__Provider Provider (None, PostgreSql, SqlServer). None
Database__SchemaName SQL schema name.
JobProcessor__Count How many job processor threads should be spawned. 2 processors
Security__AcceptApiKeysViaHeaderParameter Accept API keys via header parameter. true
Security__AcceptApiKeysViaQueryStringParameter Accept API keys via query string parameter. false
Security__AllowAnonymousAccess Allow anonymous users to consume services. false
Security__ApiKeys__X__ExpiresAt If not specified, API key will not expire.
Security__ApiKeys__X__Name Descriptive name of API key at index X.
Security__ApiKeys__X__Value Value of API key at index X.
Security__ApiKeysJson A JSON array containing desired API keys.
Security__AsyncProcessTimeout Timeout for low level processes (in async jobs). 10 minutes
Security__EnableCaseSensitiveApiKeyValidation Enable case sensitive API key validation. false
Security__FileDownloadTimeout Timeout for file download. 30 seconds
Security__MaxFileDownloadSizeInBytes How many bytes are allowed for remote downloads. 64 MB
Security__MaxFileUploadSizeInBytes How many bytes are allowed for uploads. 32 MB
Security__ProcessTimeout Timeout for low level processes (in sync calls). 30 seconds
Website__Enabled Expose the public website. false

Security__ApiKeysJson variable is a JSON array of API key objects; each object can have three properties:

  • name, required, descriptive name.
  • value, required, which will be used to perform authentication.
  • expiresAt, optional, expiration timestamp. If not specified, API key will not expire.

An example value for Security__ApiKeysJson is the following one:

[{"name":"Expiring API key","value":"123","expiresAt":"2018-12-10T13:49:51.141Z"},{"name":"Not expiring API key","value":"456"}]

Please note that setting both Security__ApiKeysJson and single array item configurations (e.g. Security__ApiKeys__0__Name) is not supported and its behavior cannot be relied upon.


Web service writes log messages to the console.

If an Azure Application Insights connection string is specified using the ApplicationInsights__ConnectionString configuration, logs and telemetry data are also sent to that service.


Setup scripts for supported systems are available:

You can customize those scripts according to your needs, but please remember that if you change schema name, you should update Database__SchemaName configuration property accordingly.


When an external database is configured, it is also used by the web service to store cache entries using the KVLite library.

Cache entries store the SHA384 of input files and the parameters used; that data is linked to the location of the output file in Thumbnailer temporary directory (/tmp/thumbnailer). Temporary files stay in that directory for at least as long as it has been specified with Database__CacheLifetime configuration.

Moreover, distributed cache is also used to track job information for API v2. Job IDs are encrypted using local keys (/tmp/thumbnailer/data-protection-keys).

So, you might want to persist the temporary directory root, /tmp/thumbnailer, in order to be able to handle the following use cases:

  • Web service receives a lot of requests and temporary files directory can grow quite a lot. In that case, a separate volume with proper size can be configured.
  • Web service works in load balancing and it is configured to use an external DB. In that case, sharing the temporary files directory is required in order to let all instances be able to read cached outputs. Moreover, sharing the same encryption keys is necessary to be able to decrypt on one node data generated on another node.

However, persisting that directory is not mandatory at all. Web service works fine without having it persisted, especially when only one node is used.


A special note on persistence applies when Docker container is run in read-only mode. In that scenario, following directories need to be mounted on writeable storage in order for web service to properly work:

  • /home/app, where LibreOffice writes configuration files at runtime.
  • /tmp, used by web service itself (/tmp/thumbnailer) and by .NET runtime.


Web service stores its templates in a dedicated directory, /opt/app/Templates. Currently, that directory contains only one template, fallback.svg, which is used to generate fallback images when thumbnail generation fails.

If templates need to be customized, then templates directory can be mounted to a local directory using a bind mount, for example:

docker run -it --rm \
  -e Security__AllowAnonymousAccess=true -p 8080:8080 \
  -v /my/templates:/opt/app/Templates:ro \

Source templates can be found on GitLab.

When templates are changed, web service should be restarted, because templates are loaded at startup.

Fallback image

Template for fallback image, stored in fallback.svg, is handled as a Liquid template using dotLiquid library. Liquid syntax can be used to apply filters and conditional logic.

Fallback image template receives a file object containing the following attributes:

  • content_type, containing input file MIME type.
  • extension, file extension deduced by Thumbnailer, which might differ from the one received as input. File extension includes the leading dot character.
  • size, file size in bytes.
  • humanized_size, file size converted into a readable string (e.g. "2.4 MB").


Please check OpenAPI docs on your instance (just visit the /swagger page) or head to the demo instance Swagger page. Each endpoint has been documented using the OpenAPI specification.

Media optimization supports following content types:

  • image/gif
  • image/jpeg
  • image/png
  • image/svg+xml
  • image/webp
  • video/mp4

Thumbnail generation supports quite a lot of content types. Anyway, you can use the test files as a quick reference to find out what the web service really supports. Inside each "format" directory you will find a copy of the latest thumbnails, that is, for each file you will find the most recent copy of its thumbnail.

However, not every content type for which a thumbnail could be "theoretically" generated is supported. Some notable formats which are not supported are the following:

For files whose thumbnail cannot be generated either because there is none, e.g. for archive files, or because it is not supported by the web service, a fallback flag can be set when requesting thumbnail generation. When enabled, a fallback image is generated when thumbnail generation fails or when it cannot be started at all. See Templates section to find out how to customize fallback images.

Synchronous API (v1)

Synchronous API is exposed through v1 endpoints and, as its name suggests, it allows to send synchronous HTTP requests for thumbnail generation or media generation, where the output file is provided as a response for each request.

This approach is quite simple but it is not recommended, because each HTTP request should have a very short timeout and that fact does not work well with the processing of large or complex files. Anyway, this kind of API was the first one to be implemented by Thumbnailer and it will be maintained in the future. There are use cases where a simple API is enough and it is preferred over a more complex one.

Synchronous requests timeout is controlled by Security__ProcessTimeout setting, as described in the Configuration section.

With a Thumbnailer instance running, as described in the Install section, you can generate the thumbnail of a sample image with the following request:

GET /api/v1/thumbnail?fileUri=https://via.placeholder.com/2048&widthPx=256&heightPx=256&shavePx=0&fill=true&smartCrop=false&responseType=Binary HTTP/1.1
Host: localhost:8080

That endpoint will generate a response containing the requested thumbnail.

Please inspect Swagger documentation of v1 endpoints in order to find further information about exposed operations. For example, input files can also be POSTed using a multipart/form-data request or with a JSON payload.

Asynchronous API (v2)

Asynchronous API is exposed through v2 endpoints and it allows to start processing jobs which can be monitored with a dedicated API. When a job is finished, its output will be available for download.

Asynchronous API is more complex to work with, because it requires at least three HTTP calls in order to obtain the operation output. However, the asynchronous approach is required when potentially large or complex files need to be processed.

Asynchronous jobs timeout is controlled by Security__AsyncProcessTimeout setting, as described in the Configuration section.

With a Thumbnailer instance running, as described in the Install section, you can start the generation of the thumbnail of a sample image with the following request:

GET /api/v2/thumbnail?fileUri=https://via.placeholder.com/2048&widthPx=256&heightPx=256&shavePx=0&fill=true&smartCrop=false HTTP/1.1
Host: localhost:8080

That endpoint will respond with a JSON payload containing the job ID:

    "failureReason": null,
    "jobId": "NEW_JOB_ID",
    "status": "Queued"

That job ID can be used to query the job status:

GET /api/v2/jobs/NEW_JOB_ID HTTP/1.1
Host: localhost:8080

When job status becomes Processed, as in sample below:

    "failureReason": null,
    "jobId": "NEW_JOB_ID",
    "status": "Processed"

Then job result is ready to be downloaded from following endpoint:

GET /api/v2/jobs/NEW_JOB_ID/download?responseType=Binary HTTP/1.1
Host: localhost:8080

That endpoint will generate a response containing the requested thumbnail.

Please inspect Swagger documentation of v2 endpoints in order to find further information about exposed operations. For example, input files can also be POSTed using a multipart/form-data request or with a JSON payload.




MRs accepted.

Small note: If editing the README, please conform to the standard-readme specification.


Visual Studio Code, with Remote Containers extension, is the recommended way to work on this project.

A development container has been configured with all required tools.

Visual Studio Community is also supported and an updated solution file, thumbnailer.sln, has been provided.

Restoring dependencies

When opening the development container, dependencies should be automatically restored.

Anyway, dependencies can be restored with following command:

dotnet restore

Starting development server

A local development server listening on port 8080 can be started with following command:

dotnet run --project ./src/PommaLabs.Thumbnailer/PommaLabs.Thumbnailer.csproj

Running tests

Tests can be run with following command:

dotnet test

Tests can also be run with following command, which collects coverage information:

./build.sh --target run-tests

Tests for a specific file format can be using the following command, where FORMAT should be the name of one of directories holding test files, written in upper case:

export FORMAT="PNG"
dotnet test --filter "Name~${FORMAT}_"

Tests can also be run again a web service instance. Following command should be adapted according to instance base URI and optional API key:

export THUMBNAILER_BASE_URI="http://localhost:8080"
dotnet test

Building Docker image

Docker image can be built with following command:

docker build . -f ./src/PommaLabs.Thumbnailer/Dockerfile.latest -t $DOCKER_TAG

Please replace $DOCKER_TAG with a valid tag (e.g. thumbnailer).


MIT © 2019-2023 Alessio Parma

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed. 
Compatible target framework(s)
Additional computed target framework(s)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
5.1.0 941 12/19/2022
5.0.0 48 11/27/2022
4.2.0 370 12/19/2021
4.1.0 400 11/21/2021
4.0.2 147 8/20/2021
3.1.0 442 2/7/2021
3.0.0 619 11/9/2020
2.1.0 420 9/10/2020
2.0.2 413 6/19/2020
2.0.1 350 6/11/2020
2.0.0 367 6/1/2020
1.7.1 395 4/13/2020
1.6.3 421 3/29/2020
1.6.0 399 3/8/2020