Magick++ ports wave 3, fixed issues with avatar and globe

This commit is contained in:
TheEssem 2020-07-20 17:10:04 -05:00
parent 8d1a560343
commit 264bcf5425
32 changed files with 479 additions and 92 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

View File

@ -5,7 +5,7 @@ exports.run = async (message) => {
message.channel.sendTyping();
const image = await require("../utils/imagedetect.js")(message);
if (image === undefined) return `${message.author.mention}, you need to provide an image to add a 9GAG watermark!`;
const buffer = await promisify(magick.watermark)(image.path, "./assets/images/9gag.png", 6, false, image.type.toUpperCase(), image.delay ? (100 / image.delay.split("/")[0]) * image.delay.split("/")[1] : 0);
const buffer = await promisify(magick.watermark)(image.path, "./assets/images/9gag.png", 6, false, false, false, image.type.toUpperCase(), image.delay ? (100 / image.delay.split("/")[0]) * image.delay.split("/")[1] : 0);
return {
file: buffer,
name: `9gag.${image.type}`

View File

@ -12,7 +12,7 @@ exports.run = async (message, args) => {
});
return member ? member.user.dynamicAvatarURL(null, 1024) : message.author.user.dynamicAvatarURL(null, 1024);
} else {
return message.author.user.dynamicAvatarURL(null, 1024);
return message.author.dynamicAvatarURL(null, 1024);
}
};

View File

