Some fixes and whatnot
This commit is contained in:
parent
330dd67063
commit
7ee571dd2b
30 changed files with 699 additions and 589 deletions
|
@ -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))]);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
@ -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();
|
|
||||||
}
|
}
|
|
@ -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);
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
@ -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"},
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
|
@ -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);
|
|
@ -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;
|
||||||
}
|
}
|
|
@ -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);
|
|
@ -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();
|
|
||||||
}
|
}
|
|
@ -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);
|
|
@ -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;
|
||||||
}
|
}
|
|
@ -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);
|
|
@ -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;
|
||||||
}
|
}
|
|
@ -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);
|
|
@ -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());
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
Loading…
Reference in a new issue