How to use graphicsmagick in node.js to crop circle picture (other use any other way to make this on node.js)

旧巷老猫 提交于 2019-12-13 00:38:59

问题


How to use graphicsmagick crop circle picture?

(use png transparent background outer circle)

I use graphicsmagick in node.js , or have any other way make this in node.js?

Before: http://i.stack.imgur.com/B34C5.png

After: http://i.stack.imgur.com/PWjQW.png


回答1:


After many hours of fiddling, I found a clean solution using node-gm and Imagemagick.

var gm = require('gm').subClass({ imageMagick: true });

var original = 'app-server/photo.jpg'; 
var output = 'app-server/photo.png';
var size = 80;

gm(original)
  .crop(233, 233,29,26)
  .resize(size, size)
  .write(output, function() {

     gm(size, size, 'none')
        .fill(output)
        .drawCircle(size/2,size/2, size/2, 0)
        .write(output, function(err) {
           console.log(err || 'done');
        });
  });



回答2:


I use another module to solve this problem:

this code is for square image (this.height = this.width)

node-pngjs

var fs = require('fs'),
PNG = require('pngjs').PNG;

fs.createReadStream(__dirname + "/input.png")
    .pipe(new PNG({
        filterType: 4
    }))
    .on('parsed', function() {
    for (var y = 0; y < this.height; y++) {
        for (var x = 0; x < this.width; x++) {
            var idx = (this.width * y + x) << 2;
            var radius = this.height / 2;
            if(y >= Math.sqrt(Math.pow(radius, 2) - Math.pow(x - radius, 2)) + radius || y <= -(Math.sqrt(Math.pow(radius, 2) - Math.pow(x - radius, 2))) + radius) {
                this.data[idx + 3] = 0;
            }
        }
    }
        this.pack().pipe(fs.createWriteStream(__dirname + "/output.png"));
    });



回答3:


I was able to do it with the following plugin: https://www.npmjs.com/package/circle-image

After you install it:

var images = require('circle-image');
var imageSizes = [125, 100, 30];
//uniqueId param is used to identify a user 
//so user the primary key or something guaranteed to be unique 
images.execute('imagepath', uniqueId, imageSizes).then(function (paths) {
  //array of circularized image paths 
  console.log(paths[0]); //circle_user_{uniqueId}_150.png 
})



回答4:


Took me hours to figure it out

  1. I wanted to avoid third party software, like ImageMagick (many npm packages are built on top of that)
  2. node-pngjs only appears to support PNG files + requires too much custom code

Here is my solution using sharp:

const sharp = require('sharp');

const width = 400,
    r = width / 2,
    circleShape = Buffer.from(`<svg><circle cx="${r}" cy="${r}" r="${r}" /></svg>`);

sharp('input.jpg')
    .resize(width, width)
    .composite([{
        input: circleShape,
        blend: 'dest-in'
    }])
    .webp()
    .toFile('output.webp', (err, info) => err ?
        console.error(err.message) :
        console.log(info)
    );

If you are interested, basing on the code above I created a utility that gets base64 encoded image (from frontend), and outputs file stream with the circle image. Used temp-write package to save processed images in temp directory.:

const fs = require('fs'),
    sharp = require('sharp'),
    tempWrite = require('temp-write');

module.exports = {
    toCircle: (base64String, width) => new Promise((resolve, reject) => {
        const imageBuffer = Buffer.from(base64String, "base64"),
            tmpImage = tempWrite.sync('', 'tmp.webp'),
            r = width / 2,
            circleShape = Buffer.from(`<svg><circle cx="${r}" cy="${r}" r="${r}" /></svg>`);

        sharp(imageBuffer)
            .resize(width, width)
            .composite([{
                input: circleShape,
                blend: 'dest-in'
            }])
            .webp()
            .toFile(tmpImage, (err) => err ?
                reject(err.message) :
                resolve(fs.createReadStream(tmpImage))
            );
    })
};



回答5:


Here is version using gm and buffers:

var gm = require('gm').subClass({ imageMagick: true });
var max = 200;
// buffer - is Buffer with picture

gm(buffer)
    .autoOrient()
    .gravity('Center')
    .resize(max, max, '^')
    .extent(max, max)
    .noProfile()
    .setFormat('png')
    .out('(')
        .rawSize(max, max)
        .out('xc:Black')
        .fill('White')
        .drawCircle(max/2,max/2, max/2, 1)
        .out('-alpha', 'Copy')
    .out(')')
    .compose('CopyOpacity')
    .out('-composite')
    .trim()
    .toBuffer((err, buffer) => {
        //...
    });

The above node.js code is equivalent to this ImageMagick command, but using buffers:

convert input.png \
        -gravity Center \
        -resize 200x200^ \
        -extent 200x200 \
        \( -size 200x200 \
           xc:Black \
           -fill White \
           -draw 'circle 100 100 100 1' \
           -alpha Copy \
        \) -compose CopyOpacity -composite \
        -trim output.png


来源:https://stackoverflow.com/questions/29256640/how-to-use-graphicsmagick-in-node-js-to-crop-circle-picture-other-use-any-other

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