@ -5,7 +5,7 @@ exports.run = async (message) => {
message.channel.sendTyping();
const image = await require("../utils/imagedetect.js")(message);
if (image === undefined) return `${message.author.mention}, you need to provide an image to add a Bandicam watermark!`;
const buffer = await promisify(magick.watermark)(image.path, "./assets/images/bandicam.png", 2, true, image.type.toUpperCase(), image.delay ? (100 / image.delay.split("/")[0]) * image.delay.split("/")[1] : 0);
const buffer = await promisify(magick.watermark)(image.path, "./assets/images/bandicam.png", 2, true, false, false, image.type.toUpperCase(), image.delay ? (100 / image.delay.split("/")[0]) * image.delay.split("/")[1] : 0);
return {
file: buffer,
name: `bandicam.${image.type}`

View File

@ -5,7 +5,7 @@ exports.run = async (message) => {
message.channel.sendTyping();
const image = await require("../utils/imagedetect.js")(message);
if (image === undefined) return `${message.author.mention}, you need to provide an image to add a DeviantArt watermark!`;
const buffer = await promisify(magick.watermark)(image.path, "./assets/images/deviantart.png", 5, true, image.type.toUpperCase(), image.delay ? (100 / image.delay.split("/")[0]) * image.delay.split("/")[1] : 0);
const buffer = await promisify(magick.watermark)(image.path, "./assets/images/deviantart.png", 5, true, false, false, image.type.toUpperCase(), image.delay ? (100 / image.delay.split("/")[0]) * image.delay.split("/")[1] : 0);
return {
file: buffer,
name: `deviantart.${image.type}`

View File

@ -5,7 +5,7 @@ exports.run = async (message) => {
message.channel.sendTyping();
const image = await require("../utils/imagedetect.js")(message);
if (image === undefined) return `${message.author.mention}, you need to provide an image to add New Funky Mode!`;
const buffer = await promisify(magick.watermark)(image.path, "./assets/images/funky.png", 3, true, image.type.toUpperCase(), image.delay ? (100 / image.delay.split("/")[0]) * image.delay.split("/")[1] : 0);
const buffer = await promisify(magick.watermark)(image.path, "./assets/images/funky.png", 3, true, false, false, image.type.toUpperCase(), image.delay ? (100 / image.delay.split("/")[0]) * image.delay.split("/")[1] : 0);
return {
file: buffer,
name: `funky.${image.type}`

View File

@ -1,14 +1,11 @@
const gm = require("gm").subClass({
imageMagick: true
});
const magick = require("../build/Release/image.node");
const { promisify } = require("util");
exports.run = async (message) => {
message.channel.sendTyping();
const image = await require("../utils/imagedetect.js")(message);
if (image === undefined) return `${message.author.mention}, you need to provide an image to mirror!`;
const data = `/tmp/${Math.random().toString(36).substring(2, 15)}.miff`;
await gm(image.path).coalesce().gravity("West").crop("50%", 0).out("+repage").writePromise(data);
const buffer = await gm(data).extent("%[fx:u.w*2]", "%[fx:u.h]").out("null:").out("(").out(data).flop().out(")").gravity("East").out("-layers", "Composite").bufferPromise(image.type, image.delay);
const buffer = await promisify(magick.mirror)(image.path, false, true, image.type.toUpperCase(), image.delay ? (100 / image.delay.split("/")[0]) * image.delay.split("/")[1] : 0);
return {
file: buffer,
name: `haah.${image.type}`

View File

@ -1,16 +1,11 @@
const gm = require("gm").subClass({
imageMagick: true
});
const magick = require("../build/Release/image.node");
const { promisify } = require("util");
exports.run = async (message) => {
message.channel.sendTyping();
const image = await require("../utils/imagedetect.js")(message);
if (image === undefined) return `${message.author.mention}, you need to provide an image to mirror!`;
const data = `/tmp/${Math.random().toString(36).substring(2, 15)}.miff`;
const size = await gm(image.path).sizePromise();
await gm(image.path).coalesce().gravity("South").crop(0, "50%").out("+repage").writePromise(data);
// const buffer = await gm(data2).extent("%[fx:u.w]", "%[fx:u.h*2]").out("null:").out(data).gravity("North").out("-layers", "Composite").bufferPromise(image.type, image.delay);
const buffer = await gm(data).extent(size.width, size.height).out("null:").out("(").out(data).flip().out(")").geometry(`+0+${size.height / 2}`).out("-layers", "Composite").bufferPromise(image.type, image.delay);
const buffer = await promisify(magick.mirror)(image.path, true, false, image.type.toUpperCase(), image.delay ? (100 / image.delay.split("/")[0]) * image.delay.split("/")[1] : 0);
return {
file: buffer,
name: `hooh.${image.type}`

View File

@ -1,13 +1,11 @@
const gm = require("gm").subClass({
imageMagick: true
});
const magick = require("../build/Release/image.node");
const { promisify } = require("util");
exports.run = async (message) => {
message.channel.sendTyping();
const image = await require("../utils/imagedetect.js")(message);
if (image === undefined) return `${message.author.mention}, you need to provide an image to add a Hypercam watermark!`;
const watermark = "./assets/images/hypercam.png";
const buffer = await gm(image.path).coalesce().out("null:").out(watermark).gravity("NorthWest").scale(null, "%[fx:u.h]").out("-layers", "composite").bufferPromise(image.type, image.delay);
const buffer = await promisify(magick.watermark)(image.path, "./assets/images/hypercam.png", 1, true, false, false, image.type.toUpperCase(), image.delay ? (100 / image.delay.split("/")[0]) * image.delay.split("/")[1] : 0);
return {
file: buffer,
name: `hypercam.${image.type}`

View File

@ -1,13 +1,11 @@
const gm = require("gm").subClass({
imageMagick: true
});
const magick = require("../build/Release/image.node");
const { promisify } = require("util");
exports.run = async (message) => {
message.channel.sendTyping();
const image = await require("../utils/imagedetect.js")(message);
if (image === undefined) return `${message.author.mention}, you need to provide an image to add a iFunny watermark!`;
const watermark = "./assets/images/ifunny.png";
const buffer = await gm(image.path).coalesce().extent("%[fx:u.w]", "%[fx:u.h+(42*min(u.w/1024,u.h/42))]").out("null:").out(watermark).gravity("South").scale("%[fx:u.w]", null).out("-layers", "composite").bufferPromise(image.type, image.delay);
const buffer = await promisify(magick.watermark)(image.path, "./assets/images/ifunny.png", 8, true, true, false, image.type.toUpperCase(), image.delay ? (100 / image.delay.split("/")[0]) * image.delay.split("/")[1] : 0);
return {
file: buffer,
name: `ifunny.${image.type}`

View File

@ -1,12 +1,11 @@
const gm = require("gm").subClass({
imageMagick: true
});
const magick = require("../build/Release/image.node");
const { promisify } = require("util");
exports.run = async (message) => {
message.channel.sendTyping();
const image = await require("../utils/imagedetect.js")(message);
if (image === undefined) return `${message.author.mention}, you need to provide an image to implode!`;
const buffer = await gm(image.path).implode([1]).bufferPromise(image.type, image.delay);
const buffer = await promisify(magick.explode)(image.path, 1, image.type.toUpperCase(), image.delay ? (100 / image.delay.split("/")[0]) * image.delay.split("/")[1] : 0);
return {
file: buffer,
name: `implode.${image.type}`

View File

@ -1,12 +1,11 @@
const gm = require("gm").subClass({
imageMagick: true
});
const magick = require("../build/Release/image.node");
const { promisify } = require("util");
exports.run = async (message) => {
message.channel.sendTyping();
const image = await require("../utils/imagedetect.js")(message);
if (image === undefined) return `${message.author.mention}, you need to provide an image to add more JPEG!`;
const buffer = await gm(`${image.path}[0]`).quality(1).bufferPromise("jpg");
const buffer = await promisify(magick.jpeg)(image.path);
return {
file: buffer,
name: "jpeg.jpg"

View File

@ -1,15 +1,12 @@
const gm = require("gm").subClass({
imageMagick: true
});
const magick = require("../build/Release/image.node");
const { promisify } = require("util");
exports.run = async (message) => {
message.channel.sendTyping();
const image = await require("../utils/imagedetect.js")(message);
if (image === undefined) return `${message.author.mention}, you need to provide an image to make a Super Smash Bros. leak meme!`;
if (image.type === "gif") return `${message.author.mention}, this command doesn't work with GIFs!`;
const template = "./assets/images/leak.png";
const buffer = await gm(template).out("-background").out("white").out("-gravity").out("Center").out("(").out("-clone").out("0").out("(").out(image.path).out("-virtual-pixel").out("white").out("-resize").out("640x360!").rotate("white", 15).out(")").out("-geometry").out("+450-200").out("-composite").out(")").out("+swap").out("-composite").out("-alpha").out("remove").out("-alpha").out("off").bufferPromise(image.type, image.delay);
// const command = gm(template).out("-background", "white").gravity("Center").out("null:").out("(").out(path).out("-resize", "640x360!").out("-virtual-pixel", "white").rotate("white", 15).coalesce().geometry("+450-200").out(")").compose("over").out("-alpha", "remove").out("-alpha", "off").out("-layers", "composite");
const buffer = await promisify(magick.leak)(image.path, image.type.toUpperCase(), image.delay ? (100 / image.delay.split("/")[0]) * image.delay.split("/")[1] : 0);
//const buffer = await gm(template).out("-background").out("white").out("-gravity").out("Center").out("(").out("-clone").out("0").out("(").out(image.path).out("-virtual-pixel").out("white").out("-resize").out("640x360!").rotate("white", 15).out(")").out("-geometry").out("+450-200").out("-composite").out(")").out("+swap").out("-composite").out("-alpha").out("remove").out("-alpha").out("off").bufferPromise(image.type, image.delay);
return {
file: buffer,
name: `leak.${image.type}`

View File

@ -1,16 +1,14 @@
const gm = require("gm").subClass({
imageMagick: true
});
const magick = require("../build/Release/image.node");
const { promisify } = require("util");
exports.run = async (message) => {
const image = await require("../utils/imagedetect.js")(message);
if (image === undefined) return `${message.author.mention}, you need to provide an image to add some magik!`;
if (image.type === "gif") return `${message.author.mention}, this command doesn't work with GIFs!`;
const processMessage = await message.channel.createMessage("<a:processing:479351417102925854> Processing... This might take a while");
const resultBuffer = await gm(image.path).in("(").in("(").coalesce().scale(600, 600).out(")").out("-liquid-rescale", "300x300").out(")").out("-liquid-rescale", "600x600").bufferPromise(image.type, image.delay);
const buffer = await promisify(magick.magik)(image.path, image.type.toUpperCase(), image.delay ? (100 / image.delay.split("/")[0]) * image.delay.split("/")[1] : 0);
await processMessage.delete();
return {
file: resultBuffer,
file: buffer,
name: `magik.${image.type}`
};
};

View File

@ -1,6 +1,5 @@
const gm = require("gm").subClass({
imageMagick: true
});
const magick = require("../build/Release/image.node");
const { promisify } = require("util");
exports.run = async (message, args) => {
message.channel.sendTyping();
@ -9,13 +8,14 @@ exports.run = async (message, args) => {
const newArgs = args.filter(item => !item.includes(image.url) );
if (args.length === 0) return `${message.author.mention}, you need to provide some text to generate a meme!`;
const [topText, bottomText] = newArgs.join(" ").split(/(?<!\\),/).map(elem => elem.trim());
const file = `/tmp/${Math.random().toString(36).substring(2, 15)}.miff`;
/*const file = `/tmp/${Math.random().toString(36).substring(2, 15)}.miff`;
const file2 = `/tmp/${Math.random().toString(36).substring(2, 15)}.png`;
const file3 = `/tmp/${Math.random().toString(36).substring(2, 15)}.png`;
await gm(image.path).coalesce().scale(600, 600).noProfile().writePromise(file);
await gm(file).out("-size", "%[fx:u.w]").out("-delete", "0--1").background("none").gravity("Center").out("(", "(").font("Impact").out("-pointsize", 40).out(`pango:<span foreground='white'>${topText.toUpperCase().replace(/&/g, "\\&amp;").replace(/>/g, "\\&gt;").replace(/</g, "\\&lt;").replace(/"/g, "\\&quot;").replace(/'/g, "\\&apos;")}</span>`).out(")", "(", "+clone").out("-alpha", "extract").out("-morphology", "EdgeOut", "Octagon", "-background", "black", "-alpha", "shape", ")").compose("DstOver").out(")", "-composite").writePromise(file2);
if (bottomText) await gm(file).out("-size", "%[fx:u.w]").out("-delete", "0--1").background("none").gravity("Center").out("(", "(").font("Impact").out("-pointsize", 40).out(`pango:<span foreground='white'>${bottomText.toUpperCase().replace(/&/g, "\\&amp;").replace(/>/g, "\\&gt;").replace(/</g, "\\&lt;").replace(/"/g, "\\&quot;").replace(/'/g, "\\&apos;")}</span>`).out(")", "(", "+clone").out("-alpha", "extract").out("-morphology", "EdgeOut", "Octagon", "-background", "black", "-alpha", "shape", ")").compose("DstOver").out(")", "-composite").writePromise(file3);
const buffer = await gm(file).out("-coalesce").out("null:").gravity("North").out(file2).out("-layers", "composite").out("null:").gravity("South").out(bottomText ? file3 : "null:").out("-layers", "composite").bufferPromise(image.type, image.delay);
const buffer = await gm(file).out("-coalesce").out("null:").gravity("North").out(file2).out("-layers", "composite").out("null:").gravity("South").out(bottomText ? file3 : "null:").out("-layers", "composite").bufferPromise(image.type, image.delay);*/
const buffer = await promisify(magick.meme)(image.path, topText.toUpperCase().replace(/&/g, "\\&amp;").replace(/>/g, "\\&gt;").replace(/</g, "\\&lt;").replace(/"/g, "\\&quot;").replace(/'/g, "\\&apos;"), bottomText ? bottomText.toUpperCase().replace(/&/g, "\\&amp;").replace(/>/g, "\\&gt;").replace(/</g, "\\&lt;").replace(/"/g, "\\&quot;").replace(/'/g, "\\&apos;") : "", image.type.toUpperCase(), image.delay ? (100 / image.delay.split("/")[0]) * image.delay.split("/")[1] : 0);
return {
file: buffer,
name: `meme.${image.type}`

View File

@ -1,15 +1,13 @@
const gm = require("gm").subClass({
imageMagick: true
});
const magick = require("../build/Release/image.node");
const { promisify } = require("util");
exports.run = async (message) => {
message.channel.sendTyping();
const image = await require("../utils/imagedetect.js")(message);
if (image === undefined) return `${message.author.mention}, you need to provide an image to add a MemeCenter watermark!`;
const watermark = "./assets/images/memecenter.png";
const output = await gm(image.path).coalesce().background("white").extent("%[fx:u.w]", "%[fx:u.h+15]").out("null:").out(watermark).gravity("SouthEast").compose("over").out("-layers", "composite").bufferPromise(image.type, image.delay);
const buffer = await promisify(magick.watermark)(image.path, "./assets/images/memecenter.png", 9, false, false, true, image.type.toUpperCase(), image.delay ? (100 / image.delay.split("/")[0]) * image.delay.split("/")[1] : 0);
return {
file: output,
file: buffer,
name: `memecenter.${image.type}`
};
};

View File

@ -7,8 +7,8 @@ using namespace Magick;
class ExplodeWorker : public Napi::AsyncWorker {
public:
ExplodeWorker(Napi::Function& callback, string in_path, string type, int delay)
: Napi::AsyncWorker(callback), in_path(in_path), type(type), delay(delay) {}
ExplodeWorker(Napi::Function& callback, string in_path, int amount, string type, int delay)
: Napi::AsyncWorker(callback), in_path(in_path), amount(amount), type(type), delay(delay) {}
~ExplodeWorker() {}
void Execute() {
@ -20,7 +20,7 @@ class ExplodeWorker : public Napi::AsyncWorker {
coalesceImages(&coalesced, frames.begin(), frames.end());
for (Image &image : coalesced) {
image.implode(-1);
image.implode(amount);
image.magick(type);
blurred.push_back(image);
}
@ -36,7 +36,7 @@ class ExplodeWorker : public Napi::AsyncWorker {
private:
string in_path, type;
int delay, wordlength, i, n;
int delay, wordlength, i, n, amount;
size_t bytes, type_size;
Blob blob;
};
@ -46,11 +46,12 @@ Napi::Value Explode(const Napi::CallbackInfo &info)
Napi::Env env = info.Env();
string in_path = info[0].As<Napi::String>().Utf8Value();
string type = info[1].As<Napi::String>().Utf8Value();
int delay = info[2].As<Napi::Number>().Int32Value();
Napi::Function cb = info[3].As<Napi::Function>();
int amount = info[1].As<Napi::Number>().Int32Value();
string type = info[2].As<Napi::String>().Utf8Value();
int delay = info[3].As<Napi::Number>().Int32Value();
Napi::Function cb = info[4].As<Napi::Function>();
ExplodeWorker* explodeWorker = new ExplodeWorker(cb, in_path, type, delay);
ExplodeWorker* explodeWorker = new ExplodeWorker(cb, in_path, amount, type, delay);
explodeWorker->Queue();
return env.Undefined();
}

View File

@ -18,8 +18,10 @@ class GlobeWorker : public Napi::AsyncWorker {
list<Image> mid;
list<Image> result;
Image distort;
Image overlay;
readImages(&frames, in_path);
distort.read("./assets/images/spheremap.png");
overlay.read("./assets/images/sphere_overlay.png");
coalesceImages(&coalesced, frames.begin(), frames.end());
if (type != "GIF") {
@ -30,12 +32,12 @@ class GlobeWorker : public Napi::AsyncWorker {
}
int i = 0;
for (Image &image : coalesced) {
image.scale(Geometry("500x500!"));
image.alphaChannel(Magick::SetAlphaChannel);
size_t width = image.columns();
image.roll(Geometry("+" + to_string(width * i / coalesced.size())));
image.composite(overlay, Magick::CenterGravity, Magick::HardLightCompositeOp);
image.composite(distort, Magick::CenterGravity, Magick::DistortCompositeOp);
image.magick("GIF");
mid.push_back(image);

View File

@ -12,6 +12,11 @@
#include "gamexplain.h"
#include "globe.h"
#include "invert.h"
#include "jpeg.h"
#include "leak.h"
#include "magik.h"
#include "meme.h"
#include "mirror.h"
#include "watermark.h"
Napi::Object Init(Napi::Env env, Napi::Object exports)
@ -29,6 +34,11 @@ Napi::Object Init(Napi::Env env, Napi::Object exports)
exports.Set(Napi::String::New(env, "gamexplain"), Napi::Function::New(env, Gamexplain));
exports.Set(Napi::String::New(env, "globe"), Napi::Function::New(env, Globe));
exports.Set(Napi::String::New(env, "invert"), Napi::Function::New(env, Invert));
exports.Set(Napi::String::New(env, "jpeg"), Napi::Function::New(env, Jpeg));
exports.Set(Napi::String::New(env, "leak"), Napi::Function::New(env, Leak));
exports.Set(Napi::String::New(env, "magik"), Napi::Function::New(env, Magik));
exports.Set(Napi::String::New(env, "meme"), Napi::Function::New(env, Meme));
exports.Set(Napi::String::New(env, "mirror"), Napi::Function::New(env, Mirror));
exports.Set(Napi::String::New(env, "watermark"), Napi::Function::New(env, Watermark));
return exports;
}

44
natives/jpeg.cc Normal file
View File

@ -0,0 +1,44 @@
#include <napi.h>
#include <list>
#include <iostream>
#include <Magick++.h>
using namespace std;
using namespace Magick;
class JpegWorker : public Napi::AsyncWorker {
public:
JpegWorker(Napi::Function& callback, string in_path)
: Napi::AsyncWorker(callback), in_path(in_path) {}
~JpegWorker() {}
void Execute() {
Image image;
image.read(in_path);
image.quality(1);
image.magick("JPEG");
image.write(&blob);
}
void OnOK() {
Callback().Call({Env().Undefined(), Napi::Buffer<char>::Copy(Env(), (char *)blob.data(), blob.length())});
}
private:
string in_path, type;
int delay, wordlength, i, n;
size_t bytes, type_size;
Blob blob;
};
Napi::Value Jpeg(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
string in_path = info[0].As<Napi::String>().Utf8Value();
Napi::Function cb = info[1].As<Napi::Function>();
JpegWorker* explodeWorker = new JpegWorker(cb, in_path);
explodeWorker->Queue();
return env.Undefined();
}

8
natives/jpeg.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef ESMBOT_NATIVES_JPEG_H_
#define ESMBOT_NATIVES_JPEG_H_
#include <napi.h>
Napi::Value Jpeg(const Napi::CallbackInfo& info);
#endif

60
natives/leak.cc Normal file
View File

@ -0,0 +1,60 @@
#include <napi.h>
#include <list>
#include <Magick++.h>
using namespace std;
using namespace Magick;
class LeakWorker : public Napi::AsyncWorker {
public:
LeakWorker(Napi::Function& callback, string in_path, string type, int delay)
: Napi::AsyncWorker(callback), in_path(in_path), type(type), delay(delay) {}
~LeakWorker() {}
void Execute() {
list<Image> frames;
list<Image> coalesced;
list<Image> mid;
Image watermark;
readImages(&frames, in_path);
watermark.read("./assets/images/leak.png");
coalesceImages(&coalesced, frames.begin(), frames.end());
for (Image &image : coalesced) {
image.backgroundColor("white");
image.scale(Geometry("640x360!"));
image.rotate(15);
image.extent(Geometry("1280x720-700+100"));
image.composite(watermark, Geometry("+0+0"), Magick::OverCompositeOp);
image.magick(type);
mid.push_back(image);
}
if (delay != 0) for_each(mid.begin(), mid.end(), animationDelayImage(delay));
writeImages(mid.begin(), mid.end(), &blob);
}
void OnOK() {
Callback().Call({Env().Undefined(), Napi::Buffer<char>::Copy(Env(), (char *)blob.data(), blob.length())});
}
private:
string in_path, type;
int delay, wordlength, i, n;
size_t bytes, type_size;
Blob blob;
};
Napi::Value Leak(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
string in_path = info[0].As<Napi::String>().Utf8Value();
string type = info[1].As<Napi::String>().Utf8Value();
int delay = info[2].As<Napi::Number>().Int32Value();
Napi::Function cb = info[3].As<Napi::Function>();
LeakWorker* blurWorker = new LeakWorker(cb, in_path, type, delay);
blurWorker->Queue();
return env.Undefined();
}

8
natives/leak.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef ESMBOT_NATIVES_LEAK_H_
#define ESMBOT_NATIVES_LEAK_H_
#include <napi.h>
Napi::Value Leak(const Napi::CallbackInfo& info);
#endif

58
natives/magik.cc Normal file
View File

@ -0,0 +1,58 @@
#include <napi.h>
#include <list>
#include <Magick++.h>
using namespace std;
using namespace Magick;
class MagikWorker : public Napi::AsyncWorker {
public:
MagikWorker(Napi::Function& callback, string in_path, string type, int delay)
: Napi::AsyncWorker(callback), in_path(in_path), type(type), delay(delay) {}
~MagikWorker() {}
void Execute() {
list<Image> frames;
list<Image> coalesced;
list<Image> blurred;
list<Image> result;
readImages(&frames, in_path);
coalesceImages(&coalesced, frames.begin(), frames.end());
for (Image &image : coalesced) {
image.scale(Geometry("350x350"));
image.liquidRescale(Geometry("175x175"));
image.liquidRescale(Geometry("350x350"));
image.magick(type);
blurred.push_back(image);
}
optimizeImageLayers(&result, blurred.begin(), blurred.end());
if (delay != 0) for_each(result.begin(), result.end(), animationDelayImage(delay));
writeImages(result.begin(), result.end(), &blob);
}
void OnOK() {
Callback().Call({Env().Undefined(), Napi::Buffer<char>::Copy(Env(), (char *)blob.data(), blob.length())});
}
private:
string in_path, type;
int delay, wordlength, i, n, amount;
size_t bytes, type_size;
Blob blob;
};
Napi::Value Magik(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
string in_path = info[0].As<Napi::String>().Utf8Value();
string type = info[1].As<Napi::String>().Utf8Value();
int delay = info[2].As<Napi::Number>().Int32Value();
Napi::Function cb = info[3].As<Napi::Function>();
MagikWorker* explodeWorker = new MagikWorker(cb, in_path, type, delay);
explodeWorker->Queue();
return env.Undefined();
}

8
natives/magik.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef ESMBOT_NATIVES_MAGIK_H_
#define ESMBOT_NATIVES_MAGIK_H_
#include <napi.h>
Napi::Value Magik(const Napi::CallbackInfo& info);
#endif

89
natives/meme.cc Normal file
View File

@ -0,0 +1,89 @@
#include <napi.h>
#include <iostream>
#include <list>
#include <Magick++.h>
using namespace std;
using namespace Magick;
class MemeWorker : public Napi::AsyncWorker {
public:
MemeWorker(Napi::Function& callback, string in_path, string text_top, string text_bottom, string type, int delay)
: Napi::AsyncWorker(callback), in_path(in_path), text_top(text_top), text_bottom(text_bottom), type(type), delay(delay) {}
~MemeWorker() {}
void Execute() {
list<Image> frames;
list<Image> coalesced;
list<Image> mid;
Image top_text;
Image bottom_text;
readImages(&frames, in_path);
coalesceImages(&coalesced, frames.begin(), frames.end());
for_each(coalesced.begin(), coalesced.end(), scaleImage(Geometry(600, 600)));
top_text.size(Geometry(to_string(coalesced.front().columns())));
top_text.backgroundColor("none");
top_text.font("Impact");
top_text.fontPointsize(40);
top_text.textGravity(Magick::CenterGravity);
top_text.read("pango:<span foreground='white'>" + text_top + "</span>");
Image top_text_fill = top_text;
top_text_fill.channel(Magick::AlphaChannel);
top_text_fill.morphology(Magick::EdgeOutMorphology, "Octagon");
top_text_fill.backgroundColor("black");
top_text_fill.alphaChannel(Magick::ShapeAlphaChannel);
top_text.composite(top_text_fill, Magick::CenterGravity, Magick::DstOverCompositeOp);
if (text_bottom != "") {
bottom_text.size(Geometry(to_string(coalesced.front().columns())));
bottom_text.backgroundColor("none");
bottom_text.font("Impact");
bottom_text.fontPointsize(40);
bottom_text.textGravity(Magick::CenterGravity);
bottom_text.read("pango:<span foreground='white'>" + text_bottom + "</span>");
Image bottom_text_fill = bottom_text;
bottom_text_fill.channel(Magick::AlphaChannel);
bottom_text_fill.morphology(Magick::EdgeOutMorphology, "Octagon");
bottom_text_fill.backgroundColor("black");
bottom_text_fill.alphaChannel(Magick::ShapeAlphaChannel);
bottom_text.composite(bottom_text_fill, Magick::CenterGravity, Magick::DstOverCompositeOp);
}
for (Image &image : coalesced) {
image.composite(top_text, Magick::NorthGravity, Magick::OverCompositeOp);
if (text_bottom != "") image.composite(bottom_text, Magick::SouthGravity, Magick::OverCompositeOp);
image.magick(type);
mid.push_back(image);
}
if (delay != 0) for_each(mid.begin(), mid.end(), animationDelayImage(delay));
writeImages(mid.begin(), mid.end(), &blob);
}
void OnOK() {
Callback().Call({Env().Undefined(), Napi::Buffer<char>::Copy(Env(), (char *)blob.data(), blob.length())});
}
private:
string in_path, type, text_top, text_bottom;
int delay, wordlength, i, n;
size_t bytes, type_size;
Blob blob;
};
Napi::Value Meme(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
string in_path = info[0].As<Napi::String>().Utf8Value();
string text_top = info[1].As<Napi::String>().Utf8Value();
string text_bottom = info[2].As<Napi::String>().Utf8Value();
string type = info[3].As<Napi::String>().Utf8Value();
int delay = info[4].As<Napi::Number>().Int32Value();
Napi::Function cb = info[5].As<Napi::Function>();
MemeWorker* blurWorker = new MemeWorker(cb, in_path, text_top, text_bottom, type, delay);
blurWorker->Queue();
return env.Undefined();
}

8
natives/meme.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef ESMBOT_NATIVES_MEME_H_
#define ESMBOT_NATIVES_MEME_H_
#include <napi.h>
Napi::Value Meme(const Napi::CallbackInfo& info);
#endif

85
natives/mirror.cc Normal file
View File

@ -0,0 +1,85 @@
#include <napi.h>
#include <list>
#include <Magick++.h>
using namespace std;
using namespace Magick;
class MirrorWorker : public Napi::AsyncWorker {
public:
MirrorWorker(Napi::Function& callback, string in_path, bool vertical, bool first, string type, int delay)
: Napi::AsyncWorker(callback), in_path(in_path), vertical(vertical), first(first), type(type), delay(delay) {}
~MirrorWorker() {}
void Execute() {
list<Image> frames;
list<Image> coalesced;
list<Image> mid;
list<Image> result;
MagickCore::GravityType gravity;
readImages(&frames, in_path);
coalesceImages(&coalesced, frames.begin(), frames.end());
if (vertical && first) {
gravity = Magick::NorthGravity;
} else if (!vertical && first) {
gravity = Magick::WestGravity;
} else if (vertical && !first) {
gravity = Magick::SouthGravity;
} else {
gravity = Magick::EastGravity;
}
for (Image &image : coalesced) {
list<Image> mirrored;
Image final;
image.extent(Geometry(to_string(vertical ? image.baseColumns() : image.baseColumns() / 2) + "x" + to_string(vertical ? image.baseRows() / 2 : image.baseRows())), gravity);
mirrored.push_back(image);
Image mirror = image;
if (vertical) {
mirror.flip();
} else {
mirror.flop();
}
if (first) {
mirrored.push_back(mirror);
} else {
mirrored.push_front(mirror);
}
appendImages(&final, mirrored.begin(), mirrored.end(), vertical);
final.magick(type);
mid.push_back(final);
}
optimizeImageLayers(&result, mid.begin(), mid.end());
if (delay != 0) for_each(result.begin(), result.end(), animationDelayImage(delay));
writeImages(result.begin(), result.end(), &blob);
}
void OnOK() {
Callback().Call({Env().Undefined(), Napi::Buffer<char>::Copy(Env(), (char *)blob.data(), blob.length())});
}
private:
string in_path, type;
int delay, wordlength, i, n;
size_t bytes, type_size;
bool vertical, first;
Blob blob;
};
Napi::Value Mirror(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
string in_path = info[0].As<Napi::String>().Utf8Value();
bool vertical = info[1].As<Napi::Boolean>().Value();
bool first = info[2].As<Napi::Boolean>().Value();
string type = info[3].As<Napi::String>().Utf8Value();
int delay = info[4].As<Napi::Number>().Int32Value();
Napi::Function cb = info[5].As<Napi::Function>();
MirrorWorker* mirrorWorker = new MirrorWorker(cb, in_path, vertical, first, type, delay);
mirrorWorker->Queue();
return env.Undefined();
}

8
natives/mirror.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef ESMBOT_NATIVES_MIRROR_H_
#define ESMBOT_NATIVES_MIRROR_H_
#include <napi.h>
Napi::Value Mirror(const Napi::CallbackInfo& info);
#endif

View File

@ -7,8 +7,8 @@ using namespace Magick;
class WatermarkWorker : public Napi::AsyncWorker {
public:
WatermarkWorker(Napi::Function& callback, string in_path, string water_path, int gravity, bool resize, string type, int delay)
: Napi::AsyncWorker(callback), in_path(in_path), water_path(water_path), gravity(gravity), resize(resize), type(type), delay(delay) {}
WatermarkWorker(Napi::Function& callback, string in_path, string water_path, int gravity, bool resize, bool append, bool mc, string type, int delay)
: Napi::AsyncWorker(callback), in_path(in_path), water_path(water_path), gravity(gravity), resize(resize), append(append), mc(mc), type(type), delay(delay) {}
~WatermarkWorker() {}
void Execute() {
@ -19,16 +19,33 @@ class WatermarkWorker : public Napi::AsyncWorker {
Image watermark;
readImages(&frames, in_path);
watermark.read(water_path);
if (resize) {
if (resize && append) {
string query(to_string(frames.front().baseColumns()) + "x");
watermark.scale(Geometry(query));
} else if (resize) {
string query("x" + to_string(frames.front().baseRows()));
watermark.scale(Geometry(query));
}
coalesceImages(&coalesced, frames.begin(), frames.end());
for (Image &image : coalesced) {
image.composite(watermark, Magick::GravityType(gravity), Magick::OverCompositeOp);
Image final;
if (append) {
list<Image> to_append;
to_append.push_back(image);
to_append.push_back(watermark);
appendImages(&final, to_append.begin(), to_append.end(), true);
} else if (mc) {
image.backgroundColor("white");
image.extent(Geometry(image.columns(), image.rows() + 15));
image.composite(watermark, Magick::GravityType(gravity), Magick::OverCompositeOp);
final = image;
} else {
image.composite(watermark, Magick::GravityType(gravity), Magick::OverCompositeOp);
final = image;
}
image.magick(type);
mid.push_back(image);
mid.push_back(final);
}
optimizeImageLayers(&result, mid.begin(), mid.end());
@ -45,7 +62,7 @@ class WatermarkWorker : public Napi::AsyncWorker {
int delay, wordlength, i, n, gravity;
size_t bytes, type_size;
Blob blob;
bool resize;
bool resize, append, mc;
};
Napi::Value Watermark(const Napi::CallbackInfo &info)
@ -56,11 +73,13 @@ Napi::Value Watermark(const Napi::CallbackInfo &info)
string water = info[1].As<Napi::String>().Utf8Value();
int gravity = info[2].As<Napi::Number>().Int32Value();
bool resize = info[3].As<Napi::Boolean>().Value();
string type = info[4].As<Napi::String>().Utf8Value();
int delay = info[5].As<Napi::Number>().Int32Value();
Napi::Function cb = info[6].As<Napi::Function>();
bool append = info[4].As<Napi::Boolean>().Value();
bool mc = info[5].As<Napi::Boolean>().Value();
string type = info[6].As<Napi::String>().Utf8Value();
int delay = info[7].As<Napi::Number>().Int32Value();
Napi::Function cb = info[8].As<Napi::Function>();
WatermarkWorker* watermarkWorker = new WatermarkWorker(cb, in_path, water, gravity, resize, type, delay);
WatermarkWorker* watermarkWorker = new WatermarkWorker(cb, in_path, water, gravity, resize, append, mc, type, delay);
watermarkWorker->Queue();
return env.Undefined();
}

22
package-lock.json generated
View File

@ -727,8 +727,8 @@
}
},
"erlpack": {
"version": "0.1.3",
"resolved": "github:abalabahaha/erlpack#5d0064f9e106841e1eead711a6451f99b0d289fd",
"version": "github:abalabahaha/erlpack#5d0064f9e106841e1eead711a6451f99b0d289fd",
"from": "github:abalabahaha/erlpack",
"optional": true,
"requires": {
"bindings": "^1.5.0",
@ -1641,9 +1641,9 @@
}
},
"node-addon-api": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.0.0.tgz",
"integrity": "sha512-sSHCgWfJ+Lui/u+0msF3oyCgvdkhxDbkCS6Q8uiJquzOimkJBvX6hl5aSSA7DR1XbMpdM8r7phjcF63sF4rkKg=="
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.0.1.tgz",
"integrity": "sha512-YUpjl57P55u2yUaKX5Bgy4t5s6SCNYMg+62XNg+k41aYbBL1NgWrZfcgljR5MxDxHDjzl0qHDNtH6SkW4DXNCA=="
},
"node-emoji": {
"version": "1.10.0",
@ -2253,9 +2253,9 @@
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
},
"simple-concat": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz",
"integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY="
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="
},
"simple-get": {
"version": "4.0.0",
@ -2792,9 +2792,9 @@
}
},
"yargs-parser": {
"version": "13.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz",
"integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
"version": "13.1.2",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
"integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"

View File

@ -33,7 +33,7 @@
"lavacord": "^1.1.9",
"moment": "^2.27.0",
"moment-duration-format": "^2.3.2",
"node-addon-api": "^3.0.0",
"node-addon-api": "^3.0.1",
"node-emoji": "^1.10.0",
"node-fetch": "^2.6.0",
"node-tweet": "^0.1.4",