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

Using resize after composite causes merging of composited images? #1908

Closed
mz8i opened this issue Oct 7, 2019 · 4 comments
Closed

Using resize after composite causes merging of composited images? #1908

mz8i opened this issue Oct 7, 2019 · 4 comments
Labels

Comments

@mz8i
Copy link

mz8i commented Oct 7, 2019

What is the output of running npx envinfo --binaries --languages --system --utilities?

  System:
    OS: Linux 4.13 Ubuntu 19.04 (Disco Dingo)
    CPU: (4) x64 Intel(R) Core(TM) i5-2540M CPU @ 2.60GHz
    Memory: 2.25 GB / 15.55 GB
    Container: Yes
    Shell: 5.5.1 - /bin/zsh
  Binaries:
    Node: 8.11.4 - ~/.nvm/versions/node/v8.11.4/bin/node
    npm: 6.11.2 - ~/.nvm/versions/node/v8.11.4/bin/npm
  Utilities:
    Make: 4.2.1 - /usr/bin/make
    GCC: 8.3.0 - /usr/bin/gcc
    Git: 2.20.1 - /usr/bin/git
    Mercurial: 4.8.2 - /usr/bin/hg
    FFmpeg: 4.1.3 - /usr/bin/ffmpeg
  Languages:
    Bash: 5.0.3 - /bin/bash
    Java: 1.8.0_222 - /usr/bin/javac
    Perl: 5.28.1 - /usr/bin/perl
    PHP: 7.2.19 - /usr/bin/php
    Python: 2.7.16 - /usr/bin/python
    Python3: 3.7.3 - /usr/bin/python3
    R: 3.5.2 - /usr/bin/R
    Ruby: 2.5.5 - /usr/bin/ruby

What are the steps to reproduce?
Stitch four 256x256 images into one 512x512 image, then resize the full result to 256x256.

What is the expected behaviour?
The result should be a single 256x256 image where each quarter of the image is one of the four composited 256x256 images. Not sure if I am using resize in the wrong way, however.

Are you able to provide a standalone code sample, without other dependencies, that demonstrates this problem?
Run this code to see the problem. Comment out the resize line to see the code correctly producing a 512x512 image.

const sharp = require('sharp');

const tileSize = 256;

(async function() {
    const topLeft = await sharp({
            create: {
                width: tileSize,
                height: tileSize,
                channels: 4,
                background: {r: 255, g: 255, b: 0, alpha: 0.5}
            }
        }).png().toBuffer(),
        topRight = await sharp({
            create: {
                width: tileSize,
                height: tileSize,
                channels: 4,
                background: { r: 255, g: 0, b: 255, alpha: 0.5 }
            }
        }).png().toBuffer(),
        bottomLeft = await sharp({
            create: {
                width: tileSize,
                height: tileSize,
                channels: 4,
                background: { r: 0, g: 255, b: 255, alpha: 0.5 }
            }
        }).png().toBuffer(),
        bottomRight = await sharp({
            create: {
                width: tileSize,
                height: tileSize,
                channels: 4,
                background: { r: 0, g: 0, b: 0, alpha: 0.5 }
            }
        }).png().toBuffer();

    await sharp({
        create: {
            width: tileSize * 2,
            height: tileSize * 2,
            channels: 4,
            background: {r: 255, g: 255, b: 255, alpha: 1}
        }
    }).composite([
        {
            input: topLeft,
            top: 0,
            left: 0
        },
        {
            input: topRight,
            top: 0,
            left: tileSize
        },
        {
            input: bottomLeft,
            top: tileSize,
            left: 0
        },
        {
            input: bottomRight,
            top: tileSize,
            left: tileSize
        }
    ])
    .resize(tileSize, tileSize, { fit: 'fill'}) // comment out this line to get result without resizing
    .png().toFile('test.png');
})();

Are you able to provide a sample image that helps explain the problem?

actual result:
test

result with resize() line commented out:
test

desired result:
test-resized

@lovell
Copy link
Owner

lovell commented Oct 9, 2019

Hi, you'll need to break this into two pipelines, the first to composite and the second to resize.

const composited = await sharp({ ... }).composite({ ... }).png().toBuffer();
const resized = await sharp(composited).resize({ ... }).toBuffer();

or you could use Streams:

const compositor = sharp({ ... }).composite({ ... }).png();
const resizer = sharp().resize({ ... });

compositor.pipe(resizer).pipe( ... );

You should be able to improve the performance of the composite operation by directly creating images, something like (untested):

.composite([
        {
-           input: topLeft,
+           input: create: {
+               width: tileSize,
+               height: tileSize,
+               channels: 4,
+               background: {r: 255, g: 255, b: 0, alpha: 0.5}
+           },
            top: 0,
            left: 0
        },

Please see #1580 for a future possible enhancement that you might like to subscribe to.

@lovell lovell added question and removed triage labels Oct 9, 2019
@mz8i
Copy link
Author

mz8i commented Oct 9, 2019

Thanks @lovell - what is the reason this doesn't work as I expected? Is it because the order of operations in a single pipeline is not preserved, and resize happends before composite? If so, maybe it would be good to highlight that fact in the docs for newcomers - unless I've missed it.

Indeed I have used two pipelines as a solution, but was hoping maybe I can further reduce it to one if I figure out what doesn't work.
Thanks for the performance suggestion - actually this was just a reproducible example, in my case the tiles come from an external source as PNG buffers.

@lovell
Copy link
Owner

lovell commented Oct 14, 2019

You may be interested in the discussion at #241.

@lovell
Copy link
Owner

lovell commented Nov 5, 2019

I hope this information helped. Please feel free to re-open with more details if further help is required.

@lovell lovell closed this as completed Nov 5, 2019
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