mirror of
https://github.com/lovell/sharp.git
synced 2026-02-11 09:06:15 +01:00
Compare commits
4 Commits
v0.35.0-rc
...
ef77388a73
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef77388a73 | ||
|
|
66764b359b | ||
|
|
8561f0da1d | ||
|
|
0468c1be9f |
@@ -758,7 +758,7 @@ When using Windows ARM64, this feature requires a CPU with ARM64v8.4 or later.
|
|||||||
| [options.effort] | <code>number</code> | <code>4</code> | CPU effort, between 0 (fastest) and 9 (slowest) |
|
| [options.effort] | <code>number</code> | <code>4</code> | CPU effort, between 0 (fastest) and 9 (slowest) |
|
||||||
| [options.chromaSubsampling] | <code>string</code> | <code>"'4:4:4'"</code> | set to '4:2:0' to use chroma subsampling |
|
| [options.chromaSubsampling] | <code>string</code> | <code>"'4:4:4'"</code> | set to '4:2:0' to use chroma subsampling |
|
||||||
| [options.bitdepth] | <code>number</code> | <code>8</code> | set bitdepth to 8, 10 or 12 bit |
|
| [options.bitdepth] | <code>number</code> | <code>8</code> | set bitdepth to 8, 10 or 12 bit |
|
||||||
| [options.tune] | <code>string</code> | <code>"'iq'"</code> | tune output for a quality metric, one of 'iq' (default), 'ssim' or 'psnr' |
|
| [options.tune] | <code>string</code> | <code>"'iq'"</code> | tune output for a quality metric, one of 'iq' (default), 'ssim' (default when lossless) or 'psnr' |
|
||||||
|
|
||||||
**Example**
|
**Example**
|
||||||
```js
|
```js
|
||||||
|
|||||||
@@ -38,4 +38,7 @@ slug: changelog/v0.35.0
|
|||||||
[#4480](https://github.com/lovell/sharp/issues/4480)
|
[#4480](https://github.com/lovell/sharp/issues/4480)
|
||||||
[@eddienubes](https://github.com/eddienubes)
|
[@eddienubes](https://github.com/eddienubes)
|
||||||
|
|
||||||
|
* Ensure HEIF primary item is used as default page/frame.
|
||||||
|
[#4487](https://github.com/lovell/sharp/issues/4487)
|
||||||
|
|
||||||
* Add WebP `exact` option for control over transparent pixel colour values.
|
* Add WebP `exact` option for control over transparent pixel colour values.
|
||||||
|
|||||||
@@ -1175,7 +1175,7 @@ function tiff (options) {
|
|||||||
* @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 9 (slowest)
|
* @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 9 (slowest)
|
||||||
* @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
|
* @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
|
||||||
* @param {number} [options.bitdepth=8] - set bitdepth to 8, 10 or 12 bit
|
* @param {number} [options.bitdepth=8] - set bitdepth to 8, 10 or 12 bit
|
||||||
* @param {string} [options.tune='iq'] - tune output for a quality metric, one of 'iq' (default), 'ssim' or 'psnr'
|
* @param {string} [options.tune='iq'] - tune output for a quality metric, one of 'iq' (default), 'ssim' (default when lossless) or 'psnr'
|
||||||
* @returns {Sharp}
|
* @returns {Sharp}
|
||||||
* @throws {Error} Invalid options
|
* @throws {Error} Invalid options
|
||||||
*/
|
*/
|
||||||
@@ -1255,7 +1255,11 @@ function heif (options) {
|
|||||||
}
|
}
|
||||||
if (is.defined(options.tune)) {
|
if (is.defined(options.tune)) {
|
||||||
if (is.string(options.tune) && is.inArray(options.tune, ['iq', 'ssim', 'psnr'])) {
|
if (is.string(options.tune) && is.inArray(options.tune, ['iq', 'ssim', 'psnr'])) {
|
||||||
this.options.heifTune = options.tune;
|
if (this.options.heifLossless && options.tune === 'iq') {
|
||||||
|
this.options.heifTune = 'ssim';
|
||||||
|
} else {
|
||||||
|
this.options.heifTune = options.tune;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw is.invalidParameterError('tune', 'one of: psnr, ssim, iq', options.tune);
|
throw is.invalidParameterError('tune', 'one of: psnr, ssim, iq', options.tune);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
'defines': [
|
'defines': [
|
||||||
'_VIPS_PUBLIC=__declspec(dllexport)',
|
'_VIPS_PUBLIC=__declspec(dllexport)',
|
||||||
'_ALLOW_KEYWORD_MACROS',
|
'_ALLOW_KEYWORD_MACROS',
|
||||||
|
'_HAS_EXCEPTIONS=1',
|
||||||
'G_DISABLE_ASSERT',
|
'G_DISABLE_ASSERT',
|
||||||
'G_DISABLE_CAST_CHECKS',
|
'G_DISABLE_CAST_CHECKS',
|
||||||
'G_DISABLE_CHECKS'
|
'G_DISABLE_CHECKS'
|
||||||
@@ -148,7 +149,8 @@
|
|||||||
['OS == "win"', {
|
['OS == "win"', {
|
||||||
'defines': [
|
'defines': [
|
||||||
'_ALLOW_KEYWORD_MACROS',
|
'_ALLOW_KEYWORD_MACROS',
|
||||||
'_FILE_OFFSET_BITS=64'
|
'_FILE_OFFSET_BITS=64',
|
||||||
|
'_HAS_EXCEPTIONS=1'
|
||||||
],
|
],
|
||||||
'link_settings': {
|
'link_settings': {
|
||||||
'libraries': [
|
'libraries': [
|
||||||
|
|||||||
@@ -426,7 +426,7 @@ namespace sharp {
|
|||||||
}
|
}
|
||||||
if (ImageTypeSupportsPage(imageType)) {
|
if (ImageTypeSupportsPage(imageType)) {
|
||||||
option->set("n", descriptor->pages);
|
option->set("n", descriptor->pages);
|
||||||
option->set("page", descriptor->page);
|
option->set("page", std::max(0, descriptor->page));
|
||||||
}
|
}
|
||||||
switch (imageType) {
|
switch (imageType) {
|
||||||
case ImageType::SVG:
|
case ImageType::SVG:
|
||||||
@@ -456,6 +456,22 @@ namespace sharp {
|
|||||||
return option;
|
return option;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Should HEIF image be re-opened using the primary item?
|
||||||
|
*/
|
||||||
|
static bool HeifPrimaryPageReopen(VImage image, InputDescriptor *descriptor) {
|
||||||
|
if (image.get_typeof(VIPS_META_N_PAGES) == G_TYPE_INT && image.get_typeof("heif-primary") == G_TYPE_INT) {
|
||||||
|
if (image.get_int(VIPS_META_N_PAGES) > 1 && descriptor->pages == 1 && descriptor->page == -1) {
|
||||||
|
int const pagePrimary = image.get_int("heif-primary");
|
||||||
|
if (pagePrimary != 0) {
|
||||||
|
descriptor->page = pagePrimary;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Open an image from the given InputDescriptor (filesystem, compressed buffer, raw pixel data)
|
Open an image from the given InputDescriptor (filesystem, compressed buffer, raw pixel data)
|
||||||
*/
|
*/
|
||||||
@@ -490,6 +506,9 @@ namespace sharp {
|
|||||||
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
|
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
|
||||||
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
||||||
image = SetDensity(image, descriptor->density);
|
image = SetDensity(image, descriptor->density);
|
||||||
|
} else if (imageType == ImageType::HEIF && HeifPrimaryPageReopen(image, descriptor)) {
|
||||||
|
option = GetOptionsForImageType(imageType, descriptor);
|
||||||
|
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
|
||||||
}
|
}
|
||||||
} catch (vips::VError const &err) {
|
} catch (vips::VError const &err) {
|
||||||
throw vips::VError(std::string("Input buffer has corrupt header: ") + err.what());
|
throw vips::VError(std::string("Input buffer has corrupt header: ") + err.what());
|
||||||
@@ -577,6 +596,9 @@ namespace sharp {
|
|||||||
image = VImage::new_from_file(descriptor->file.data(), option);
|
image = VImage::new_from_file(descriptor->file.data(), option);
|
||||||
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
||||||
image = SetDensity(image, descriptor->density);
|
image = SetDensity(image, descriptor->density);
|
||||||
|
} else if (imageType == ImageType::HEIF && HeifPrimaryPageReopen(image, descriptor)) {
|
||||||
|
option = GetOptionsForImageType(imageType, descriptor);
|
||||||
|
image = VImage::new_from_file(descriptor->file.data(), option);
|
||||||
}
|
}
|
||||||
} catch (vips::VError const &err) {
|
} catch (vips::VError const &err) {
|
||||||
throw vips::VError(std::string("Input file has corrupt header: ") + err.what());
|
throw vips::VError(std::string("Input file has corrupt header: ") + err.what());
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ namespace sharp {
|
|||||||
rawPremultiplied(false),
|
rawPremultiplied(false),
|
||||||
rawPageHeight(0),
|
rawPageHeight(0),
|
||||||
pages(1),
|
pages(1),
|
||||||
page(0),
|
page(-1),
|
||||||
createChannels(0),
|
createChannels(0),
|
||||||
createWidth(0),
|
createWidth(0),
|
||||||
createHeight(0),
|
createHeight(0),
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
if (nPages == -1) {
|
if (nPages == -1) {
|
||||||
// Resolve the number of pages if we need to render until the end of the document
|
// Resolve the number of pages if we need to render until the end of the document
|
||||||
nPages = image.get_typeof(VIPS_META_N_PAGES) != 0
|
nPages = image.get_typeof(VIPS_META_N_PAGES) != 0
|
||||||
? image.get_int(VIPS_META_N_PAGES) - baton->input->page
|
? image.get_int(VIPS_META_N_PAGES) - std::max(0, baton->input->page)
|
||||||
: 1;
|
: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
test/fixtures/index.js
vendored
2
test/fixtures/index.js
vendored
@@ -127,7 +127,7 @@ module.exports = {
|
|||||||
inputSvgSmallViewBox: getPath('circle.svg'),
|
inputSvgSmallViewBox: getPath('circle.svg'),
|
||||||
inputSvgWithEmbeddedImages: getPath('struct-image-04-t.svg'), // https://dev.w3.org/SVG/profiles/1.2T/test/svg/struct-image-04-t.svg
|
inputSvgWithEmbeddedImages: getPath('struct-image-04-t.svg'), // https://dev.w3.org/SVG/profiles/1.2T/test/svg/struct-image-04-t.svg
|
||||||
inputAvif: getPath('sdr_cosmos12920_cicp1-13-6_yuv444_full_qp10.avif'), // CC by-nc-nd https://github.com/AOMediaCodec/av1-avif/tree/master/testFiles/Netflix
|
inputAvif: getPath('sdr_cosmos12920_cicp1-13-6_yuv444_full_qp10.avif'), // CC by-nc-nd https://github.com/AOMediaCodec/av1-avif/tree/master/testFiles/Netflix
|
||||||
|
inputAvifWithPitmBox: getPath('pitm.avif'), // https://github.com/lovell/sharp/issues/4487
|
||||||
inputJPGBig: getPath('flowers.jpeg'),
|
inputJPGBig: getPath('flowers.jpeg'),
|
||||||
|
|
||||||
inputPngDotAndLines: getPath('dot-and-lines.png'),
|
inputPngDotAndLines: getPath('dot-and-lines.png'),
|
||||||
|
|||||||
BIN
test/fixtures/pitm.avif
vendored
Normal file
BIN
test/fixtures/pitm.avif
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
@@ -7,7 +7,13 @@ const { describe, it } = require('node:test');
|
|||||||
const assert = require('node:assert');
|
const assert = require('node:assert');
|
||||||
|
|
||||||
const sharp = require('../../');
|
const sharp = require('../../');
|
||||||
const { inputAvif, inputJpg, inputGifAnimated } = require('../fixtures');
|
const {
|
||||||
|
inputAvif,
|
||||||
|
inputAvifWithPitmBox,
|
||||||
|
inputJpg,
|
||||||
|
inputGifAnimated,
|
||||||
|
inputPng,
|
||||||
|
} = require('../fixtures');
|
||||||
|
|
||||||
describe('AVIF', () => {
|
describe('AVIF', () => {
|
||||||
it('called without options does not throw an error', () => {
|
it('called without options does not throw an error', () => {
|
||||||
@@ -17,16 +23,13 @@ describe('AVIF', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('can convert AVIF to JPEG', async () => {
|
it('can convert AVIF to JPEG', async () => {
|
||||||
const data = await sharp(inputAvif)
|
const data = await sharp(inputAvif).resize(32).jpeg().toBuffer();
|
||||||
.resize(32)
|
|
||||||
.jpeg()
|
|
||||||
.toBuffer();
|
|
||||||
const { size, ...metadata } = await sharp(data).metadata();
|
const { size, ...metadata } = await sharp(data).metadata();
|
||||||
void size;
|
void size;
|
||||||
assert.deepStrictEqual(metadata, {
|
assert.deepStrictEqual(metadata, {
|
||||||
autoOrient: {
|
autoOrient: {
|
||||||
height: 13,
|
height: 13,
|
||||||
width: 32
|
width: 32,
|
||||||
},
|
},
|
||||||
channels: 3,
|
channels: 3,
|
||||||
chromaSubsampling: '4:2:0',
|
chromaSubsampling: '4:2:0',
|
||||||
@@ -41,7 +44,7 @@ describe('AVIF', () => {
|
|||||||
isProgressive: false,
|
isProgressive: false,
|
||||||
isPalette: false,
|
isPalette: false,
|
||||||
space: 'srgb',
|
space: 'srgb',
|
||||||
width: 32
|
width: 32,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -55,7 +58,7 @@ describe('AVIF', () => {
|
|||||||
assert.deepStrictEqual(metadata, {
|
assert.deepStrictEqual(metadata, {
|
||||||
autoOrient: {
|
autoOrient: {
|
||||||
height: 26,
|
height: 26,
|
||||||
width: 32
|
width: 32,
|
||||||
},
|
},
|
||||||
channels: 3,
|
channels: 3,
|
||||||
compression: 'av1',
|
compression: 'av1',
|
||||||
@@ -70,20 +73,47 @@ describe('AVIF', () => {
|
|||||||
pagePrimary: 0,
|
pagePrimary: 0,
|
||||||
pages: 1,
|
pages: 1,
|
||||||
space: 'srgb',
|
space: 'srgb',
|
||||||
width: 32
|
width: 32,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can passthrough AVIF', async () => {
|
it('can convert PNG to lossless AVIF', async () => {
|
||||||
const data = await sharp(inputAvif)
|
const data = await sharp(inputPng)
|
||||||
.resize(32)
|
.resize(32)
|
||||||
|
.avif({ lossless: true, effort: 0 })
|
||||||
.toBuffer();
|
.toBuffer();
|
||||||
const { size, ...metadata } = await sharp(data).metadata();
|
const { size, ...metadata } = await sharp(data).metadata();
|
||||||
void size;
|
void size;
|
||||||
|
assert.deepStrictEqual(metadata, {
|
||||||
|
autoOrient: {
|
||||||
|
height: 24,
|
||||||
|
width: 32,
|
||||||
|
},
|
||||||
|
channels: 3,
|
||||||
|
compression: 'av1',
|
||||||
|
depth: 'uchar',
|
||||||
|
format: 'heif',
|
||||||
|
hasAlpha: false,
|
||||||
|
hasProfile: false,
|
||||||
|
height: 24,
|
||||||
|
isProgressive: false,
|
||||||
|
isPalette: false,
|
||||||
|
bitsPerSample: 8,
|
||||||
|
pagePrimary: 0,
|
||||||
|
pages: 1,
|
||||||
|
space: 'srgb',
|
||||||
|
width: 32,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can passthrough AVIF', async () => {
|
||||||
|
const data = await sharp(inputAvif).resize(32).toBuffer();
|
||||||
|
const { size, ...metadata } = await sharp(data).metadata();
|
||||||
|
void size;
|
||||||
assert.deepStrictEqual(metadata, {
|
assert.deepStrictEqual(metadata, {
|
||||||
autoOrient: {
|
autoOrient: {
|
||||||
height: 13,
|
height: 13,
|
||||||
width: 32
|
width: 32,
|
||||||
},
|
},
|
||||||
channels: 3,
|
channels: 3,
|
||||||
compression: 'av1',
|
compression: 'av1',
|
||||||
@@ -98,7 +128,7 @@ describe('AVIF', () => {
|
|||||||
pagePrimary: 0,
|
pagePrimary: 0,
|
||||||
pages: 1,
|
pages: 1,
|
||||||
space: 'srgb',
|
space: 'srgb',
|
||||||
width: 32
|
width: 32,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -112,7 +142,7 @@ describe('AVIF', () => {
|
|||||||
assert.deepStrictEqual(metadata, {
|
assert.deepStrictEqual(metadata, {
|
||||||
autoOrient: {
|
autoOrient: {
|
||||||
height: 300,
|
height: 300,
|
||||||
width: 10
|
width: 10,
|
||||||
},
|
},
|
||||||
channels: 4,
|
channels: 4,
|
||||||
compression: 'av1',
|
compression: 'av1',
|
||||||
@@ -127,7 +157,7 @@ describe('AVIF', () => {
|
|||||||
pagePrimary: 0,
|
pagePrimary: 0,
|
||||||
pages: 1,
|
pages: 1,
|
||||||
space: 'srgb',
|
space: 'srgb',
|
||||||
width: 10
|
width: 10,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -142,7 +172,7 @@ describe('AVIF', () => {
|
|||||||
assert.deepStrictEqual(metadata, {
|
assert.deepStrictEqual(metadata, {
|
||||||
autoOrient: {
|
autoOrient: {
|
||||||
height: 26,
|
height: 26,
|
||||||
width: 32
|
width: 32,
|
||||||
},
|
},
|
||||||
channels: 3,
|
channels: 3,
|
||||||
compression: 'av1',
|
compression: 'av1',
|
||||||
@@ -157,30 +187,37 @@ describe('AVIF', () => {
|
|||||||
pagePrimary: 0,
|
pagePrimary: 0,
|
||||||
pages: 1,
|
pages: 1,
|
||||||
space: 'srgb',
|
space: 'srgb',
|
||||||
width: 32
|
width: 32,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Invalid width - too large', async () =>
|
it('Invalid width - too large', async () =>
|
||||||
assert.rejects(
|
assert.rejects(
|
||||||
() => sharp({ create: { width: 16385, height: 16, channels: 3, background: 'red' } }).avif().toBuffer(),
|
() =>
|
||||||
/Processed image is too large for the HEIF format/
|
sharp({
|
||||||
)
|
create: { width: 16385, height: 16, channels: 3, background: 'red' },
|
||||||
);
|
})
|
||||||
|
.avif()
|
||||||
|
.toBuffer(),
|
||||||
|
/Processed image is too large for the HEIF format/,
|
||||||
|
));
|
||||||
|
|
||||||
it('Invalid height - too large', async () =>
|
it('Invalid height - too large', async () =>
|
||||||
assert.rejects(
|
assert.rejects(
|
||||||
() => sharp({ create: { width: 16, height: 16385, channels: 3, background: 'red' } }).avif().toBuffer(),
|
() =>
|
||||||
/Processed image is too large for the HEIF format/
|
sharp({
|
||||||
)
|
create: { width: 16, height: 16385, channels: 3, background: 'red' },
|
||||||
);
|
})
|
||||||
|
.avif()
|
||||||
|
.toBuffer(),
|
||||||
|
/Processed image is too large for the HEIF format/,
|
||||||
|
));
|
||||||
|
|
||||||
it('Invalid bitdepth value throws error', () =>
|
it('Invalid bitdepth value throws error', () =>
|
||||||
assert.throws(
|
assert.throws(
|
||||||
() => sharp().avif({ bitdepth: 11 }),
|
() => sharp().avif({ bitdepth: 11 }),
|
||||||
/Expected 8, 10 or 12 for bitdepth but received 11 of type number/
|
/Expected 8, 10 or 12 for bitdepth but received 11 of type number/,
|
||||||
)
|
));
|
||||||
);
|
|
||||||
|
|
||||||
it('Different tune options result in different file sizes', async () => {
|
it('Different tune options result in different file sizes', async () => {
|
||||||
const ssim = await sharp(inputJpg)
|
const ssim = await sharp(inputJpg)
|
||||||
@@ -192,5 +229,47 @@ describe('AVIF', () => {
|
|||||||
.avif({ tune: 'iq', effort: 0 })
|
.avif({ tune: 'iq', effort: 0 })
|
||||||
.toBuffer();
|
.toBuffer();
|
||||||
assert(ssim.length < iq.length);
|
assert(ssim.length < iq.length);
|
||||||
})
|
});
|
||||||
|
|
||||||
|
it('AVIF with non-zero primary item uses it as default page', async () => {
|
||||||
|
const { exif, ...metadata } = await sharp(inputAvifWithPitmBox).metadata();
|
||||||
|
void exif;
|
||||||
|
assert.deepStrictEqual(metadata, {
|
||||||
|
format: 'heif',
|
||||||
|
width: 4096,
|
||||||
|
height: 800,
|
||||||
|
space: 'srgb',
|
||||||
|
channels: 3,
|
||||||
|
depth: 'uchar',
|
||||||
|
isProgressive: false,
|
||||||
|
isPalette: false,
|
||||||
|
bitsPerSample: 8,
|
||||||
|
pages: 5,
|
||||||
|
pagePrimary: 4,
|
||||||
|
compression: 'av1',
|
||||||
|
resolutionUnit: 'cm',
|
||||||
|
hasProfile: false,
|
||||||
|
hasAlpha: false,
|
||||||
|
autoOrient: { width: 4096, height: 800 },
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await sharp(inputAvifWithPitmBox)
|
||||||
|
.png({ compressionLevel: 0 })
|
||||||
|
.toBuffer();
|
||||||
|
const { size, ...pngMetadata } = await sharp(data).metadata();
|
||||||
|
assert.deepStrictEqual(pngMetadata, {
|
||||||
|
format: 'png',
|
||||||
|
width: 4096,
|
||||||
|
height: 800,
|
||||||
|
space: 'srgb',
|
||||||
|
channels: 3,
|
||||||
|
depth: 'uchar',
|
||||||
|
isProgressive: false,
|
||||||
|
isPalette: false,
|
||||||
|
bitsPerSample: 8,
|
||||||
|
hasProfile: false,
|
||||||
|
hasAlpha: false,
|
||||||
|
autoOrient: { width: 4096, height: 800 },
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user