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

Composite stream #3136

Closed
softy2k opened this issue Mar 14, 2022 · 14 comments
Closed

Composite stream #3136

softy2k opened this issue Mar 14, 2022 · 14 comments
Labels

Comments

@softy2k
Copy link

softy2k commented Mar 14, 2022

I try to do something like this:
HTTP Request -> API ( composite some PNG images from HDD, using Express js and Sharp) -> Response To Request whit one PNG Image

I have server.js :

const express = require('express')
const resize = require('./resize')
const server = express()

server.get('/', (req, res) => {
  // Extract the query-parameter
  const widthString = req.query.width
  const heightString = req.query.height
  const format = req.query.format

  // Parse to integer if possible
  let width, height
  if (widthString) width = parseInt(widthString)
  if (heightString) height = parseInt(heightString)

  // Set the content-type of the response
  res.type(`image/${format || 'png'}`)

  // Get the resized image
  resize('nodejs.png', format, width, height).pipe(res)
})

server.listen(8000, () => {
  console.log('Server started!')
})

I have resize.js:

const fs = require('fs')
const sharp = require('sharp')

module.exports = function resize(path, format, width, height) {
    let base = "C:/base.png";

    let composite = [
        { "input": "C:/image1.png" },
        { "input": "C:/image2.png" },
        { "input": "C:/image3.png" },
        { "input": "C:/image4.png" },
    ]

    const finalImage = sharp(base)
        .flatten({ background: '#e7e7e7' })
        .composite(composite)
        // .png()
        .toBuffer()
        .then((finishedImageBuffer) => {
            console.log("Writing to storage");
            return sharp(finishedImageBuffer)
                .toFile('C:/output.png');
        })


    return  stream.pipe ?????
}

For debug only, write to file is working (but I don't need to write file)

I don't know syntax for last return to respond with finalImage as stream pipe.

@lovell
Copy link
Owner

lovell commented Mar 14, 2022

A sharp instance implements a Duplex stream and assumes it can be acted upon as a ReadableStream unless/until toBuffer() or toFile() are used instead. Remove those functions from the chain and return the sharp instance, which you can then pipe data out of.

@softy2k
Copy link
Author

softy2k commented Mar 14, 2022

Something like this ?

  let finalImage = sharp().flatten({ background: '#e7e7e7' })
  .composite(composite)
  .png()

  return readStream.pipe(finalImage)

Which is the right way to init readStream ? If I set const readStream = fs.createReadStream("C:/base.png") I receive error.

I'm a beginner in nodes js and express, and I'm hooked

@softy2k
Copy link
Author

softy2k commented Mar 14, 2022

No success with:

let finalImage = sharp(base).flatten({ background: '#e7e7e7' })
    .composite(composite)
    .png()

let readableStream = fs.createReadStream(path).pipe(finalImage)
return readableStream

I got:

Error: Unexpected data on Writable Stream

@softy2k
Copy link
Author

softy2k commented Mar 14, 2022

I don't know how correct it is, but I did it with:

  let finalImage = sharp(base).flatten({ background: '#e7e7e7' })
    .composite(composite)
    .png()

  const Stream = require('stream')
  const readableStream = new Stream.Readable({
    read() { }
  })

  return readableStream.pipe(finalImage)

As I said, I'm a beginner at Node JS. If it is even more correct than that, please let me know

@lovell
Copy link
Owner

lovell commented Mar 14, 2022

If base is a filesystem path to the input, you should be able to return finalImage directly and remove the readableStream entirely.

return sharp(base)
  .flatten({ background: '#e7e7e7' })
  .composite(composite)
  .png()

@softy2k
Copy link
Author

softy2k commented Mar 14, 2022

Thanks a lot for the explanations, it works perfectly.
But I still have a problem.

If I want to resize the final picture, adding line .resize({ width: 412 }) , I get an error : Image to composite must have same dimensions or smaller.

return sharp(base)
  .flatten({ background: '#e7e7e7' })
  .composite(composite)
  .png()
  .resize({ width: 412 })

How to proceed?

@softy2k
Copy link
Author

softy2k commented Mar 15, 2022

Somebody ?

@softy2k
Copy link
Author

softy2k commented Mar 17, 2022

lovell, can you give me a llitle help here ?

@lovell
Copy link
Owner

lovell commented Mar 18, 2022

You'll need to split this into two pipelines:

const compositor = sharp(base).composite(composite).png()
const resizer = sharp().resize({ width: 412 })
return compositor.pipe(resizer)

@softy2k
Copy link
Author

softy2k commented Mar 23, 2022

Thanks, works like a charm...

@softy2k
Copy link
Author

softy2k commented Mar 24, 2022

I have another question.
If I have a missing picture in the picture array list for composites I get the error:

Error: Input file is missing
Emitted 'error' event on Sharp instance at:
    at Object.<anonymous> (C:\Sharp\node_modules\sharp\lib\output.js:1149:16), 

and the application fails completely (must be restarted).

I tried to catch the error with try and catch, but without success.

      let compositor = "";
      try {
        compositor = sharp(base).composite(composite).png();
      }
      catch (err) {
        compositor = sharp(base);
        console.log("Error: Missing Image(s) in Composite");
      }

How can I prevent this situation? In other words, how can I handle this kind of error?
Obviously, I could check if I have all the pictures before I send them to sharp composite, but maybe it's a simpler variant.

@softy2k
Copy link
Author

softy2k commented Mar 29, 2022

Again, lovell, can you give me a llitle help here ?

@lovell
Copy link
Owner

lovell commented Mar 29, 2022

If you're using Stream-based output, you'll need to add error handling to those Streams. This is more of a general Node.js question, unrelated to sharp, and suited to a site such as Stack Overflow.

As an aside, please don't post "nag" messages asking for updates - there are 3 on this issue alone.

@lovell lovell closed this as completed Mar 29, 2022
@softy2k
Copy link
Author

softy2k commented Mar 29, 2022

I understand your point.

I had no choice because:

  • you made the fastest image processing node; for this reason I have to use it (as I can)
  • because I am a beginner in nodes js, as much as I would like, some issues are beyond me; and when I asked for help, the only person who answered me was you; days passed until I asked for help again

Anyway, thanks again for your answers. And I will try not to stress you too much in the future (I don't promise, I'm just trying).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants