Git Product home page Git Product logo

wasm-vips's Introduction

wasm-vips

libvips for the browser and Node.js, compiled to WebAssembly with Emscripten.

Programs that use wasm-vips don't manipulate images directly, instead they create pipelines of image processing operations building on a source image. When the end of the pipe is connected to a destination, the whole pipeline executes at once, streaming the image in parallel from source to destination a section at a time. Because wasm-vips is parallel, it's quick, and because it doesn't need to keep entire images in memory, it's light.

Note

This library is still under early development. See: #1.

Engine support

An engine that supports WebAssembly SIMD. This is present on most major browser engines.

For V8-based engines, at least version 9.1.54 is required to match the final SIMD opcodes, this corresponds to Chrome 91, Node.js 16.4.0 and Deno 1.9.0.

For Spidermonkey-based engines, the JavaScript engine used in Mozilla Firefox and whose version numbers are aligned, at least version 89 is required.

For JavaScriptCore-based engines, the built-in JavaScript engine for WebKit, at least version 615.1.17 is required. This corresponds to Safari 16.4.

Chrome
Chrome
Firefox
Firefox
Safari
Safari
Edge
Edge
Node.js
Node.js
Deno
Deno
✔️
version 91+
✔️
version 89+
✔️
version 16.4+
✔️
version 91+
✔️
version 16.4+
✔️
version 1.9+

Installation

wasm-vips can be installed with your favorite package manager.

npm install wasm-vips
yarn add wasm-vips

Usage

Browser

Requires vips.js (or vips-es6.js) and vips.wasm to be served from the same directory.

Since wasm-vips requires the SharedArrayBuffer API, the website needs to opt-in to a cross-origin isolated state, by serving the following HTTP headers on both the main document and vips*.js script:

Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin

See https://web.dev/coop-coep/ for more information.

After that, wasm-vips can be imported and initialized like this:

<script src="vips.js"></script>
<script type="module">
  const vips = await Vips();
</script>

Or, if you prefer to use ES6 modules:

<script type="module">
  import Vips from './vips-es6.js';
  const vips = await Vips();
</script>

This requires support for import() in workers.

Node.js

On Node.js, wasm-vips is published as a dual-package, so it can be imported as both CommonJS and ES6 module:

// ES6 module
import Vips from 'wasm-vips';

// CommonJS module
const Vips = require('wasm-vips');

Then, wasm-vips can be initialized like this:

// Usage with top-level await
const vips = await Vips();

// Usage with .then
Vips().then(vips => {
  // Code here
});

Deno

On Deno, the web ES6 module can be reused and imported from a CDN such as jsDelivr:

import Vips from 'https://cdn.jsdelivr.net/npm/wasm-vips/lib/vips-es6.js';

const vips = await Vips();

Example

// Load an image from a file
let im = vips.Image.newFromFile('owl.jpg');

// Put im at position (100, 100) in a 3000 x 3000 pixel image,
// make the other pixels in the image by mirroring im up / down /
// left / right, see
// https://libvips.github.io/libvips/API/current/libvips-conversion.html#vips-embed
im = im.embed(100, 100, 3000, 3000, {
  extend: 'mirror'
});

// Multiply the green (middle) band by 2, leave the other two alone
im = im.multiply([1, 2, 1]);

// Make an image from an array constant, convolve with it
const mask = vips.Image.newFromArray([
  [-1, -1, -1],
  [-1, 16, -1],
  [-1, -1, -1]
], 8.0);

im = im.conv(mask, {
  precision: 'integer'
});

// Finally, write the result to a buffer
const outBuffer = im.writeToBuffer('.jpg');

wasm-vips's People

Contributors

atjn avatar bentron2000 avatar kleisauke avatar lovell avatar rreverser avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wasm-vips's Issues

Usage on Cloudflare Worker

Hello,

This is a cool project, and I was thinking of using it in Cloudflare Workers and saw your card here https://github.com/kleisauke/wasm-vips/projects/1#card-44661973
There's a hurdle, however, that prevents this from being possible: "The module and script together must be under 1MB after gzip compression" - https://community.cloudflare.com/t/what-is-the-maximum-allowed-size-of-a-webassembly-module/66453/2

The .wasm file is ~4.3 MB uncompressed, and ~1.41MB (gzip 9) compressed. Maybe a slimmed version of the library could still be used, with some support for formats dropped?

Error: need to see wasm magic number

No idea why I am suddenly getting the following error:

image

I have used this library about a year ago, and it worked fine for me, today I upgraded deps and the lib is not working anymore.

I am using vite+react +typescript. do I need specific vite config? I get the same error regardless how I import vips in index.html (es6 or not).

PS: it works just fine if I import wasm-vips in the react component where I need vips. But then I can't get to build the project, it crashes with JS heap out of memory. So importing in index is my only option, I believe.

Typescript typedef fix

Was just looking at this library, to be used in my react app with typescript. turns out the type definition that comes with library are like

declare namespace vips { ... }

i.e. they are not exported. you need to export them so that the lib is usable in other TS projects.

export namespace vips

otherwise we get following error:

File 'x/node_modules/wasm-vips/lib/vips.d.ts' is not a module.ts(2306)

Add progress information

On the command line --vips-progress runs a progress indicator during computation. It can be useful to see where libvips is looping and how often.

I wonder if it's possible to expose progress in a similar way in wasm-vips, for example by adding an option to provide a callback function that gets called with the current progress. That way, if an operation takes a bit longer, one can display a progress bar to users as well.

writeToBuffer increases RSS size till OOMKilled

I am trying to perform certain operations on a multi-page tiff image using the sharp package. Except for trim, flip and rotate, all needed operations are successfully performed by sharp.

For flip, sharp flips the whole image and its order too. For trim and rotate, it simply throws an error. This is a known issue, lovell/sharp#1580.

Using the vips.Image.arrayjoin function, I was able to get the desired output, but overtime it increases my rss memory size drastically, eventually killing the process. The heap is not increasing as the GC works promptly. The memory jump happens at the writeToBuffer function call.

Is there any different way of getting the same results, without the rss size jump?

Attaching the code and the input image. Thank you.


Code to create the image (handle-multi-image.mjs)
import { readFileSync } from "node:fs";
import Vips from "wasm-vips";
import sharp from "sharp";

function log(msg) {
    const obj = {};

    for (const [key, value] of Object.entries(process.memoryUsage())) {
        obj[key] = Math.round(value / (1024 * 1024))
    }

    console.log(msg, "\n" + JSON.stringify(obj, null, 4) + "\n");
}

async function createMultiPageImage(buffer, op, ...params) {
    const buffers = [];
    const { pages: pageCount } = await sharp(buffer, { pages: -1 }).metadata();

    for (let i = 0; i < pageCount; i++) {
        buffers.push(sharp(buffer, { pages: 1, page: i })[op](...params).toBuffer());
    }

    const results = await Promise.allSettled(buffers);
    const pages = [];

    for (const { status, value, reason } of results) {
        if (status === "fulfilled") {
            pages.push(value);
        } else {
            throw reason;
        }
    }

    const vips = await Vips();
    vips.concurrency(1);
    vips.Cache.max(0);

    const vipsPages = pages.map((page) => vips.Image.newFromBuffer(page, "", { access: vips.Access.sequential }));
    const vipsImage = vips.Image.arrayjoin(vipsPages, { across: 1 });

    const { height, format } = await sharp(pages[0]).metadata(); // height changes can occur

    const vipsBuffer = vipsImage.writeToBuffer("." + format, { page_height: height }).buffer;

    vipsPages.map((vipsPage) => vipsPage.delete());
    vipsImage.delete();
    vips.shutdown();

    return Buffer.from(vipsBuffer);
}

let buffer = readFileSync("./multi_page_images/multipage.tiff");

buffer = await sharp(buffer, { pages: -1 }).flop().toBuffer();
log("flop");

buffer = await sharp(buffer, { pages: -1 }).negate().toBuffer();
log("negate");

buffer = await createMultiPageImage(buffer, "flip");
log("flip");

buffer = await createMultiPageImage(buffer, "rotate", 30);
log("rotate");

buffer = await createMultiPageImage(buffer, "trim");
log("trim");

process.exit();
Output
flop 
{
    "rss": 62,
    "heapTotal": 12,
    "heapUsed": 7,
    "external": 1,
    "arrayBuffers": 0
}

negate 
{
    "rss": 65,
    "heapTotal": 12,
    "heapUsed": 7,
    "external": 1,
    "arrayBuffers": 0
}

