Last active
May 16, 2020 02:42
-
-
Save kellymears/90f53c1387c6817dc82793f38e1533da to your computer and use it in GitHub Desktop.
Asynchronously process a set of images using rxjs and sharp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fs = require('fs-extra') | |
const sharp = require('sharp') | |
const globby = require('globby') | |
const {Observable, from} = require('rxjs') | |
const {concatMap} = require('rxjs/operators') | |
const pino = require('pino') | |
const prettifier = require('pino-pretty') | |
/** | |
* Logger util | |
*/ | |
const logger = pino({ | |
sync: false, | |
prettyPrint: { | |
levelFirst: true, | |
}, | |
prettifier, | |
}) | |
/** | |
* Media sources | |
*/ | |
const SOURCES = [ | |
'web/app/uploads/**/*.jpg', | |
'web/app/uploads/**/*.jpeg', | |
'web/app/uploads/**/*.png', | |
'web/app/themes/sage/resources/assets/images/*.jpg', | |
'web/app/themes/sage/resources/assets/images/*.jpeg', | |
'web/app/themes/sage/resources/assets/images/*.png', | |
] | |
/** | |
* Options | |
*/ | |
const options = { | |
png: { | |
progressive: true, | |
quality: 50, | |
compressionLevel: 6, | |
}, | |
jpeg: { | |
progressive: true, | |
quality: 50, | |
optimizeScans: true, | |
}, | |
resize: { | |
width: 2560, | |
height: 1440, | |
withoutEnlargement: true, | |
}, | |
} | |
/** | |
* Return the sharp method for | |
* a given image file | |
*/ | |
const sharpHandler = path => { | |
const exts = { | |
png: 'png', | |
jpg: 'jpeg', | |
jpeg: 'jpeg', | |
} | |
const ext = exts[path.split('.').pop()] | |
return ext ? ext : null | |
} | |
/** | |
* Return tmp path for any given file. | |
*/ | |
const tmp = path => | |
path.replace('web/', 'tmp/') | |
/** | |
* Asynchronously process a set of images | |
* using the Lovell/Sharp library | |
* | |
* @param {array} sources -- glob strings | |
*/ | |
const process = async sources => { | |
/** Resolve array of image paths */ | |
const media = await globby(sources) | |
/** | |
* Process images as a metastream | |
* of functional observables. | |
*/ | |
const processing = new Observable(obs => { | |
from(media).pipe( | |
concatMap(async img => { | |
/** Copy to tmp */ | |
try { | |
await fs.copy(img, tmp(img)) | |
} catch (e) { | |
logger.error(e) | |
} | |
/** | |
* Process image. | |
*/ | |
try { | |
await sharp(tmp(img))[`${sharpHandler(img)}`]( | |
options[`${sharpHandler(img)}`] | |
).resize(options.resize).toFile(img) | |
} catch (e) { | |
logger.error(e) | |
} | |
/** Remove tmp */ | |
try { | |
await fs.remove(tmp(img)) | |
} catch (e) { | |
logger.error(e) | |
} | |
obs.next(img) | |
}) | |
) | |
.subscribe({ | |
next: next => obs.next(next), | |
}) | |
}) | |
/** | |
* Log metastream's emitted events | |
*/ | |
processing.subscribe({ | |
next: next => next && logger.info(next), | |
}) | |
} | |
process(SOURCES) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment