Some fixes and whatnot

This commit is contained in:
Essem 2022-11-27 14:52:40 -06:00
parent 330dd67063
commit 7ee571dd2b
No known key found for this signature in database
GPG key ID: 7D497397CC3A2A8C
30 changed files with 699 additions and 589 deletions

View file

@ -11,7 +11,7 @@ import { createRequire } from "module";
import EventEmitter from "events"; import EventEmitter from "events";
const nodeRequire = createRequire(import.meta.url); const nodeRequire = createRequire(import.meta.url);
const magick = nodeRequire(`../build/${process.env.DEBUG && process.env.DEBUG === "true" ? "Debug" : "Release"}/image.node`); const img = nodeRequire(`../build/${process.env.DEBUG && process.env.DEBUG === "true" ? "Debug" : "Release"}/image.node`);
const Rerror = 0x01; const Rerror = 0x01;
const Tqueue = 0x02; const Tqueue = 0x02;
@ -92,7 +92,7 @@ wss.on("connection", (ws, request) => {
const cur = Buffer.alloc(2); const cur = Buffer.alloc(2);
cur.writeUInt16LE(jobAmount); cur.writeUInt16LE(jobAmount);
const formats = {}; const formats = {};
for (const cmd of Object.keys(magick)) { for (const cmd of img.funcs) {
formats[cmd] = ["image/png", "image/gif", "image/jpeg", "image/webp"]; formats[cmd] = ["image/png", "image/gif", "image/jpeg", "image/webp"];
} }
const init = Buffer.concat([Buffer.from([Rinit]), Buffer.from([0x00, 0x00]), num, cur, Buffer.from(JSON.stringify(formats))]); const init = Buffer.concat([Buffer.from([Rinit]), Buffer.from([0x00, 0x00]), num, cur, Buffer.from(JSON.stringify(formats))]);

View file

@ -1,35 +1,35 @@
#include "common.h" #include "common.h"
#include <vips/vips8>
#include <string>
#include <map> #include <map>
#include <string>
#include <vips/vips8>
using namespace std; using namespace std;
using namespace vips; using namespace vips;
char* Blur(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize) { char *Blur(string type, char *BufferData, size_t BufferLength,
string caption = Arguments["caption"]; map<string, any> Arguments, size_t *DataSize) {
string font = MAP_GET(Arguments, "font"); bool sharp = MAP_GET(Arguments, "sharp", bool);
bool sharp = MAP_GET(Arguments, "sharp") == "true"; VOption *options = VImage::option()->set("access", "sequential");
VOption *options = VImage::option()->set("access", "sequential");
VImage in = VImage in =
VImage::new_from_buffer(BufferData, BufferLength, "", VImage::new_from_buffer(BufferData, BufferLength, "",
type == "gif" ? options->set("n", -1) : options) type == "gif" ? options->set("n", -1) : options)
.colourspace(VIPS_INTERPRETATION_sRGB); .colourspace(VIPS_INTERPRETATION_sRGB);
if (!in.has_alpha()) in = in.bandjoin(255); if (!in.has_alpha())
in = in.bandjoin(255);
// TODO: find a better way to calculate the intensity for GIFs without // TODO: find a better way to calculate the intensity for GIFs without
// splitting frames // splitting frames
VImage out = sharp ? in.sharpen(VImage::option()->set("sigma", 3)) VImage out =
: in.gaussblur(15); sharp ? in.sharpen(VImage::option()->set("sigma", 3)) : in.gaussblur(15);
void *buf; void *buf;
out.write_to_buffer(("." + type).c_str(), &buf, DataSize); out.write_to_buffer(("." + type).c_str(), &buf, DataSize);
vips_error_clear(); vips_error_clear();
vips_thread_shutdown(); vips_thread_shutdown();
return (char*) buf; return (char *)buf;
} }

View file

@ -1,8 +1,11 @@
#pragma once #pragma once
#include <napi.h> #include <any>
#include <map>
#include <string>
using std::string; using std::any;
using std::map; using std::map;
using std::string;
char* Blur(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize); char* Blur(string type, char* BufferData, size_t BufferLength, map<string, any> Arguments, size_t* DataSize);

View file

@ -7,65 +7,76 @@
using namespace std; using namespace std;
using namespace vips; using namespace vips;
char* Caption(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize) { char *Caption(string type, char *BufferData, size_t BufferLength,
map<string, any> Arguments, size_t *DataSize) {
string caption = Arguments["caption"]; string caption = MAP_GET(Arguments, "caption", string);
string font = MAP_GET(Arguments, "font"); string font = MAP_GET(Arguments, "font", string);
string basePath = MAP_GET(Arguments, "basePath", string);
VOption *options = VImage::option()->set("access", "sequential"); VOption *options = VImage::option()->set("access", "sequential");
VImage in = VImage in =
VImage::new_from_buffer(BufferData, BufferLength, "", VImage::new_from_buffer(BufferData, BufferLength, "",
type == "gif" ? options->set("n", -1) : options) type == "gif" ? options->set("n", -1) : options)
.colourspace(VIPS_INTERPRETATION_sRGB); .colourspace(VIPS_INTERPRETATION_sRGB);
if (!in.has_alpha())
in = in.bandjoin(255);
int width = in.width(); if (!in.has_alpha())
int size = width / 10; in = in.bandjoin(255);
int pageHeight = vips_image_get_page_height(in.get_image());
int nPages = vips_image_get_n_pages(in.get_image());
int textWidth = width - ((width / 25) * 2);
string font_string = (font == "roboto" ? "Roboto Condensed" : font) + " " + int width = in.width();
(font != "impact" ? "bold" : "normal") + " " + int size = width / 10;
to_string(size); int pageHeight = vips_image_get_page_height(in.get_image());
int nPages = vips_image_get_n_pages(in.get_image());
int textWidth = width - ((width / 25) * 2);
string captionText = "<span background=\"white\">" + caption + "</span>"; string font_string = (font == "roboto" ? "Roboto Condensed" : font) + " " +
(font != "impact" ? "bold" : "normal") + " " +
to_string(size);
VImage text = string captionText = "<span background=\"white\">" + caption + "</span>";
VImage::text(captionText.c_str(), VImage::option()
->set("rgba", true)
->set("align", VIPS_ALIGN_CENTRE)
->set("font", font_string.c_str())
->set("width", textWidth));
VImage captionImage =
((text == (vector<double>){0, 0, 0, 0}).bandand())
.ifthenelse(255, text)
.gravity(VIPS_COMPASS_DIRECTION_CENTRE, width, text.height() + size,
VImage::option()->set("extend", "white"));
vector<VImage> img; VImage text;
for (int i = 0; i < nPages; i++) { auto findResult = fontPaths.find(font);
VImage img_frame = if (findResult != fontPaths.end()) {
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in; text = VImage::text(
VImage frame = captionImage.join( ".", VImage::option()->set("fontfile",
img_frame, VIPS_DIRECTION_VERTICAL, (basePath + findResult->second).c_str()));
VImage::option()->set("background", 0xffffff)->set("expand", true)); }
img.push_back(frame); text = VImage::text(
} captionText.c_str(),
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1)); VImage::option()
final.set(VIPS_META_PAGE_HEIGHT, pageHeight + captionImage.height()); ->set("rgba", true)
->set("align", VIPS_ALIGN_CENTRE)
->set("font", font_string.c_str())
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str())
->set("width", textWidth));
VImage captionImage =
((text == (vector<double>){0, 0, 0, 0}).bandand())
.ifthenelse(255, text)
.gravity(VIPS_COMPASS_DIRECTION_CENTRE, width, text.height() + size,
VImage::option()->set("extend", "white"));
void* buf; vector<VImage> img;
final.write_to_buffer( for (int i = 0; i < nPages; i++) {
("." + type).c_str(), &buf, DataSize, VImage img_frame =
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1) type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
: 0); VImage frame = captionImage.join(
img_frame, VIPS_DIRECTION_VERTICAL,
VImage::option()->set("background", 0xffffff)->set("expand", true));
img.push_back(frame);
}
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
final.set(VIPS_META_PAGE_HEIGHT, pageHeight + captionImage.height());
vips_error_clear(); void *buf;
vips_thread_shutdown(); final.write_to_buffer(
("." + type).c_str(), &buf, DataSize,
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1)
: 0);
return (char*) buf; vips_error_clear();
vips_thread_shutdown();
return (char *)buf;
} }

View file

@ -1,7 +1,11 @@
#pragma once #pragma once
#include <any>
#include <map> #include <map>
#include <string> #include <string>
#include <napi.h>
char* Caption(std::string type, char* BufferData, size_t BufferLength, std::map<std::string, std::string> Arguments, size_t* DataSize); using std::any;
using std::map;
using std::string;
char* Caption(string type, char* BufferData, size_t BufferLength, map<string, any> Arguments, size_t* DataSize);

View file

@ -1,85 +1,85 @@
#include "common.h" #include "common.h"
#include "common.h"
#include <string>
#include <map> #include <map>
#include <string>
#include <vips/vips8> #include <vips/vips8>
using namespace std; using namespace std;
using namespace vips; using namespace vips;
char* CaptionTwo(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize) { char *CaptionTwo(string type, char *BufferData, size_t BufferLength,
map<string, any> Arguments, size_t *DataSize) {
bool top = MAP_GET(Arguments, "top") == "true"; bool top = MAP_GET(Arguments, "top", bool);
string caption = Arguments["caption"]; string caption = MAP_GET(Arguments, "caption", string);
string font = MAP_GET(Arguments, "font"); string font = MAP_GET(Arguments, "font", string);
string basePath = MAP_GET(Arguments, "basePath"); string basePath = MAP_GET(Arguments, "basePath", string);
VOption *options = VImage::option()->set("access", "sequential"); VOption *options = VImage::option()->set("access", "sequential");
VImage in = VImage in =
VImage::new_from_buffer(BufferData, BufferLength, "", VImage::new_from_buffer(BufferData, BufferLength, "",
type == "gif" ? options->set("n", -1) : options) type == "gif" ? options->set("n", -1) : options)
.colourspace(VIPS_INTERPRETATION_sRGB); .colourspace(VIPS_INTERPRETATION_sRGB);
if (!in.has_alpha())
in = in.bandjoin(255);
int width = in.width(); if (!in.has_alpha())
int size = width / 13; in = in.bandjoin(255);
int pageHeight = vips_image_get_page_height(in.get_image());
int nPages = vips_image_get_n_pages(in.get_image());
int textWidth = width - ((width / 25) * 2);
string font_string = (font == "roboto" ? "Roboto Condensed" : font) + int width = in.width();
", Twemoji Color Emoji " + to_string(size); int size = width / 13;
int pageHeight = vips_image_get_page_height(in.get_image());
int nPages = vips_image_get_n_pages(in.get_image());
int textWidth = width - ((width / 25) * 2);
string captionText = "<span background=\"white\">" + caption + "</span>"; string font_string = (font == "roboto" ? "Roboto Condensed" : font) +
", Twemoji Color Emoji " + to_string(size);
VImage text; string captionText = "<span background=\"white\">" + caption + "</span>";
auto findResult = fontPaths.find(font);
if (findResult != fontPaths.end()) { VImage text;
text = VImage::text( auto findResult = fontPaths.find(font);
".", VImage::option()->set("fontfile", if (findResult != fontPaths.end()) {
(basePath + findResult->second).c_str()));
}
text = VImage::text( text = VImage::text(
captionText.c_str(), ".", VImage::option()->set("fontfile",
VImage::option() (basePath + findResult->second).c_str()));
->set("rgba", true) }
->set("font", font_string.c_str()) text = VImage::text(
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str()) captionText.c_str(),
->set("align", VIPS_ALIGN_LOW) VImage::option()
->set("width", textWidth)); ->set("rgba", true)
VImage captionImage = ->set("font", font_string.c_str())
((text == (vector<double>){0, 0, 0, 0}).bandand()) ->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str())
.ifthenelse(255, text) ->set("align", VIPS_ALIGN_LOW)
.embed(width / 25, width / 25, width, text.height() + size, ->set("width", textWidth));
VImage::option()->set("extend", "white")); VImage captionImage =
((text == (vector<double>){0, 0, 0, 0}).bandand())
.ifthenelse(255, text)
.embed(width / 25, width / 25, width, text.height() + size,
VImage::option()->set("extend", "white"));
vector<VImage> img; vector<VImage> img;
for (int i = 0; i < nPages; i++) { for (int i = 0; i < nPages; i++) {
VImage img_frame = VImage img_frame =
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in; type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
VImage frame = VImage frame =
(top ? captionImage : img_frame) (top ? captionImage : img_frame)
.join(top ? img_frame : captionImage, VIPS_DIRECTION_VERTICAL, .join(top ? img_frame : captionImage, VIPS_DIRECTION_VERTICAL,
VImage::option() VImage::option()
->set("background", 0xffffff) ->set("background", 0xffffff)
->set("expand", true)); ->set("expand", true));
img.push_back(frame); img.push_back(frame);
} }
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1)); VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
final.set(VIPS_META_PAGE_HEIGHT, pageHeight + captionImage.height()); final.set(VIPS_META_PAGE_HEIGHT, pageHeight + captionImage.height());
void *buf; void *buf;
final.write_to_buffer( final.write_to_buffer(
("." + type).c_str(), &buf, DataSize, ("." + type).c_str(), &buf, DataSize,
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1) type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1)
: 0); : 0);
vips_error_clear(); vips_error_clear();
vips_thread_shutdown(); vips_thread_shutdown();
return (char*) buf; return (char *)buf;
} }

View file

@ -1,7 +1,11 @@
#pragma once #pragma once
#include <any>
#include <map> #include <map>
#include <string> #include <string>
#include <napi.h>
char* CaptionTwo(std::string type, char* BufferData, size_t BufferLength, std::map<std::string, std::string> Arguments, size_t* DataSize); using std::any;
using std::map;
using std::string;
char* CaptionTwo(string type, char* BufferData, size_t BufferLength, map<string, any> Arguments, size_t* DataSize);

View file

@ -1,48 +1,53 @@
#include "common.h"
#include <Magick++.h> #include <Magick++.h>
#include <napi.h>
#include <cstring>
#include <iostream> #include <iostream>
#include <string>
#include <map>
#include <list> #include <list>
#include <map>
#include <string>
using namespace std; using namespace std;
using namespace Magick; using namespace Magick;
char* Circle(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize) { char *Circle(string type, char *BufferData, size_t BufferLength,
map<string, any> Arguments, size_t *DataSize) {
Blob blob;
list<Image> frames; Blob blob;
list<Image> coalesced;
list<Image> blurred; list<Image> frames;
try { list<Image> coalesced;
readImages(&frames, Blob(BufferData, BufferLength)); list<Image> blurred;
} catch (Magick::WarningCoder &warning) { try {
cerr << "Coder Warning: " << warning.what() << endl; readImages(&frames, Blob(BufferData, BufferLength));
} catch (Magick::Warning &warning) { } catch (Magick::WarningCoder &warning) {
cerr << "Warning: " << warning.what() << endl; cerr << "Coder Warning: " << warning.what() << endl;
} catch (Magick::Warning &warning) {
cerr << "Warning: " << warning.what() << endl;
}
coalesceImages(&coalesced, frames.begin(), frames.end());
for (Image &image : coalesced) {
image.rotationalBlur(10);
image.magick(type);
blurred.push_back(image);
}
optimizeTransparency(blurred.begin(), blurred.end());
if (type == "gif") {
for (Image &image : blurred) {
image.quantizeDitherMethod(FloydSteinbergDitherMethod);
image.quantize();
} }
coalesceImages(&coalesced, frames.begin(), frames.end()); }
for (Image &image : coalesced) { writeImages(blurred.begin(), blurred.end(), &blob);
image.rotationalBlur(10);
image.magick(type);
blurred.push_back(image);
}
optimizeTransparency(blurred.begin(), blurred.end()); *DataSize = blob.length();
if (type == "gif") { // workaround because the data is tied to the blob
for (Image &image : blurred) { char *data = (char *)malloc(*DataSize);
image.quantizeDitherMethod(FloydSteinbergDitherMethod); memcpy(data, blob.data(), *DataSize);
image.quantize(); return data;
}
}
writeImages(blurred.begin(), blurred.end(), &blob);
*DataSize = blob.length();
return (char*) blob.data();
} }

View file

@ -1,10 +1,11 @@
#pragma once #pragma once
#include <napi.h> #include <any>
#include <string>
#include <map> #include <map>
#include <string>
using std::string; using std::any;
using std::map; using std::map;
using std::string;
char* Circle(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize); char* Circle(string type, char* BufferData, size_t BufferLength, map<string, any> Arguments, size_t* DataSize);

View file

@ -1,8 +1,8 @@
#include <napi.h> #include "common.h"
#include <vips/vips8>
#include <map> #include <map>
#include <string> #include <string>
#include <vips/vips8>
using namespace std; using namespace std;
using namespace vips; using namespace vips;
@ -10,30 +10,31 @@ using namespace vips;
VImage sepia = VImage::new_matrixv(3, 3, 0.3588, 0.7044, 0.1368, 0.2990, 0.5870, VImage sepia = VImage::new_matrixv(3, 3, 0.3588, 0.7044, 0.1368, 0.2990, 0.5870,
0.1140, 0.2392, 0.4696, 0.0912); 0.1140, 0.2392, 0.4696, 0.0912);
char* Colors(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize) { char *Colors(string type, char *BufferData, size_t BufferLength,
map<string, any> Arguments, size_t *DataSize) {
string color = Arguments["color"]; string color = MAP_GET(Arguments, "color", string);
VOption *options = VImage::option()->set("access", "sequential"); VOption *options = VImage::option()->set("access", "sequential");
VImage in = VImage in =
VImage::new_from_buffer(BufferData, BufferLength, "", VImage::new_from_buffer(BufferData, BufferLength, "",
type == "gif" ? options->set("n", -1) : options) type == "gif" ? options->set("n", -1) : options)
.colourspace(VIPS_INTERPRETATION_sRGB); .colourspace(VIPS_INTERPRETATION_sRGB);
VImage out; VImage out;
if (color == "grayscale") { if (color == "grayscale") {
out = in.colourspace(VIPS_INTERPRETATION_B_W); out = in.colourspace(VIPS_INTERPRETATION_B_W);
} else if (color == "sepia") { } else if (color == "sepia") {
out = in.flatten().recomb(sepia); out = in.flatten().recomb(sepia);
} }
void *buf; void *buf;
out.write_to_buffer(("." + type).c_str(), &buf, DataSize); out.write_to_buffer(("." + type).c_str(), &buf, DataSize);
vips_error_clear(); vips_error_clear();
vips_thread_shutdown(); vips_thread_shutdown();
return (char*) buf; return (char *)buf;
} }

View file

@ -1,10 +1,11 @@
#pragma once #pragma once
#include <napi.h> #include <any>
#include <map> #include <map>
#include <string> #include <string>
using std::any;
using std::map; using std::map;
using std::string; using std::string;
char* Colors(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize); char* Colors(string type, char* BufferData, size_t BufferLength, map<string, any> Arguments, size_t* DataSize);

View file

@ -1,10 +1,12 @@
#pragma once #pragma once
#include <any>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#define MAP_HAS(ARRAY, KEY) (ARRAY.count(KEY) > 0) #define MAP_HAS(ARRAY, KEY) (ARRAY.count(KEY) > 0)
#define MAP_GET(ARRAY, KEY) (MAP_HAS(ARRAY, KEY) ? ARRAY.at(KEY) : NULL) // C++ has forced my hand #define MAP_GET(ARRAY, KEY, TYPE) (MAP_HAS(ARRAY, KEY) ? any_cast<TYPE>(ARRAY.at(KEY)) : NULL) // C++ has forced my hand
#define MAP_GET_FALLBACK(ARRAY, KEY, TYPE, FALLBACK) (MAP_HAS(ARRAY, KEY) ? any_cast<TYPE>(ARRAY.at(KEY)) : FALLBACK)
const std::unordered_map<std::string, std::string> fontPaths { const std::unordered_map<std::string, std::string> fontPaths {
{"futura", "assets/fonts/caption.otf"}, {"futura", "assets/fonts/caption.otf"},

View file

@ -1,4 +1,4 @@
#include <napi.h> #include "common.h"
#include <map> #include <map>
#include <string> #include <string>
#include <vips/vips8> #include <vips/vips8>
@ -6,47 +6,48 @@
using namespace std; using namespace std;
using namespace vips; using namespace vips;
char* Crop(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize) { char *Crop(string type, char *BufferData, size_t BufferLength,
map<string, any> Arguments, size_t *DataSize) {
VOption *options = VImage::option()->set("access", "sequential"); VOption *options = VImage::option()->set("access", "sequential");
VImage in = VImage in =
VImage::new_from_buffer(BufferData, BufferLength, "", VImage::new_from_buffer(BufferData, BufferLength, "",
type == "gif" ? options->set("n", -1) : options) type == "gif" ? options->set("n", -1) : options)
.colourspace(VIPS_INTERPRETATION_sRGB); .colourspace(VIPS_INTERPRETATION_sRGB);
int width = in.width(); int width = in.width();
int pageHeight = vips_image_get_page_height(in.get_image()); int pageHeight = vips_image_get_page_height(in.get_image());
int nPages = vips_image_get_n_pages(in.get_image()); int nPages = vips_image_get_n_pages(in.get_image());
vector<VImage> img; vector<VImage> img;
int finalHeight = 0; int finalHeight = 0;
for (int i = 0; i < nPages; i++) { for (int i = 0; i < nPages; i++) {
VImage img_frame = VImage img_frame =
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in; type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
int frameWidth = img_frame.width(); int frameWidth = img_frame.width();
int frameHeight = img_frame.height(); int frameHeight = img_frame.height();
bool widthOrHeight = frameWidth / frameHeight >= 1; bool widthOrHeight = frameWidth / frameHeight >= 1;
int size = widthOrHeight ? frameHeight : frameWidth; int size = widthOrHeight ? frameHeight : frameWidth;
// img_frame.crop(frameWidth - size, frameHeight - size, size, size); // img_frame.crop(frameWidth - size, frameHeight - size, size, size);
VImage result = img_frame.smartcrop( VImage result = img_frame.smartcrop(
size, size, size, size,
VImage::option()->set("interesting", VIPS_INTERESTING_CENTRE)); VImage::option()->set("interesting", VIPS_INTERESTING_CENTRE));
finalHeight = size; finalHeight = size;
img.push_back(result); img.push_back(result);
} }
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1)); VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
final.set(VIPS_META_PAGE_HEIGHT, finalHeight); final.set(VIPS_META_PAGE_HEIGHT, finalHeight);
void *buf; void *buf;
final.write_to_buffer( final.write_to_buffer(
("." + type).c_str(), &buf, DataSize, ("." + type).c_str(), &buf, DataSize,
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1) type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1)
: 0); : 0);
vips_error_clear(); vips_error_clear();
vips_thread_shutdown(); vips_thread_shutdown();
return (char*) buf; return (char *)buf;
} }

View file

@ -1,10 +1,11 @@
#pragma once #pragma once
#include <napi.h> #include <any>
#include <map> #include <map>
#include <string> #include <string>
using std::any;
using std::map; using std::map;
using std::string; using std::string;
char* Crop(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize); char* Crop(string type, char* BufferData, size_t BufferLength, map<string, any> Arguments, size_t* DataSize);

View file

@ -1,63 +1,64 @@
#include "common.h"
#include <map> #include <map>
#include <vips/vips8> #include <vips/vips8>
using namespace std; using namespace std;
using namespace vips; using namespace vips;
char* Deepfry(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize) { char *Deepfry(string type, char *BufferData, size_t BufferLength,
map<string, any> Arguments, size_t *DataSize) {
VOption *options = VImage::option()->set("access", "sequential"); VOption *options = VImage::option()->set("access", "sequential");
VImage in = VImage in =
VImage::new_from_buffer(BufferData, BufferLength, "", VImage::new_from_buffer(BufferData, BufferLength, "",
type == "gif" ? options->set("n", -1) : options) type == "gif" ? options->set("n", -1) : options)
.colourspace(VIPS_INTERPRETATION_sRGB); .colourspace(VIPS_INTERPRETATION_sRGB);
if (!in.has_alpha()) if (!in.has_alpha())
in = in.bandjoin(255); in = in.bandjoin(255);
int width = in.width(); int width = in.width();
int pageHeight = vips_image_get_page_height(in.get_image()); int pageHeight = vips_image_get_page_height(in.get_image());
int totalHeight = in.height(); int totalHeight = in.height();
int nPages = vips_image_get_n_pages(in.get_image()); int nPages = vips_image_get_n_pages(in.get_image());
VImage fried = (in * 1.3 - (255.0 * 1.3 - 255.0)) * 1.5; VImage fried = (in * 1.3 - (255.0 * 1.3 - 255.0)) * 1.5;
VImage final; VImage final;
if (totalHeight > 65500 && type == "gif") { if (totalHeight > 65500 && type == "gif") {
vector<VImage> img; vector<VImage> img;
for (int i = 0; i < nPages; i++) { for (int i = 0; i < nPages; i++) {
VImage img_frame = in.crop(0, i * pageHeight, width, pageHeight); VImage img_frame = in.crop(0, i * pageHeight, width, pageHeight);
void *jpgBuf;
size_t jpgLength;
img_frame.write_to_buffer(
".jpg", &jpgBuf, &jpgLength,
VImage::option()->set("Q", 1)->set("strip", true));
VImage jpeged = VImage::new_from_buffer(jpgBuf, jpgLength, "");
jpeged.set(VIPS_META_PAGE_HEIGHT, pageHeight);
jpeged.set("delay", in.get_array_int("delay"));
img.push_back(jpeged);
}
final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
final.set(VIPS_META_PAGE_HEIGHT, pageHeight);
} else {
void *jpgBuf; void *jpgBuf;
size_t jpgLength; size_t jpgLength;
fried.write_to_buffer(".jpg", &jpgBuf, &jpgLength, img_frame.write_to_buffer(
VImage::option()->set("Q", 1)->set("strip", true)); ".jpg", &jpgBuf, &jpgLength,
final = VImage::new_from_buffer(jpgBuf, jpgLength, ""); VImage::option()->set("Q", 1)->set("strip", true));
final.set(VIPS_META_PAGE_HEIGHT, pageHeight); VImage jpeged = VImage::new_from_buffer(jpgBuf, jpgLength, "");
if (type == "gif") jpeged.set(VIPS_META_PAGE_HEIGHT, pageHeight);
final.set("delay", fried.get_array_int("delay")); jpeged.set("delay", in.get_array_int("delay"));
img.push_back(jpeged);
} }
final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
final.set(VIPS_META_PAGE_HEIGHT, pageHeight);
} else {
void *jpgBuf;
size_t jpgLength;
fried.write_to_buffer(".jpg", &jpgBuf, &jpgLength,
VImage::option()->set("Q", 1)->set("strip", true));
final = VImage::new_from_buffer(jpgBuf, jpgLength, "");
final.set(VIPS_META_PAGE_HEIGHT, pageHeight);
if (type == "gif")
final.set("delay", fried.get_array_int("delay"));
}
void *buf; void *buf;
final.write_to_buffer(("." + type).c_str(), &buf, DataSize, final.write_to_buffer(("." + type).c_str(), &buf, DataSize,
type == "gif" ? VImage::option()->set("dither", 0) type == "gif" ? VImage::option()->set("dither", 0) : 0);
: 0);
vips_error_clear(); vips_error_clear();
vips_thread_shutdown(); vips_thread_shutdown();
return (char*) buf; return (char *)buf;
} }

View file

@ -1,10 +1,11 @@
#pragma once #pragma once
#include <napi.h> #include <any>
#include <map> #include <map>
#include <string> #include <string>
using std::any;
using std::map; using std::map;
using std::string; using std::string;
char* Deepfry(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize); char* Deepfry(string type, char* BufferData, size_t BufferLength, map<string, any> Arguments, size_t* DataSize);

View file

@ -2,52 +2,57 @@
#include <Magick++.h> #include <Magick++.h>
#include <cstring>
#include <iostream> #include <iostream>
#include <string>
#include <map>
#include <list> #include <list>
#include <map>
#include <string>
using namespace std; using namespace std;
using namespace Magick; using namespace Magick;
char* Explode(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize) { char *Explode(string type, char *BufferData, size_t BufferLength,
map<string, any> Arguments, size_t *DataSize) {
int amount = stoi(Arguments.at("amount")); int amount = MAP_GET(Arguments, "amount", int);
int delay = MAP_HAS(Arguments, "delay") ? stoi(Arguments.at("delay")) : 0; int delay = MAP_GET_FALLBACK(Arguments, "delay", int, 0);
Blob blob; Blob blob;
list<Image> frames; list<Image> frames;
list<Image> coalesced; list<Image> coalesced;
list<Image> blurred; list<Image> blurred;
try { try {
readImages(&frames, Blob(BufferData, BufferLength)); readImages(&frames, Blob(BufferData, BufferLength));
} catch (Magick::WarningCoder &warning) { } catch (Magick::WarningCoder &warning) {
cerr << "Coder Warning: " << warning.what() << endl; cerr << "Coder Warning: " << warning.what() << endl;
} catch (Magick::Warning &warning) { } catch (Magick::Warning &warning) {
cerr << "Warning: " << warning.what() << endl; cerr << "Warning: " << warning.what() << endl;
}
coalesceImages(&coalesced, frames.begin(), frames.end());
for (Image &image : coalesced) {
image.implode(amount);
image.magick(type);
blurred.push_back(image);
}
optimizeTransparency(blurred.begin(), blurred.end());
if (type == "gif") {
for (Image &image : blurred) {
image.quantizeDither(false);
image.quantize();
if (delay != 0) image.animationDelay(delay);
} }
coalesceImages(&coalesced, frames.begin(), frames.end()); }
for (Image &image : coalesced) { writeImages(blurred.begin(), blurred.end(), &blob);
image.implode(amount);
image.magick(type);
blurred.push_back(image);
}
optimizeTransparency(blurred.begin(), blurred.end()); *DataSize = blob.length();
if (type == "gif") { // workaround because the data is tied to the blob
for (Image &image : blurred) { char *data = (char *)malloc(*DataSize);
image.quantizeDither(false); memcpy(data, blob.data(), *DataSize);
image.quantize(); return data;
if (delay != 0) image.animationDelay(delay);
}
}
writeImages(blurred.begin(), blurred.end(), &blob);
*DataSize = blob.length();
return (char*) blob.data();
} }

View file

@ -1,10 +1,11 @@
#pragma once #pragma once
#include <napi.h> #include <any>
#include <string>
#include <map> #include <map>
#include <string>
using std::any;
using std::map; using std::map;
using std::string; using std::string;
char* Explode(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize); char* Explode(string type, char* BufferData, size_t BufferLength, map<string, any> Arguments, size_t* DataSize);

View file

@ -1,61 +1,64 @@
#include <napi.h> #include "common.h"
#include <vips/vips8>
#include <string>
#include <map> #include <map>
#include <string>
#include <vips/vips8>
using namespace std; using namespace std;
using namespace vips; using namespace vips;
char* Flag(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize) { char *Flag(string type, char *BufferData, size_t BufferLength,
map<string, any> Arguments, size_t *DataSize) {
string overlay = Arguments["overlay"]; string overlay = MAP_GET(Arguments, "overlay", string);
string basePath = Arguments["basePath"]; string basePath = MAP_GET(Arguments, "basePath", string);
VOption *options = VImage::option()->set("access", "sequential"); VOption *options = VImage::option()->set("access", "sequential");
VImage in = VImage in =
VImage::new_from_buffer(BufferData, BufferLength, "", VImage::new_from_buffer(BufferData, BufferLength, "",
type == "gif" ? options->set("n", -1) : options) type == "gif" ? options->set("n", -1) : options)
.colourspace(VIPS_INTERPRETATION_sRGB); .colourspace(VIPS_INTERPRETATION_sRGB);
if (!in.has_alpha()) in = in.bandjoin(255); if (!in.has_alpha())
in = in.bandjoin(255);
int width = in.width(); int width = in.width();
int pageHeight = vips_image_get_page_height(in.get_image()); int pageHeight = vips_image_get_page_height(in.get_image());
int nPages = vips_image_get_n_pages(in.get_image()); int nPages = vips_image_get_n_pages(in.get_image());
string assetPath = basePath + overlay; string assetPath = basePath + overlay;
VImage overlayInput = VImage::new_from_file(assetPath.c_str()); VImage overlayInput = VImage::new_from_file(assetPath.c_str());
VImage overlayImage = overlayInput.resize( VImage overlayImage = overlayInput.resize(
(double)width / (double)overlayInput.width(), (double)width / (double)overlayInput.width(),
VImage::option()->set( VImage::option()->set("vscale", (double)pageHeight /
"vscale", (double)pageHeight / (double)overlayInput.height())); (double)overlayInput.height()));
if (!overlayImage.has_alpha()) { if (!overlayImage.has_alpha()) {
overlayImage = overlayImage.bandjoin(127); overlayImage = overlayImage.bandjoin(127);
} else { } else {
// this is a pretty cool line, just saying // this is a pretty cool line, just saying
overlayImage = overlayImage * vector<double>{1, 1, 1, 0.5}; overlayImage = overlayImage * vector<double>{1, 1, 1, 0.5};
} }
vector<VImage> img; vector<VImage> img;
for (int i = 0; i < nPages; i++) { for (int i = 0; i < nPages; i++) {
VImage img_frame = VImage img_frame =
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in; type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
VImage composited = VImage composited =
img_frame.composite2(overlayImage, VIPS_BLEND_MODE_OVER); img_frame.composite2(overlayImage, VIPS_BLEND_MODE_OVER);
img.push_back(composited); img.push_back(composited);
} }
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1)); VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
final.set(VIPS_META_PAGE_HEIGHT, pageHeight); final.set(VIPS_META_PAGE_HEIGHT, pageHeight);
void *buf; void *buf;
final.write_to_buffer( final.write_to_buffer(
("." + type).c_str(), &buf, DataSize, ("." + type).c_str(), &buf, DataSize,
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1) : 0); type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1)
: 0);
vips_error_clear(); vips_error_clear();
vips_thread_shutdown(); vips_thread_shutdown();
return (char*) buf; return (char *)buf;
} }

View file

@ -1,10 +1,11 @@
#pragma once #pragma once
#include <napi.h> #include <any>
#include <map> #include <map>
#include <string> #include <string>
using std::any;
using std::map; using std::map;
using std::string; using std::string;
char* Flag(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize); char* Flag(string type, char* BufferData, size_t BufferLength, map<string, any> Arguments, size_t* DataSize);

View file

@ -7,44 +7,46 @@
using namespace std; using namespace std;
using namespace vips; using namespace vips;
char* Flip(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize) { char *Flip(string type, char *BufferData, size_t BufferLength,
map<string, any> Arguments, size_t *DataSize) {
bool flop = MAP_GET(Arguments, "flop") == "true"; bool flop = MAP_GET(Arguments, "flop", bool);
VOption *options = VImage::option()->set("access", "sequential"); VImage in = VImage::new_from_buffer(BufferData, BufferLength, "",
type == "gif"
? VImage::option()->set("n", -1)->set(
"access", "sequential")
: 0)
.colourspace(VIPS_INTERPRETATION_sRGB);
if (!in.has_alpha())
in = in.bandjoin(255);
VImage in = VImage out;
VImage::new_from_buffer(BufferData, BufferLength, "", if (flop) {
type == "gif" ? VImage::option()->set("n", -1)->set("access", "sequential") : 0) out = in.flip(VIPS_DIRECTION_HORIZONTAL);
.colourspace(VIPS_INTERPRETATION_sRGB); } else if (type == "gif") {
if (!in.has_alpha()) in = in.bandjoin(255); // libvips gif handling is both a blessing and a curse
vector<VImage> img;
VImage out; int pageHeight = vips_image_get_page_height(in.get_image());
if (flop) { int nPages = vips_image_get_n_pages(in.get_image());
out = in.flip(VIPS_DIRECTION_HORIZONTAL); for (int i = 0; i < nPages; i++) {
} else if (type == "gif") { VImage img_frame = in.crop(0, i * pageHeight, in.width(), pageHeight);
// libvips gif handling is both a blessing and a curse VImage flipped = img_frame.flip(VIPS_DIRECTION_VERTICAL);
vector<VImage> img; img.push_back(flipped);
int pageHeight = vips_image_get_page_height(in.get_image());
int nPages = vips_image_get_n_pages(in.get_image());
for (int i = 0; i < nPages; i++) {
VImage img_frame = in.crop(0, i * pageHeight, in.width(), pageHeight);
VImage flipped = img_frame.flip(VIPS_DIRECTION_VERTICAL);
img.push_back(flipped);
}
out = VImage::arrayjoin(img, VImage::option()->set("across", 1));
out.set(VIPS_META_PAGE_HEIGHT, pageHeight);
} else {
out = in.flip(VIPS_DIRECTION_VERTICAL);
} }
out = VImage::arrayjoin(img, VImage::option()->set("across", 1));
out.set(VIPS_META_PAGE_HEIGHT, pageHeight);
} else {
out = in.flip(VIPS_DIRECTION_VERTICAL);
}
void* buf; void *buf;
out.write_to_buffer( out.write_to_buffer(
("." + type).c_str(), &buf, DataSize, ("." + type).c_str(), &buf, DataSize,
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1) type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1)
: 0); : 0);
vips_error_clear(); vips_error_clear();
vips_thread_shutdown(); vips_thread_shutdown();
return (char*) buf; return (char *)buf;
} }

