mirror of
https://github.com/lovell/sharp.git
synced 2025-07-14 04:40:13 +02:00
Add support for OME-TIFF subIFDs #2557
This commit is contained in:
parent
8c33d0aa56
commit
43a085d1ae
@ -28,6 +28,7 @@ Implements the [stream.Duplex][1] class.
|
||||
- `options.density` **[number][8]** number representing the DPI for vector images in the range 1 to 100000. (optional, default `72`)
|
||||
- `options.pages` **[number][8]** number of pages to extract for multi-page input (GIF, WebP, AVIF, TIFF, PDF), use -1 for all pages. (optional, default `1`)
|
||||
- `options.page` **[number][8]** page number to start extracting from for multi-page input (GIF, WebP, AVIF, TIFF, PDF), zero based. (optional, default `0`)
|
||||
- `options.subifd` **[number][8]** subIFD (Sub Image File Directory) to extract for OME-TIFF, defaults to main image. (optional, default `-1`)
|
||||
- `options.level` **[number][8]** level to extract from a multi-level input (OpenSlide), zero based. (optional, default `0`)
|
||||
- `options.animated` **[boolean][7]** Set to `true` to read all frames/pages of an animated image (equivalent of setting `pages` to `-1`). (optional, default `false`)
|
||||
- `options.raw` **[Object][6]?** describes raw pixel input image data. See `raw()` for pixel ordering.
|
||||
|
@ -21,6 +21,7 @@ A `Promise` is returned when `callback` is not provided.
|
||||
- `delay`: Delay in ms between each page in an animated image, provided as an array of integers.
|
||||
- `pagePrimary`: Number of the primary page in a HEIF image
|
||||
- `levels`: Details of each level in a multi-level image provided as an array of objects, requires libvips compiled with support for OpenSlide
|
||||
- `subifds`: Number of Sub Image File Directories in an OME-TIFF image
|
||||
- `hasProfile`: Boolean indicating the presence of an embedded ICC profile
|
||||
- `hasAlpha`: Boolean indicating the presence of an alpha transparency channel
|
||||
- `orientation`: Number value of the EXIF Orientation header, if present
|
||||
|
@ -8,8 +8,11 @@ Requires libvips v8.10.6
|
||||
|
||||
* Ensure all installation errors are logged with a more obvious prefix.
|
||||
|
||||
* Add support for OME-TIFF Sub Image File Directories (subIFD).
|
||||
[#2557](https://github.com/lovell/sharp/issues/2557)
|
||||
|
||||
* Allow `ensureAlpha` to set the alpha transparency level.
|
||||
[#2634](https://github.com/lovell/sharp/issues/2634)
|
||||
[#2634](https://github.com/lovell/sharp/issues/2634)
|
||||
|
||||
### v0.28.0 - 29th March 2021
|
||||
|
||||
|
@ -132,6 +132,7 @@ const debuglog = util.debuglog('sharp');
|
||||
* @param {number} [options.density=72] - number representing the DPI for vector images in the range 1 to 100000.
|
||||
* @param {number} [options.pages=1] - number of pages to extract for multi-page input (GIF, WebP, AVIF, TIFF, PDF), use -1 for all pages.
|
||||
* @param {number} [options.page=0] - page number to start extracting from for multi-page input (GIF, WebP, AVIF, TIFF, PDF), zero based.
|
||||
* @param {number} [options.subifd=-1] - subIFD (Sub Image File Directory) to extract for OME-TIFF, defaults to main image.
|
||||
* @param {number} [options.level=0] - level to extract from a multi-level input (OpenSlide), zero based.
|
||||
* @param {boolean} [options.animated=false] - Set to `true` to read all frames/pages of an animated image (equivalent of setting `pages` to `-1`).
|
||||
* @param {Object} [options.raw] - describes raw pixel input image data. See `raw()` for pixel ordering.
|
||||
|
15
lib/input.js
15
lib/input.js
@ -9,9 +9,9 @@ const sharp = require('../build/Release/sharp.node');
|
||||
* @private
|
||||
*/
|
||||
function _inputOptionsFromObject (obj) {
|
||||
const { raw, density, limitInputPixels, sequentialRead, failOnError, animated, page, pages } = obj;
|
||||
return [raw, density, limitInputPixels, sequentialRead, failOnError, animated, page, pages].some(is.defined)
|
||||
? { raw, density, limitInputPixels, sequentialRead, failOnError, animated, page, pages }
|
||||
const { raw, density, limitInputPixels, sequentialRead, failOnError, animated, page, pages, subifd } = obj;
|
||||
return [raw, density, limitInputPixels, sequentialRead, failOnError, animated, page, pages, subifd].some(is.defined)
|
||||
? { raw, density, limitInputPixels, sequentialRead, failOnError, animated, page, pages, subifd }
|
||||
: undefined;
|
||||
}
|
||||
|
||||
@ -131,6 +131,14 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
||||
throw is.invalidParameterError('level', 'integer between 0 and 256', inputOptions.level);
|
||||
}
|
||||
}
|
||||
// Sub Image File Directory (TIFF)
|
||||
if (is.defined(inputOptions.subifd)) {
|
||||
if (is.integer(inputOptions.subifd) && is.inRange(inputOptions.subifd, -1, 100000)) {
|
||||
inputDescriptor.subifd = inputOptions.subifd;
|
||||
} else {
|
||||
throw is.invalidParameterError('subifd', 'integer between -1 and 100000', inputOptions.subifd);
|
||||
}
|
||||
}
|
||||
// Create new image
|
||||
if (is.defined(inputOptions.create)) {
|
||||
if (
|
||||
@ -255,6 +263,7 @@ function _isStreamInput () {
|
||||
* - `delay`: Delay in ms between each page in an animated image, provided as an array of integers.
|
||||
* - `pagePrimary`: Number of the primary page in a HEIF image
|
||||
* - `levels`: Details of each level in a multi-level image provided as an array of objects, requires libvips compiled with support for OpenSlide
|
||||
* - `subifds`: Number of Sub Image File Directories in an OME-TIFF image
|
||||
* - `hasProfile`: Boolean indicating the presence of an embedded ICC profile
|
||||
* - `hasAlpha`: Boolean indicating the presence of an alpha transparency channel
|
||||
* - `orientation`: Number value of the EXIF Orientation header, if present
|
||||
|
@ -104,6 +104,10 @@ namespace sharp {
|
||||
if (HasAttr(input, "level")) {
|
||||
descriptor->level = AttrAsUint32(input, "level");
|
||||
}
|
||||
// subIFD (OME-TIFF)
|
||||
if (HasAttr(input, "subifd")) {
|
||||
descriptor->subifd = AttrAsInt32(input, "subifd");
|
||||
}
|
||||
// Create new image
|
||||
if (HasAttr(input, "createChannels")) {
|
||||
descriptor->createChannels = AttrAsUint32(input, "createChannels");
|
||||
@ -319,6 +323,9 @@ namespace sharp {
|
||||
if (imageType == ImageType::OPENSLIDE) {
|
||||
option->set("level", descriptor->level);
|
||||
}
|
||||
if (imageType == ImageType::TIFF) {
|
||||
option->set("subifd", descriptor->subifd);
|
||||
}
|
||||
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
|
||||
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
||||
image = SetDensity(image, descriptor->density);
|
||||
@ -391,6 +398,9 @@ namespace sharp {
|
||||
if (imageType == ImageType::OPENSLIDE) {
|
||||
option->set("level", descriptor->level);
|
||||
}
|
||||
if (imageType == ImageType::TIFF) {
|
||||
option->set("subifd", descriptor->subifd);
|
||||
}
|
||||
image = VImage::new_from_file(descriptor->file.data(), option);
|
||||
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
||||
image = SetDensity(image, descriptor->density);
|
||||
|
@ -60,6 +60,7 @@ namespace sharp {
|
||||
int pages;
|
||||
int page;
|
||||
int level;
|
||||
int subifd;
|
||||
int createChannels;
|
||||
int createWidth;
|
||||
int createHeight;
|
||||
@ -82,6 +83,7 @@ namespace sharp {
|
||||
pages(1),
|
||||
page(0),
|
||||
level(0),
|
||||
subifd(-1),
|
||||
createChannels(0),
|
||||
createWidth(0),
|
||||
createHeight(0),
|
||||
|
@ -86,6 +86,9 @@ class MetadataWorker : public Napi::AsyncWorker {
|
||||
baton->levels.push_back(std::pair<int, int>(width, height));
|
||||
}
|
||||
}
|
||||
if (image.get_typeof(VIPS_META_N_SUBIFDS) == G_TYPE_INT) {
|
||||
baton->subifds = image.get_int(VIPS_META_N_SUBIFDS);
|
||||
}
|
||||
baton->hasProfile = sharp::HasProfile(image);
|
||||
// Derived attributes
|
||||
baton->hasAlpha = sharp::HasAlpha(image);
|
||||
@ -203,6 +206,9 @@ class MetadataWorker : public Napi::AsyncWorker {
|
||||
}
|
||||
info.Set("levels", levels);
|
||||
}
|
||||
if (baton->subifds > 0) {
|
||||
info.Set("subifds", baton->subifds);
|
||||
}
|
||||
info.Set("hasProfile", baton->hasProfile);
|
||||
info.Set("hasAlpha", baton->hasAlpha);
|
||||
if (baton->orientation > 0) {
|
||||
|
@ -41,6 +41,7 @@ struct MetadataBaton {
|
||||
int pagePrimary;
|
||||
std::string compression;
|
||||
std::vector<std::pair<int, int>> levels;
|
||||
int subifds;
|
||||
bool hasProfile;
|
||||
bool hasAlpha;
|
||||
int orientation;
|
||||
@ -68,6 +69,7 @@ struct MetadataBaton {
|
||||
pageHeight(0),
|
||||
loop(-1),
|
||||
pagePrimary(-1),
|
||||
subifds(0),
|
||||
hasProfile(false),
|
||||
hasAlpha(false),
|
||||
orientation(0),
|
||||
|
@ -718,6 +718,19 @@ describe('Input/output', function () {
|
||||
sharp({ level: -1 });
|
||||
}, /Expected integer between 0 and 256 for level but received -1 of type number/);
|
||||
});
|
||||
it('Valid subifd property', function () {
|
||||
sharp({ subifd: 1 });
|
||||
});
|
||||
it('Invalid subifd property (string) throws', function () {
|
||||
assert.throws(function () {
|
||||
sharp({ subifd: '1' });
|
||||
}, /Expected integer between -1 and 100000 for subifd but received 1 of type string/);
|
||||
});
|
||||
it('Invalid subifd property (float) throws', function () {
|
||||
assert.throws(function () {
|
||||
sharp({ subifd: 1.2 });
|
||||
}, /Expected integer between -1 and 100000 for subifd but received 1.2 of type number/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('create new image', function () {
|
||||
|
Loading…
x
Reference in New Issue
Block a user