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

Read Image Synchronously #303

Open ghost opened 7 years ago

ghost commented 7 years ago

I need this to block the main thread for reasons.

Could I maybe use fs.readFileSync and somehow turn that into a data URL?

hipstersmoothie commented 6 years ago

We definitely need to be non blocking on file reads. My suggestion would be to do the following and just giving jimp a buffer:

const buffer = fs.readFileSync('./path/to/your/file.png');
const image = new Jimp(buffer)

image.resize(...)
Clonkex commented 5 years ago

Is this something we can do currently? I REALLY need synchronous operations and I'm struggling to find a way.

EDIT: After testing and getting really confused for ages I finally realised it seems like new Jimp(buffer) still does thing asynchronously, so no, I can't do what you've shown here. Well that sucks. I guess I'll have to create some super jank counter system to know when all of my images have loaded :|

mindinsomnia commented 5 years ago

My workaround on this for now is just to store an array list of operations that need working through, and as the async promises return I'm just fetching another item from the list to perform operations on. Really need sequential operation for my needs since I'm working on thousands of image files, don't really want to load them and be editing them all at once.

Clonkex commented 5 years ago

@mindinsomnia Nice workaround. My "solution" was to have two separate loops. The first one determines which (and how many) images need to be loaded, the second starts them all loading. Then, in the callback for the image loading completion I make it decrement the counter. If the counter has reached 0, that means all images have loaded for this job and processing can begin. It's messy and awkward and would be 6000 times easier with synchronous processing. I just wanted to whip up a quick image processing script, but no, it couldn't possibly be that simple...

I'm really not sure why people are so keen to get rid of synchronous processing completely when it's only beneficial with certain types of user-facing programs, and greatly increases code complexity for a lot of other types of programs.

@hipstersmoothie Can we re-open this issue? The solution provided doesn't actually work.

andreekeberg commented 4 years ago

If you only want to decode an image (to get an ImageData object containing a width, height and Uint8ClampedArray) and not use any other methods, this is the workaround I found when trying to do this in my ImageData package.

You will need know the mime type of your image (I used mime-kind since I needed to be able to check both file paths and Buffers, but there are a lot of packages that do this), and provided you have that, you can directly access the image decoders:

const type = 'image/jpeg'
const buffer = fs.readFileSync('./path/to/your/file.png')
const imageData = jimp.decoders[type](buffer)
peterslany commented 2 years ago

Extending the @andreekeberg solution. If you need to process images synchronously and use the Jimp object and its methods, this worked for me (Jimp version 0.16.1):

// Reading the file
const type = 'image/png'
const buffer = fs.readFileSync('./input.png');
const imageData = jimp.decoders[type](buffer);
const baseImage =  new Jimp(imageData);

// ... process the image

// Writing to file
fs.writeFileSync(`./result.png`, Jimp.encoders[type](baseImage)); 
hipstersmoothie commented 1 year ago

Seems like a candidate for cleanup up weird stuff we do in our constructor @nopeless

nopeless commented 1 year ago

We should never support sync

This will run in browsers/servers where response time is crucial

Imo, jimp's constructor should only accept a uint array of either rgba or rgb. any other means (filename, url, number array, uriencoded, jpeg) should be a method

hipstersmoothie commented 1 year ago

imo we shouldn't even expose the constructor

import * as jimp from 'jimp';

const image = await jimp.read('/my-image.png')
const image = jimp.create(buffer)
const image = jimp.create({ height, width })
Clonkex commented 1 year ago

We should never support sync This will run in browsers/servers where response time is crucial

I disagree. This might run on a server where response time is critical, but it's certainly not the only use-case. I have extensively used Jimp for offline processing tools. For offline tools where you only care about quickly writing the tool and not about whether it blocks UI, synchronous programming is just easier. There's less to think about and it's harder to screw yourself over.

Then again, async-await makes it much easier than it used to be, so maybe it's not such a big deal. I just know there have been situations where it sucked that I was forced to use async-await. Certainly it's a significant hurdle to beginners.

hipstersmoothie commented 1 year ago

Having a way to create a jimp instance from a buffer easily seems like a good win. For loading files I suspect we will go full async.

VirtualTim commented 1 year ago

We should never support sync

This will run in browsers/servers where response time is crucial

Just to add my 5c, my use case is using this in a test framework where I'm dealing with raw images, and when those images don't match I write them out as pngs, to make image comparison easier.

I'm currently running 1404 tests in ~25 seconds, so performance is more than sufficient, and I'd personally favour ease of writing tests over more speed.

nopeless commented 1 year ago

We should never support sync

This will run in browsers/servers where response time is crucial

Just to add my 5c, my use case is using this in a test framework where I'm dealing with raw images, and when those images don't match I write them out as pngs, to make image comparison easier.

I'm currently running 1404 tests in ~25 seconds, so performance is more than sufficient, and I'd personally favour ease of writing tests over more speed.

I am guessing that is a CI server (or modern hardware).

I think what you brought is a valid point. Speed may not be the biggest concern

nopeless commented 1 year ago

We should never support sync This will run in browsers/servers where response time is crucial

I disagree. This might run on a server where response time is critical, but it's certainly not the only use-case. I have extensively used Jimp for offline processing tools. For offline tools where you only care about quickly writing the tool and not about whether it blocks UI, synchronous programming is just easier. There's less to think about and it's harder to screw yourself over.

Then again, async-await makes it much easier than it used to be, so maybe it's not such a big deal. I just know there have been situations where it sucked that I was forced to use async-await. Certainly it's a significant hurdle to beginners.

Modern node allows top level await, making async programming even easier.

One reasoning might be that a previously sync function had needs to be migrated to an async function and providing sync methods will allow developers to upgrade to latest without much hassle