mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 18:40:16 +02:00
Add support for writing dz format to zip container (#402)
To enable this you can either use the `.zip` or `.szi` file extensions or use `.tile({container: 'zip'})` with the `.dzi` extension.
This commit is contained in:
parent
ef61da3051
commit
b224874332
@ -527,14 +527,17 @@ The default behaviour, when `withMetadata` is not used, is to strip all metadata
|
||||
|
||||
#### tile(options)
|
||||
|
||||
The size, overlap and directory layout to use when generating square Deep Zoom image pyramid tiles.
|
||||
The size, overlap, container and directory layout to use when generating square Deep Zoom image pyramid tiles.
|
||||
|
||||
`options` is an Object with one or more of the following attributes:
|
||||
|
||||
* `size` is an integral Number between 1 and 8192. The default value is 256 pixels.
|
||||
* `overlap` is an integral Number between 0 and 8192. The default value is 0 pixels.
|
||||
* `container` is a String, with value `fs` or `zip`. The default value is `fs`.
|
||||
* `layout` is a String, with value `dz`, `zoomify` or `google`. The default value is `dz`.
|
||||
|
||||
You can also use the file extension .zip or .szi to write to a ZIP container instead of the filesystem.
|
||||
|
||||
```javascript
|
||||
sharp('input.tiff')
|
||||
.tile({
|
||||
|
8
index.js
8
index.js
@ -660,6 +660,14 @@ Sharp.prototype.tile = function(tile) {
|
||||
throw new Error('Invalid tile overlap (0 to 8192) ' + tile.overlap);
|
||||
}
|
||||
}
|
||||
// Container
|
||||
if (isDefined(tile.container)) {
|
||||
if (isString(tile.container) && contains(tile.container, ['fs', 'zip'])) {
|
||||
this.options.tileContainer = tile.container;
|
||||
} else {
|
||||
throw new Error('Invalid tile container ' + tile.container);
|
||||
}
|
||||
}
|
||||
// Layout
|
||||
if (isDefined(tile.layout)) {
|
||||
if (isString(tile.layout) && contains(tile.layout, ['dz', 'google', 'zoomify'])) {
|
||||
|
@ -58,6 +58,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"async": "^1.5.2",
|
||||
"bufferutil": "^1.2.1",
|
||||
"coveralls": "^2.11.9",
|
||||
"exif-reader": "^1.0.0",
|
||||
"icc": "^0.0.2",
|
||||
@ -66,7 +67,7 @@
|
||||
"mocha-jshint": "^2.3.1",
|
||||
"node-cpplint": "^0.4.0",
|
||||
"rimraf": "^2.5.2",
|
||||
"bufferutil": "^1.2.1"
|
||||
"unzip": "^0.1.11"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"config": {
|
||||
|
@ -52,6 +52,9 @@ namespace sharp {
|
||||
bool IsDz(std::string const &str) {
|
||||
return EndsWith(str, ".dzi") || EndsWith(str, ".DZI");
|
||||
}
|
||||
bool IsDzZip(std::string const &str) {
|
||||
return EndsWith(str, ".zip") || EndsWith(str, ".ZIP") || EndsWith(str, ".szi") || EndsWith(str, ".SZI");
|
||||
}
|
||||
|
||||
/*
|
||||
Provide a string identifier for the given image type.
|
||||
|
@ -35,6 +35,7 @@ namespace sharp {
|
||||
bool IsWebp(std::string const &str);
|
||||
bool IsTiff(std::string const &str);
|
||||
bool IsDz(std::string const &str);
|
||||
bool IsDzZip(std::string const &str);
|
||||
|
||||
/*
|
||||
Provide a string identifier for the given image type.
|
||||
|
@ -65,6 +65,7 @@ using sharp::IsPng;
|
||||
using sharp::IsWebp;
|
||||
using sharp::IsTiff;
|
||||
using sharp::IsDz;
|
||||
using sharp::IsDzZip;
|
||||
using sharp::FreeCallback;
|
||||
using sharp::CalculateCrop;
|
||||
using sharp::counterProcess;
|
||||
@ -743,7 +744,8 @@ class PipelineWorker : public AsyncWorker {
|
||||
bool isWebp = IsWebp(baton->fileOut);
|
||||
bool isTiff = IsTiff(baton->fileOut);
|
||||
bool isDz = IsDz(baton->fileOut);
|
||||
bool matchInput = baton->formatOut == "input" && !(isJpeg || isPng || isWebp || isTiff || isDz);
|
||||
bool isDzZip = IsDzZip(baton->fileOut);
|
||||
bool matchInput = baton->formatOut == "input" && !(isJpeg || isPng || isWebp || isTiff || isDz || isDzZip);
|
||||
if (baton->formatOut == "jpeg" || isJpeg || (matchInput && inputImageType == ImageType::JPEG)) {
|
||||
// Write JPEG to file
|
||||
image.jpegsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
||||
@ -784,12 +786,16 @@ class PipelineWorker : public AsyncWorker {
|
||||
);
|
||||
baton->formatOut = "tiff";
|
||||
baton->channels = std::min(baton->channels, 3);
|
||||
} else if (baton->formatOut == "dz" || IsDz(baton->fileOut)) {
|
||||
} else if (baton->formatOut == "dz" || isDz || isDzZip) {
|
||||
if (isDzZip) {
|
||||
baton->tileContainer = VIPS_FOREIGN_DZ_CONTAINER_ZIP;
|
||||
}
|
||||
// Write DZ to file
|
||||
image.dzsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
||||
->set("strip", !baton->withMetadata)
|
||||
->set("tile_size", baton->tileSize)
|
||||
->set("overlap", baton->tileOverlap)
|
||||
->set("container", baton->tileContainer)
|
||||
->set("layout", baton->tileLayout)
|
||||
);
|
||||
baton->formatOut = "dz";
|
||||
@ -1058,6 +1064,12 @@ NAN_METHOD(pipeline) {
|
||||
// Tile output
|
||||
baton->tileSize = attrAs<int32_t>(options, "tileSize");
|
||||
baton->tileOverlap = attrAs<int32_t>(options, "tileOverlap");
|
||||
std::string tileContainer = attrAsStr(options, "tileContainer");
|
||||
if (tileContainer == "zip") {
|
||||
baton->tileContainer = VIPS_FOREIGN_DZ_CONTAINER_ZIP;
|
||||
} else {
|
||||
baton->tileContainer = VIPS_FOREIGN_DZ_CONTAINER_FS;
|
||||
}
|
||||
std::string tileLayout = attrAsStr(options, "tileLayout");
|
||||
if (tileLayout == "google") {
|
||||
baton->tileLayout = VIPS_FOREIGN_DZ_LAYOUT_GOOGLE;
|
||||
|
@ -81,6 +81,7 @@ struct PipelineBaton {
|
||||
int withMetadataOrientation;
|
||||
int tileSize;
|
||||
int tileOverlap;
|
||||
VipsForeignDzContainer tileContainer;
|
||||
VipsForeignDzLayout tileLayout;
|
||||
|
||||
PipelineBaton():
|
||||
@ -130,6 +131,7 @@ struct PipelineBaton {
|
||||
withMetadataOrientation(-1),
|
||||
tileSize(256),
|
||||
tileOverlap(0),
|
||||
tileContainer(VIPS_FOREIGN_DZ_CONTAINER_FS),
|
||||
tileLayout(VIPS_FOREIGN_DZ_LAYOUT_DZ) {
|
||||
background[0] = 0.0;
|
||||
background[1] = 0.0;
|
||||
|
@ -6,6 +6,7 @@ var assert = require('assert');
|
||||
|
||||
var async = require('async');
|
||||
var rimraf = require('rimraf');
|
||||
var unzip = require('unzip');
|
||||
|
||||
var sharp = require('../../index');
|
||||
var fixtures = require('../fixtures');
|
||||
@ -88,6 +89,26 @@ describe('Tile', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('Valid container values pass', function() {
|
||||
['fs', 'zip'].forEach(function(container) {
|
||||
assert.doesNotThrow(function() {
|
||||
sharp().tile({
|
||||
container: container
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Invalid container values fail', function() {
|
||||
['zoinks', 1].forEach(function(container) {
|
||||
assert.throws(function() {
|
||||
sharp().tile({
|
||||
container: container
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Valid layout values pass', function() {
|
||||
['dz', 'google', 'zoomify'].forEach(function(layout) {
|
||||
assert.doesNotThrow(function() {
|
||||
@ -190,6 +211,58 @@ describe('Tile', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('Write to ZIP container using file extension', function(done) {
|
||||
var container = fixtures.path('output.dz.container.zip');
|
||||
var extractTo = fixtures.path('output.dz.container');
|
||||
var directory = path.join(extractTo, 'output.dz.container_files');
|
||||
rimraf(directory, function() {
|
||||
sharp(fixtures.inputJpg)
|
||||
.toFile(container, function(err, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual('dz', info.format);
|
||||
fs.stat(container, function(err, stat) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(true, stat.isFile());
|
||||
assert.strictEqual(true, stat.size > 0);
|
||||
fs.createReadStream(container)
|
||||
.pipe(unzip.Extract({path: path.dirname(extractTo)}))
|
||||
.on('error', function(err) { throw err; })
|
||||
.on('close', function() {
|
||||
assertDeepZoomTiles(directory, 256, 13, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Write to ZIP container using container tile option', function(done) {
|
||||
var container = fixtures.path('output.dz.containeropt.zip');
|
||||
var extractTo = fixtures.path('output.dz.containeropt');
|
||||
var directory = path.join(extractTo, 'output.dz.containeropt_files');
|
||||
rimraf(directory, function() {
|
||||
sharp(fixtures.inputJpg)
|
||||
.tile({
|
||||
container: 'zip'
|
||||
})
|
||||
.toFile(fixtures.path('output.dz.containeropt.dzi'), function(err, info) {
|
||||
// Vips overrides .dzi extension to .zip used by container var below
|
||||
if (err) throw err;
|
||||
assert.strictEqual('dz', info.format);
|
||||
fs.stat(container, function(err, stat) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(true, stat.isFile());
|
||||
assert.strictEqual(true, stat.size > 0);
|
||||
fs.createReadStream(container)
|
||||
.pipe(unzip.Extract({path: path.dirname(extractTo)}))
|
||||
.on('error', function(err) { throw err; })
|
||||
.on('close', function() {
|
||||
assertDeepZoomTiles(directory, 256, 13, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user