jimp-dev / jimp

An image processing library written entirely in JavaScript for Node, with zero external or native dependencies.
http://jimp-dev.github.io/jimp/
MIT License
13.9k stars 761 forks source link

Jimp Browser Support #1194

Closed marvinruder closed 2 weeks ago

marvinruder commented 1 year ago

Is your feature request related to a problem? Please describe. At the moment, some problems arise when attempting to use Jimp in React (similar issues were reported from users of other tools, e.g. React Native). The following are known so far:

Describe the solution you'd like The issues described above are resolved and Jimp can be used in frontend tools like React using import Jimp from "jimp[/es]"; without a problem.

Describe alternatives you've considered Using the browser version of Jimp via require("jimp/browser/lib/jimp.js"); const { Jimp } = window; is a possible workaround, but that version is aimed more at using Jimp in plain HTML/JS than by bundling tools such as Webpack, Rollup etc., which should be able to handle jimp or jimp/es properly.

sergeushenecz commented 1 year ago

image

crutchcorn commented 1 year ago

It might be worthwhile to explore an option similar to how @wmhilton has done so with isomorphic-git using FS as a property to pass in:

https://isomorphic-git.org/docs/en/fs#docsNav

@wmhilton has even created a browser-first FS package called "LighningFS" that might be a good package to point to for official browser support, alongside an example repo that integrates it:

https://github.com/isomorphic-git/lightning-fs

crutchcorn commented 1 year ago

Also worth mentioning - @marvinruder you may want to look into the work being done by @danielholmes :

https://github.com/danielholmes/jimp-vite

suneox commented 1 year ago

It can work well on example, this lib using for node so some related packages don't work you need to use a build for the browser version and then I have resolved this and workaround by loading jimp.js on index.html and defining a global type for Jimp variable

hipstersmoothie commented 1 year ago

Yeah that one works but we're talking about esm usage rather than bundling. Bundling means we can't tree shake things. Right now our esm breaks browsers

gabycush commented 1 year ago