flip 
{
    "rss": 314,
    "heapTotal": 32,
    "heapUsed": 17,
    "external": 8,
    "arrayBuffers": 7
}

rotate 
{
    "rss": 447,
    "heapTotal": 36,
    "heapUsed": 25,
    "external": 18,
    "arrayBuffers": 17
}

trim 
{
    "rss": 500,
    "heapTotal": 58,
    "heapUsed": 21,
    "external": 24,
    "arrayBuffers": 24
}

Image file multipage.tiff

ab [vips::Error]: no such operation pdfload_buffer VipsOperation: class "pdfload_buffer" not found

        const vipsImage = vips.Image.pdfloadBuffer(attachment, {page: pageNumber});
        const  image = vipsImage.pngsaveBuffer();

I wanted to create preview image for pdf with same scale in node js, but seems like it's not working, throws me an error

ab [vips::Error]: no such operation pdfload_buffer VipsOperation: class "pdfload_buffer" not found

I am using
Node - v18.16.0
"wasm-vips": "^0.0.5"

Is this something that is not developed or is it a bug

Unexplained "Aborted(OOM)" after processing 100+ images

Is there some sort of memory freeing function that I need to call after processing an image? Here's a playground link that produces an OOM error after processing (resize+crop) 131 images on my machine using Chrome. Here's a version that downloads the images in parallel - just to make it faster to reproduce (Edit: This seems like it causes fetch to return 503 errors sometimes - might be hitting reddit's rate limit. Maybe best to stick with the serial version). Here's the code for the serial-download version in case the link stops working for whatever reason (just processes some random images a reddit crawl):

(async function() {
    let urls = ["https://i.redd.it/da5l9vs50pw41.jpg","https://i.redd.it/m3pio5xwpza11.jpg","https://i.redd.it/e4n4xfdcrn171.jpg","https://i.redd.it/8lyhh8ll8cz61.jpg","https://i.redd.it/6xmxo1sgww461.jpg","https://i.redd.it/e04r96pyu7661.jpg","https://i.redd.it/onv6ztoviia81.jpg","https://i.redd.it/9gmzytttqoz61.jpg","https://i.redd.it/qmi6atan2lw51.jpg","https://i.redd.it/wc2gn9zi68j81.jpg","https://i.redd.it/c7mu1mh0x3j81.jpg","https://i.redd.it/j6mseiw6fae51.jpg","https://i.redd.it/7bb8np8gd9341.jpg","https://i.redd.it/un7khlbn9p511.jpg","https://i.redd.it/uelrbrwoylb71.jpg","https://i.redd.it/zan3igrsyhe61.jpg","https://i.redd.it/zz5vhf9elwo51.jpg","https://i.redd.it/4k2jcjnu9jt61.jpg","https://i.redd.it/xostagonpk661.jpg","https://i.redd.it/zy1q562nsad51.jpg","https://i.redd.it/6tii7d8si6l51.jpg","https://i.redd.it/2gefr7z8jhk31.jpg","https://i.redd.it/v9j5oesxq7061.jpg","https://i.redd.it/kzrr5a1odty31.jpg","https://i.redd.it/cpnmvysw0v971.jpg","https://i.redd.it/qfhfj8lej5o31.jpg","https://i.redd.it/efivkxyyvau61.jpg","https://i.redd.it/im0h47syytp61.jpg","https://i.redd.it/mxnmde2ub4z41.jpg","https://i.redd.it/4woa9fqlmem81.jpg","https://i.redd.it/9q6yww7396h71.jpg","https://i.redd.it/rd0apaws6li71.jpg","https://i.redd.it/pquhc2vwkzi31.jpg","https://i.redd.it/omnzun6ck1c71.jpg","https://i.redd.it/i85e5rrnjze51.jpg","https://i.redd.it/6nauzstwtpz71.jpg","https://i.redd.it/azs0s9vsv5651.png","https://i.redd.it/yekcl9gh84m41.jpg","https://i.redd.it/rzw5wyyvhzm51.jpg","https://i.redd.it/5e8f00nykd351.jpg","https://i.redd.it/jvf0bavwidr51.jpg","https://i.redd.it/5cc6e70uuw071.jpg","https://i.redd.it/whijm0y3wm771.png","https://i.redd.it/vcr6hi6pdzj21.jpg","https://i.redd.it/jg0c505rkn031.jpg","https://i.redd.it/6r8i57hmzk151.jpg","https://i.redd.it/p953j6senj911.jpg","https://i.redd.it/ehm99ecd4hj31.jpg","https://i.redd.it/fyuj8gve8wv61.jpg","https://i.redd.it/hhzi0bohsux51.jpg","https://i.redd.it/nnt5h8uft8e71.jpg","https://i.redd.it/s1hkx7o3ish41.jpg","https://i.redd.it/pk1ync3eisd61.jpg","https://i.redd.it/ncixvdyv98ry.jpg","https://i.redd.it/f2kxutvlknt41.jpg","https://i.redd.it/5de989avicr61.jpg","https://i.redd.it/2vi4gig59xg61.jpg","https://i.redd.it/u0rw3lwc3eq51.jpg","https://i.redd.it/52zy9xfgzbe71.jpg","https://i.redd.it/3q8dt1x554d61.png","https://i.redd.it/tvt3pusbxzf51.png","https://i.redd.it/7jd7q7vj3uv61.jpg","https://i.redd.it/7mctpdtlyxj71.png","https://i.redd.it/gyp3t225yv771.png","https://i.redd.it/60pgr9krn3f61.jpg","https://i.redd.it/x85vmjyi9pm41.jpg","https://i.redd.it/zot5tf1px4s61.png","https://i.redd.it/hxr41ui0wua71.jpg","https://i.redd.it/hmntbgxuqrf71.jpg","https://i.redd.it/el8mrm7hb6l61.png","https://i.redd.it/uazqlebns0s61.jpg","https://i.redd.it/ai3p7lqsdza71.jpg","https://i.redd.it/ktn8uzhclfj31.jpg","https://i.redd.it/4ztf3ghst0551.jpg","https://i.redd.it/fmz9q8r7sq751.png","https://i.redd.it/gtuu82nfu4m51.jpg","https://i.redd.it/ca61jlh16t061.jpg","https://i.redd.it/xfuply7inyv41.jpg","https://i.redd.it/il2zmku6kws51.jpg","https://i.redd.it/0x3f9vzpdtl31.jpg","https://i.redd.it/3sxvu3rdz0e71.jpg","https://i.redd.it/sghsuxblrv121.jpg","https://i.redd.it/n64d18rzs3o11.jpg","https://i.redd.it/hxw9izutyly21.jpg","https://i.redd.it/ayqmdfh721561.jpg","https://i.redd.it/ukal69gn59541.jpg","https://i.redd.it/j9sisg2qpp961.jpg","https://i.redd.it/4o5sl7e9hsl11.jpg","https://i.redd.it/gbpgulwdzpj01.png","https://i.redd.it/idrqrrb22uq21.jpg","https://i.redd.it/uif309pkp8o41.jpg","https://i.redd.it/7ez4zax0oxe41.jpg","https://i.redd.it/v9ej47demvu71.jpg","https://i.redd.it/9khfanlv6td81.jpg","https://i.redd.it/84ntovzvc8l81.jpg","https://i.redd.it/320vwt255k741.jpg","https://i.redd.it/n7csnrox12u41.jpg","https://i.redd.it/yic7vl8aejw31.jpg","https://i.redd.it/84y8a6203t281.jpg","https://i.redd.it/mtoris57v0x21.jpg","https://i.redd.it/sxy849qiz7n61.jpg","https://i.redd.it/yog1jyhjf8z41.jpg","https://i.redd.it/s4b6svg4lxl51.jpg", "https://i.redd.it/hdk4b5xtuzn61.jpg", "https://i.redd.it/tgko381hb8v31.jpg","https://i.redd.it/8uacm87m29pz.jpg","https://i.redd.it/8z7s1nq3c8x51.jpg","https://i.redd.it/09fwaqmy4u861.jpg","https://i.redd.it/lly5zy9utgt51.jpg","https://i.redd.it/m3oj6bnvciw51.jpg","https://i.redd.it/kzqgzlf5dn671.jpg","https://i.redd.it/vrgnyz6t6d031.jpg","https://i.redd.it/n8pr3mcqcrp61.jpg","https://i.redd.it/2vwvsbvd4wk71.png","https://i.redd.it/h7g4vq7k2ua51.jpg","https://i.redd.it/pok5vf0oyw951.jpg","https://i.redd.it/cz4io1enf9u71.jpg","https://i.redd.it/yva1g21hud651.jpg","https://i.redd.it/ag6fy2rhlxy61.jpg","https://i.redd.it/q8dp44mi00j51.jpg","https://i.redd.it/3x4ts386p2o21.jpg","https://i.redd.it/uza17i9f4kf61.png","https://i.redd.it/0d9dc3843k351.jpg","https://i.redd.it/5wx9saod3an71.jpg","https://i.redd.it/wiher0wk9i971.jpg","https://i.redd.it/x74dmusde7d71.jpg","https://i.redd.it/lpyevf1h86m71.jpg","https://i.redd.it/d7mi2ht1f5e81.jpg","https://i.redd.it/1cfmqym7hgk31.jpg","https://i.redd.it/hff40ikq83yy.jpg","https://i.redd.it/jexqfabxjp101.jpg","https://i.redd.it/t4sy6nsm8k961.jpg","https://i.redd.it/dunc1rs1xen51.jpg","https://i.redd.it/uya09vdouco51.png","https://i.redd.it/vmp6ahqncjj71.jpg","https://i.redd.it/0y2qh0j1ipx51.jpg","https://i.redd.it/fzzh0503i1o41.jpg","https://i.redd.it/i2v0ewtw9td31.png","https://i.redd.it/967oyqgk45451.jpg","https://i.redd.it/4fm6k26yvet01.jpg","https://i.redd.it/ashh5e519w981.jpg","https://i.redd.it/u9buu31s1if41.jpg","https://i.redd.it/zs1xwvzfx6961.jpg","https://i.redd.it/n8qul0zl0c761.jpg","https://i.redd.it/pav1vhsi9lh81.jpg","https://i.redd.it/vne1mqo7fcb41.jpg","https://i.redd.it/frqsmby8wd961.jpg","https://i.redd.it/pafsyxk60yt51.jpg","https://i.redd.it/l6ruqz9k5yr41.jpg","https://i.redd.it/e8q0vcpiq1161.jpg","https://i.redd.it/bor84tyj94881.jpg","https://i.redd.it/9cljma8x5do51.jpg","https://i.redd.it/mlt6vezh62h71.jpg","https://i.redd.it/iz4lpfbcosy41.jpg","https://i.redd.it/6z31hza0eui51.jpg","https://i.redd.it/54cgeaqrrs461.jpg","https://i.redd.it/a8z6uua2nn021.jpg","https://i.redd.it/k0z8cdcongr71.jpg","https://i.redd.it/7o7kgcv9oip41.jpg","https://i.redd.it/6i547mkjjvu31.jpg","https://i.redd.it/bn8639lchue51.jpg","https://i.redd.it/ntsd1gl4l1z51.jpg","https://i.redd.it/jc1cf51xgg521.jpg","https://i.redd.it/dp0arkzf2fq41.jpg","https://i.redd.it/xcefk2s3dnl81.jpg","https://i.redd.it/bgxdyio9qs471.jpg","https://i.redd.it/f2rlgow542c51.png","https://i.redd.it/v7f2018phxz71.jpg","https://i.redd.it/mvgclpc9phw51.jpg"];
    let nProcessed = 0;
    for(let url of urls) {
        let blob = await fetch(`https://temporary-restricted-cors-proxy.glitch.me?url=${url}`, {referrer:""}).then(r => r.blob());
        blob = await bicubicResizeAndCenterCrop(blob);
        const blobURL = URL.createObjectURL(blob);
        const img = document.createElement('img');
        img.src = blobURL;
        img.title = url;
        document.getElementById('output').appendChild(img);
        console.log(nProcessed++, url);
    }
    console.log("FINISHED");
})();

async function bicubicResizeAndCenterCrop(blob) {
    let im = vips.Image.newFromBuffer(await blob.arrayBuffer());

    // Resize so smallest side is 224px:
    let resizeFactor = 1;
    if(im.width > im.height) {
        resizeFactor = 224/im.height;
    } else {
        resizeFactor = 224/im.width; 
    }

    im = im.resize(resizeFactor, {kernel:vips.Kernel.cubic});

    // crop to 224x224:
    let left = (im.width - 224)/2;
    let top = (im.height - 224)/2;
    im = im.crop(left, top, 224, 224)

    let outBuffer = new Uint8Array(im.writeToBuffer('.png'));
    return new Blob([outBuffer], { type: 'image/png' });
}

Here's the error I'm seeing in Chrome DevTools:

Aborted(OOM)
Pe @ vips.js?ad40afff8535a54512ad:1
Wa @ vips.js?ad40afff8535a54512ad:1
$func731 @ vips.wasm?ad40afff8535a54512ad:0x353b3
$mb @ vips.wasm?ad40afff8535a54512ad:0x9489
$func373 @ vips.wasm?ad40afff8535a54512ad:0x1930f
$func1635 @ vips.wasm?ad40afff8535a54512ad:0xb9d30
...
...
$func4883 @ vips.wasm?ad40afff8535a54512ad:0x281093
n.invokeEntryPoint @ vips.js?ad40afff8535a54512ad:1
self.onmessage @ vips.worker.js?ad40afff8535a54512ad:1
Show 47 more frames
vips.worker.js?ad40afff8535a54512ad:1 worker.js onmessage() captured an uncaught exception: RuntimeError: Aborted(OOM). Build with -s ASSERTIONS=1 for more info.
threadPrintErr @ vips.worker.js?ad40afff8535a54512ad:1
self.onmessage @ vips.worker.js?ad40afff8535a54512ad:1
vips.worker.js?ad40afff8535a54512ad:1 RuntimeError: Aborted(OOM). Build with -s ASSERTIONS=1 for more info.
    at Pe (vips.js?ad40afff8535a54512ad:1:5312)
    at Wa (vips.js?ad40afff8535a54512ad:1:79304)
    at vips.wasm?ad40afff8535a54512ad:0x353b3
    ...
    ...
    at vips.wasm?ad40afff8535a54512ad:0xa746
    at r (vips.js?ad40afff8535a54512ad:1:81710)
threadPrintErr @ vips.worker.js?ad40afff8535a54512ad:1
self.onmessage @ vips.worker.js?ad40afff8535a54512ad:1
vips.js?ad40afff8535a54512ad:1 worker sent an error! https://wasm-vips.kleisauke.nl/lib/vips.worker.js?ad40afff8535a54512ad:1: Uncaught RuntimeError: Aborted(OOM). Build with -s ASSERTIONS=1 for more info.
t.onerror @ vips.js?ad40afff8535a54512ad:1
error (async)
ce @ vips.js?ad40afff8535a54512ad:1
(anonymous) @ vips.js?ad40afff8535a54512ad:1
e @ vips.js?ad40afff8535a54512ad:1
t @ vips.js?ad40afff8535a54512ad:1
Promise.then (async)
(anonymous) @ vips.js?ad40afff8535a54512ad:1
Promise.then (async)
(anonymous) @ vips.js?ad40afff8535a54512ad:1
(anonymous) @ vips.js?ad40afff8535a54512ad:1
(anonymous) @ playground-runner.html:104
vips.js?ad40afff8535a54512ad:1 Uncaught ErrorEvent {isTrusted: true, message: 'Uncaught RuntimeError: Aborted(OOM). Build with -s ASSERTIONS=1 for more info.', filename: 'https://wasm-vips.kleisauke.nl/lib/vips.worker.js?ad40afff8535a54512ad', lineno: 1, colno: 1925, …}
t.onerror @ vips.js?ad40afff8535a54512ad:1
error (async)
ce @ vips.js?ad40afff8535a54512ad:1
(anonymous) @ vips.js?ad40afff8535a54512ad:1
e @ vips.js?ad40afff8535a54512ad:1
t @ vips.js?ad40afff8535a54512ad:1
Promise.then (async)
(anonymous) @ vips.js?ad40afff8535a54512ad:1
Promise.then (async)
(anonymous) @ vips.js?ad40afff8535a54512ad:1
(anonymous) @ vips.js?ad40afff8535a54512ad:1
(anonymous) @ playground-runner.html:104
vips.worker.js?ad40afff8535a54512ad:1 Uncaught RuntimeError: Aborted(OOM). Build with -s ASSERTIONS=1 for more info.
    at Pe (vips.js?ad40afff8535a54512ad:1:5312)
    at Wa (vips.js?ad40afff8535a54512ad:1:79304)
    at vips.wasm?ad40afff8535a54512ad:0x353b3
    ...
    ...
    at vips.wasm?ad40afff8535a54512ad:0xa746
    at r (vips.js?ad40afff8535a54512ad:1:81710)

image

Any idea what's happening here?

WebAssembly.Memory Error

I am using the latest version of wasm-vips
but in production I am getting the following error:

requested a shared WebAssembly.Memory but the returned buffer is not a SharedArrayBuffer, indicating that while the browser has SharedArrayBuffer it does not have WebAssembly threads support - you may need to set a flag

I am setting the headers correctly:
image

I also get the vips.js correctly. Also the console doesn't exactly print anything. I got it by breaking on all exceptions.
I am on latest version on mac, using it in native webview.

How do you resample upscale an image using wasm-vips?

Loading the image like this works fine.

const vips = await Vips();
let im = vips.Image.newFromFile('in.jpg');

What I do not know is the syntax for resampling and upscaling an image using lanzcos3.

It looks like I need to use vips.affine as shown in the vips docs. What would my javascript statement be in order to resample upscale my image.

Thanks,
Dan

How can I use this in a Vue3 js component compiled using vite?

This works fine if I put it in my index.html

<script src="vips.js"></script>
<script type="module">
  const vips = await Vips();
</script>

But how do I use the variable vips from a vue component?

Example

myVueComp.vue

template
stuff here....
template

export default {
  name: 'SideNav',
  setup() {
    return {}
},
  methods: {

    updateStats() {
  //In this method I want to access Vips
}
}

So in the updateStats method I want to access the const vips variable I declared in my idex.html <script type="module"></script>

I have tried using the standard import * as Vips from 'wasm-vips' but it throws errors.

Any ideas?

Thanks,
Dan

HEIC support

Does libvips-wasm support HEIC decoding? From the announcement it's not very clear: JPG, PNG, TIFF, WebP are mentioned, but it's not clear if the list is exhaustive.

It would be very useful for creating an in-browser HEIC->JPG converter. Modern iPhone photos are in HEIC and Windows often has broken HEIC decoding.

Unstable on Deno

Running the await Vips() snippet form the README on Deno results in the following:

Deno 1.32.1
exit using ctrl+d, ctrl+c, or close()
REPL is running with all permissions allowed.
To specify permissions, run `deno repl` with allow flags.
> import Vips from 'https://cdn.jsdelivr.net/npm/wasm-vips/lib/vips-es6.js';

undefined
> const vips = await Vips();
error: Uncaught (in worker "") TypeError: na is not a function
    at https://cdn.jsdelivr.net/npm/wasm-vips/lib/vips-es6.js:116:217
    at new Promise (<anonymous>)
    at e (https://cdn.jsdelivr.net/npm/wasm-vips/lib/vips-es6.js:116:191)
    at f (https://cdn.jsdelivr.net/npm/wasm-vips/lib/vips-es6.js:116:467)
    at dd (https://cdn.jsdelivr.net/npm/wasm-vips/lib/vips-es6.js:117:361)
    at https://cdn.jsdelivr.net/npm/wasm-vips/lib/vips-es6.js:118:327

Not working on deno deploy

ReferenceError: Worker is not defined
    at Object.nb (https://cdn.jsdelivr.net/npm/wasm-vips/lib/vips-es6.js:102:450)
    at Object.Fc (https://cdn.jsdelivr.net/npm/wasm-vips/lib/vips-es6.js:99:127)
    at Object.init (https://cdn.jsdelivr.net/npm/wasm-vips/lib/vips-es6.js:99:58)
    at https://cdn.jsdelivr.net/npm/wasm-vips/lib/vips-es6.js:348:221
    at file:///src/main.ts:11:20

Docker compilation error

Hi.

I'm trying to compile the library using the docker file but I get the next error:

=============================================
Compiling JS bindings
=============================================
configure: cmake /src -DCMAKE_BUILD_TYPE=Release -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=/src/lib -DENVIRONMENT=web;node -DENABLE_MODULES=true -DENABLE_WASMFS=false -DCMAKE_TOOLCHAIN_FILE=/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_CROSSCOMPILING_EMULATOR=/usr/bin/node
-- Found PkgConfig: /usr/bin/pkg-config (found version "1.8.0")
-- Checking for module 'vips>=8.14'
--   Found vips, version 8.14.2
-- Configuring done
-- Generating done
-- Build files have been written to: /src/build/deps/wasm-vips
[ 10%] Building CXX object src/CMakeFiles/wasm-vips.dir/bindings/connection.cpp.o
[ 20%] Building CXX object src/CMakeFiles/wasm-vips.dir/bindings/image.cpp.o
[ 30%] Building CXX object src/CMakeFiles/wasm-vips.dir/bindings/interpolate.cpp.o
[ 40%] Building CXX object src/CMakeFiles/wasm-vips.dir/bindings/option.cpp.o
[ 50%] Building CXX object src/CMakeFiles/wasm-vips.dir/bindings/utils.cpp.o
[ 60%] Building CXX object src/CMakeFiles/wasm-vips.dir/vips-emscripten.cpp.o
/src/src/bindings/connection.cpp:41:9: error: use of undeclared identifier 'EM_FUNC_SIG_JPJ'
        EM_FUNC_SIG_JPJ, self->read_callback, buffer, length);
        ^
/src/src/bindings/connection.cpp:52:9: error: use of undeclared identifier 'EM_FUNC_SIG_JJI'
        EM_FUNC_SIG_JJI, self->seek_callback, offset, whence);
        ^
/src/src/bindings/connection.cpp:95:9: error: use of undeclared identifier 'EM_FUNC_SIG_JPJ'
        EM_FUNC_SIG_JPJ, self->write_callback, buffer, length);
        ^
/src/src/bindings/connection.cpp:109:9: error: use of undeclared identifier 'EM_FUNC_SIG_JPJ'
        EM_FUNC_SIG_JPJ, self->read_callback, buffer, length);
        ^
/src/src/bindings/connection.cpp:120:9: error: use of undeclared identifier 'EM_FUNC_SIG_JJI'
        EM_FUNC_SIG_JJI, self->seek_callback, offset, whence);
        ^
5 errors generated.
em++: error: '/emsdk/upstream/bin/clang++ -target wasm32-unknown-emscripten -fvisibility=default -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-cxx-exceptions -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr -D__EMSCRIPTEN_SHARED_MEMORY__=1 -DEMSCRIPTEN --sysroot=/emsdk/upstream/emscripten/cache/sysroot -Xclang -iwithsysroot/include/fakesdl -Xclang -iwithsysroot/include/compat -O3 -pthread -fexceptions -mnontrapping-fptoint -msimd128 -fPIC -O3 -std=c++11 -DG_DISABLE_ASSERT -DG_DISABLE_CAST_CHECKS -DG_DISABLE_CHECKS -I/src/build/target/include/glib-2.0 -I/src/build/target/lib/glib-2.0/include -I/src/build/target/include/webp -DWASM_SIMD_COMPAT_SLOW -DWASM_BIGINT -DNDEBUG -c -MD -MT src/CMakeFiles/wasm-vips.dir/bindings/connection.cpp.o -MF CMakeFiles/wasm-vips.dir/bindings/connection.cpp.o.d -matomics -mbulk-memory /src/src/bindings/connection.cpp -o CMakeFiles/wasm-vips.dir/bindings/connection.cpp.o' failed (returned 1)
make[2]: *** [src/CMakeFiles/wasm-vips.dir/build.make:77: src/CMakeFiles/wasm-vips.dir/bindings/connection.cpp.o] Error 1
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [CMakeFiles/Makefile2:106: src/CMakeFiles/wasm-vips.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

Do you know what the issue could be?

Thanks in advance.

JPEG 2000 Support

I've been trying saving to the various image formats supported by libvips and most work without issue.

However, when I try to save to a JPEG 2000, I get the error:

no such operation jp2ksave_buffer
VipsOperation: class "jp2ksave_buffer" not found

I'd assume this is due to JPEG 2000 support not currently being built into the binary. Would it be possible to add support for JPEG 2000? Thanks.

Usage in Web Workers (again)

I saw a previous query about using wasm-vips in a web worker - but the op closed it due to realising that the lib opens its own web worker. #7

Would it be possible to use this lib inside a custom webworker? if so - any guidance would be greatly appreciated.

[question] - SharedArrayBuffer is not available

Need to simply know if wasm-vips will work without SharedArrayBuffer with some efforts?

Background:
I am working on a desktop application. as it's a desktop application, there's no 'server' per se. so I can't really set the headers to make SharedArrayBuffer available easily. I have been digging into other alternatives to make this work but it's been a long time and I haven't found anything substantial.

Is there any way I will be able to make wasm-vips work without SAB api? I am fine with performance hit. or any other vips lib that you are aware of that doesn't use SAB api? any help is appreciated I have been chasing this for a long time

`wasm-vips` is unstable on Node `18.14.2+` and `19.4.0+`

Node has recently made a change to the WASM interpreter that is causing errors in wasm-vips. The errors seem completely random and affect many modules, but the most affected module seems to be libspng which cannot decode even a simple png file.

The issue was introduced in Node 18.14.2 and 19.4.0. I was not able to reproduce this error in the Chromium browser, version 110.0.5481.177 and 112.0.5615.20.
The issue does not affect wasm-vips version 0.0.4, although I am not sure when exactly the issue was "introduced". Maybe with the switch to Meson for libvips? I know for sure that b24ca0b and later is affected.
I hope this is not OS-specific, but FYI I have only run these tests on Ubuntu 22.04, on an Intel 10th-gen x64 chip.

I noticed the errors while working on EWAB, but the test suite also reports errors on these versions:

Full test suite report

1) colour
       cmyk:
     vips::Error: unable to call colourspace
vips__file_open_read: unable to open file "cmyk" for reading
unix error: No such file or directory
profile_load: unable to load profile "cmyk"

      at Wc (file:///home/anton/Documents/GitHub/wasm-vips/lib/vips-node.mjs:125:428)
      at wasm://wasm/0152235e:wasm-function[4260]:0x1ae91f
      at Nd.Image$colourspace (eval at Ge (file:///home/anton/Documents/GitHub/wasm-vips/lib/vips-node.mjs:162:242), <anonymous>:10:10)
      at a.<computed> [as colourspace] (file:///home/anton/Documents/GitHub/wasm-vips/lib/vips-node.mjs:152:259)
      at Context.<anonymous> (file:///home/anton/Documents/GitHub/wasm-vips/test/unit/test_colour.js:212:21)
      at process.processImmediate (node:internal/timers:475:21)

  2) connection
       image
         writeToTarget
           custom:

      AssertionError: expected 242 to equal +0
      + expected - actual

      -242
      +0
      
      at Context.<anonymous> (file:///home/anton/Documents/GitHub/wasm-vips/test/unit/test_connection.js:161:55)
      at process.processImmediate (node:internal/timers:475:21)

  3) foreign
       png:
     AssertionError: expected +0 to be close to 38671 +/- 0.0001
      at file:///home/anton/Documents/GitHub/wasm-vips/test/unit/helpers.js:181:33
      at Array.forEach (<anonymous>)
      at Module.assertAlmostEqualObjects (file:///home/anton/Documents/GitHub/wasm-vips/test/unit/helpers.js:180:19)
      at pngValid (file:///home/anton/Documents/GitHub/wasm-vips/test/unit/test_foreign.js:396:15)
      at fileLoader (file:///home/anton/Documents/GitHub/wasm-vips/test/unit/test_foreign.js:79:5)
      at Context.<anonymous> (file:///home/anton/Documents/GitHub/wasm-vips/test/unit/test_foreign.js:402:5)
      at process.processImmediate (node:internal/timers:475:21)

  4) foreign
       svgload:
     vips::Error: unable to load from file ./images/logo.svgz
VipsForeignLoad: "./images/logo.svgz" is not a known file format

      at Wc (file:///home/anton/Documents/GitHub/wasm-vips/lib/vips-node.mjs:125:428)
      at wasm://wasm/0152235e:wasm-function[1301]:0x7e5ec
      at Function.Image$newFromFile (eval at Ge (file:///home/anton/Documents/GitHub/wasm-vips/lib/vips-node.mjs:162:242), <anonymous>:8:10)
      at a.<computed> [as newFromFile] (file:///home/anton/Documents/GitHub/wasm-vips/lib/vips-node.mjs:152:259)
      at fileLoader (file:///home/anton/Documents/GitHub/wasm-vips/test/unit/test_foreign.js:80:21)
      at Context.<anonymous> (file:///home/anton/Documents/GitHub/wasm-vips/test/unit/test_foreign.js:883:5)
      at process.processImmediate (node:internal/timers:475:21)

  5) resample
       thumbnail:

      AssertionError: expected 48.23111979166666 to be below 1
      + expected - actual

      -48.23111979166666
      +1
      
      at Context.<anonymous> (file:///home/anton/Documents/GitHub/wasm-vips/test/unit/test_resample.js:268:82)
      at process.processImmediate (node:internal/timers:475:21)

Pending fixes:

Interlace option in jpegsaveBuffer doesn’t seem to work

Hi. First, your lib is a game changer! I'm a big fan.

This is the possible bug I'm talking about:

const outputBuffer = image.jpegsaveBuffer({ Q: 90, interlace: true })
const blob = new Blob([outputBuffer], { type: 'image/jpeg' })
const url = URL.createObjectURL(blob)
// <a href="${url}" download="image.jpg" rel="download">Download image</a>

The image produced this way still loads top to bottom.
What should I do to make my jpegs progressive using wasm-vips?

Support custom `stdout` and `stderr`

I am using wasm-vips as a dependency for a CLI tool. Currently, if vips encounters a warning, it will output it directly to the console. This is pretty annoying because the CLI tool already is outputting information to the console, so now there are random fragments of vips warnings cluttered in with the rest of the information.

I would like to be able to receive the warnings in a function, where I can write my own logic for when and where the output should be logged.
If that is not possible, the next best thing would be to tell wasm-vips to never output anything.

Maybe this is already supported? But I can't seem to figure out how it works. I have already tried this, as an attempt to make it stop outputting to the CLI, but it did not work:

import newVips from "wasm-vips";
const vips = await newVips({
	print: (stdout) => {return ""},
	printErr: (stderr) => {return ""},
	preRun: module => {
		module.print = (stdout) => {return ""};
		module.printErr = (stderr) => {return ""};
	},
});

Error: NODERAWFS is currently only supported on Node.js environment. at vips.js:9 when loading in browser

Steps to reproduce: Just follow the Browser setup in the documentation
Use node express as a simple webserver to serve index.html

  1. create a simple index.html with
<script src="vips.js"></script> <script type="module"> const vips = await Vips(); </script>
  1. npm install wasm-vips
  2. Copy vips.js, vips.wasm and vips.worker.js from node_modules/wasm-vips to your root folder

As per directions set appropriate headers for SharedArrayBuffer

Run index.html and you will get stated error

TS types improvements

Hi! 👋

Firstly, thanks for your work on this project! 🙂

Today I used patch-package to patch [email protected] for the project I'm working on.

I wanted to use types from .*saveBuffer functions to generate yup validators, but it wasn't possible because exports don't exist. So I added some improvements for types

example of usage:

import { useEffect, useState } from 'react';
import VipsWASM from 'wasm-vips';

type VipsTypes = typeof VipsWASM;

export const useVips = () => {
  const [vips, setVips] = useState<VipsTypes | undefined>(undefined);
  const [cleanup, setCleanup] = useState<(() => void) | undefined>(undefined);

  useEffect(() => {
    if (vips) return;
    VipsWASM({
      // TODO: check does it affect loading speed
      // dynamicLibraries: ['vips-jxl.wasm', 'vips-heif.wasm', 'vips-resvg.wasm'],
      // Workers need to import the unbundled version of `vips.js`
      mainScriptUrlOrBlob: './vips.js',
      // wasm-vips is served from the public directory
      locateFile: (fileName) => fileName,
      preRun: (module) => {
        module.setAutoDeleteLater(false);
        // TODO: figure out how to make this work
        // module.setAutoDeleteLater(true);
        module.setDelayFunction((fn: () => void) => setCleanup(fn));
      },
    }).then((vips) => {
      vips.concurrency(10);
      setVips(vips);
    });

    return () => {
      if (!vips) return;

      type ImageAutoGen = VipsWASM.ImageAutoGen;
      type webpsaveBufferType = ImageAutoGen['webpsaveBuffer'];
      type webpsaveBufferParams = Parameters<webpsaveBufferType>;
      type webpsaveBufferOptions = webpsaveBufferParams[0];
      const object: webpsaveBufferOptions = {};

      if (vips) {
        // @ts-ignore don't understand why it throws error
        // it doesn't catch types narrowing
        return vips.shutdown();
      }
    };
  }, []);

  return { vips, cleanup };
};

Here is the diff that solved my problem:

diff --git a/node_modules/wasm-vips/lib/vips.d.ts b/node_modules/wasm-vips/lib/vips.d.ts
index e97c352..6754e55 100644
--- a/node_modules/wasm-vips/lib/vips.d.ts
+++ b/node_modules/wasm-vips/lib/vips.d.ts
@@ -1,4 +1,4 @@
-declare function Vips(config?: Partial<EmscriptenModule>): Promise<NonNullable<typeof Vips>>;
+export declare function Vips(config?: Partial<EmscriptenModule>): Promise<NonNullable<typeof Vips>>;
 
 type ModuleCallback = { (module?: any): void };
 
@@ -26,7 +26,7 @@ interface EmscriptenModule {
     workaroundCors: boolean;
 }
 
-declare module Vips {
+export declare module Vips {
     // Allow single pixels/images as input.
     type SingleOrArray<T> = T | T[];
 

This issue body was partially generated by patch-package.

I understand that I shoud've probably updated this - https://github.com/kleisauke/wasm-vips/blob/master/build/gen_type_declarations.py, but i'm not fluent enough in python to do it currently. Thanks

Promise remains in pending mode

Hello,

I'm trying to setup wasm-vips but I fail to do so. Given the following example:

<script type="module">
    import Vips from './node_modules/wasm-vips/lib/vips-es6.js';
    function resolved(result) {
        console.log(result); // never displayed
    }

    function rejected(result) {
        console.error(result); // never displayed
    }

    let prms = Vips();
    prms.then(resolved, rejected);
    console.log(prms); // is a pending Promise

    setInterval(function(){
        console.log(prms); // always pending
    }, 2000)
</script>

Browser is Firefox 120.0.1 and index.html is served with those headers:

Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin

I'm a bit stuck, surely I did something wrong (I'm no full-time JS dev).

Any idea for me ?

Error `heifload: ignoring nclx profile` when converting to AVIF and resizing

For some images such as https://github.com/swissspidy/media-experiments/blob/f6a7f9f26694b79a25ae2b844d2cc9a344d356a7/tests/e2e/assets/wordpress-logo-512x512.png I am getting this error when trying to convert to AVIF:

Screenshot 2024-01-18 at 22 53 30

Existing issues with same error:

Weird thing is that this is a PNG / AVIF situation, so not sure why HEIF would be involved here.

Here's a playground repro:

https://wasm-vips.kleisauke.nl/playground/?modules=jxl-heif&deflate=rVZtb9s2EP4rN3-RUjiSk2HA4MUJkGIBAgwoNnTYhzhAaekkc5BIjaTiuq3_-44UKdmak3hFAsSieC_P3XPHEx8mmRTaQCPK27YoUMEC2IZxA_HoWaDJ1jFEa2MaPU9TxTZJyc26XbUaFXkxKEySyTrVG661bni-TWvMOTvHzw0qXpNcpzXjIjWoaYmXmDKtkZYbqfJGodbnlSzl-U8Xl5_pP6GoIjiDs2RVyVVsF0wptu0ijc9-WYouevbEi1H4JHhCZe5rVuKdVDUzcZ_jYEiQbWV6I3rlX9DZxIPPKXyFDc_Neg4_zmZTWCMv18a_ZEo2cyhYpRF2UzCqRes-ANjAyb3ADdzaHB46xEfr02wbnEPELVxq4SLYDaFZyz__-I2M6TfJFDKDH1Z_Y2boPbbSQZfXJenlMmstyV751wrtW0wAZWR16ZlolZGm9017vU2Jxhvcbu_zOJKtaVoTEeNNgyJ_v-ZVHpOHLjmmtyKDohWZ4VIcI5u0zKqjzy7_aVnFzZawZ8nPl0txBl_tdgif7Ej0xBudOCcJEXanZO0rDZ0n6MCDmWwsuCZD52tpfp9DwHkHF1Qdu72zNsGiNX2bONBko7jBjzLgRImrw7T37RC9dd8svZukiytEVSETbXOTuM60OwpNq4Q3pL3dEe72e25EWieiJdCfrpky76nbKADXbiMS_8OGtaX2yuVGRAMT9Kzw_1LuIfwxCCcAdoFG7zhN4b7wCSVeh2v4gkomQz5BshhpfvtGs8av0w6Jzv67oOU29jLotv9yar2rXsl4Op4B8354QZA_BJE9yoTo6TvCEA27eiUYrw45mu7HMm6dHaAdDQ7JDgdYLPpYDgFDxG53sVfvG4iYsdOVxBFQSTNaK4x8Em8dqg-HinnHVdf2tgvBrFHQjLFPN_UaLkpXVqf7cU2VZlUlN5rcomKGxED9bdU1UgPlsOKmZg2VlkrmvEilaJ5Bbr8N2iXfp2T56nrgKjRFz1ToJF_8sNk3WGd3Par5oLY0NwcNsy-Z97jpgNs34dA9TnncZN8VyQtN7xI8jO5YIIeFewt2XufgaFTD8Xszdl4AfY24wM7bHhPnyg6gCgs7V2YexnWsO5qoovEpf4AZPO43sDeOw2fIxX9-wCOpp3B5WOIORNmsT8Z4HmFMkM2KqnZ6UheHgJ1tyMkXp4fsO-mZrFaSHNSnoryE8VzhOxvrNHbVo5kmm1DrjpL-LUTbTcaDa8eJl4jRbeW12wPN0A-i2kJGQxRYQYTDJ-f-k_2GCgmVFCVtrtAOVrpz5274nnDpmEwnVzl_Ap4vlpPuXrecXF-ltHe9FCSln8d_AQ

Enhancement — more modular loading

First off, let me say how impressed I am with wasm-vips — amazing job 🤩👏🥳 Can't tell you how great your lib "just works" in comparison to about 8 other browser-based image manipulation libs I've tried, despite its supposed alpha quality. (If this is alpha quality, all the other libs are laughably early pre-alphas!)

The suggestion here is around more modular loading. The dynamicLibraries option is super helpful and shaves off quite a few unnecessary MB. However, I was wondering whether we could extend the concept to some of the more "core" Vips functionality. For instance, I only need webp resizing and encoding. I realize tree-shaking WASM is not yet a thing and may never be, but perhaps it's possible to further granulate wasm-vips analogously to dynamicLibraries. For instance I can imagine passing only features: ["resize", "web-encode"] or however the API might look.

Probably a big ask because ostensibly libvips itself isn't modular in the way I'm describing, but worth a discussion, I think.

Thanks again!

Certain parameters on `jpegSaveBuffer` ignored

Certain parameters on jpegSaveBuffer operation are ignored and I can't seem to find why that's the case?
If you could help me figure out what the bug I might be, I could help contribute?

(process:42): VIPS-WARNING **: 01:55:30.646: ignoring quant_table

(process:42): VIPS-WARNING **: 01:55:30.865: ignoring trellis_quant

(process:42): VIPS-WARNING **: 01:55:30.865: ignoring overshoot_deringing

(process:42): VIPS-WARNING **: 01:55:30.866: ignoring optimize_scans

Build failed

Build with npm run build on Mac, I always got this:

[ 80%] Linking CXX executable ../../../../lib/web/vips.js
wasm-ld: error: unable to find library -lUSE_PTHREADS=1
wasm-ld: error: unable to find library -lUSE_PTHREADS=1
wasm-ld: error: unable to find library -lUSE_PTHREADS=1

Error: no such operation text

When I use vips.Image.text to create text image,something wrong happend

const vips = await Vips();
const image = vips.Image.text("test");

Run this code,I got blow errors:

Error: no such operation text
VipsOperation: class "text" not found

I'm not sure if this is a bug, I only want to add some font watermask to my picture.Do you have a better way?

[Question] How do you deal with CDNs and Vite

Hi. I have the following situation. I'm working with an admin panel. Some images and scripts come from an external CDN. The main project is not a NodeJS app. I use Vite as a bundler for CSS and some scripts.

I want to use this library to crop images, generate webp and thumbnails on client side but when I add the required headers for cross-origin isolation, all the images and scripts from the CDN stop working. The same happen with my assets from my local Vite Dev Server.

I am currently still looking for a solution to this and I would be very grateful if you know of any strategies, tricks or anything you can share to solve this problem.

setup wasm-vips for next.js/react

First of all would like to thank for your job, it's awesome that people making possible projects like this one. I think it has bright future.

So I was working with node.js sharp library, wrapper around libvips. Found out that everything now can be done even without backend, found out about your project and started trying to work but stuck. I have no problems when using it on backend (I didn't try much because it's not what I wanted). But it produces different errors each time I'm trying to make it work with next.js

For example I'm constantly getting this error:
B7735319-586E-46FA-B617-03712A19B44A

Link to my project: https://github.com/serafimsanvol/my-app/blob/main/src/app/page.tsx

It's just basic next starter project so I'm sure that there is something with library configuration but I don't know what are workarounds here, can you help/explain/tell me that it's bug and actually unexpected behaviour?

On different project with slightly different setup and set headers as required it shows different error:

E7FA1AAE-6227-44E9-BC4B-0BC504D551CB

Any help/suggestions appreciated, thanks

SIMD support is musted?

This repo is awesome!
At this stage it looks like simd support is necessary, is it possible to build no simd version for lower version browsers (those that don't support simd)?

CDN-hosted browser files

Exciting project! Thanks for working on this and sharing it.

In this comment it is mentioned that the browser files can be downloaded from here:

Would it be possible to publish these in such a way that they can be accessed via unpkg.com or deno.land/x with a simple import like e.g. this?

import vips from "https://unpkg.com/[email protected]/web/vips.js"

Web Worker support?

First I want to say thank you for this project!

I was hoping to use it in a web worker to move image processing off of the main thread. However, when new Vips() is instantiated a ReferenceError: window is not defined is thrown because window is not available to workers. It looks to be coming from emscripten.

Any ideas on how to compile for a worker?

DOMException: Failed to execute 'open' on 'XMLHttpRequest': Invalid URL

Hi, I'm really excited to try this project, but couldn't seem to get it running locally (Firefox & Chrome)

This was my minimum attempt:

<!DOCTYPE html>
<html>

<head>
    <title>wasm-vips</title>
</head>

<body>
</body>

<script src="./vips.js"></script>
<script type="module">
    const vips = await Vips();
</script>

</html>

Folder structure:

libvips
 ┣ index.html
 ┣ vips-jxl.wasm
 ┣ vips.js
 ┣ vips.wasm
 ┗ vips.worker.js

Console output:

Uncaught (in promise) DOMException: Failed to execute 'open' on 'XMLHttpRequest': Invalid URL
    at oa (http://127.0.0.1:5555/vips.js:12:500)
    at http://127.0.0.1:5555/vips.js:116:217
    at new Promise (<anonymous>)
    at e (http://127.0.0.1:5555/vips.js:116:191)
    at f (http://127.0.0.1:5555/vips.js:116:467)
    at fd (http://127.0.0.1:5555/vips.js:117:361)
    at http://127.0.0.1:5555/vips.js:118:327

worker sent an error! http://127.0.0.1:5555/vips.worker.js:1: Uncaught SyntaxError: Failed to execute 'open' on 'XMLHttpRequest': Invalid URL
Lb.a.onerror @ vips.js:101

project.zip

No paths work when reading files (Deno)

In Deno, vips.Image.newFromBuffer(buffer) works well! But opening local files directly for example vips.Image.newFromFile('sample.jpg') always complains:

error: vips::Error: unable to load from file sample.jpg
VipsForeignLoad: file "sample.jpg" does not exist

I thought it would be an issue of relative paths, but I tried all kinds of absolute and relative paths (relative to Deno.cwd(), or import.meta.url, or the directory where vips-es6.js is stored), with and without file:// prefix, with no luck.

Furthermore I tried a simple filename without path, and put a sample.jpg in every directory I could think of where it might try to load it. No luck.

Am I missing something, or is this is a bug with wasm-vips on deno?

Deno 1.38.5, wasm-vips version is i guess 0.0.7 (or whatever it is that jsdelivr is giving - I manually downloaded vips-es6.js and all the other JS and WASM file from jsdelivr in order to install and import locally since it seems using jsdelivr the wasm files are loaded again over the net every run? - could we perhaps somehow have these zipped on new releases?)

PS:

I'm running on VPS's with limited RAM, so while ArrayBuffers work, I'm hoping passing file paths directly would negate the need for allocating big in and out buffers, and perhaps allow vips to process data in a more streaming manner (if it does that, or does it need to load the full file data in memory?).

Ideally for Deno, it would be great if we were able to work with ReadableStream in and WritableStream out, but that does not appear possible at the moment. That's why I'm looking into passing file paths instead of ArrayBuffer

```Uncaught RuntimeError: Aborted(OOM)``` when writeToBuffer

Hello, I want to use this library to complete the following tasks: combine multiple small images into one large image in the browser and download it to the user's local.
So I write a demo, here are some main code snippets:

const urls = [have 1000 urls]
console.log('urls.length', urls.length)

const WIDTH = 1000
const HEIGHT = 720

const colNum = ~~Math.sqrt(urls.length)
const rowNum = ~~(urls.length / colNum)

window.startMerge = async () => {
  const images = await Promise.all(
    urls.map(async (url, index) => {
      return vips.Image.newFromBuffer(await fetch(url).then(res => res.arrayBuffer()))
    })
  )
  // merge images
  let mergeImage = await vips.Image.black(WIDTH * colNum, HEIGHT * rowNum)
  for (let i = 0; i < rowNum; i++) {
    for (let j = 0; j < colNum; j++) {
      const image = images[i * colNum + j]
      mergeImage = await mergeImage.insert(image, j * WIDTH, i * HEIGHT)
      // dispose image
      image.delete()
    }
  }
  console.log('mergeImage', mergeImage)

  const buffer = await mergeImage.writeToBuffer('.jpg') // OOM happened
  // const blob = new Blob([buffer], { type: 'image/jpeg' })
  // const url = URL.createObjectURL(blob)
  // const img = document.createElement('img')
  // img.src = url
  // img.style.position = 'fixed'
  // img.style.top = '0'
  // img.style.left = '0'
  // img.style.zIndex = '9999'
  // document.body.appendChild(img)
}

Does this mean that large files need to be streamed out? Instead of the overall output as it is now.

Usage in Browser

I've installed this npm package in a repo using storybook, as I'm trying to experiment with it in React but I'm unable to get it working in the browser. Of course, it downloads a version of the package for node use only, so I'm wondering how to get this working in a browser, since the files provided by the npm package use things specific to node.

I know the playground works, so do I have to grab a copy of this repo and build things locally?

`heifsave` is not defined

import Vips from 'wasm-vips';

const vips = await Vips();

let im = vips.Image.newFromFile('test.4.jpg');
im.heifsave('testoutput.avif');

This fails on wasm-vips 0.0.4, perhaps some build flag is missing?

`WasmTrapJSTypeError` while loading an SVG when building with LTO

This test program:

import Vips from './lib/vips-node.mjs';

const vips = await Vips({
  dynamicLibraries: ['vips-resvg.wasm']
});

const svg =
  '<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" id="svg-root" />';
const im = vips.Image.newFromBuffer(svg);
im.writeToFile('x.png');

Fails with:

$ node test.mjs
wasm://wasm/00561afe:1


TypeError: type incompatibility when transforming from/to JS
    at wasm://wasm/00561afe:wasm-function[616]:0x7a3aa
    at gh (lib/vips-node.mjs:314:433)
    at wasm://wasm/00561afe:wasm-function[1113]:0xeafb9
    at wasm://wasm/00561afe:wasm-function[201]:0xcf95
    at wasm://wasm/00561afe:wasm-function[1304]:0x119fa2
    at wasm://wasm/0169d79e:wasm-function[6279]:0x474c27
    at wasm://wasm/0169d79e:wasm-function[311]:0x1ca8a
    at wasm://wasm/0169d79e:wasm-function[1465]:0xfbd6f
    at wasm://wasm/0169d79e:wasm-function[6208]:0x46ab34
    at sh (lib/vips-node.mjs:315:262)

Node.js v18.16.0
Readable stack trace
  1) SVG input
       Convert SVG with embedded images to PNG, respecting dimensions, autoconvert to PNG:
     Uncaught TypeError: type incompatibility when transforming from/to JS
      at rosvgtree::parse::parse::h46e668755e5e4dd7 (wasm://wasm/030b2c16:wasm-function[1098]:0xe5bf3)
      at invoke_vii (build/Release/sharp-emscripten-wasm32.node.js:7803:27)
      at _$LT$usvg_tree..Tree$u20$as$u20$usvg_parser..TreeParsing$GT$::from_str::h2ad984f34c8b8916 (wasm://wasm/030b2c16:wasm-function[1699]:0x161843)
      at _$LT$usvg_tree..Tree$u20$as$u20$usvg_parser..TreeParsing$GT$::from_data::hb74bbe40b8ecb9f0 (wasm://wasm/030b2c16:wasm-function[596]:0x60ca1)
      at invoke_viiii (build/Release/sharp-emscripten-wasm32.node.js:7936:27)
      at resvg_parse_tree_from_file (wasm://wasm/030b2c16:wasm-function[594]:0x60283)
      at vips_foreign_load_svg_file_header (wasm://wasm/030b2c16:wasm-function[5339]:0x2b4596)
      at vips_foreign_load_build (wasm://wasm/030b2c16:wasm-function[4480]:0x21e4af)
      at vips_object_build (wasm://wasm/030b2c16:wasm-function[4667]:0x2313ac)
      at vips_cache_operation_buildp (wasm://wasm/030b2c16:wasm-function[4227]:0x1ea98a)

When wasm-vips was build with LTO enabled, i.e:

$ npm run build -- --enable-lto

It looks like this error orginates from V8:
https://github.com/nodejs/node/blob/v18.16.0/deps/v8/src/common/message-template.h#L600

Building without LTO or removing id="svg-root" from this particular SVG seems to fix this.

This was found while trying to update wasm-vips in lovell/sharp#3522.

Build fails when compiling for node-es6

My build fails when compiling newer versions of wasm-vips. It fails when generating the node-es6 bindings with the following errors:

wasm-ld: error: /src/build/target/lib/libz.a(crc32.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `crc_table`; recompile with -fPIC
wasm-ld: error: /src/build/target/lib/libz.a(crc32.o): relocation R_WASM_MEMORY_ADDR_LEB cannot be used against symbol `functable`; recompile with -fPIC
wasm-ld: error: /src/build/target/lib/libz.a(functable.o): relocation R_WASM_TABLE_INDEX_SLEB cannot be used against symbol `insert_string_c`; recompile with -fPIC
wasm-ld: error: /src/build/target/lib/libz.a(functable.o): relocation R_WASM_MEMORY_ADDR_LEB cannot be used against symbol `cpu_check_features.features_checked`; recompile with -fPIC
wasm-ld: error: /src/build/target/lib/libz.a(functable.o): relocation R_WASM_TABLE_INDEX_SLEB cannot be used against symbol `quick_insert_string_c`; recompile with -fPIC

There are many more lines that are all similar to the ones above.

I am building this in the Docker container by running npm run build, so I would be surprised if this issue is specific to my computer.

I am happy to test a fix for you. I am trying to figure one out myself, but so far have not found anything.

Errors with vite

In dev mode

Failed to resolve entry for package "/Users/user/projects/astro-vips/node_modules/.vite/deps". The package may have incorrect main/module/exports specified in its package.json.
9:04:39 PM [vite] Internal server error: Failed to resolve entry for package "/Users/user/projects/astro-vips/node_modules/.vite/deps". The package may have incorrect main/module/exports specified in its package.json.
  Plugin: vite:asset-import-meta-url
  File: /Users/user/projects/astro-vips/node_modules/.vite/deps/wasm-vips.js?v=c3cd4bc3
      at packageEntryFailure (file:///Users/user/projects/astro-vips/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:28725:11)
      at resolvePackageEntry (file:///Users/user/projects/astro-vips/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:28722:5)
      at tryCleanFsResolve (file:///Users/user/projects/astro-vips/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:28381:28)
      at tryFsResolve (file:///Users/user/projects/astro-vips/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:28328:17)
      at TransformContext.transform (file:///Users/user/projects/astro-vips/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:43235:32)
      at Object.transform (file:///Users/user/projects/astro-vips/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:44352:62)
      at async loadAndTransform (file:///Users/user/projects/astro-vips/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:55026:29)
      at async viteTransformMiddleware (file:///Users/user/projects/astro-vips/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:64430:32)
09:07:28 PM [astro] Configuration updated. Restarting...

While dev mode starts to work with

optimizeDeps: {
    exclude: ["wasm-vips"],
},

This causes errors in build

vite v4.5.0 building for production...
transforming (11) node_modules/react/cjs/react-jsx-runtime.production.min.jsUnexpected early exit. This happens when Promises returned by plugins cannot resolve. Unfinished hook action(s) on exit:
(commonjs--resolver) resolveId "wasm-vips" "/Users/user/projects/astro-vips/src/components/VipsExample.tsx"
(vite:worker-import-meta-url) transform "/Users/user/projects/astro-vips/node_modules/wasm-vips/lib/vips-es6.js"
✓ 30 modules transformed.
✓ built in 526ms
file:///Users/user/projects/astro-vips/node_modules/rollup/dist/es/shared/node-entry.js:25902
                    reject(new Error(`Unexpected early exit. This happens when Promises returned by plugins cannot resolve. Unfinished hook action(s) on exit:\n` +
                           ^

Error: Unexpected early exit. This happens when Promises returned by plugins cannot resolve. Unfinished hook action(s) on exit:
(commonjs--resolver) resolveId "./vips-es6.js" "/Users/user/projects/astro-vips/node_modules/wasm-vips/lib/vips-es6.worker.js"
(vite:worker-import-meta-url) transform "/Users/user/projects/astro-vips/node_modules/wasm-vips/lib/vips-es6.js"
    at process.handleBeforeExit (file:///Users/user/projects/astro-vips/node_modules/rollup/dist/es/shared/node-entry.js:25902:28)
    at Object.onceWrapper (node:events:629:26)
    at process.emit (node:events:514:28) {
  code: 'PLUGIN_ERROR',
  plugin: 'commonjs--resolver',
  hook: 'resolveId',
  id: '/Users/user/projects/astro-vips/node_modules/wasm-vips/lib/vips-es6.js',
  watchFiles: [
    '\x00astro-entry:/Users/user/projects/astro-vips/src/components/VipsExample',
    '/Users/user/projects/astro-vips/node_modules/@astrojs/react/client.js',
    '/Users/user/projects/astro-vips/src/components/VipsExample.tsx',
    '/Users/user/projects/astro-vips/node_modules/react/index.js',
    '/Users/user/projects/astro-vips/node_modules/react-dom/client.js',
    '/Users/user/projects/astro-vips/node_modules/@astrojs/react/static-html.js',
    '/Users/user/projects/astro-vips/node_modules/react/cjs/react.production.min.js',
    '/Users/user/projects/astro-vips/node_modules/react-dom/index.js',
    '/Users/user/projects/astro-vips/package.json',
    '/Users/user/projects/astro-vips/node_modules/react/jsx-runtime.js',
    '/Users/user/projects/astro-vips/node_modules/wasm-vips/lib/vips-es6.js',
    '\x00commonjsHelpers.js',
    '\x00/Users/user/projects/astro-vips/node_modules/react/index.js?commonjs-module',
    '\x00/Users/user/projects/astro-vips/node_modules/react/cjs/react.production.min.js?commonjs-proxy',
    '\x00/Users/user/projects/astro-vips/node_modules/react/cjs/react.production.min.js?commonjs-exports',
    '/Users/user/projects/astro-vips/node_modules/react-dom/cjs/react-dom.production.min.js',
    '/Users/user/projects/astro-vips/node_modules/react/cjs/react-jsx-runtime.production.min.js',
    '/Users/user/projects/astro-vips/node_modules/scheduler/index.js',
    '\x00/Users/user/projects/astro-vips/node_modules/react/jsx-runtime.js?commonjs-module',
    '\x00/Users/user/projects/astro-vips/node_modules/react/cjs/react-jsx-runtime.production.min.js?commonjs-proxy',
    '\x00/Users/user/projects/astro-vips/node_modules/react/cjs/react-jsx-runtime.production.min.js?commonjs-exports',
    '\x00/Users/user/projects/astro-vips/node_modules/react/index.js?commonjs-proxy',
    '/Users/user/projects/astro-vips/node_modules/scheduler/cjs/scheduler.production.min.js',
    '\x00/Users/user/projects/astro-vips/node_modules/react-dom/client.js?commonjs-exports',
    '\x00/Users/user/projects/astro-vips/node_modules/react-dom/index.js?commonjs-proxy',
    '\x00/Users/user/projects/astro-vips/node_modules/react-dom/index.js?commonjs-module',
    '\x00/Users/user/projects/astro-vips/node_modules/react-dom/cjs/react-dom.production.min.js?commonjs-proxy',
    '\x00/Users/user/projects/astro-vips/node_modules/react-dom/cjs/react-dom.production.min.js?commonjs-exports',
    '\x00/Users/user/projects/astro-vips/node_modules/scheduler/index.js?commonjs-proxy',
    '\x00/Users/user/projects/astro-vips/node_modules/scheduler/index.js?commonjs-module',
    '\x00/Users/user/projects/astro-vips/node_modules/scheduler/cjs/scheduler.production.min.js?commonjs-proxy',
    '\x00/Users/user/projects/astro-vips/node_modules/scheduler/cjs/scheduler.production.min.js?commonjs-exports'
  ]
}

I would love to use wasm-vips, I just need to figure out how to import and use it

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.