mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 10:30:15 +02:00
Add limitInputPixels option to reject input #115
This commit is contained in:
parent
c93f79daa7
commit
8421e3aa5f
@ -254,6 +254,12 @@ A Promises/A+ promise is returned when `callback` is not provided.
|
|||||||
|
|
||||||
An advanced setting that switches the libvips access method to `VIPS_ACCESS_SEQUENTIAL`. This will reduce memory usage and can improve performance on some systems.
|
An advanced setting that switches the libvips access method to `VIPS_ACCESS_SEQUENTIAL`. This will reduce memory usage and can improve performance on some systems.
|
||||||
|
|
||||||
|
#### limitInputPixels(pixels)
|
||||||
|
|
||||||
|
Do not process input images where the number of pixels (width * height) exceeds this limit.
|
||||||
|
|
||||||
|
`pixels` is the integral Number of pixels, with a value between 1 and the default 268402689 (0x3FFF * 0x3FFF).
|
||||||
|
|
||||||
### Image transformation options
|
### Image transformation options
|
||||||
|
|
||||||
#### resize(width, [height])
|
#### resize(width, [height])
|
||||||
|
28
index.js
28
index.js
@ -11,6 +11,12 @@ var BluebirdPromise = require('bluebird');
|
|||||||
var sharp = require('./build/Release/sharp');
|
var sharp = require('./build/Release/sharp');
|
||||||
var libvipsVersion = sharp.libvipsVersion();
|
var libvipsVersion = sharp.libvipsVersion();
|
||||||
|
|
||||||
|
var maximum = {
|
||||||
|
width: 0x3FFF,
|
||||||
|
height: 0x3FFF,
|
||||||
|
pixels: Math.pow(0x3FFF, 2)
|
||||||
|
};
|
||||||
|
|
||||||
var Sharp = function(input) {
|
var Sharp = function(input) {
|
||||||
if (!(this instanceof Sharp)) {
|
if (!(this instanceof Sharp)) {
|
||||||
return new Sharp(input);
|
return new Sharp(input);
|
||||||
@ -21,6 +27,7 @@ var Sharp = function(input) {
|
|||||||
bufferIn: null,
|
bufferIn: null,
|
||||||
streamIn: false,
|
streamIn: false,
|
||||||
sequentialRead: false,
|
sequentialRead: false,
|
||||||
|
limitInputPixels: maximum.pixels,
|
||||||
// ICC profiles
|
// ICC profiles
|
||||||
iccProfilePath: path.join(__dirname, 'icc') + path.sep,
|
iccProfilePath: path.join(__dirname, 'icc') + path.sep,
|
||||||
// resize options
|
// resize options
|
||||||
@ -366,24 +373,37 @@ Sharp.prototype.resize = function(width, height) {
|
|||||||
if (!width) {
|
if (!width) {
|
||||||
this.options.width = -1;
|
this.options.width = -1;
|
||||||
} else {
|
} else {
|
||||||
if (typeof width === 'number' && !Number.isNaN(width) && width % 1 === 0 && width > 0 && width <= 0x3FFF) {
|
if (typeof width === 'number' && !Number.isNaN(width) && width % 1 === 0 && width > 0 && width <= maximum.width) {
|
||||||
this.options.width = width;
|
this.options.width = width;
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Invalid width ' + width);
|
throw new Error('Invalid width (1 to ' + maximum.width + ') ' + width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!height) {
|
if (!height) {
|
||||||
this.options.height = -1;
|
this.options.height = -1;
|
||||||
} else {
|
} else {
|
||||||
if (typeof height === 'number' && !Number.isNaN(height) && height % 1 === 0 && height > 0 && height <= 0x3FFF) {
|
if (typeof height === 'number' && !Number.isNaN(height) && height % 1 === 0 && height > 0 && height <= maximum.height) {
|
||||||
this.options.height = height;
|
this.options.height = height;
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Invalid height ' + height);
|
throw new Error('Invalid height (1 to ' + maximum.height + ') ' + height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Limit the total number of pixels for input images
|
||||||
|
Assumes the image dimensions contained in the file header can be trusted
|
||||||
|
*/
|
||||||
|
Sharp.prototype.limitInputPixels = function(limit) {
|
||||||
|
if (typeof limit === 'number' && !Number.isNaN(limit) && limit % 1 === 0 && limit > 0 && limit <= maximum.pixels) {
|
||||||
|
this.options.limitInputPixels = limit;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid pixel limit (1 to ' + maximum.pixels + ') ' + limit);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Write output image data to a file
|
Write output image data to a file
|
||||||
*/
|
*/
|
||||||
|
@ -54,6 +54,7 @@ struct ResizeBaton {
|
|||||||
void* bufferIn;
|
void* bufferIn;
|
||||||
size_t bufferInLength;
|
size_t bufferInLength;
|
||||||
std::string iccProfilePath;
|
std::string iccProfilePath;
|
||||||
|
int limitInputPixels;
|
||||||
std::string output;
|
std::string output;
|
||||||
std::string outputFormat;
|
std::string outputFormat;
|
||||||
void* bufferOut;
|
void* bufferOut;
|
||||||
@ -94,6 +95,7 @@ struct ResizeBaton {
|
|||||||
|
|
||||||
ResizeBaton():
|
ResizeBaton():
|
||||||
bufferInLength(0),
|
bufferInLength(0),
|
||||||
|
limitInputPixels(0),
|
||||||
outputFormat(""),
|
outputFormat(""),
|
||||||
bufferOutLength(0),
|
bufferOutLength(0),
|
||||||
topOffsetPre(-1),
|
topOffsetPre(-1),
|
||||||
@ -178,6 +180,12 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
}
|
}
|
||||||
vips_object_local(hook, image);
|
vips_object_local(hook, image);
|
||||||
|
|
||||||
|
// Limit input images to a given number of pixels, where pixels = width * height
|
||||||
|
if (image->Xsize * image->Ysize > baton->limitInputPixels) {
|
||||||
|
(baton->err).append("Input image exceeds pixel limit");
|
||||||
|
return Error(baton, hook);
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate angle of rotation
|
// Calculate angle of rotation
|
||||||
Angle rotation;
|
Angle rotation;
|
||||||
bool flip;
|
bool flip;
|
||||||
@ -923,6 +931,8 @@ NAN_METHOD(resize) {
|
|||||||
}
|
}
|
||||||
// ICC profile to use when input CMYK image has no embedded profile
|
// ICC profile to use when input CMYK image has no embedded profile
|
||||||
baton->iccProfilePath = *String::Utf8Value(options->Get(NanNew<String>("iccProfilePath"))->ToString());
|
baton->iccProfilePath = *String::Utf8Value(options->Get(NanNew<String>("iccProfilePath"))->ToString());
|
||||||
|
// Limit input images to a given number of pixels, where pixels = width * height
|
||||||
|
baton->limitInputPixels = options->Get(NanNew<String>("limitInputPixels"))->Int32Value();
|
||||||
// Extract image options
|
// Extract image options
|
||||||
baton->topOffsetPre = options->Get(NanNew<String>("topOffsetPre"))->Int32Value();
|
baton->topOffsetPre = options->Get(NanNew<String>("topOffsetPre"))->Int32Value();
|
||||||
baton->leftOffsetPre = options->Get(NanNew<String>("leftOffsetPre"))->Int32Value();
|
baton->leftOffsetPre = options->Get(NanNew<String>("leftOffsetPre"))->Int32Value();
|
||||||
|
@ -524,4 +524,72 @@ describe('Input/output', function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
describe('Limit pixel count of input image', function() {
|
||||||
|
|
||||||
|
it('Invalid fails - negative', function(done) {
|
||||||
|
var isValid = false;
|
||||||
|
try {
|
||||||
|
sharp().limitInputPixels(-1);
|
||||||
|
isValid = true;
|
||||||
|
} catch (e) {}
|
||||||
|
assert(!isValid);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Invalid fails - float', function(done) {
|
||||||
|
var isValid = false;
|
||||||
|
try {
|
||||||
|
sharp().limitInputPixels(12.3);
|
||||||
|
isValid = true;
|
||||||
|
} catch (e) {}
|
||||||
|
assert(!isValid);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Invalid fails - huge', function(done) {
|
||||||
|
var isValid = false;
|
||||||
|
try {
|
||||||
|
sharp().limitInputPixels(Math.pow(0x3FFF, 2) + 1);
|
||||||
|
isValid = true;
|
||||||
|
} catch (e) {}
|
||||||
|
assert(!isValid);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Invalid fails - string', function(done) {
|
||||||
|
var isValid = false;
|
||||||
|
try {
|
||||||
|
sharp().limitInputPixels('fail');
|
||||||
|
isValid = true;
|
||||||
|
} catch (e) {}
|
||||||
|
assert(!isValid);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Same size as input works', function(done) {
|
||||||
|
sharp(fixtures.inputJpg).metadata(function(err, metadata) {
|
||||||
|
if (err) throw err;
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.limitInputPixels(metadata.width * metadata.height)
|
||||||
|
.toBuffer(function(err) {
|
||||||
|
assert.strictEqual(true, !err);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Smaller than input fails', function(done) {
|
||||||
|
sharp(fixtures.inputJpg).metadata(function(err, metadata) {
|
||||||
|
if (err) throw err;
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.limitInputPixels(metadata.width * metadata.height - 1)
|
||||||
|
.toBuffer(function(err) {
|
||||||
|
assert.strictEqual(true, !!err);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user