View file

@ -1,10 +1,11 @@
#pragma once #pragma once
#include <napi.h> #include <any>
#include <map> #include <map>
#include <string> #include <string>
using std::any;
using std::map; using std::map;
using std::string; using std::string;
char* Flip(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize); char* Flip(string type, char* BufferData, size_t BufferLength, map<string, any> Arguments, size_t* DataSize);

View file

@ -51,11 +51,12 @@ Napi::Value Freeze(const Napi::CallbackInfo &info) {
} else if (frame >= 0 && !loop) { } else if (frame >= 0 && !loop) {
VOption *options = VImage::option()->set("access", "sequential"); VOption *options = VImage::option()->set("access", "sequential");
VImage in = VImage::new_from_buffer( VImage in = VImage::new_from_buffer(data.Data(), data.Length(), "",
data.Data(), data.Length(), "", type == "gif" ? options->set("n", -1)
type == "gif" ? options->set("n", -1) : options) : options)
.colourspace(VIPS_INTERPRETATION_sRGB); .colourspace(VIPS_INTERPRETATION_sRGB);
if (!in.has_alpha()) in = in.bandjoin(255); if (!in.has_alpha())
in = in.bandjoin(255);
int pageHeight = vips_image_get_page_height(in.get_image()); int pageHeight = vips_image_get_page_height(in.get_image());
int nPages = vips_image_get_n_pages(in.get_image()); int nPages = vips_image_get_n_pages(in.get_image());

View file

@ -21,7 +21,8 @@ Napi::Value Gamexplain(const Napi::CallbackInfo &info) {
VImage::new_from_buffer(data.Data(), data.Length(), "", VImage::new_from_buffer(data.Data(), data.Length(), "",
type == "gif" ? options->set("n", -1) : options) type == "gif" ? options->set("n", -1) : options)
.colourspace(VIPS_INTERPRETATION_sRGB); .colourspace(VIPS_INTERPRETATION_sRGB);
if (!in.has_alpha()) in = in.bandjoin(255); if (!in.has_alpha())
in = in.bandjoin(255);
string assetPath = basePath + "assets/images/gamexplain.png"; string assetPath = basePath + "assets/images/gamexplain.png";
VImage tmpl = VImage::new_from_file(assetPath.c_str()); VImage tmpl = VImage::new_from_file(assetPath.c_str());
@ -50,7 +51,8 @@ Napi::Value Gamexplain(const Napi::CallbackInfo &info) {
size_t length; size_t length;
final.write_to_buffer( final.write_to_buffer(
("." + type).c_str(), &buf, &length, ("." + type).c_str(), &buf, &length,
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1) : 0); type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1)
: 0);
result.Set("data", Napi::Buffer<char>::Copy(env, (char *)buf, length)); result.Set("data", Napi::Buffer<char>::Copy(env, (char *)buf, length));
result.Set("type", type); result.Set("type", type);

View file

@ -23,7 +23,8 @@ Napi::Value Globe(const Napi::CallbackInfo &info) {
type == "gif" ? options->set("n", -1)->set("access", "sequential") type == "gif" ? options->set("n", -1)->set("access", "sequential")
: options) : options)
.colourspace(VIPS_INTERPRETATION_sRGB); .colourspace(VIPS_INTERPRETATION_sRGB);
if (!in.has_alpha()) in = in.bandjoin(255); if (!in.has_alpha())
in = in.bandjoin(255);
int width = in.width(); int width = in.width();
int pageHeight = vips_image_get_page_height(in.get_image()); int pageHeight = vips_image_get_page_height(in.get_image());

View file

@ -3,6 +3,8 @@
#include <napi.h> #include <napi.h>
#include <map> #include <map>
#include <string> #include <string>
#include <iostream>
#include <any>
#include "blur.h" #include "blur.h"
#include "colors.h" #include "colors.h"
@ -42,7 +44,6 @@
#include "watermark.h" #include "watermark.h"
#include "whisper.h" #include "whisper.h"
#include "zamn.h" #include "zamn.h"
#include <iostream>
#ifdef _WIN32 #ifdef _WIN32
#include <Magick++.h> #include <Magick++.h>
@ -51,10 +52,10 @@
using namespace std; using namespace std;
std::map<std::string, char* (*)(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize)> FunctionMap = { std::map<std::string, char* (*)(string type, char* BufferData, size_t BufferLength, map<string, any> Arguments, size_t* DataSize)> FunctionMap = {
{"blur", &Blur},
{"caption", &Caption}, {"caption", &Caption},
{"caption2", &CaptionTwo}, {"captionTwo", &CaptionTwo},
{"blur", &Blur},
{"circle", &Circle}, {"circle", &Circle},
{"colors", &Colors}, {"colors", &Colors},
{"crop", &Crop}, {"crop", &Crop},
@ -62,8 +63,8 @@ std::map<std::string, char* (*)(string type, char* BufferData, size_t BufferLeng
{"explode", &Explode}, {"explode", &Explode},
{"flag", &Flag}, {"flag", &Flag},
{"flip", &Flip}, {"flip", &Flip},
{"watermark", &Watermark}, {"uncaption", &Uncaption},
{"uncaption", &Uncaption} {"watermark", &Watermark}
}; };
std::map<std::string, Napi::Value (*)(const Napi::CallbackInfo &info)> OldFunctionMap = { std::map<std::string, Napi::Value (*)(const Napi::CallbackInfo &info)> OldFunctionMap = {
@ -94,6 +95,17 @@ std::map<std::string, Napi::Value (*)(const Napi::CallbackInfo &info)> OldFuncti
{"zamn", Zamn} {"zamn", Zamn}
}; };
bool isNapiValueInt(Napi::Env& env, Napi::Value& num) {
return env.Global()
.Get("Number")
.ToObject()
.Get("isInteger")
.As<Napi::Function>()
.Call({num})
.ToBoolean()
.Value();
}
Napi::Value NewProcessImage(const Napi::CallbackInfo &info) { Napi::Value NewProcessImage(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env(); Napi::Env env = info.Env();
Napi::Object result = Napi::Object::New(env); Napi::Object result = Napi::Object::New(env);
@ -106,7 +118,7 @@ Napi::Value NewProcessImage(const Napi::CallbackInfo &info) {
Napi::Array properties = obj.GetPropertyNames(); Napi::Array properties = obj.GetPropertyNames();
std::map<string, string> Arguments; std::map<string, any> Arguments;
for (unsigned int i = 0; i < properties.Length(); i++) { for (unsigned int i = 0; i < properties.Length(); i++) {
string property = properties.Get(uint32_t(i)).As<Napi::String>().Utf8Value(); string property = properties.Get(uint32_t(i)).As<Napi::String>().Utf8Value();
@ -115,7 +127,21 @@ Napi::Value NewProcessImage(const Napi::CallbackInfo &info) {
continue; continue;
} }
Arguments[property] = obj.Get(property).ToString().As<Napi::String>().Utf8Value(); auto val = obj.Get(property);
if (val.IsBoolean()) {
Arguments[property] = val.ToBoolean().Value();
} else if (val.IsString()) {
Arguments[property] = val.ToString().As<Napi::String>().Utf8Value();
} else if (val.IsNumber()) {
auto num = val.ToNumber();
if (isNapiValueInt(env, num)) {
Arguments[property] = num.Int32Value();
} else {
Arguments[property] = num.FloatValue();
}
} else {
Arguments[property] = val;
}
} }
size_t length = 0; size_t length = 0;
@ -159,6 +185,21 @@ Napi::Object Init(Napi::Env env, Napi::Object exports){
vips_error_exit(NULL); vips_error_exit(NULL);
exports.Set(Napi::String::New(env, "image"), Napi::Function::New(env, ProcessImage)); // new function handler exports.Set(Napi::String::New(env, "image"), Napi::Function::New(env, ProcessImage)); // new function handler
Napi::Array arr = Napi::Array::New(env);
size_t i = 0;
for (auto const& imap: FunctionMap) {
Napi::HandleScope scope(env);
arr[i] = Napi::String::New(env, imap.first);
i++;
}
for(auto const& imap: OldFunctionMap) {
Napi::HandleScope scope(env);
arr[i] = Napi::String::New(env, imap.first);
i++;
}
exports.Set(Napi::String::New(env, "funcs"), arr);
return exports; return exports;
} }

View file

@ -1,56 +1,57 @@
#include "common.h" #include "common.h"
#include <vips/vips8>
#include <map> #include <map>
#include <vips/vips8>
using namespace std; using namespace std;
using namespace vips; using namespace vips;
char* Uncaption(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize) { char *Uncaption(string type, char *BufferData, size_t BufferLength,
map<string, any> Arguments, size_t *DataSize) {
float tolerance = MAP_HAS(Arguments, "tolerance") float tolerance = MAP_GET_FALLBACK(Arguments, "tolerance", float, 0.5);
? stof(Arguments["tolerance"])
: 0.5;
VOption *options = VImage::option(); VOption *options = VImage::option();
VImage in = VImage in =
VImage::new_from_buffer(BufferData, BufferLength, "", VImage::new_from_buffer(
type == "gif" ? options->set("n", -1)->set("access", "sequential") : options) BufferData, BufferLength, "",
.colourspace(VIPS_INTERPRETATION_sRGB); type == "gif" ? options->set("n", -1)->set("access", "sequential")
if (!in.has_alpha()) in = in.bandjoin(255); : options)
.colourspace(VIPS_INTERPRETATION_sRGB);
if (!in.has_alpha())
in = in.bandjoin(255);
int width = in.width(); int width = in.width();
int pageHeight = vips_image_get_page_height(in.get_image()); int pageHeight = vips_image_get_page_height(in.get_image());
int nPages = vips_image_get_n_pages(in.get_image()); int nPages = vips_image_get_n_pages(in.get_image());
VImage first = VImage first =
in.crop(0, 0, 3, pageHeight).colourspace(VIPS_INTERPRETATION_B_W) > in.crop(0, 0, 3, pageHeight).colourspace(VIPS_INTERPRETATION_B_W) >
(255 * tolerance); (255 * tolerance);
int top, captionWidth, captionHeight; int top, captionWidth, captionHeight;
first.find_trim(&top, &captionWidth, &captionHeight); first.find_trim(&top, &captionWidth, &captionHeight);
vector<VImage> img; vector<VImage> img;
int newHeight = pageHeight - top; int newHeight = pageHeight - top;
if (top == pageHeight) { if (top == pageHeight) {
newHeight = pageHeight; newHeight = pageHeight;
top = 0; top = 0;
} }
for (int i = 0; i < nPages; i++) { for (int i = 0; i < nPages; i++) {
VImage img_frame = VImage img_frame = in.crop(0, (i * pageHeight) + top, width, newHeight);
in.crop(0, (i * pageHeight) + top, width, newHeight); img.push_back(img_frame);
img.push_back(img_frame); }
} VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1)); final.set(VIPS_META_PAGE_HEIGHT, newHeight);
final.set(VIPS_META_PAGE_HEIGHT, newHeight);
void *buf;
final.write_to_buffer(
("." + type).c_str(), &buf, DataSize,
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1) : 0);
void *buf;
final.write_to_buffer(
("." + type).c_str(), &buf, DataSize,
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1)
: 0);
vips_error_clear(); vips_error_clear();
vips_thread_shutdown(); vips_thread_shutdown();
return (char*) buf; return (char *)buf;
} }

View file

@ -1,5 +1,11 @@
#pragma once #pragma once
#include <any>
#include <map> #include <map>
#include <string>
char* Uncaption(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize); using std::any;
using std::map;
using std::string;
char* Uncaption(string type, char* BufferData, size_t BufferLength, map<string, any> Arguments, size_t* DataSize);

View file

