Convert / resize / transcode / down-sample photos & videos to be web-friendly
This is one of the core modules of thumbsup.github.io.
npm install thumbsup-downsize --save
This module requires the following binaries available in the system path, depending on the type of files you need to process:
- GraphicsMagick for processing images
- ImageMagick for HEIC support
- FFMpeg for processing videos
- Gifsicle for processing animated GIFs
To run the tests, you will also need
const downsize = require('thumbsup-downsize')
const options = { height: 100, width: 100 }
downsize.image('source.tiff', 'thumb.jpg', options, (err) => {
console.log(err || 'Thumbnail created successfully')
})
.image(source, target, options, callback)
Processes the image in source
and creates a new image in target
.
The image is appropriately converted if needed based on the target
file extension.
You can specify the following options:
// proportionally resize the photo to a maximum height
opts = { height: 300 }
// proportionally resize the photo to a maximum width
opts = { width: 300 }
// resize and crop the photo to exactly height x width
// the image will not be distorted
opts = { height: 100, width: 100 }
// quality between 0 and 100
opts = { quality: 80 }
By default, all metadata is removed from downsized images. This option will keep all EXIF / IPTC / XMP metadata in the target files.
When setting this option to true, images will no longer be auto-rotated.
opts = { keepMetadata: true }
You can overlay a transparent watermark over the final image:
opts = {
watermark: {
file: 'path/watermark.png', // transparent PNG
position: 'NorthEast' // position of the watermark
}
}
The possible values for position
are:
Repeat
to repeat the watermark across the whole imageCenter
to position the watermark in the middleNorthWest
,North
,NorthEast
,West
,East
,SouthWest
,South
,SouthEast
to position the watermark along the edge
Note: watermarks are not compatible with cropped images.
The watermark
option will simply be ignored if both width and height are specified.
You can specify extra arguments that will be passed to GraphicsMagick. This only works with output arguments.
opts = {
args: [
'-unsharp 2 0.5 0.7 0',
'-modulate 120'
]
}
By default, only the first frame of an animated GIF is exported. You can keep the entire animation by specifying:
opts = { animated: true }
This offloads the processing of the image to Gifsicle. Note that:
- The destination file extension must be
.gif
- The only other supported parameters are
width
andheight
(e.g. no watermarks) - Cropping (specifying both width and height) is not supported and will throw an error
The flag is simply ignored if the source file is not a GIF.
.still(source, target, options, callback)
Extract a single frame from the video in source
, and writes the image to target
.
This method supports all the same options as .image()
, with the addition of:
opts = {
// take the screenshot at the very start of the video
seek: 0
// take the screenshot after N second (default = 1)
seek: 1
// take the screenshot in the middle of the video
seek: -1
}
If seeking fails for any reason, the first frame is used instead.
.video(source, target, options, callback)
Transcodes the video in source
to a web-friendly format and lower bitrate, and writes it in target
.
You can specify the following options:
The default export format is mp4
.
You can specify an export format by adding a format
option:
opts = { format: 'mp4' } // H264 encoder
opts = { format: 'webm' } // VP9 encoder
Note: encoding as webm
is much slower.
The default behaviour is to use CRF (constant rate factor) to control the output quality.
The default value is 75%
.
// value between 0 (worst) and 100 (best)
opts = { quality: 75 }
Notes:
- the quality scale is not linear
- you will most likely want a value between 50% and 90%
- values over 90% can generate files larger than the original
Instead of CRF, you can specify a variable bitrate (a.k.a. average bitrate, or target bitrate) by using the bitrate
option.
Check the ffmpeg docmentation for more information.
This is not compatible with the quality
option.
opts = { bitrate: '1200k' }
Enable VAAPI HW acceleration if supported on your platform (typically Intel/AMD chipsets).
Requires intel-media-driver package to enable.
This is not compatiable with the quality
option and requires a bitrate
setting.
The default value is none
.
// values 'vaapi' or 'none'
opts = { hwaccel: 'vaapi' }
The default export video FPS is 25. You can specify an explicit FPS by adding a framerate
option:
opts = { framerate: 60 }
opts = { framerate: 0 } // preserve the original source video's FPS
By default, all metadata is removed from the target video. This option preserves the metadata.
opts = { keepMetadata: true }
The .video()
call returns an EventEmitter
to follow the progress of the conversion, since it can take a long time.
const emitter = downsize.video(/* ... */)
emitter.on('progress', percent => console.log(`${percent}%`))
Image/video resizing is hard to unit test. Instead, this repo contains an integration test suite made of many different resized files, covering different file formats and edge cases.
When submitting a change, make sure you run the build locally.
npm test
If you don't have all dependencies installed, you can also run the tests in Docker.
docker build -t downsize-test .