From a89bebb03c9eff8fc6d1ca26e903c60388813a36 Mon Sep 17 00:00:00 2001 From: Kevin Martensson Date: Thu, 14 Sep 2017 23:38:49 +0200 Subject: [PATCH] Add support for streams --- index.js | 50 +++++++++++++++++++++++++++++--------------------- package.json | 5 +++-- readme.md | 10 +++++----- test.js | 23 +++++++++++++++-------- 4 files changed, 52 insertions(+), 36 deletions(-) diff --git a/index.js b/index.js index 5ea2b92..c1f9e72 100644 --- a/index.js +++ b/index.js @@ -1,23 +1,23 @@ 'use strict'; -const execBuffer = require('exec-buffer'); +const execa = require('execa'); const isPng = require('is-png'); +const isStream = require('is-stream'); const pngquant = require('pngquant-bin'); -module.exports = opts => buf => { +module.exports = opts => input => { opts = Object.assign({}, opts); - if (!Buffer.isBuffer(buf)) { - return Promise.reject(new TypeError('Expected a buffer')); + const isBuffer = Buffer.isBuffer(input); + + if (!isBuffer && !isStream(input)) { + return Promise.reject(new TypeError(`Expected a Buffer or Stream, got ${typeof input}`)); } - if (!isPng(buf)) { - return Promise.resolve(buf); + if (isBuffer && !isPng(input)) { + return Promise.resolve(input); } - const args = [ - '--output', execBuffer.output, - execBuffer.input - ]; + const args = ['-']; if (opts.floyd && typeof opts.floyd === 'number') { args.push(`--floyd=${opts.floyd}`); @@ -47,16 +47,24 @@ module.exports = opts => buf => { args.push('--verbose'); } - return execBuffer({ - input: buf, - bin: pngquant, - args - }).catch(err => { - if (err.code === 99) { - return buf; - } - - err.message = err.stderr || err.message; - throw err; + const cp = execa(pngquant, args, { + encoding: null, + input }); + + const promise = cp + .then(res => res.stdout) + .catch(err => { + if (err.code === 99) { + return input; + } + + err.message = err.stderr || err.message; + throw err; + }); + + cp.stdout.then = promise.then.bind(promise); + cp.stdout.catch = promise.catch.bind(promise); + + return cp.stdout; }; diff --git a/package.json b/package.json index a3ee5f4..04257c0 100644 --- a/package.json +++ b/package.json @@ -40,13 +40,14 @@ "pngquant" ], "dependencies": { - "exec-buffer": "^3.0.0", + "execa": "^0.8.0", "is-png": "^1.0.0", + "is-stream": "^1.1.0", "pngquant-bin": "^3.0.0" }, "devDependencies": { "ava": "*", - "pify": "^3.0.0", + "get-stream": "^3.0.0", "xo": "*" } } diff --git a/readme.md b/readme.md index 60e6fb9..7357356 100644 --- a/readme.md +++ b/readme.md @@ -24,9 +24,9 @@ imagemin(['images/*.png'], 'build/images', {use: [imageminPngquant()]}).then(() ## API -### imageminPngquant([options])(buffer) +### imageminPngquant([options])(input) -Returns a promise for a buffer. +Returns a `Promise` for a `Buffer`. #### options @@ -76,11 +76,11 @@ Default: `false` Print verbose status messages. -#### buffer +#### input -Type: `Buffer` +Type: `Buffer` `Stream` -Buffer to optimize. +Buffer or stream to optimize. ## License diff --git a/test.js b/test.js index 9a4b431..4477673 100644 --- a/test.js +++ b/test.js @@ -1,14 +1,12 @@ import fs from 'fs'; import path from 'path'; +import getStream from 'get-stream'; import isPng from 'is-png'; -import pify from 'pify'; import test from 'ava'; -import m from './'; - -const fsP = pify(fs); +import m from '.'; test('optimize a PNG', async t => { - const buf = await fsP.readFile(path.join(__dirname, 'fixture.png')); + const buf = await fs.readFileSync(path.join(__dirname, 'fixture.png')); const data = await m()(buf); t.true(data.length < buf.length); @@ -16,7 +14,7 @@ test('optimize a PNG', async t => { }); test('support pngquant options', async t => { - const buf = await fsP.readFile(path.join(__dirname, 'fixture.png')); + const buf = await fs.readFileSync(path.join(__dirname, 'fixture.png')); const data = await m({ speed: 10, quality: 100 @@ -26,15 +24,24 @@ test('support pngquant options', async t => { t.true(isPng(data)); }); +test('support streams', async t => { + const buf = await fs.readFileSync(path.join(__dirname, 'fixture.png')); + const stream = fs.createReadStream(path.join(__dirname, 'fixture.png')); + const data = await getStream.buffer(m()(stream)); + + t.true(data.length < buf.length); + t.true(isPng(data)); +}); + test('skip optimizing a non-PNG file', async t => { - const buf = await fsP.readFile(__filename); + const buf = await fs.readFileSync(__filename); const data = await m()(buf); t.is(data.length, buf.length); }); test('skip optimizing a fully optimized PNG', async t => { - const buf = await fsP.readFile(path.join(__dirname, 'fixture-no-compress.png')); + const buf = await fs.readFileSync(path.join(__dirname, 'fixture-no-compress.png')); const data = await m({quality: 100})(buf); t.is(data.length, buf.length); t.true(isPng(data));