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

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();
}