Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pipe image data to a stream #23

Open
EyalAr opened this issue Jul 2, 2014 · 10 comments
Open

Pipe image data to a stream #23

EyalAr opened this issue Jul 2, 2014 · 10 comments

Comments

@EyalAr
Copy link
Owner

EyalAr commented Jul 2, 2014

No description provided.

@bensmeets
Copy link

Hi, was this available already somehow? I've seen the examples of reading from a stream, but can't figure out how to write back to a stream.

To give some context. I've seen people use imagemagick in examples, and afterwards using "pipe" to get it back in their main process' stream. Hoped this would be a good alternative (without needing IM).

@EyalAr
Copy link
Owner Author

EyalAr commented Oct 20, 2014

@bensmeets

I haven't added streams support to the API yet (pull requests are welcome!).

I'm not sure exactly what you need, can you clarify?

Basically, if you want to stream image data out, you can get the image as a buffer and use it as a basis for a stream (see here for example).
If you want to get image data into your app from a stream, you can store it in a buffer and then use lwip.open to decode the buffer.

@bensmeets
Copy link

Thanks Eyal, I'm aware that my questions must be strange. I feel like I only know half of what I need to ask the right questions :)

I'll try to clarify a bit. I'm twiggling my thumbs with MeteorJS. Using a package for that called CollectionFS which helps with managing uploaded images. All of their examples are using ImageMagick, where I would much rather have something without dependencies like lwip.

Now. The CollectionFS has support for plugging in "transformations". Somewhere in this whole setup, something is not working like it should. I've played with Async libraries, wrappers, etc. all over the place. But still no go.

Their transformation functions have this signature:

function myTransformFunction(fileObj, readStream, writeStream);

So my thought was, heck just read in the readStream, do magic lwip stuff and write back to the writeStream.... not so easy though :)

Here is one of their examples using ImageMagick (just a snippet for the syntax):

transformWrite: function(fileObj, readStream, writeStream) {
  // Transform the image into a 10x10px thumbnail
  gm(readStream, fileObj.name()).resize('10', '10').stream().pipe(writeStream);
}

is something like this possible in lwip through this new stream support you mentioned? Or is this something for the future.

Cheers.

@EyalAr
Copy link
Owner Author

EyalAr commented Oct 20, 2014

@bensmeets
Based on the docs I'd try something like this:

  1. Define your own readable stream.
  2. Pipe it to the writable stream provided by CollectionFS.
  3. Read data from the readable stream provided by CollectionFS into a buffer, until the stream is exhausted.
  4. Once you have all the data in the buffer, decode it with lwip.
  5. Use lwip to manipulate the image.
  6. Encode the image to a buffer and emit the data your readable stream.

Pseudo code (not tested):

transformWrite: function(fileObj, readStream, writeStream) {

    // Create a new readable stream
    var middleStream = /* new stream.Transform() */;
    middleStream.pipe(writeStream);

    // temporary cache for original image data
    var oImBuf = new Buffer();

    // original image format (for decoder)
    var ext = fileObj.extension;

    // read original image from the stream
    readStream.on('data', function(chunk) {

        oImBuf = Buffer.concat(oImBuf, chunk);

    });

    // ready to decode original image
    readStream.on('end', function() {

        lwip.open(oImBuf, ext, function(err, img) {

            // do some manipulations...
            img.batch()
                .scale(0.5)
                .sharpen(10)
                // get buffer of new manipulated image as a JPEG
                .toBuffer('jpg', function(err, nImBuf){

                    // emit the new image to the middle stream
                    /* middleStream.push(nImBuf); */

                    // close the stream
                    /* middleStream.end(); */

                });

        });

    });

}

Note that:

  1. We pipe our own read stream to the framework's write stream.
  2. We publish data to our stream only when we finish manipulating the image.
  3. I have commented out the parts related to our custom read stream because I'm not sure this is exactly how it works. It might be needed to create a class that implements a readable stream. But that shouldn't be very complicated.

Let me know if it helps.

@bensmeets
Copy link

@EyalAr Thanks, very grateful that you took the time for such a complete comment.

I've been struggling with it a lot and finally decided that the CollectionFS is too much black box material for me. It kept throwing errors at me when this was implemented. I'm switching to something more manual that gives some more insights.

I'm keep the above code put though! The manual alternative will need it as well. When I get it working there I'll shout out.

Ohhhh the good old days of synchronous code :)......

@bensmeets
Copy link

Just to keep things together, the issue was with the syntax for streaming, after switching to something more manual (regarding CollectionFS), everything went without a problem.

@EyalAr
Copy link
Owner Author

EyalAr commented Oct 22, 2014

@bensmeets
Awesome, thanks for the update 👍

@wmassingham
Copy link

Any update on streams? I'm trying to get an image in through busboy, process it with lwip, then send it out to MongoDB GridFS. Busboy puts out a stream and GridFS prefers a stream, but lwip is in the middle with only buffers.

@EyalAr
Copy link
Owner Author

EyalAr commented Dec 19, 2014

@wmassingham I'll try to target it to v0.0.7. In the meantime, perhaps you can try to adapt the pseudo code I posted above.

Also, it would be good if you can post a sample of how you see streams implemented. If it was available, how would you use it?

Thanks.

@EyalAr EyalAr added this to the v0.0.7 milestone Dec 19, 2014
@bencooling
Copy link

For what its worth this solution worked for me

lwip.open(filename, function (err, originalImage) {

  if (err) {
    throw err;
  }

  originalImage
    .batch()
    .resize(200, 200)
    .toBuffer('jpg', function (err, buffer) {

      var bufferStream = new stream.PassThrough();
      bufferStream.end( buffer );
      // bufferStream.pipe( process.stdout );

    });
});

@EyalAr EyalAr modified the milestones: v0.0.7, v0.0.8 Jun 8, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants