4

Given two images, say under img (in size of 1024x768) folder (img1.png and img2.png), I need to resize img2 (say 300x300) and put on img1 in x and y (say 100, 200) from top left of img1. The end result should be 1024x768 size image.

Using gm (https://github.com/aheckmann/gm), tried this:

gm('./img/img1.png')
.composite('./img/img2.png')
.geometry('300x300+100+200')
.write('resultGM.png', (err) => {
  if (err) console.log(err);
});

Expectedly (because of chain on whole operation) it produces 300x300 image. Then I tried this:

gm('./img/img1.png')
.composite(
  gm('./img/img2.png')
  .geometry('300x300+100+200')
)
.write('resultGM.png', (err) => {
  if (err) console.log(err);
});

hoping composite function accepts buffer, but no chance, it only accepts file path, and it gives error. After spending 2-3 hours and reading few posts (only could find some discussions here: How to do composite with gm node.js? and here: Combine two gm objects while resizing one of them in graphicsMagick for NodeJS (this one doesn't answer the question in fact), I couldn't find any solution to do this operation in memory using streams or buffer. It's possible to do while writing to a temporary file. Is there any body out there who could find a solution for in memory resize and merge images on the fly?

Community
  • 1
  • 1
Ahmet Cetin
  • 3,683
  • 3
  • 25
  • 34

3 Answers3

4

Using ImageMagick instead of GraphicMagic;

After a few hours of searching finally i have figured out how to merge two images resizing and re-ordering layer positions (over, under, etc.) using gm.

Let's have a look this image first:

enter image description here

After a few minutes digging up ImageMagick's compose help page, i saw the usage of DstOver positioning.

http://www.imagemagick.org/Usage/compose/#dstover

So, i have tried this code below and it worked like a charm!

imageMagick(background)
    .composite(image)
    .in('-compose', 'Dst_Over')
    .in('-geometry', '253x253+15+15')
    .write(output, function (err) {
    if (err) console.error(err);
        else console.log('Compose OK!');
    });
Canser Yanbakan
  • 3,780
  • 3
  • 39
  • 65
1

Finally I could do it, here I post for reference for anyone may need it:

gm()
.in('-geometry', '+0+0')
.in('./img/img1.png')
.in('-geometry', '300x300+100+200')
.in('./img/img2.png')
.flatten()
.write('resultGM.png', function (err) {
  if (err) console.log(err);
});
Ahmet Cetin
  • 3,683
  • 3
  • 25
  • 34
0

You can use gravity to help postion your layer and then use geometry to dial it in like:

import * as graphics from 'gm';
const gm = graphics.subClass({ imageMagick: true });

type GravityDirection = 'NorthWest'
    | 'North'
    | 'NorthEast'
    | 'West'
    | 'Center'
    | 'East'
    | 'SouthWest'
    | 'South'
    | 'SouthEast';


 gm('pathToTopLayerImg')
   .in('pathToBaseImg')
   .gravity('Center')
   .geometry('+10+10')
   .out('-composite')
   .write('pathToDestination', err => {
      if (err) console.log(err);
   })

If you want to add additional layers to your base image then:

 gm('pathToFirstLayerImg')
   .in('pathToBaseImg')
   .gravity('Center')
   .geometry('+10+10')
   .out('-composite')
   .out('pathToSecondLayer')
   .out('-gravity', 'NorthWest')
   .out('-geometry', '+10+10')
   .out('-composite')
   .write('pathToDestination', err => {
      if (err) console.log(err);
   })

You can add as many layers as you like with this pattern but keep in mind that it will read all images into memory so you may want to only do two at a time if you have a lot of layers composed of large images.

tommyc38
  • 703
  • 1
  • 8
  • 21