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

# Only final operation available in composite chain #2856

Closed
HoPGoldy opened this issue Aug 24, 2021 · 5 comments
Closed

# Only final operation available in composite chain #2856

HoPGoldy opened this issue Aug 24, 2021 · 5 comments
Labels

Comments

@HoPGoldy
Copy link

HoPGoldy commented Aug 24, 2021

What are you trying to achieve?

Every composite operation in the chain can be found in the final result.

Have you searched for similar questions?

I found similar problem and solution in the following issue, but the problem still confuses me.

Are you able to provide a minimal, standalone code sample that demonstrates this question?

here is a simple case, I created a 1 * 3 black rectangle, and then called composite three times to try to fill it with 1 * 1 blue tiles.

const sharp = require('sharp');

const run = async function () {
    // 100 * 300 rect background 
    const bg = await sharp({ create: {
        height: 100, width: 300, channels: 4, background: 'black'
    }}).png();

    // 100 * 100 tile
    const blueTile = await sharp({ create: {
        height: 100, width: 100, channels: 4, background: 'blue'
    }}).png().toBuffer();

    const result = bg.composite([{
        input: blueTile,
        blend: 'atop',
        left: 0,
        top: 0
    }]).composite([{
        input: blueTile,
        blend: 'atop',
        left: 100,
        top: 0
    }]).composite([{
        input: blueTile,
        blend: 'atop',
        left: 200,
        top: 0
    }])

    result.toFile('./testResult.png');
}

run();

In my expectation, the entire picture will be filled with blue, but the final result shows that only the last composite takes effect:

final png

What am I thinking

I know that I can use .composite([ ..., ..., ... ]) to combine multiple layers at the same time, but I need to get each tile through an async function, so I try to solve this through a reduce, and then the problem occurs.

With searching issue, I found that I can finish job by executing toBuffer after each composite and then re-instancing with sharp(). But I'm dealing with a large tilemap, and every buffering/instancing will take a lot of time.

So, below is my question:

  • Why would chain use of composite cause this problem?
  • Is there a way to solve this problem without buffering/instancing in each iteration?
@lovell
Copy link
Owner

lovell commented Aug 24, 2021

I know that I can use .composite([ ..., ..., ... ]) to combine multiple layers at the same time,

This is the correct approach, which can be mixed with await as follows:

.composite([
  {
    input: await sourceOfImage1(),
    ...
  },
  {
    input: await sourceOfImage2(),
    ...
  }
]

If you're using create then this can be passed directly to composite:

.composite([
  {
    input: {
      create: {
        height: 100, width: 300, channels: 4, background: 'black'
      }
    },
    ...
  }
]

@HoPGoldy
Copy link
Author

Thank you for your confirm! but I encountered a strange problem while rewriting. It looks like a memory leak?

Below is an reproduce case. In this case, I loop await to generate a tile array, and composite them to the background layer.

const sharp = require("sharp");

const ROW_LENGTH = 180

const createTileBuffer = async function () {
    const tile = sharp({
        create: { height: 150, width: 150, channels: 4, background: '#fff' }
    });
    return tile.png().toBuffer();
}

const run = async function () {
    const tiles = [];

    for (const index in Array.from({ length: ROW_LENGTH })) {
        tiles.push(await createTileBuffer())
    }

    const rowBg = sharp({
        create: { height: 150, width: ROW_LENGTH * 150, channels: 4, background: '#fff' }
    });

    const rowSharp = rowBg.composite(tiles.map((input, index) => ({
        input,
        blend: 'atop',
        top: 0,
        left: index * 150
    })));

    // Error will be thrown here  
    await rowSharp.toBuffer()
}

run()

When I run node test.js, no error throw on the console. But when I define in package.json:

{
  "scripts": {
    "case": "node test.js"
  }
}

Add run npm run case, an error occurred strangely:

PS D:\project\source> npm run case

> screeps-world-printer@1.0.0 case D:\project\source
> node test.js

npm ERR! code ELIFECYCLE
npm ERR! errno 3221225725
npm ERR! screeps-world-printer@1.0.0 case: `node test.js`
npm ERR! Exit status 3221225725
npm ERR!
npm ERR! Failed at the screeps-world-printer@1.0.0 case script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\huangpuguang\AppData\Roaming\npm-cache\_logs\2021-08-30T12_29_35_503Z-debug.log

And yarn output same:

PS D:\project\source> yarn run case
yarn run v1.22.10
$ node test.js
error Command failed with exit code 3221225725.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

But when I commented await rowSharp.toBuffer() at the end, the problem disappeared. Even if I set ROW_LENGTH to a large number (like 9000), the code will just exit correctly after a long time.

Here is my npx envinfo --binaries --system:

  System:
    OS: Windows 10 10.0.19042
    CPU: (6) x64 Intel(R) Core(TM) i5-9400F CPU @ 2.90GHz
    Memory: 9.63 GB / 15.94 GB
  Binaries:
    Node: 12.16.1 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.10 - C:\Program Files\nodejs\yarn.CMD
    npm: 6.13.4 - C:\Program Files\nodejs\npm.CMD

@HoPGoldy
Copy link
Author

I reproduced this issue on github actions machine.

@lovell
Copy link
Owner

lovell commented Aug 30, 2021

Exit code 3221225725 looks like a stack overflow so you'll need to break this up into a number of pipelines. I notice you've already seen #2286.

@HoPGoldy
Copy link
Author

HoPGoldy commented Sep 1, 2021

Yes, it's not hard to solve, I'm just confused about the unexpected behavior of the composite chain.

Anyway, thank you for created such a cool project!

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