@ -1,154 +1,157 @@
#include "common.h" #include "common.h"
#include <vips/vips8>
#include <map> #include <map>
#include <vips/vips8>
using namespace std; using namespace std;
using namespace vips; using namespace vips;
char* Watermark(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize) { char *Watermark(string type, char *BufferData, size_t BufferLength,
map<string, any> Arguments, size_t *DataSize) {
string water = Arguments["water"]; string water = MAP_GET(Arguments, "water", string);
int gravity = stoi(Arguments["gravity"]); int gravity = MAP_GET(Arguments, "gravity", int);
bool resize = MAP_HAS(Arguments, "resize") ? Arguments["resize"] == "true" : false;; bool resize = MAP_GET_FALLBACK(Arguments, "resize", bool, false);
float yscale = MAP_HAS(Arguments, "yscale") ? stof(Arguments["yscale"]) : false; ;
float yscale = MAP_GET_FALLBACK(Arguments, "yscale", float, false);
bool append = MAP_HAS(Arguments, "append") ? Arguments["append"] == "true" : false; bool append = MAP_GET_FALLBACK(Arguments, "append", bool, false);
bool alpha = MAP_HAS(Arguments, "alpha") ? Arguments["alpha"] == "true" : false; bool alpha = MAP_GET_FALLBACK(Arguments, "alpha", bool, false);
bool flip = MAP_HAS(Arguments, "flip") ? Arguments["flip"] == "true" : false; bool flip = MAP_GET_FALLBACK(Arguments, "flip", bool, false);
bool mc = MAP_HAS(Arguments, "mc");
string basePath = Arguments["basePath"]; bool mc = MAP_HAS(Arguments, "mc");
VOption *options = VImage::option()->set("access", "sequential"); string basePath = MAP_GET(Arguments, "basePath", string);
VImage in = VOption *options = VImage::option()->set("access", "sequential");
VImage::new_from_buffer(BufferData, BufferLength, "",
type == "gif" ? options->set("n", -1) : options)
.colourspace(VIPS_INTERPRETATION_sRGB);
if (!in.has_alpha()) in = in.bandjoin(255);
string merged = basePath + water; VImage in =
VImage watermark = VImage::new_from_file(merged.c_str()); VImage::new_from_buffer(BufferData, BufferLength, "",
type == "gif" ? options->set("n", -1) : options)
.colourspace(VIPS_INTERPRETATION_sRGB);
if (!in.has_alpha())
in = in.bandjoin(255);
int width = in.width(); string merged = basePath + water;
int pageHeight = vips_image_get_page_height(in.get_image()); VImage watermark = VImage::new_from_file(merged.c_str());
int nPages = vips_image_get_n_pages(in.get_image());
if (flip) { int width = in.width();
watermark = watermark.flip(VIPS_DIRECTION_HORIZONTAL); int pageHeight = vips_image_get_page_height(in.get_image());
} int nPages = vips_image_get_n_pages(in.get_image());
if (resize && append) { if (flip) {
watermark = watermark.resize((double)width / (double)watermark.width()); watermark = watermark.flip(VIPS_DIRECTION_HORIZONTAL);
} else if (resize && yscale) { }
watermark = watermark.resize(
(double)width / (double)watermark.width(),
VImage::option()->set("vscale", (double)(pageHeight * yscale) /
(double)watermark.height()));
} else if (resize) {
watermark =
watermark.resize((double)pageHeight / (double)watermark.height());
}
int x = 0, y = 0; if (resize && append) {
switch (gravity) { watermark = watermark.resize((double)width / (double)watermark.width());
case 1: } else if (resize && yscale) {
break; watermark = watermark.resize(
case 2: (double)width / (double)watermark.width(),
x = (width / 2) - (watermark.width() / 2); VImage::option()->set("vscale", (double)(pageHeight * yscale) /
break; (double)watermark.height()));
case 3: } else if (resize) {
x = width - watermark.width(); watermark =
break; watermark.resize((double)pageHeight / (double)watermark.height());
case 5: }
x = (width / 2) - (watermark.width() / 2);
y = (pageHeight / 2) - (watermark.height() / 2);
break;
case 6:
x = width - watermark.width();
y = (pageHeight / 2) - (watermark.height() / 2);
break;
case 8:
x = (width / 2) - (watermark.width() / 2);
y = pageHeight - watermark.height();
break;
case 9:
x = width - watermark.width();
y = pageHeight - watermark.height();
break;
}
vector<VImage> img; int x = 0, y = 0;
int addedHeight = 0; switch (gravity) {
VImage contentAlpha; case 1:
VImage frameAlpha; break;
VImage bg; case 2:
VImage frame; x = (width / 2) - (watermark.width() / 2);
for (int i = 0; i < nPages; i++) { break;
VImage img_frame = case 3:
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in; x = width - watermark.width();
if (append) { break;
VImage appended = img_frame.join(watermark, VIPS_DIRECTION_VERTICAL, case 5:
VImage::option()->set("expand", true)); x = (width / 2) - (watermark.width() / 2);
addedHeight = watermark.height(); y = (pageHeight / 2) - (watermark.height() / 2);
img.push_back(appended); break;
} else if (mc) { case 6:
VImage padded = x = width - watermark.width();
img_frame.embed(0, 0, width, pageHeight + 15, y = (pageHeight / 2) - (watermark.height() / 2);
VImage::option()->set("background", 0xffffff)); break;
VImage composited = case 8:
padded.composite2(watermark, VIPS_BLEND_MODE_OVER, x = (width / 2) - (watermark.width() / 2);
VImage::option() y = pageHeight - watermark.height();
->set("x", width - 190) break;
->set("y", padded.height() - 22)); case 9:
addedHeight = 15; x = width - watermark.width();
img.push_back(composited); y = pageHeight - watermark.height();
} else { break;
VImage composited; }
if (alpha) {
if (i == 0) { vector<VImage> img;
contentAlpha = watermark.extract_band(0).embed( int addedHeight = 0;
x, y, width, pageHeight, VImage contentAlpha;
VImage::option()->set("extend", "white")); VImage frameAlpha;
frameAlpha = watermark.extract_band(1).embed( VImage bg;
x, y, width, pageHeight, VImage frame;
VImage::option()->set("extend", "black")); for (int i = 0; i < nPages; i++) {
bg = VImage img_frame =
frameAlpha.new_from_image({0, 0, 0}).copy(VImage::option()->set( type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
"interpretation", VIPS_INTERPRETATION_sRGB)); if (append) {
frame = bg.bandjoin(frameAlpha); VImage appended = img_frame.join(watermark, VIPS_DIRECTION_VERTICAL,
if (type == "jpg" || type == "jpeg") { VImage::option()->set("expand", true));
type = "png"; addedHeight = watermark.height();
} img.push_back(appended);
} else if (mc) {
VImage padded =
img_frame.embed(0, 0, width, pageHeight + 15,
VImage::option()->set("background", 0xffffff));
VImage composited =
padded.composite2(watermark, VIPS_BLEND_MODE_OVER,
VImage::option()
->set("x", width - 190)
->set("y", padded.height() - 22));
addedHeight = 15;
img.push_back(composited);
} else {
VImage composited;
if (alpha) {
if (i == 0) {
contentAlpha = watermark.extract_band(0).embed(
x, y, width, pageHeight,
VImage::option()->set("extend", "white"));
frameAlpha = watermark.extract_band(1).embed(
x, y, width, pageHeight,
VImage::option()->set("extend", "black"));
bg = frameAlpha.new_from_image({0, 0, 0}).copy(VImage::option()->set(
"interpretation", VIPS_INTERPRETATION_sRGB));
frame = bg.bandjoin(frameAlpha);
if (type == "jpg" || type == "jpeg") {
type = "png";
} }
VImage content =
img_frame.extract_band(0, VImage::option()->set("n", 3))
.bandjoin(contentAlpha & img_frame.extract_band(3));
composited =
content.composite2(frame, VIPS_BLEND_MODE_OVER,
VImage::option()->set("x", x)->set("y", y));
} else {
composited =
img_frame.composite2(watermark, VIPS_BLEND_MODE_OVER,
VImage::option()->set("x", x)->set("y", y));
} }
img.push_back(composited); VImage content =
} img_frame.extract_band(0, VImage::option()->set("n", 3))
} .bandjoin(contentAlpha & img_frame.extract_band(3));
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
final.set(VIPS_META_PAGE_HEIGHT, pageHeight + addedHeight);
void *buf; composited =
final.write_to_buffer( content.composite2(frame, VIPS_BLEND_MODE_OVER,
("." + type).c_str(), &buf, DataSize, VImage::option()->set("x", x)->set("y", y));
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1) : 0); } else {
composited =
img_frame.composite2(watermark, VIPS_BLEND_MODE_OVER,
VImage::option()->set("x", x)->set("y", y));
}
img.push_back(composited);
}
}
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
final.set(VIPS_META_PAGE_HEIGHT, pageHeight + addedHeight);
void *buf;
final.write_to_buffer(
("." + type).c_str(), &buf, DataSize,
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1)
: 0);
vips_error_clear(); vips_error_clear();
vips_thread_shutdown(); vips_thread_shutdown();
return (char*) buf; return (char *)buf;
} }

View file

@ -1,5 +1,11 @@
#pragma once #pragma once
#include <napi.h> #include <any>
#include <map>
#include <string>
char* Watermark(string type, char* BufferData, size_t BufferLength, map<string, string> Arguments, size_t* DataSize); using std::any;
using std::map;
using std::string;
char* Watermark(string type, char* BufferData, size_t BufferLength, map<string, any> Arguments, size_t* DataSize);