When using the jimp/es import, accessing some built-in Node APIs like fs, path etc. is attempted and the build fails (example: Can't resolve 'fs' in '…/node_modules/@jimp/core/es'). Reproducable in jimp-dev/jimp-react

I'm having this issue too, is a solution in the works or is there a specific suggested workaround?

Ronkiro commented 1 year ago

My solution for NextJS was to load jimp and import from window, similar approach from the issue's text but not using the library for the browser (it was giving me the error that self is not defined).

Code:

import 'jimp';
const { Jimp } = window as any;

Hope it helps anyone

angello0926 commented 1 year ago

My solution for NextJS was to load jimp and import from window, similar approach from the issue's text but not using the library for the browser (it was giving me the error that self is not defined).

Code:

import 'jimp';
const { Jimp } = window as any;

Hope it helps anyone

This really helps me to get through this issue for now! Struggled for a few hours, thanks!

MBrunoS commented 1 year ago

I tried all the suggestions, but still couldn't make it work... I'm trying to use Jimp in a Web Worker, with Vite. So, I'm not being able to use the lib. I'd even help with this bug, but I don't know where to start right now.

xenova commented 1 year ago

I got Jimp working in the browser/webworker/node/... with this ugly hack:

ES6:

// For some reason, Jimp attaches to self, even in Node.
// https://github.com/jimp-dev/jimp/issues/466
import * as _Jimp from 'jimp';

// @ts-ignore
const Jimp = (typeof self !== 'undefined') ? (self.Jimp || _Jimp) : _Jimp;

CommonJS:

// For some reason, Jimp attaches to self, even in Node.
// https://github.com/jimp-dev/jimp/issues/466
const _Jimp = require('jimp');

// @ts-ignore
const Jimp = (typeof self !== 'undefined') ? (self.Jimp || _Jimp) : _Jimp;
sexnine commented 1 year ago

@xenova I don't know why this works, but it works.

I've been struggling to get Jimp working on Cloudflare Workers (using SvelteKit) for wayyy too long and you're solution just works.

One thing I noticed using your solution is instantiating a new Jimp instance I have to do new Jimp.default(...) on Node.js but on Cloudflare Workers new Jimp(...) is the only way that works.

I am extremely grateful that you shared your solution, so thanks <3.

xenova commented 1 year ago

I don't know why this works, but it works.

That's exactly what I thought when I got it working 🤣 ...

One thing I noticed using your solution is instantiating a new Jimp instance I have to do new Jimp.default(...) on Node.js but on Cloudflare Workers new Jimp(...) is the only way that works.

Interesting. I haven't had an issue with creating new Jimp instances with my node.js version... but it's good to know you found a solution!

I am extremely grateful that you shared your solution, so thanks <3.

Happy to help!

LetMeDream commented 1 year ago

My solution for NextJS was to load jimp and import from window, similar approach from the issue's text but not using the library for the browser (it was giving me the error that self is not defined).

Code:

import 'jimp';
const { Jimp } = window as any;

Hope it helps anyone

Ok but, where is that code supposed to go inside the next Js project? In the component that's gonna use Jimp?

LetMeDream commented 1 year ago

I got Jimp working in the browser/webworker/node/... with this ugly hack:

ES6:

// For some reason, Jimp attaches to self, even in Node.
// https://github.com/jimp-dev/jimp/issues/466
import * as _Jimp from 'jimp';

// @ts-ignore
const Jimp = (typeof self !== 'undefined') ? (self.Jimp || _Jimp) : _Jimp;

CommonJS:

// For some reason, Jimp attaches to self, even in Node.
// https://github.com/jimp-dev/jimp/issues/466
const _Jimp = require('jimp');

// @ts-ignore
const Jimp = (typeof self !== 'undefined') ? (self.Jimp || _Jimp) : _Jimp;

This works in Next JS and apps created using CRA. Not in Vite, tho.

patrickelectric commented 1 year ago

No luck when using it in a webpage in a typescript project:

[vue warn]: Error in v-on handler (Promise/async): "TypeError: jimp__WEBPACK_IMPORTED_MODULE_7___default(...) is not a function"

found in

---> <VBtn>
       <GenericViewer> at src/components/vehiclesetup/viewers/GenericViewer.vue
         <VehicleViewer> at src/components/vehiclesetup/viewers/VehicleViewer.vue
           <VCard>
             <SetupOverview> at src/components/vehiclesetup/SetupOverview.vue
               <VehicleSetupView> at src/views/VehicleSetupView.vue
                 <VMain>
                   <VApp>
                     <App> at src/App.vue
                       <Root>

w

Lofavreel commented 1 year ago

I got Jimp working in the browser/webworker/node/... with this ugly hack:

ES6:

// For some reason, Jimp attaches to self, even in Node.
// https://github.com/jimp-dev/jimp/issues/466
import * as _Jimp from 'jimp';

// @ts-ignore
const Jimp = (typeof self !== 'undefined') ? (self.Jimp || _Jimp) : _Jimp;

CommonJS:

// For some reason, Jimp attaches to self, even in Node.
// https://github.com/jimp-dev/jimp/issues/466
const _Jimp = require('jimp');

// @ts-ignore
const Jimp = (typeof self !== 'undefined') ? (self.Jimp || _Jimp) : _Jimp;

Because some were wondering why your proposed workaround works: I just did a little digging, because I had the same issue. I found this in the @jimp/core/ index.js (in both es and dist); it is before the last three lines of code in those files:

if (process.env.ENVIRONMENT === "BROWSER") {
  // For use in a web browser or web worker
  /* global self */
  let gl;
  if (typeof window !== "undefined" && typeof window === "object") {
    gl = window;
  }
  if (typeof self !== "undefined" && typeof self === "object") {
    gl = self;
  }
  gl.Jimp = Jimp;
  gl.Buffer = Buffer;
}

I don't know why and I don't think I will look into it, but maybe this will give the right person a starting idea on where to look to resolve this issue.

hipstersmoothie commented 1 year ago

Any help from someone in the community would be appreciated. If you want to submit a PR I'd be happy to Shepard that PR. At the time unfortunately I don't see myself doing this soon.

jcard0na commented 1 year ago

Just for others usign React, the workaround mentioned on the issue's text worked for me:

export default function App() {
    require("jimp/browser/lib/jimp.js"); 
    const { Jimp } = window
    ...
};

this also worked:


import 'jimp';

export default function App() {
    const { Jimp } = window;
    ...
};
devenkhatri commented 1 year ago

My solution for NextJS was to load jimp and import from window, similar approach from the issue's text but not using the library for the browser (it was giving me the error that self is not defined). Code:

import 'jimp';
const { Jimp } = window as any;

Hope it helps anyone

This really helps me to get through this issue for now! Struggled for a few hours, thanks!

Thanks for this suggestion. This worked for me.

da7a90-backup commented 1 year ago

For Vercel edge the workaround mentioned by @xenova works locally but not on production and even locally you have to set unstable_allowDynamic and point it to the library in node_modules but that doesn't seem to work for some reason when trying to deploy to production.

sergeushenecz commented 1 year ago

My solution. Version 0.22.10

import  'jimp/browser/lib/jimp';
const { Jimp } = window;
meepen commented 10 months ago

none of these work very well for typescript...

Ronkiro commented 10 months ago

none of these work very well for typescript...

@meepen check my comment https://github.com/jimp-dev/jimp/issues/1194#issuecomment-1449287374 it may help you

sameert89 commented 10 months ago

For react native/expo with hermes engine, this actually works, I cannot understand why it is like that, any insigths would be very helpful.

import * as _Jimp from 'jimp';
const Jimp = (typeof self !== 'undefined') ? (self.Jimp || _Jimp) : _Jimp;
Ronkiro commented 9 months ago

@sameert89 React Native newbie here, but it seems that self works like window for RN. This snippet checks if it's existent/accessible, if it is then use it, else use the normal variable. It's similar to the solution i pointed https://github.com/jimp-dev/jimp/issues/1194#issuecomment-1449287374 and to the one pointed in the first post

NayamAmarshe commented 8 months ago

none of these work very well for typescript...

Maybe try this:

import "jimp";

const ReactComponent = () => {
  const { Jimp } = window as Window & typeof globalThis & {
    Jimp: typeof import("jimp");
  };
...
tsgouros commented 6 months ago

For react native/expo with hermes engine, this actually works, I cannot understand why it is like that, any insigths would be very helpful.

import * as _Jimp from 'jimp';
const Jimp = (typeof self !== 'undefined') ? (self.Jimp || _Jimp) : _Jimp;

I was very excited to find this comment, since I am also trying to use Jimp in React Native (w/o Expo), but it does not work for me. Or it partly works, in that I can use the constructor to create an object to receive an image:

const jp = new Jimp(256, 256, "#000000", (err, image) => {
  console.log("+++", err);
});

But I can't seem to use that value to access functionality like Jimp.read() which is what I need.

neko-para commented 5 months ago

For those want to use jimp in browser with typescript definition, here's a guide. First, import browser build. As it pollute into window.Jimp, place doesn't matter.

import 'jimp/browser/lib/jimp.js'

Then, add a dts file

declare var Jimp: typeof import('jimp')

Just use Jimp.xxx.

vickyRathee commented 5 months ago

@sexnine Can you please prove the example code for Cloudflare? I can't get it work for some reason.

sexnine commented 5 months ago

@sexnine Can you please prove the example code for Cloudflare? I can't get it work for some reason.

Are you using Sveltekit on CF workers, or just vanilla workers? Typescript or JS?

I can try to make a quick demo later today :)

vickyRathee commented 5 months ago

Just a vanilla worker using Typescript. I am trying to resize a puppeteer screenshot and upload to R2 to generate website thumbnail.

This was my code when I was testing with sharp

image

trungpd1102 commented 4 months ago

Just a vanilla worker using Typescript. I am trying to resize a puppeteer screenshot and upload to R2 to generate website thumbnail.

This was my code when I was testing with sharp

image

hipstersmoothie commented 2 weeks ago

:rocket: Issue was released in v1.0.2 :rocket: