From e674858bcf0cee68111febd41ad3373531ec70c0 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Sun, 26 May 2024 15:06:07 +0200 Subject: [PATCH] Test build for upcoming libvips 8.16.0 --- CHANGELOG.md | 6 +- build.sh | 8 +- lib/vips.d.ts | 177 +++++++++++++++++++++++++++++++- src/bindings/vips-operators.cpp | 90 +++++++++++++++- src/bindings/vips-operators.h | 54 +++++++++- src/vips-emscripten.cpp | 27 ++++- test/unit/test_arithmetic.js | 37 +++++++ test/unit/test_conversion.js | 6 ++ test/unit/test_create.js | 47 +++++++++ test/unit/test_foreign.js | 40 ++++++-- test/unit/test_iofuncs.js | 2 +- test/unit/test_resample.js | 7 ++ 12 files changed, 470 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d123107d..975249369 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [v0.0.10] - TBD -Uses libvips v8.15.2, compiled with Emscripten v3.1.63. +Uses libvips v8.16.0, compiled with Emscripten v3.1.63. + +### Changed + +- Update methods/enums for libvips 8.16. ## [v0.0.9] - 2024-06-01 diff --git a/build.sh b/build.sh index ac7e4951c..1b19ecb24 100755 --- a/build.sh +++ b/build.sh @@ -180,7 +180,7 @@ VERSION_TIFF=4.6.0 # https://gitlab.com/libtiff/libtiff VERSION_RESVG=0.42.0 # https://github.com/RazrFalcon/resvg VERSION_AOM=3.9.1 # https://aomedia.googlesource.com/aom VERSION_HEIF=1.17.6 # https://github.com/strukturag/libheif -VERSION_VIPS=8.15.2 # https://github.com/libvips/libvips +VERSION_VIPS=9878a5c # https://github.com/libvips/libvips VERSION_EMSCRIPTEN="$(emcc -dumpversion)" @@ -477,12 +477,12 @@ node --version [ -f "$TARGET/lib/pkgconfig/vips.pc" ] || ( stage "Compiling vips" mkdir $DEPS/vips - curl -Ls https://github.com/libvips/libvips/releases/download/v$VERSION_VIPS/vips-$(without_prerelease $VERSION_VIPS).tar.xz | tar xJC $DEPS/vips --strip-components=1 + curl -Ls https://github.com/libvips/libvips/archive/$VERSION_VIPS.tar.gz | tar xzC $DEPS/vips --strip-components=1 cd $DEPS/vips # Emscripten specific patches - curl -Ls https://github.com/libvips/libvips/compare/v$VERSION_VIPS...kleisauke:wasm-vips-8.15.patch | patch -p1 + curl -Ls https://github.com/libvips/libvips/compare/$VERSION_VIPS...kleisauke:wasm-vips-8.16.patch | patch -p1 # Disable HBR support in heifsave - curl -Ls https://github.com/kleisauke/libvips/commit/ad921cf9396dc5a224e93c71b601e87bd3a8a521.patch | patch -p1 + curl -Ls https://github.com/kleisauke/libvips/commit/88b4db95ec6c13860638a0a94e7ef44ea7ce0c19.patch | patch -p1 # Disable building man pages, gettext po files, tools, and (fuzz-)tests sed -i "/subdir('man')/{N;N;N;N;d;}" meson.build meson setup _build --prefix=$TARGET --cross-file=$MESON_CROSS --default-library=static --buildtype=release \ diff --git a/lib/vips.d.ts b/lib/vips.d.ts index 489ba2ab6..3abcb622c 100644 --- a/lib/vips.d.ts +++ b/lib/vips.d.ts @@ -2339,6 +2339,30 @@ declare module Vips { none = 3 // 'none' } + /** + * The SDF to generate, + * + * See also: vips_sdf(). + */ + enum SdfShape { + /** + * A circle at @a, radius @r + */ + circle = 0, // 'circle' + /** + * A box from @a to @b + */ + box = 1, // 'box' + /** + * A box with rounded @corners from @a to @b + */ + rounded_box = 2, // 'rounded-box' + /** + * A line from @a to @b + */ + line = 3 // 'line' + } + /** * How sensitive loaders are to errors, from never stop (very insensitive), to * stop on the smallest warning (very sensitive). @@ -3703,6 +3727,14 @@ declare module Vips { * @return Output image. */ static jxlload(filename: string, options?: { + /** + * First page to load. + */ + page?: number + /** + * Number of pages to load, -1 for all. + */ + n?: number /** * Force open via memory. */ @@ -3732,6 +3764,14 @@ declare module Vips { * @return Output image. */ static jxlloadBuffer(buffer: Blob, options?: { + /** + * First page to load. + */ + page?: number + /** + * Number of pages to load, -1 for all. + */ + n?: number /** * Force open via memory. */ @@ -3761,6 +3801,14 @@ declare module Vips { * @return Output image. */ static jxlloadSource(source: Source, options?: { + /** + * First page to load. + */ + page?: number + /** + * Number of pages to load, -1 for all. + */ + n?: number /** * Force open via memory. */ @@ -4919,6 +4967,33 @@ declare module Vips { flags?: number | undefined }): Image; + /** + * Create an sdf image. + * @param width Image width in pixels. + * @param height Image height in pixels. + * @param shape SDF shape to create. + * @param options Optional options. + * @return Output image. + */ + static sdf(width: number, height: number, shape: SdfShape | Enum, options?: { + /** + * Radius. + */ + r?: number + /** + * Point a. + */ + a?: ArrayConstant + /** + * Point b. + */ + b?: ArrayConstant + /** + * Corner radii. + */ + corners?: ArrayConstant + }): Image; + /** * Make a 2d sine wave. * @param width Image width in pixels. @@ -5862,6 +5937,12 @@ declare module Vips { */ add(right: Image | ArrayConstant): Image; + /** + * Append an alpha channel. + * @return Output image. + */ + addalpha(): Image; + /** * Affine transform of an image. * @param matrix Transformation matrix. @@ -6042,6 +6123,22 @@ declare module Vips { shift?: boolean }): Image; + /** + * Clamp values of an image. + * @param options Optional options. + * @return Output image. + */ + clamp(options?: { + /** + * Minimum value. + */ + min?: number + /** + * Maximum value. + */ + max?: number + }): Image; + /** * Convert to a new colorspace. * @param space Destination color space. @@ -7574,7 +7671,7 @@ declare module Vips { /** * Save image in jpeg2000 format. - * @param filename Filename to load from. + * @param filename Filename to save to. * @param options Optional options. */ jp2ksave(filename: string, options?: { @@ -7945,7 +8042,7 @@ declare module Vips { /** * Save image in jpeg-xl format. - * @param filename Filename to load from. + * @param filename Filename to save to. * @param options Optional options. */ jxlsave(filename: string, options?: { @@ -8408,6 +8505,13 @@ declare module Vips { y_array?: number[] | undefined }): number; + /** + * Maximum of a pair of images. + * @param right Right-hand image argument. + * @return Output image. + */ + maxpair(right: Image | ArrayConstant): Image; + /** * Measure a set of patches on a color chart. * @param h Number of patches across chart. @@ -8482,6 +8586,13 @@ declare module Vips { y_array?: number[] | undefined }): number; + /** + * Minimum of a pair of images. + * @param right Right-hand image argument. + * @return Output image. + */ + minpair(right: Image | ArrayConstant): Image; + /** * Morphology operation. * @param mask Input matrix image. @@ -9022,11 +9133,35 @@ declare module Vips { }): void; /** - * Write raw image to file descriptor. - * @param fd File descriptor to write to. + * Write raw image to buffer. + * @param options Optional options. + * @return Buffer to save to. + */ + rawsaveBuffer(options?: { + /** + * Which metadata to retain. + */ + keep?: ForeignKeep | Flag + /** + * Background value. + */ + background?: ArrayConstant + /** + * Set page height for multipage save. + */ + page_height?: number + /** + * Filename of icc profile to embed. + */ + profile?: string + }): Uint8Array; + + /** + * Write raw image to target. + * @param target Target to save to. * @param options Optional options. */ - rawsaveFd(fd: number, options?: { + rawsaveTarget(target: Target, options?: { /** * Which metadata to retain. */ @@ -10010,10 +10145,18 @@ declare module Vips { * Level of cpu effort to reduce file size. */ effort?: number + /** + * Desired target size in bytes. + */ + target_size?: number /** * Allow mixed encoding (might reduce file size). */ mixed?: boolean + /** + * Number of entropy-analysis passes (in [1..10]). + */ + passes?: number /** * Which metadata to retain. */ @@ -10078,10 +10221,18 @@ declare module Vips { * Level of cpu effort to reduce file size. */ effort?: number + /** + * Desired target size in bytes. + */ + target_size?: number /** * Allow mixed encoding (might reduce file size). */ mixed?: boolean + /** + * Number of entropy-analysis passes (in [1..10]). + */ + passes?: number /** * Which metadata to retain. */ @@ -10145,10 +10296,18 @@ declare module Vips { * Level of cpu effort to reduce file size. */ effort?: number + /** + * Desired target size in bytes. + */ + target_size?: number /** * Allow mixed encoding (might reduce file size). */ mixed?: boolean + /** + * Number of entropy-analysis passes (in [1..10]). + */ + passes?: number /** * Which metadata to retain. */ @@ -10213,10 +10372,18 @@ declare module Vips { * Level of cpu effort to reduce file size. */ effort?: number + /** + * Desired target size in bytes. + */ + target_size?: number /** * Allow mixed encoding (might reduce file size). */ mixed?: boolean + /** + * Number of entropy-analysis passes (in [1..10]). + */ + passes?: number /** * Which metadata to retain. */ diff --git a/src/bindings/vips-operators.cpp b/src/bindings/vips-operators.cpp index 677fd369d..441d785c8 100644 --- a/src/bindings/vips-operators.cpp +++ b/src/bindings/vips-operators.cpp @@ -917,6 +917,21 @@ Image Image::rawload(const std::string &filename, int width, int height, int ban return out; } +Image Image::sdf(int width, int height, emscripten::val shape, emscripten::val js_options) +{ + Image out; + + Image::call("sdf", nullptr, + (new Option) + ->set("out", &out) + ->set("width", width) + ->set("height", height) + ->set("shape", VIPS_TYPE_SDF_SHAPE, shape), + js_options); + + return out; +} + Image Image::sines(int width, int height, emscripten::val js_options) { Image out; @@ -1465,6 +1480,18 @@ Image Image::abs() const return out; } +Image Image::addalpha() const +{ + Image out; + + this->call("addalpha", + (new Option) + ->set("in", *this) + ->set("out", &out)); + + return out; +} + Image Image::affine(const std::vector &matrix, emscripten::val js_options) const { Image out; @@ -1646,6 +1673,19 @@ Image Image::cast(emscripten::val format, emscripten::val js_options) const return out; } +Image Image::clamp(emscripten::val js_options) const +{ + Image out; + + this->call("clamp", + (new Option) + ->set("in", *this) + ->set("out", &out), + js_options); + + return out; +} + Image Image::colourspace(emscripten::val space, emscripten::val js_options) const { Image out; @@ -2970,6 +3010,19 @@ double Image::max(emscripten::val js_options) const return out; } +Image Image::maxpair(emscripten::val right) const +{ + Image out; + + this->call("maxpair", + (new Option) + ->set("left", *this) + ->set("out", &out) + ->set("right", VIPS_TYPE_IMAGE, right, this)); + + return out; +} + Image Image::measure(int h, int v, emscripten::val js_options) const { Image out; @@ -3015,6 +3068,19 @@ double Image::min(emscripten::val js_options) const return out; } +Image Image::minpair(emscripten::val right) const +{ + Image out; + + this->call("minpair", + (new Option) + ->set("left", *this) + ->set("out", &out) + ->set("right", VIPS_TYPE_IMAGE, right, this)); + + return out; +} + Image Image::morph(emscripten::val mask, emscripten::val morph) const { Image out; @@ -3310,12 +3376,30 @@ void Image::rawsave(const std::string &filename, emscripten::val js_options) con js_options); } -void Image::rawsave_fd(int fd, emscripten::val js_options) const +emscripten::val Image::rawsave_buffer(emscripten::val js_options) const +{ + VipsBlob *buffer; + + this->call("rawsave_buffer", + (new Option) + ->set("in", *this) + ->set("buffer", &buffer), + js_options); + + emscripten::val result = BlobVal.new_(emscripten::typed_memory_view( + VIPS_AREA(buffer)->length, + reinterpret_cast(VIPS_AREA(buffer)->data))); + vips_area_unref(VIPS_AREA(buffer)); + + return result; +} + +void Image::rawsave_target(const Target &target, emscripten::val js_options) const { - this->call("rawsave_fd", + this->call("rawsave_target", (new Option) ->set("in", *this) - ->set("fd", fd), + ->set("target", target), js_options); } diff --git a/src/bindings/vips-operators.h b/src/bindings/vips-operators.h index a5837bb92..1265fb82a 100644 --- a/src/bindings/vips-operators.h +++ b/src/bindings/vips-operators.h @@ -569,6 +569,16 @@ static Image radload_source(const Source &source, emscripten::val js_options = e */ static Image rawload(const std::string &filename, int width, int height, int bands, emscripten::val js_options = emscripten::val::null()); +/** + * Create an sdf image. + * @param width Image width in pixels. + * @param height Image height in pixels. + * @param shape SDF shape to create. + * @param js_options Optional options. + * @return Output image. + */ +static Image sdf(int width, int height, emscripten::val shape, emscripten::val js_options = emscripten::val::null()); + /** * Make a 2d sine wave. * @param width Image width in pixels. @@ -878,6 +888,12 @@ Image Yxy2XYZ() const; */ Image abs() const; +/** + * Append an alpha channel. + * @return Output image. + */ +Image addalpha() const; + /** * Affine transform of an image. * @param matrix Transformation matrix. @@ -975,6 +991,13 @@ Image case_image(emscripten::val cases) const; */ Image cast(emscripten::val format, emscripten::val js_options = emscripten::val::null()) const; +/** + * Clamp values of an image. + * @param js_options Optional options. + * @return Output image. + */ +Image clamp(emscripten::val js_options = emscripten::val::null()) const; + /** * Convert to a new colorspace. * @param space Destination color space. @@ -1570,7 +1593,7 @@ Image join(emscripten::val in2, emscripten::val direction, emscripten::val js_op /** * Save image in jpeg2000 format. - * @param filename Filename to load from. + * @param filename Filename to save to. * @param js_options Optional options. */ void jp2ksave(const std::string &filename, emscripten::val js_options = emscripten::val::null()) const; @@ -1618,7 +1641,7 @@ void jpegsave_target(const Target &target, emscripten::val js_options = emscript /** * Save image in jpeg-xl format. - * @param filename Filename to load from. + * @param filename Filename to save to. * @param js_options Optional options. */ void jxlsave(const std::string &filename, emscripten::val js_options = emscripten::val::null()) const; @@ -1754,6 +1777,13 @@ void matrixsave_target(const Target &target, emscripten::val js_options = emscri */ double max(emscripten::val js_options = emscripten::val::null()) const; +/** + * Maximum of a pair of images. + * @param right Right-hand image argument. + * @return Output image. + */ +Image maxpair(emscripten::val right) const; + /** * Measure a set of patches on a color chart. * @param h Number of patches across chart. @@ -1781,6 +1811,13 @@ Image merge(emscripten::val sec, emscripten::val direction, int dx, int dy, emsc */ double min(emscripten::val js_options = emscripten::val::null()) const; +/** + * Minimum of a pair of images. + * @param right Right-hand image argument. + * @return Output image. + */ +Image minpair(emscripten::val right) const; + /** * Morphology operation. * @param mask Input matrix image. @@ -1961,11 +1998,18 @@ Image rank(int width, int height, int index) const; void rawsave(const std::string &filename, emscripten::val js_options = emscripten::val::null()) const; /** - * Write raw image to file descriptor. - * @param fd File descriptor to write to. + * Write raw image to buffer. + * @param js_options Optional options. + * @return Buffer to save to. + */ +emscripten::val rawsave_buffer(emscripten::val js_options = emscripten::val::null()) const; + +/** + * Write raw image to target. + * @param target Target to save to. * @param js_options Optional options. */ -void rawsave_fd(int fd, emscripten::val js_options = emscripten::val::null()) const; +void rawsave_target(const Target &target, emscripten::val js_options = emscripten::val::null()) const; /** * Linear recombination with matrix. diff --git a/src/vips-emscripten.cpp b/src/vips-emscripten.cpp index 980a22c89..5f91e8af5 100644 --- a/src/vips-emscripten.cpp +++ b/src/vips-emscripten.cpp @@ -283,6 +283,12 @@ EMSCRIPTEN_BINDINGS(my_module) { .value("word_char", VIPS_TEXT_WRAP_WORD_CHAR) .value("none", VIPS_TEXT_WRAP_NONE); + enum_("SdfShape") + .value("circle", VIPS_SDF_SHAPE_CIRCLE) + .value("box", VIPS_SDF_SHAPE_BOX) + .value("rounded_box", VIPS_SDF_SHAPE_ROUNDED_BOX) + .value("line", VIPS_SDF_SHAPE_LINE); + enum_("FailOn") .value("none", VIPS_FAIL_ON_NONE) .value("truncated", VIPS_FAIL_ON_TRUNCATED) @@ -1362,6 +1368,10 @@ EMSCRIPTEN_BINDINGS(my_module) { .class_function("rawload", optional_override([](const std::string &filename, int width, int height, int bands) { return Image::rawload(filename, width, height, bands); })) + .class_function("sdf", &Image::sdf) + .class_function("sdf", optional_override([](int width, int height, emscripten::val shape) { + return Image::sdf(width, height, shape); + })) .class_function("sines", &Image::sines) .class_function("sines", optional_override([](int width, int height) { return Image::sines(width, height); @@ -1474,6 +1484,7 @@ EMSCRIPTEN_BINDINGS(my_module) { .function("XYZ2scRGB", &Image::XYZ2scRGB) .function("Yxy2XYZ", &Image::Yxy2XYZ) .function("abs", &Image::abs) + .function("addalpha", &Image::addalpha) .function("affine", &Image::affine) .function("affine", optional_override([](const Image &image, const std::vector &matrix) { return image.affine(matrix); @@ -1507,6 +1518,10 @@ EMSCRIPTEN_BINDINGS(my_module) { .function("cast", optional_override([](const Image &image, emscripten::val format) { return image.cast(format); })) + .function("clamp", &Image::clamp) + .function("clamp", optional_override([](const Image &image) { + return image.clamp(); + })) .function("colourspace", &Image::colourspace) .function("colourspace", optional_override([](const Image &image, emscripten::val space) { return image.colourspace(space); @@ -1808,6 +1823,7 @@ EMSCRIPTEN_BINDINGS(my_module) { .function("max", optional_override([](const Image &image) { return image.max(); })) + .function("maxpair", &Image::maxpair) .function("measure", &Image::measure) .function("measure", optional_override([](const Image &image, int h, int v) { return image.measure(h, v); @@ -1820,6 +1836,7 @@ EMSCRIPTEN_BINDINGS(my_module) { .function("min", optional_override([](const Image &image) { return image.min(); })) + .function("minpair", &Image::minpair) .function("mosaic", &Image::mosaic) .function("mosaic", optional_override([](const Image &image, emscripten::val sec, emscripten::val direction, int xref, int yref, int xsec, int ysec) { return image.mosaic(sec, direction, xref, yref, xsec, ysec); @@ -1885,9 +1902,13 @@ EMSCRIPTEN_BINDINGS(my_module) { .function("rawsave", optional_override([](const Image &image, const std::string &filename) { image.rawsave(filename); })) - .function("rawsaveFd", &Image::rawsave_fd) - .function("rawsaveFd", optional_override([](const Image &image, int fd) { - image.rawsave_fd(fd); + .function("rawsaveBuffer", &Image::rawsave_buffer) + .function("rawsaveBuffer", optional_override([](const Image &image) { + return image.rawsave_buffer(); + })) + .function("rawsaveTarget", &Image::rawsave_target) + .function("rawsaveTarget", optional_override([](const Image &image, const Target &target) { + image.rawsave_target(target); })) .function("recomb", &Image::recomb) .function("reduce", &Image::reduce) diff --git a/test/unit/test_arithmetic.js b/test/unit/test_arithmetic.js index fcabddeff..06e970d00 100644 --- a/test/unit/test_arithmetic.js +++ b/test/unit/test_arithmetic.js @@ -841,4 +841,41 @@ describe('arithmetic', () => { expect(im3.max()).to.be.closeTo(sum, 1e-6); } }); + + it('clamp', function () { + for (const fmt of Helpers.noncomplexFormats) { + for (let x = 0; x < 100; x += 10) { + const im2 = colour.add(x).cast(fmt); + let im3 = im2.clamp(); + expect(im3.max()).to.be.at.most(1.0); + expect(im3.min()).to.be.at.least(0.0); + + im3 = im2.clamp({ min: 14, max: 45 }); + expect(im3.max()).to.be.at.most(45); + expect(im3.min()).to.be.at.least(14); + } + } + }); + + it('minpair', function () { + for (const fmt of Helpers.noncomplexFormats) { + for (let x = 0; x < 100; x += 10) { + const im2 = colour.subtract(x).multiply(5).cast(fmt); + const im3 = im2.minpair(colour); + const im4 = im2.less(colour).ifthenelse(im2, colour); + expect(im3.subtract(im4).abs().max()).to.equal(0.0); + } + } + }); + + it('maxpair', function () { + for (const fmt of Helpers.noncomplexFormats) { + for (let x = 0; x < 100; x += 10) { + const im2 = colour.subtract(x).multiply(5).cast(fmt); + const im3 = im2.maxpair(colour); + const im4 = im2.more(colour).ifthenelse(im2, colour); + expect(im3.subtract(im4).abs().max()).to.equal(0.0); + } + } + }); }); diff --git a/test/unit/test_conversion.js b/test/unit/test_conversion.js index 9aed76741..ef25b3b8a 100644 --- a/test/unit/test_conversion.js +++ b/test/unit/test_conversion.js @@ -117,6 +117,12 @@ describe('conversion', () => { expect(x.extractBand(4).avg()).to.equal(2); }); + it('addalpha', function () { + const x = colour.addalpha(); + expect(x.bands).to.equal(4); + expect(x.extractBand(3).avg()).to.equal(255); + }); + it('bandmean', function () { const bandmean = (x) => x instanceof vips.Image ? x.bandmean() diff --git a/test/unit/test_create.js b/test/unit/test_create.js index f3f7678b1..67ada9296 100644 --- a/test/unit/test_create.js +++ b/test/unit/test_create.js @@ -548,6 +548,53 @@ describe('create', () => { Helpers.assertAlmostEqualObjects(p, [45, 35]); }); + it('sdf', function () { + let im = vips.Image.sdf(128, 128, vips.SdfShape.circle, { + a: [64, 64], + r: 32 + }); + expect(im.bands).to.equal(1); + expect(im.format).to.equal('float'); + expect(im.width).to.equal(128); + expect(im.height).to.equal(128); + let p = im.getpoint(45, 35); + Helpers.assertAlmostEqualObjects(p, [2.670], 0.01); + + im = vips.Image.sdf(128, 128, vips.SdfShape.box, { + a: [10, 10], + b: [50, 40] + }); + expect(im.bands).to.equal(1); + expect(im.format).to.equal('float'); + expect(im.width).to.equal(128); + expect(im.height).to.equal(128); + p = im.getpoint(45, 35); + Helpers.assertAlmostEqualObjects(p, [-5.0]); + + im = vips.Image.sdf(128, 128, vips.SdfShape.rounded_box, { + a: [10, 10], + b: [50, 40], + corners: [50, 0, 0, 0] + }); + expect(im.bands).to.equal(1); + expect(im.format).to.equal('float'); + expect(im.width).to.equal(128); + expect(im.height).to.equal(128); + p = im.getpoint(45, 35); + Helpers.assertAlmostEqualObjects(p, [13.640], 0.01); + + im = vips.Image.sdf(128, 128, vips.SdfShape.line, { + a: [10, 10], + b: [50, 40] + }); + expect(im.bands).to.equal(1); + expect(im.format).to.equal('float'); + expect(im.width).to.equal(128); + expect(im.height).to.equal(128); + p = im.getpoint(45, 35); + Helpers.assertAlmostEqualObjects(p, [1.0]); + }); + it('zone', function () { const im = vips.Image.zone(128, 128); expect(im.width).to.equal(128); diff --git a/test/unit/test_foreign.js b/test/unit/test_foreign.js index bd4dd43c3..48ccf208e 100644 --- a/test/unit/test_foreign.js +++ b/test/unit/test_foreign.js @@ -148,7 +148,7 @@ describe('foreign', () => { it('vips', function () { // ftruncate() is not yet available in the Node backend of WasmFS. - // https://github.com/emscripten-core/emscripten/blob/3.1.48/system/lib/wasmfs/backends/node_backend.cpp#L120-L122 + // https://github.com/emscripten-core/emscripten/blob/3.1.63/system/lib/wasmfs/backends/node_backend.cpp#L120-L122 if (typeof vips.FS.statBufToObject === 'function') { return this.skip(); } @@ -400,6 +400,7 @@ describe('foreign', () => { expect(im.height).to.equal(442); expect(im.bands).to.equal(3); expect(im.getInt('bits-per-sample')).to.equal(16); + expect(im.getTypeof('palette')).to.equal(0); }; fileLoader('pngload', Helpers.pngFile, pngValid); @@ -752,6 +753,12 @@ describe('foreign', () => { expect(im.width).to.equal(13); expect(im.height).to.equal(16731); buf = im.webpsaveBuffer(); // eslint-disable-line no-unused-vars + + // target_size should reasonably work, +/- 2% is fine + im = vips.Image.newFromFile(Helpers.webpFile); + buf = im.webpsaveBuffer({ target_size: 20000, keep: vips.ForeignKeep.none }); + expect(buf.byteLength).to.be.below(20400); + expect(buf.byteLength).to.be.above(19600); }); it('gifload', function () { @@ -766,7 +773,6 @@ describe('foreign', () => { expect(im.width).to.equal(159); expect(im.height).to.equal(203); expect(im.bands).to.equal(3); - expect(im.getInt('bits-per-sample')).to.equal(4); }; fileLoader('gifload', Helpers.gifFile, gifValid); @@ -777,6 +783,8 @@ describe('foreign', () => { expect(x1.getInt('n-pages')).to.equal(1); expect(x1.getArrayDouble('background')).to.deep.equal([81.0, 81.0, 81.0]); expect(x1.getInt('interlaced')).to.equal(1); + expect(x1.getInt('bits-per-sample')).to.equal(4); + expect(x1.getInt('palette')).to.equal(1); x1 = vips.Image.newFromFile(Helpers.gifAnimFile, { n: -1 }); // our test gif has delay 0 for the first frame set in error @@ -784,6 +792,7 @@ describe('foreign', () => { expect(x1.getInt('loop')).to.equal(32761); expect(x1.getArrayDouble('background')).to.deep.equal([255.0, 255.0, 255.0]); expect(x1.getTypeof('interlaced')).to.equal(0); + expect(x1.getInt('palette')).to.equal(1); // test deprecated fields too expect(x1.getInt('gif-loop')).to.equal(32760); expect(x1.getInt('gif-delay')).to.equal(0); @@ -883,22 +892,25 @@ describe('foreign', () => { return this.skip(); } - saveLoad('%s.ppm', mono); saveLoad('%s.ppm', colour); - saveLoadFile('%s.ppm', '[ascii]', mono, 0); + saveLoadFile('%s.pgm', '[ascii]', mono, 0); saveLoadFile('%s.ppm', '[ascii]', colour, 0); - saveLoadFile('%s.ppm', '[ascii,bitdepth=1]', onebit, 0); + saveLoadFile('%s.pbm', '[ascii]', onebit, 0); const rgb16 = colour.colourspace('rgb16'); const grey16 = mono.colourspace('rgb16'); - saveLoad('%s.ppm', grey16); saveLoad('%s.ppm', rgb16); saveLoadFile('%s.ppm', '[ascii]', grey16, 0); saveLoadFile('%s.ppm', '[ascii]', rgb16, 0); + + const source = vips.Source.newFromMemory('P1\n#\n#\n1 1\n0\n'); + const im = vips.Image.ppmloadSource(source); + expect(im.width).to.equal(1); + expect(im.height).to.equal(1); }); it('radload', function () { @@ -964,6 +976,18 @@ describe('foreign', () => { im = vips.Image.newFromBuffer(svg, ''); expect(im.width).to.equal(1); expect(im.height).to.equal(1); + + // scale up + svg = ''; + im = vips.Image.newFromBuffer(svg, '', { scale: 10000 }); + expect(im.width).to.equal(10000); + expect(im.height).to.equal(10000); + + // scale down + svg = ''; + im = vips.Image.newFromBuffer(svg, '', { scale: 0.0001 }); + expect(im.width).to.equal(10); + expect(im.height).to.equal(10); }); it('heifload', function () { @@ -1002,10 +1026,8 @@ describe('foreign', () => { return this.skip(); } - // TODO(kleisauke): Remove `subsample_mode: 'off'` when libvips >= 8.16, see: - // https://github.com/libvips/libvips/commit/dbd298cc8c9789dfc0fc6917b2492cb570406a7a saveLoadBuffer('heifsave_buffer', 'heifload_buffer', - colour, 0, { compression: 'av1', lossless: true, subsample_mode: 'off' }); + colour, 0, { compression: 'av1', lossless: true }); saveLoad('%s.avif', colour); }); diff --git a/test/unit/test_iofuncs.js b/test/unit/test_iofuncs.js index 1f2cb5458..400bb32a2 100644 --- a/test/unit/test_iofuncs.js +++ b/test/unit/test_iofuncs.js @@ -65,7 +65,7 @@ describe('iofuncs', () => { it('revalidate', function () { // ftruncate() is not yet available in the Node backend of WasmFS. - // https://github.com/emscripten-core/emscripten/blob/3.1.48/system/lib/wasmfs/backends/node_backend.cpp#L120-L122 + // https://github.com/emscripten-core/emscripten/blob/3.1.63/system/lib/wasmfs/backends/node_backend.cpp#L120-L122 if (typeof vips.FS.statBufToObject === 'function') { return this.skip(); } diff --git a/test/unit/test_resample.js b/test/unit/test_resample.js index 2cda8f5ba..2ab579a06 100644 --- a/test/unit/test_resample.js +++ b/test/unit/test_resample.js @@ -268,6 +268,13 @@ describe('resample', () => { im2 = vips.Image.newFromFile(Helpers.rgbaCorrectFile); expect(Math.abs(im1.flatten({ background: 255 }).avg() - im2.avg())).to.be.below(1); } + + // thumbnailing a 16-bit image should always make an 8-bit image + const rgb16Buffer = vips.Image.newFromFile(Helpers.jpegFile) + .colourspace(vips.Interpretation.rgb16) + .writeToBuffer('.png'); + const thumb = vips.Image.thumbnailBuffer(rgb16Buffer, 128); + expect(thumb.format).to.equal('uchar'); }); describe('similarity', () => {