GitHub Action
Thumbnails generator
To add the thumbnail generator to your GitHub Actions pipeline, specify the name of this repository, optionally with a tag number (@v1.1
is the current version) as a step
within your workflow.yml
file.
Inside your .github/workflows/workflow.yml
file:
steps:
- uses: actions/checkout@master
- uses: subic/ghaction-thumbnails@master
with: # Required arguments:
source: 'images' # Input images folder, required both as an argument and as an existing directory path in repository which is also the reason for the previous checkout step (default: 'images').
output: 'thumbnails' # Output thumbnails container folder, can be same as input or base directory, if the directory doesn't exist it will be created recursively (default: 'thumbnails').
sizes: 480 # Output widths or dimensions separated with an 'x', can be a number or a comma-delimited string. Prefix height only sizes with 'x' when not setting widths; eg. "x360, x1080" (default: 480)).
Note: The action is meant to be used in a (web assets) build chain so it only exposes the output directory and its contents to other GitHub actions. When using as a separate or individual build action, you will probably want to commit the generated image files. See the full example workflow file below or the example repository for details.
The action supports 10 input arguments (source
, output
, sizes
, subfolder
, filename
, extensions
, fit
, position
, enlarge
and overwrite
) but only the first three are required and validated. When others are omitted or wrong the action tries to defensively fall back onto sensible defaults which still generate useful images but it will error out on some illegal arguments. The images are processed using sharp so most of the optional arguments are just settings passed over to the actual image processing task.
Input | Description | Required | Default |
---|---|---|---|
source |
Source images folder | ✓ | 'images' |
output |
Thumbnails output folder | ✓ | 'thumbnails' |
sizes |
Thumbnail sizes | ✓ | 480 |
subfolder |
Thumbnails subfolder pattern | 𐄂 | '%D' |
filename |
Thumbnail filename pattern | 𐄂 | '%F' |
extensions |
Image extensions filter | 𐄂 | 'jpg, jpeg, png, webp, gif, tiff' |
fit |
How the images should be resized to dimension | 𐄂 | 'cover' |
position |
Position, gravity or strategy for cover or contain | 𐄂 | 'centre' |
enlarge |
Enlarge smaller images to thumbnail dimensions | 𐄂 | true |
overwrite |
Overwrite existing images | 𐄂 | false |
Input images directory path (string) relative to the repository base. Required both as an argument and as an existing directory path in repository. Action throws error if the argument path is not an existing repository folder. Default is 'images'
.
Output thumbnails directory path (string) relative to the repository base. It is required but the directory will be (recursively) created if not present. The argument will be output as a path string from the action to be used in further workflow jobs or steps. Default is 'thumbnails'
.
Output thumbnail dimensions (number, string or comma-delimited string of numbers or strings). Any number of sizes separated with a comma can be supplied but at least one is required. If the size is a number only, it will be treated as width; prefix it with an x
to process it as height dimension. To set both output width and height dimensions, pass width and height with the x
separator eg. 1920x1080
. Default value is 480
.
Subfolder (string) pattern for each width. Use false
to output directly to the output
folder but note that any existing or generated files will not be overwritten by default. Pattern strings %D
, %W
and %H
can be used to be replaced by the generated image dimension values where %W
is image width in pixels, %H
is image height in pixels and %D
is width or height if width is not set.
Note: Even when using
subfolder: false
source images can not and will never be overwritten. The action uses sharp's toFile output option which means the source and destination file can not match. If that is a requirement image processing task can be modified or replaced completely to eg. use sharp streams or imagemagick or review some of the alternatives.
Thumbnail output filename (string) pattern. In addition to the above subfolder
patterns %D
, %W
and %H
, additional replace patterns are available: %F
, %N
and %E
where %F
is input filename, which is same as %N%E
- %N
is input base filename and %E
is the input file's extension. Default is %F
.
Input files images extensions filter (string or comma-delimited string of strings). Sharp can process JPEG, PNG, WebP, GIF, SVG and TIFF image files so possible values are 'jpg'
or 'jpeg'
, 'png'
, 'webp'
, 'gif'
, 'tiff'
, 'svg'
or any combination of them as a comma-delimited string. Default is 'jpg, jpeg, png, webp, gif, tiff' as vector image thumbnails are probably not needed.
Sharp input parameter (string) for how the image should be resized to fit both provided thumbnail dimensions. Possible values:
'cover'
(default): Preserving aspect ratio, ensure the image covers both provided dimensions by cropping/clipping to fit.'contain'
: Preserving aspect ratio, contain within both provided dimensions using "letter-boxing" where necessary.'fill'
: Ignore the aspect ratio of the input and stretch to both provided dimensions.'inside'
: Preserving aspect ratio, resize the image to be as large as possible while ensuring its dimensions are less than or equal to both those specified.'outside'
: Preserving aspect ratio, resize the image to be as small as possible while ensuring its dimensions are greater than or equal to both those specified.Note: Both width and height action sizes options have to be set for this argument to apply.
Sharp input parameter (string) for position, gravity or strategy when using a fit
of cover
or contain
. Options are: top
, right top
, right
, right bottom
, bottom
, left bottom
, left
, left top
, north
, northeast
, east
, southeast
, south
, southwest
, west
, northwest
, center
, centre
(default), entropy
(fit
: 'cover'
only) and attention
(fit
: 'cover'
only)
A (string) parameter wether to enlarge generated thumbnails if the source image width or height are less than the specified dimensions. Possible values: 'true'
(default) or 'false'
.
A (string) parameter wether to overwrite any existing files in the output
folder. Possible values: 'true'
or 'false'
(default).
If there are no breaking errors, the action only sets a single output: thumbnails
which is the repository relative path string for the container output
images folder. It can be used in any further image actions or passed to a commit repository action.
Example commented workflow file with all optional arguments and example commit step using the output environment variable. It will trigger on any new or modified files added to the /images
repository folder (set under paths:
) and generate (and commit) 480 px wide image thumbnails for new images in thumbnails/480
repo folder.
name: Generate thumbnails
on:
push:
branches:
- master
paths:
- 'images/*' # Only run on this path changes
jobs:
generate_thumbnails:
name: Generate thumbnails
runs-on: ubuntu-latest
timeout-minutes: 10 # Should be enough for all runs, GH default is 360 which is unreasonable...
steps:
- name: Checkout repository # Check out the repo to access the input image folder.
uses: actions/checkout@master
- name: Process Images
id: images
uses: subic/ghaction-thumbnails@v1.1 # Tag number optional, breaking changes not expected.
with: # Arguments:
source: 'images' # REQUIRED
output: 'thumbnails' # REQUIRED
sizes: 480 # REQUIRED
extensions: 'jpg, jpeg, png, webp, gif, tiff'
subfolder: '%D'
filename: '%F'
fit: 'cover'
position: 'centre'
enlarge: 'true'
overwrite: 'false'
- name: Commit thumbnail folder # This step will commit generated files, remove if not used as a single purpose workflow. Will exit gracefully if no changes are found.
run: |
echo "Committing folder ${{steps.images.outputs.thumbnails}}"
git config --local user.name "${{github.actor}}"
git config --local user.email "${{github.actor}}@users.noreply.github.com"
git add ./${{steps.images.outputs.thumbnails}}" || exit 0
git commit -m "[skip ci] Auto-generated missing thumbnails" -a || exit 0
git push -f -q https://${{secrets.GITHUB_TOKEN}}@github.com/${{github.repository}}
An example repository with the workflow file usage example is available here. You can fork it and after pushing an image to the images
folder on GitHub, example thumbnails will be generated in the output
folder. A comparison test
folder is also available which will run the action and its alternatives for comparison.
The action was developed as a way to prevent excess thumbnail generation when using a build tool for a static website - when using "git as a cms" with tools such as netlifycms or GitHub pages, any files generated as part of the build process are not committed to the source repository and therefore needlessly regenerated on each full build.
The code is (somewhat) commented and built as to allow easy automatization for any thumbnail generation need. The actual image processing task is hot-plugable to allow replacement of sharp output, script or even sharp itself.
.
├── dist # Compiled main script code with modules (for GH linux)
├── helpers # Helper functions folder
│ ├── folders.js # Node files system helper scripts
│ ├── images.js # Image processing script
│ └── inputs.js # Input arguments validation helper scripts
├── .gitignore
├── action.yml # Main action file
├── index.js # Main script file
├── LICENSE.md
├── package-lock.json
└── package.json
The images helper script will be called on each required source file with the provided options. See the script parameters for the values that are passed to each instance. The resizeImage
export script can be customized for further processing using sharp or the sharp dependency can be replace entirely (eg. with node-imagemagick) by modifying this file.
When forking for modification keep in mind the action calls the compiled version in the dist
folder. You can generate it using vercel/ncc
by running npm run build:action
npm script. If you want to skip the compilation step on each change, you can point the action's runs/main
parameter to index.js
but you will have to commit the node_modules
folder to your repository. For more information see here. Also keep in mind that sharp uses platform dependant binaries so make sure the correct version for GitHub linux runner is installed (the provided npm script npm run install:action
makes sure of it while also skipping the optional dev dependencies).
- GitHub Actions Toolkit - The GitHub ToolKit for developing GitHub Actions.
- sharp - High performance Node.js image processing.
In addition, the following devDependencies
are used for linting only: eslint
, eslint-config-airbnb-base
and eslint-plugin-import
.
Or keep your life simple and avoid the whole use-case with Netlify Large Media or Cloudinary.
Any contributions welcome! Open a new issue or submit a pull request.
The code in this project is released under the MIT License.