how to pass image buffer data to gm in() GraphicsMagic

故事扮演 提交于 2019-12-03 22:07:43

Without modifying the source of GraphicsMagick itself, you can't. The gm module interacts with the GraphicsMagick program through the command line. The arguments you're passing through the .in() method are being converted into command-line arguments. The GraphicsMagick program only accepts filenames for this argument and will not attempt to process any direct form of data.

If you really needed to make this work without the filesystem, you could always download the GraphicsMagick source code and change the CLI to accept some form of data blob instead of a URL for this argument.

Actually I was creating a poster with two different image one is template image "background" and 2nd is top image with some text. I tried with gm but i loose image quality. Someone guide me to use Buffer data as input to improve the image quality. I tried but don't know how to pass Buffer data as an input. So finally i decided to use node child process with command string. Here is the sample code i am sharing with you.

var fs = require('fs');

var gm = require("gm");
var exec = require('child_process').exec;
var IMAGEFILEPATH = "/images";
var gmcreateImage = function() {

var imageConfig = {"topimage":{"density":"300x300","startx":925,"starty":650,"width":575,"height":825},
 "offers": [
          {"startx": 75, "starty": 850, "msg": "SAVE 5$", "textcolor": "#4f61ac", "font": "Arial Bold", "fontsize":34,"stroke":{"color":"#4f61ac","width":4}},
          {"startx": 75, "starty": 970, "msg": "per gallon", "textcolor": "#4f61ac", "font": "Arial Bold", "fontsize":34,"stroke":{"color":"#4f61ac","width":4}},
          {"startx": 75, "starty": 1150, "msg": "With the purchase of", "textcolor": "black", "font": "Arial", "fontsize":18,"stroke":{"color":"black","width":1}},
          {"startx": 75, "starty": 1260, "msg": "any Pepsi Z0 S2", "textcolor": "black", "font": "Arial", "fontsize":16,"stroke":{"color":"black","width":1}},
          {"startx": 75, "starty": 1370, "msg": "on all flavours", "textcolor": "black", "font": "Arial", "fontsize":16,"stroke":{"color":"black","width":1}},
          {"startx": 75, "starty": 1480, "msg": "Ask for details.", "textcolor": "black", "font": "Arial", "fontsize":18,"stroke":{"color":"black","width":1}}
]};
    var addLast=imageConfig.topimage.last;
    var commandStr = "gm convert '-page' '+0+0' '-units' 'PixelsPerInch' '-density' '" + imageConfig.topimage.density + "' '" + IMAGEFILEPATH+ "/template.jpg' ";

    var imageActualPosition={};
    imageActualPosition["x"] = imageConfig.topimage.startx;
    imageActualPosition["y"] = imageConfig.topimage.starty;

    if (!addLast) {
        commandStr += " '-page' '+" + imageActualPosition["x"] + "+" + imageActualPosition["y"] + "' '" + IMAGEFILEPATH + "/top.jpg' ";
    }

    var offers = imageConfig.offers;
    for (var i in offers) {
        var color = offers[i].textcolor;
        var startX = offers[i].startx;
        var startY = offers[i].starty;
        var font = offers[i].font;
        var fontSize = offers[i].fontsize;
        var msg = offers[i].msg;
        var offerStr = "";
        if (offers[i].stroke) {
            offerStr += " '-stroke' '" + offers[i].stroke.color + "' '-strokewidth' '" + offers[i].stroke.width + "'";
        }
        offerStr += " '-fill' '" + color + "' '-pointsize' '" + fontSize + "' '-draw' 'text " + startX + " " + startY + " \"" + msg + "\"'";
        commandStr += offerStr;
    }
    if (addLast) {
        commandStr += " '-page' '+" + imageActualPosition["x"] + "+" + imageActualPosition["y"] + "' '" + IMAGEFILEPATH + "/top.jpg' ";
    }
    var finalImage="done.jpg";
    commandStr += " '-mosaic' '-quality' '100' '" + IMAGEFILEPATH + finalImage + "'";
    exec(commandStr, function(err, stdout, stderr) {
            if (err) {
                console.log("Error while executing gm commands" + err);
                return;
            } else {
                console.log("Done See your image");
            }
    })
};
gmcreateImage();

As noted in another response, graphicsmagick doesn't allow a buffer as an input. However, interestingly, it does allow an HTTP URL as an input. If you are determined to get this to work without modifying graphicsmagick's source code, try something like this:

setup

Add the uuid module:

npm install uuid

Create a global object to hold the buffers:

const magickbuffers = {}

Create an http server in your script:

const uuid = require('uuid')
const http = require('http')
const magickserver = new http.Server()
const magickport = 9555

magickserver.on('request', (req, res) => {
  res.writeHead(200, { 'Content-Type': 'image/png' })
  if (magickbuffers[req.url]) {
    res.end(magickbuffers[req.url])
  }
  else {
    res.end("\n")
  }
})

magickserver.listen(magickport, () => {})

Create a prototype to supply a usable local url so graphicsmagick can find the buffer on the local server and hand it off as an image, and also to handle the storage of the buffer:

Object.prototype.openBuffer = function() {
  this.id = uuid()
  magickbuffers[`/${this.id}`] = this
  return `http://localhost:${magickport}/${this.id}`
}

Create another prototype to handle the cleanup of the buffer once you're completely done with it:

Object.prototype.closeBuffer = function() {
  delete magickbuffers[`/${this.id}`]
  return true
}

usage

Old example that is desired but doesn't work:

gm()
  .in('-page', '+0+0')
  .in(bufferone) // gm cant use a buffer here, this won't work
  .in('-page', '+50+20')
  .in(buffertwo) // or here
  .mosaic()
  .stream('png', function (err, stdout, stderr) {
    stdout.pipe(writestream)
  })

New method that works:

let one = bufferone.openBuffer() 
let two = buffertwo.openBuffer() 
gm()
  .in('-page', '+0+0')
  .in(one) // gm recognizes this because 'one' is a url pointing to the buffer
  .in('-page', '+50+20')
  .in(two)
  .mosaic()
  .stream('png', function (err, stdout, stderr) {
    stdout.pipe(writestream)
    bufferone.closeBuffer() // do this once gm has completely finished using these buffers
    buffertwo.closeBuffer() // don't forget to do this for each buffer manipulated with .openBuffer()
  })    

I haven't figured out how to do it with both an image and the watermark as buffers, but I have figured out how to keep the image as a buffer:

gm(imageBuffer)
    .composite('./logo_path.png')
    .geometry(geometry)
    .gravity('SouthEast')
    .dissolve(this.options.opacity)
    .toBuffer(function (err, buffer) {
      next(err, buffer, 'image/jpeg');
    });
};

Check out the code in this great library for more info.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!