mirror of
https://github.com/lovell/sharp.git
synced 2026-02-04 13:46:19 +01:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f99e42d447 | ||
|
|
9b4387be97 | ||
|
|
9c3631ecb7 | ||
|
|
31ca68fb14 |
36
README.md
36
README.md
@@ -18,9 +18,23 @@ Under the hood you'll find the blazingly fast [libvips](https://github.com/jcupi
|
||||
## Prerequisites
|
||||
|
||||
* Node.js v0.8+
|
||||
* [libvips](https://github.com/jcupitt/libvips) v7.38+
|
||||
* [libvips](https://github.com/jcupitt/libvips) v7.38.5+
|
||||
|
||||
For the sharpest results, please compile libvips from source.
|
||||
### Install libvips on Mac OS via homebrew
|
||||
|
||||
brew tap homebrew/science
|
||||
brew install vips
|
||||
|
||||
### Install libvips on Ubuntu Linux
|
||||
|
||||
sudo apt-get install automake build-essential git gobject-introspection gtk-doc-tools libfftw3-dev libglib2.0-dev libjpeg-turbo8-dev libpng12-dev libwebp-dev libtiff5-dev liborc-0.4-dev libxml2-dev swig
|
||||
git clone https://github.com/jcupitt/libvips.git
|
||||
cd libvips
|
||||
./bootstrap.sh
|
||||
./configure --enable-debug=no
|
||||
make
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
|
||||
## Install
|
||||
|
||||
@@ -38,9 +52,9 @@ Scale and crop to `width` x `height` calling `callback` when complete.
|
||||
|
||||
`output` can either be a filename String or one of `sharp.buffer.jpeg`, `sharp.buffer.png` or `sharp.buffer.webp` to pass a Buffer containing JPEG, PNG or WebP image data to `callback`.
|
||||
|
||||
`width` is the Number of pixels wide the resultant image should be.
|
||||
`width` is the Number of pixels wide the resultant image should be. Use a value of -1 to auto-scale the width to match the height.
|
||||
|
||||
`height` is the Number of pixels high the resultant image should be.
|
||||
`height` is the Number of pixels high the resultant image should be. Use a value of -1 to auto-scale the height to match the width.
|
||||
|
||||
`options` is optional, and can contain one or more of:
|
||||
|
||||
@@ -64,20 +78,20 @@ sharp.resize("input.jpg", "output.jpg", 300, 200, function(err) {
|
||||
```
|
||||
|
||||
```javascript
|
||||
sharp.resize("input.jpg", sharp.buffer.jpeg, 300, 200, {progressive: true}, function(err, buffer) {
|
||||
sharp.resize("input.jpg", sharp.buffer.jpeg, -1, 200, {progressive: true}, function(err, buffer) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
// buffer contains progressive JPEG image data
|
||||
// buffer contains progressive JPEG image data, 200 pixels high
|
||||
});
|
||||
```
|
||||
|
||||
```javascript
|
||||
sharp.resize("input.webp", sharp.buffer.png, 300, 200, {sharpen: true}, function(err, buffer) {
|
||||
sharp.resize("input.webp", sharp.buffer.png, 300, -1, {sharpen: true}, function(err, buffer) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
// buffer contains sharpened PNG image data (converted from JPEG)
|
||||
// buffer contains sharpened PNG image data (converted from JPEG), 300 pixels wide
|
||||
});
|
||||
```
|
||||
|
||||
@@ -103,11 +117,11 @@ sharp.resize("input.jpg", sharp.buffer.webp, 200, 300, {canvas: sharp.canvas.emb
|
||||
|
||||
### cache([limit])
|
||||
|
||||
If `limit` is provided, set the `vips` internal cache limit to this value in MB. The default value is 100.
|
||||
If `limit` is provided, set the (soft) limit of _libvips_ working/cache memory to this value in MB. The default value is 100.
|
||||
|
||||
Always returns cache statistics, namely current usage, high water mark and maximum limit.
|
||||
This method always returns cache statistics, useful for determining how much working memory is required for a particular task.
|
||||
|
||||
The high water mark may be higher than the maximum limit.
|
||||
Warnings such as _Application transferred too many scanlines_ are a good indicator you've set this value too low.
|
||||
|
||||
```javascript
|
||||
var stats = sharp.cache(); // { current: 98, high: 115, limit: 100 }
|
||||
|
||||
9
index.js
9
index.js
@@ -42,6 +42,10 @@ module.exports.resize = function(input, output, width, height, options, callback
|
||||
callback("Invalid height " + height);
|
||||
return;
|
||||
}
|
||||
if (outWidth < 1 && outHeight < 1) {
|
||||
callback("Width and/or height required");
|
||||
return;
|
||||
}
|
||||
var canvas = options.canvas || "c";
|
||||
if (canvas.length !== 1 || "cwb".indexOf(canvas) === -1) {
|
||||
callback("Invalid canvas " + canvas);
|
||||
@@ -50,15 +54,16 @@ module.exports.resize = function(input, output, width, height, options, callback
|
||||
var sharpen = !!options.sharpen;
|
||||
var progessive = !!options.progessive;
|
||||
var sequentialRead = !!options.sequentialRead;
|
||||
sharp.resize(options.inFile, options.inBuffer, output, width, height, canvas, sharpen, progessive, sequentialRead, callback);
|
||||
sharp.resize(options.inFile, options.inBuffer, output, outWidth, outHeight, canvas, sharpen, progessive, sequentialRead, callback);
|
||||
};
|
||||
|
||||
module.exports.cache = function(limit) {
|
||||
"use strict";
|
||||
if (Number.isNaN(limit)) {
|
||||
limit = null;
|
||||
}
|
||||
return sharp.cache(limit);
|
||||
}
|
||||
};
|
||||
|
||||
/* Deprecated v0.0.x methods */
|
||||
module.exports.crop = function(input, output, width, height, sharpen, callback) {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"name": "sharp",
|
||||
"version": "0.1.7",
|
||||
"version": "0.1.8",
|
||||
"author": "Lovell Fuller",
|
||||
"description": "High performance module to resize JPEG, PNG, WebP and TIFF images using the libvips image processing library",
|
||||
"scripts": {
|
||||
"test": "node tests/perf.js"
|
||||
"test": "node tests/unit && node tests/perf"
|
||||
},
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
|
||||
23
src/sharp.cc
23
src/sharp.cc
@@ -15,8 +15,8 @@ struct resize_baton {
|
||||
std::string file_out;
|
||||
void* buffer_out;
|
||||
size_t buffer_out_len;
|
||||
int width;
|
||||
int height;
|
||||
int width;
|
||||
int height;
|
||||
bool crop;
|
||||
VipsExtend extend;
|
||||
bool sharpen;
|
||||
@@ -119,7 +119,24 @@ void resize_async(uv_work_t *work) {
|
||||
|
||||
double xfactor = static_cast<double>(in->Xsize) / std::max(baton->width, 1);
|
||||
double yfactor = static_cast<double>(in->Ysize) / std::max(baton->height, 1);
|
||||
double factor = baton->crop ? std::min(xfactor, yfactor) : std::max(xfactor, yfactor);
|
||||
double factor;
|
||||
if (baton->width > 0 && baton->height > 0) {
|
||||
// Fixed width and height
|
||||
factor = baton->crop ? std::min(xfactor, yfactor) : std::max(xfactor, yfactor);
|
||||
} else if (baton->width > 0) {
|
||||
// Fixed width, auto height
|
||||
factor = xfactor;
|
||||
baton->height = floor(in->Ysize * factor);
|
||||
} else if (baton->height > 0) {
|
||||
// Fixed height, auto width
|
||||
factor = yfactor;
|
||||
baton->width = floor(in->Xsize * factor);
|
||||
} else {
|
||||
resize_error(baton, in);
|
||||
(baton->err).append("Width and/or height required");
|
||||
return;
|
||||
}
|
||||
|
||||
factor = std::max(factor, 1.0);
|
||||
int shrink = floor(factor);
|
||||
double residual = shrink / factor;
|
||||
|
||||
75
tests/random.js
Executable file
75
tests/random.js
Executable file
@@ -0,0 +1,75 @@
|
||||
var sharp = require("../index");
|
||||
var fs = require("fs");
|
||||
var imagemagick = require("imagemagick");
|
||||
var gm = require("gm");
|
||||
var epeg = require("epeg");
|
||||
var async = require("async");
|
||||
var assert = require("assert");
|
||||
var Benchmark = require("benchmark");
|
||||
|
||||
var inputJpg = __dirname + "/2569067123_aca715a2ee_o.jpg"; // http://www.flickr.com/photos/grizdave/2569067123/
|
||||
var outputJpg = __dirname + "/output.jpg";
|
||||
|
||||
var min = 320;
|
||||
var max = 960;
|
||||
|
||||
var randomDimension = function() {
|
||||
return Math.random() * (max - min) + min;
|
||||
};
|
||||
|
||||
new Benchmark.Suite("random").add("imagemagick", {
|
||||
defer: true,
|
||||
fn: function(deferred) {
|
||||
imagemagick.resize({
|
||||
srcPath: inputJpg,
|
||||
dstPath: outputJpg,
|
||||
quality: 0.8,
|
||||
width: randomDimension(),
|
||||
height: randomDimension()
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
} else {
|
||||
deferred.resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
}).add("gm", {
|
||||
defer: true,
|
||||
fn: function(deferred) {
|
||||
gm(inputJpg).resize(randomDimension(), randomDimension()).quality(80).toBuffer(function (err, buffer) {
|
||||
if (err) {
|
||||
throw err;
|
||||
} else {
|
||||
assert.notStrictEqual(null, buffer);
|
||||
deferred.resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
}).add("epeg", {
|
||||
defer: true,
|
||||
fn: function(deferred) {
|
||||
var image = new epeg.Image({path: inputJpg});
|
||||
var buffer = image.downsize(randomDimension(), randomDimension(), 80).process();
|
||||
assert.notStrictEqual(null, buffer);
|
||||
deferred.resolve();
|
||||
}
|
||||
}).add("sharp", {
|
||||
defer: true,
|
||||
fn: function(deferred) {
|
||||
sharp.resize(inputJpg, sharp.buffer.jpeg, randomDimension(), randomDimension(), function(err, buffer) {
|
||||
if (err) {
|
||||
throw err;
|
||||
} else {
|
||||
assert.notStrictEqual(null, buffer);
|
||||
deferred.resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
}).on("cycle", function(event) {
|
||||
console.log(String(event.target));
|
||||
}).on("complete", function() {
|
||||
var winner = this.filter("fastest").pluck("name");
|
||||
assert.strictEqual("sharp", String(winner), "sharp was slower than " + winner);
|
||||
console.dir(sharp.cache());
|
||||
}).run();
|
||||
34
tests/unit.js
Executable file
34
tests/unit.js
Executable file
@@ -0,0 +1,34 @@
|
||||
var sharp = require("../index");
|
||||
var imagemagick = require("imagemagick");
|
||||
var assert = require("assert");
|
||||
|
||||
var inputJpg = __dirname + "/2569067123_aca715a2ee_o.jpg"; // http://www.flickr.com/photos/grizdave/2569067123/
|
||||
var outputJpg = __dirname + "/output.jpg";
|
||||
|
||||
sharp.resize(inputJpg, outputJpg, 320, 240, function(err) {
|
||||
if (err) throw err;
|
||||
imagemagick.identify(outputJpg, function(err, features) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(320, features.width);
|
||||
assert.strictEqual(240, features.height);
|
||||
|
||||
sharp.resize(inputJpg, outputJpg, 320, -1, function(err) {
|
||||
if (err) throw err;
|
||||
imagemagick.identify(outputJpg, function(err, features) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(320, features.width);
|
||||
assert.strictEqual(262, features.height);
|
||||
});
|
||||
|
||||
sharp.resize(inputJpg, outputJpg, -1, 320, function(err) {
|
||||
if (err) throw err;
|
||||
imagemagick.identify(outputJpg, function(err, features) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(392, features.width);
|
||||
assert.strictEqual(320, features.height);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user