Natives Rework (Thank you Essem)
Co-authored-by: Essem <TheEssem@users.noreply.github.com>
This commit is contained in:
parent
b424b2f813
commit
ff7f0a3110
88 changed files with 3358 additions and 3104 deletions
42
app.js
42
app.js
|
@ -75,27 +75,27 @@ async function* getFiles(dir) {
|
|||
async function init() {
|
||||
await exec("git rev-parse HEAD").then(output => output.stdout.substring(0, 7), () => "unknown commit").then(o => process.env.GIT_REV = o);
|
||||
console.log(`
|
||||
,*\`$ z\`"v
|
||||
F zBw\`% A ,W "W
|
||||
,\` ,EBBBWp"%. ,-=~~==-,+* 4BBE T
|
||||
M BBBBBBBB* ,w=####Wpw 4BBBBB# 1
|
||||
F BBBBBBBMwBBBBBBBBBBBBB#wXBBBBBH E
|
||||
F BBBBBBkBBBBBBBBBBBBBBBBBBBBE4BL k
|
||||
# BFBBBBBBBBBBBBF" "RBBBW F
|
||||
V ' 4BBBBBBBBBBM TBBL F
|
||||
F BBBBBBBBBBF JBB L
|
||||
F FBBBBBBBEB BBL 4
|
||||
E [BB4BBBBEBL BBL 4
|
||||
I #BBBBBBBEB 4BBH *w
|
||||
A 4BBBBBBBBBEW, ,BBBB W [
|
||||
.A ,k 4BBBBBBBBBBBEBW####BBBBBBM BF F
|
||||
k <BBBw BBBBEBBBBBBBBBBBBBBBBBQ4BM #
|
||||
5, REBBB4BBBBB#BBBBBBBBBBBBP5BFF ,F
|
||||
*w \`*4BBW\`"FF#F##FFFF"\` , * +"
|
||||
*+, " F'"'*^~~~^"^\` V+*^
|
||||
\`"""
|
||||
|
||||
esmBot ${esmBotVersion} (${process.env.GIT_REV})
|
||||
████
|
||||
████▒▒▒▒
|
||||
████▒▒████▒▒
|
||||
████▒▒██████▒▒
|
||||
████▒▒██████████▒▒
|
||||
████▒▒████████████▒▒
|
||||
████▒▒██████████████▒▒
|
||||
████▒▒██████████████▒▒▒▒
|
||||
████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
|
||||
████▒▒████████████▒▒██▒▒██▒▒
|
||||
████▒▒██████████▒▒████▒▒████▒▒
|
||||
████▒▒██████▒▒██████▒▒██████▒▒
|
||||
████▒▒████▒▒████████▒▒████████▒▒
|
||||
████▒▒▒▒██████████▒▒██████████▒▒
|
||||
████▒▒██████████▒▒██████████▒▒██
|
||||
████▒▒▒▒▒▒████▒▒████▒▒▒▒▒▒████
|
||||
████████▒▒▒▒▒▒▒▒▒▒████████
|
||||
██████████████████████
|
||||
██████████
|
||||
|
||||
mrmBot-matrix ${esmBotVersion} (${process.env.GIT_REV})
|
||||
`);
|
||||
|
||||
if (!types.classic && !types.application) {
|
||||
|
|
|
@ -79,14 +79,17 @@ class ImageCommand extends Command {
|
|||
}
|
||||
|
||||
try {
|
||||
const { buffer, type } = await runImageJob(imageParams);
|
||||
const { buffer, type, width, height } = await runImageJob(imageParams);
|
||||
if (type === "nogif" && this.constructor.requiresGIF) {
|
||||
return "That isn't a GIF!";
|
||||
}
|
||||
this.success = true;
|
||||
return {
|
||||
contents: buffer,
|
||||
name: `${this.constructor.command}.${type}`
|
||||
name: `${this.constructor.command}.${type}`,
|
||||
type,
|
||||
width,
|
||||
height
|
||||
};
|
||||
} catch (e) {
|
||||
if (e === "Request ended prematurely due to a closed connection") return "This image job couldn't be completed because the server it was running on went down. Try running your command again.";
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import ImageCommand from "../../classes/imageCommand.js";
|
||||
|
||||
class ExplodeCommand extends ImageCommand {
|
||||
params = {
|
||||
implode: false
|
||||
};
|
||||
|
||||
static category = "image-editing"
|
||||
static description = "Explodes an image";
|
||||
static aliases = ["exp"];
|
||||
|
|
|
@ -2,6 +2,9 @@ import ImageCommand from "../../classes/imageCommand.js";
|
|||
|
||||
class FlipCommand extends ImageCommand {
|
||||
static category = "image-editing"
|
||||
params = {
|
||||
flop: false
|
||||
};
|
||||
static description = "Flips an image";
|
||||
|
||||
static noImage = "You need to provide an image/GIF to flip!";
|
||||
|
|
|
@ -99,11 +99,15 @@ export default async function (matrixClient, event, room, toStartOfTimeline) {
|
|||
} else {
|
||||
const mxcUri = await matrixClient.uploadContent(result.contents);
|
||||
// TODO: make info object get width, height, and mime from natives so i dont need to read the buffer
|
||||
const imgsize = sizeOf(result.contents)
|
||||
let mime = imgsize.type;
|
||||
if (mime == "jpg") {
|
||||
mime = "jpeg";
|
||||
// const imgsize = sizeOf(result.contents)
|
||||
const mime = result.type;
|
||||
const imgsize = {
|
||||
width: result.width,
|
||||
height: result.height
|
||||
}
|
||||
// if (mime === "jpg") {
|
||||
// mime = "jpeg";
|
||||
// }
|
||||
await matrixClient.sendImageMessage(event.event.room_id, mxcUri.content_uri, {h: imgsize.height, w: imgsize.width, mimetype: `image/${mime}`, size: result.contents.length, thumbnail_info: {h: imgsize.height, w: imgsize.width, mimetype: `image/${mime}`, size: result.contents.length}}, result.name)
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -1,31 +1,36 @@
|
|||
#include <map>
|
||||
#include <string>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Blur(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t *DataSize) {
|
||||
bool sharp = GetArgument<bool>(Arguments, "sharp");
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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);
|
||||
|
||||
// TODO: find a better way to calculate the intensity for GIFs without
|
||||
// splitting frames
|
||||
VImage out =
|
||||
sharp ? in.sharpen(VImage::option()->set("sigma", 3)) : in.gaussblur(15);
|
||||
|
||||
void *buf;
|
||||
out.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
return (char *)buf;
|
||||
}
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Blur(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t *DataSize) {
|
||||
bool sharp = GetArgument<bool>(Arguments, "sharp");
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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);
|
||||
|
||||
// TODO: find a better way to calculate the intensity for GIFs without
|
||||
// splitting frames
|
||||
VImage out =
|
||||
sharp ? in.sharpen(VImage::option()->set("sigma", 3)) : in.gaussblur(15);
|
||||
|
||||
void *buf;
|
||||
out.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = out.width();
|
||||
output["height"] = vips_image_get_page_height(in.get_image());
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Blur(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Blur(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,51 +1,56 @@
|
|||
#include <math.h>
|
||||
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Bounce(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, [[maybe_unused]] ArgumentMap Arguments,
|
||||
size_t *DataSize) {
|
||||
VOption *options = VImage::option();
|
||||
|
||||
VImage in =
|
||||
VImage::new_from_buffer(
|
||||
BufferData, BufferLength, "",
|
||||
type == "gif" ? options->set("n", -1)->set("access", "sequential")
|
||||
: options)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
if (!in.has_alpha()) in = in.bandjoin(255);
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = type == "gif" ? vips_image_get_n_pages(in.get_image()) : 15;
|
||||
double mult = M_PI / nPages;
|
||||
int halfHeight = pageHeight / 2;
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
double height = halfHeight * ((abs(sin(i * mult)) * -1) + 1);
|
||||
VImage embedded =
|
||||
img_frame.embed(0, height, width, pageHeight + halfHeight);
|
||||
img.push_back(embedded);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight + halfHeight);
|
||||
if (type != "gif") {
|
||||
vector<int> delay(30, 50);
|
||||
final.set("delay", delay);
|
||||
}
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(".gif", &buf, DataSize);
|
||||
|
||||
*outType = "gif";
|
||||
|
||||
return (char *)buf;
|
||||
#include <math.h>
|
||||
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Bounce(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, [[maybe_unused]] ArgumentMap Arguments,
|
||||
size_t *DataSize) {
|
||||
VOption *options = VImage::option();
|
||||
|
||||
VImage in =
|
||||
VImage::new_from_buffer(
|
||||
BufferData, BufferLength, "",
|
||||
type == "gif" ? options->set("n", -1)->set("access", "sequential")
|
||||
: options)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
if (!in.has_alpha()) in = in.bandjoin(255);
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = type == "gif" ? vips_image_get_n_pages(in.get_image()) : 15;
|
||||
double mult = M_PI / nPages;
|
||||
int halfHeight = pageHeight / 2;
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
double height = halfHeight * ((abs(sin(i * mult)) * -1) + 1);
|
||||
VImage embedded =
|
||||
img_frame.embed(0, height, width, pageHeight + halfHeight);
|
||||
img.push_back(embedded);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight + halfHeight);
|
||||
if (type != "gif") {
|
||||
vector<int> delay(30, 50);
|
||||
final.set("delay", delay);
|
||||
}
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(".gif", &buf, DataSize);
|
||||
|
||||
*outType = "gif";
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = width;
|
||||
output["height"] = pageHeight + halfHeight;
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Bounce(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Bounce(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,77 +1,82 @@
|
|||
#include <map>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Caption(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
string caption = GetArgument<string>(Arguments, "caption");
|
||||
string font = GetArgument<string>(Arguments, "font");
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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();
|
||||
int size = width / 10;
|
||||
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) + " " +
|
||||
(font != "impact" ? "bold" : "normal") + " " +
|
||||
to_string(size);
|
||||
|
||||
string captionText = "<span background=\"white\">" + caption + "</span>";
|
||||
|
||||
VImage text;
|
||||
auto findResult = fontPaths.find(font);
|
||||
if (findResult != fontPaths.end()) {
|
||||
text = VImage::text(
|
||||
".", VImage::option()->set("fontfile",
|
||||
(basePath + findResult->second).c_str()));
|
||||
}
|
||||
text = VImage::text(
|
||||
captionText.c_str(),
|
||||
VImage::option()
|
||||
->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"));
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
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());
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
return (char *)buf;
|
||||
}
|
||||
#include <map>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Caption(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
string caption = GetArgument<string>(Arguments, "caption");
|
||||
string font = GetArgument<string>(Arguments, "font");
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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();
|
||||
int size = width / 10;
|
||||
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) + " " +
|
||||
(font != "impact" ? "bold" : "normal") + " " +
|
||||
to_string(size);
|
||||
|
||||
string captionText = "<span background=\"white\">" + caption + "</span>";
|
||||
|
||||
VImage text;
|
||||
auto findResult = fontPaths.find(font);
|
||||
if (findResult != fontPaths.end()) {
|
||||
text = VImage::text(
|
||||
".", VImage::option()->set("fontfile",
|
||||
(basePath + findResult->second).c_str()));
|
||||
}
|
||||
text = VImage::text(
|
||||
captionText.c_str(),
|
||||
VImage::option()
|
||||
->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"));
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
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());
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = final.width();
|
||||
output["height"] = vips_image_get_page_height(in.get_image());
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Caption(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Caption(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,81 +1,86 @@
|
|||
#include <map>
|
||||
#include <string>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *CaptionTwo(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
bool top = GetArgument<bool>(Arguments, "top");
|
||||
string caption = GetArgument<string>(Arguments, "caption");
|
||||
string font = GetArgument<string>(Arguments, "font");
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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();
|
||||
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 font_string = (font == "roboto" ? "Roboto Condensed" : font) +
|
||||
", Twemoji Color Emoji " + to_string(size);
|
||||
|
||||
string captionText = "<span background=\"white\">" + caption + "</span>";
|
||||
|
||||
VImage text;
|
||||
auto findResult = fontPaths.find(font);
|
||||
if (findResult != fontPaths.end()) {
|
||||
text = VImage::text(
|
||||
".", VImage::option()->set("fontfile",
|
||||
(basePath + findResult->second).c_str()));
|
||||
}
|
||||
text = VImage::text(
|
||||
captionText.c_str(),
|
||||
VImage::option()
|
||||
->set("rgba", true)
|
||||
->set("font", font_string.c_str())
|
||||
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str())
|
||||
->set("align", VIPS_ALIGN_LOW)
|
||||
->set("width", textWidth));
|
||||
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;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
VImage frame =
|
||||
(top ? captionImage : img_frame)
|
||||
.join(top ? img_frame : captionImage, 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());
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
return (char *)buf;
|
||||
}
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap CaptionTwo(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
bool top = GetArgument<bool>(Arguments, "top");
|
||||
string caption = GetArgument<string>(Arguments, "caption");
|
||||
string font = GetArgument<string>(Arguments, "font");
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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();
|
||||
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 font_string = (font == "roboto" ? "Roboto Condensed" : font) +
|
||||
", Twemoji Color Emoji " + to_string(size);
|
||||
|
||||
string captionText = "<span background=\"white\">" + caption + "</span>";
|
||||
|
||||
VImage text;
|
||||
auto findResult = fontPaths.find(font);
|
||||
if (findResult != fontPaths.end()) {
|
||||
text = VImage::text(
|
||||
".", VImage::option()->set("fontfile",
|
||||
(basePath + findResult->second).c_str()));
|
||||
}
|
||||
text = VImage::text(
|
||||
captionText.c_str(),
|
||||
VImage::option()
|
||||
->set("rgba", true)
|
||||
->set("font", font_string.c_str())
|
||||
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str())
|
||||
->set("align", VIPS_ALIGN_LOW)
|
||||
->set("width", textWidth));
|
||||
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;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
VImage frame =
|
||||
(top ? captionImage : img_frame)
|
||||
.join(top ? img_frame : captionImage, 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());
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = final.width();
|
||||
output["height"] = vips_image_get_page_height(in.get_image());
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* CaptionTwo(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap CaptionTwo(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,54 +1,60 @@
|
|||
#include <Magick++.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Magick;
|
||||
|
||||
char *Circle(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, [[maybe_unused]] ArgumentMap Arguments,
|
||||
size_t *DataSize) {
|
||||
Blob blob;
|
||||
|
||||
list<Image> frames;
|
||||
list<Image> coalesced;
|
||||
list<Image> blurred;
|
||||
try {
|
||||
readImages(&frames, Blob(BufferData, BufferLength));
|
||||
} catch (Magick::WarningCoder &warning) {
|
||||
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(*outType);
|
||||
blurred.push_back(image);
|
||||
}
|
||||
|
||||
optimizeTransparency(blurred.begin(), blurred.end());
|
||||
|
||||
if (*outType == "gif") {
|
||||
for (Image &image : blurred) {
|
||||
image.quantizeDitherMethod(FloydSteinbergDitherMethod);
|
||||
image.quantize();
|
||||
}
|
||||
}
|
||||
|
||||
writeImages(blurred.begin(), blurred.end(), &blob);
|
||||
|
||||
*DataSize = blob.length();
|
||||
|
||||
// workaround because the data is tied to the blob
|
||||
char *data = (char *)malloc(*DataSize);
|
||||
memcpy(data, blob.data(), *DataSize);
|
||||
return data;
|
||||
#include <Magick++.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Magick;
|
||||
|
||||
ArgumentMap Circle(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, [[maybe_unused]] ArgumentMap Arguments,
|
||||
size_t *DataSize) {
|
||||
Blob blob;
|
||||
|
||||
list<Image> frames;
|
||||
list<Image> coalesced;
|
||||
list<Image> blurred;
|
||||
try {
|
||||
readImages(&frames, Blob(BufferData, BufferLength));
|
||||
} catch (Magick::WarningCoder &warning) {
|
||||
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(*outType);
|
||||
blurred.push_back(image);
|
||||
}
|
||||
|
||||
optimizeTransparency(blurred.begin(), blurred.end());
|
||||
|
||||
if (*outType == "gif") {
|
||||
for (Image &image : blurred) {
|
||||
image.quantizeDitherMethod(FloydSteinbergDitherMethod);
|
||||
image.quantize();
|
||||
}
|
||||
}
|
||||
|
||||
writeImages(blurred.begin(), blurred.end(), &blob);
|
||||
|
||||
*DataSize = blob.length();
|
||||
|
||||
// workaround because the data is tied to the blob
|
||||
char *data = (char *)malloc(*DataSize);
|
||||
memcpy(data, blob.data(), *DataSize);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = data;
|
||||
output["width"] = (int)blurred.front().columns();
|
||||
output["height"] = (int)blurred.front().rows();
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Circle(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Circle(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,26 +1,26 @@
|
|||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#include "../common.h"
|
||||
|
||||
void showUsage(char *path) {
|
||||
std::cout << "Usage: " << path << " operation [--arg=\"param\"] [...]" << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc < 1 ||
|
||||
(argc == 1 && !strcmp(argv[1], "-h"))) {
|
||||
showUsage(argv[0]);
|
||||
#ifdef _WIN32
|
||||
system("PAUSE");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *op = argv[1];
|
||||
|
||||
//handleArguments(argc, argv);
|
||||
|
||||
std::cout << "This does nothing yet, but it might in the future!" << std::endl;
|
||||
return 0;
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#include "../common.h"
|
||||
|
||||
void showUsage(char *path) {
|
||||
std::cout << "Usage: " << path << " operation [--arg=\"param\"] [...]" << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc < 1 ||
|
||||
(argc == 1 && !strcmp(argv[1], "-h"))) {
|
||||
showUsage(argv[0]);
|
||||
#ifdef _WIN32
|
||||
system("PAUSE");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *op = argv[1];
|
||||
|
||||
//handleArguments(argc, argv);
|
||||
|
||||
std::cout << "This does nothing yet, but it might in the future!" << std::endl;
|
||||
return 0;
|
||||
}
|
|
@ -1,36 +1,41 @@
|
|||
#include <map>
|
||||
#include <string>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
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);
|
||||
|
||||
char *Colors(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
string color = GetArgument<string>(Arguments, "color");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
VImage::new_from_buffer(BufferData, BufferLength, "",
|
||||
type == "gif" ? options->set("n", -1) : options)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
|
||||
VImage out;
|
||||
|
||||
if (color == "grayscale") {
|
||||
out = in.colourspace(VIPS_INTERPRETATION_B_W);
|
||||
} else if (color == "sepia") {
|
||||
out = in.extract_band(0, VImage::option()->set("n", 3)).recomb(sepia);
|
||||
}
|
||||
|
||||
void *buf;
|
||||
out.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
return (char *)buf;
|
||||
}
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
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);
|
||||
|
||||
ArgumentMap Colors(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
string color = GetArgument<string>(Arguments, "color");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
VImage::new_from_buffer(BufferData, BufferLength, "",
|
||||
type == "gif" ? options->set("n", -1) : options)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
|
||||
VImage out;
|
||||
|
||||
if (color == "grayscale") {
|
||||
out = in.colourspace(VIPS_INTERPRETATION_B_W);
|
||||
} else if (color == "sepia") {
|
||||
out = in.extract_band(0, VImage::option()->set("n", 3)).recomb(sepia);
|
||||
}
|
||||
|
||||
void *buf;
|
||||
out.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = out.width();
|
||||
output["height"] = vips_image_get_page_height(in.get_image());
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Colors(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Colors(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
258
natives/common.h
258
natives/common.h
|
@ -1,130 +1,130 @@
|
|||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <variant>
|
||||
|
||||
using std::map;
|
||||
using std::string;
|
||||
using std::variant;
|
||||
|
||||
typedef variant<string, float, bool, int> ArgumentVariant;
|
||||
typedef map<string, ArgumentVariant> ArgumentMap;
|
||||
|
||||
#include "blur.h"
|
||||
#include "bounce.h"
|
||||
#include "caption.h"
|
||||
#include "caption2.h"
|
||||
#include "circle.h"
|
||||
#include "colors.h"
|
||||
#include "crop.h"
|
||||
#include "deepfry.h"
|
||||
#include "explode.h"
|
||||
#include "flag.h"
|
||||
#include "flip.h"
|
||||
#include "freeze.h"
|
||||
#include "gamexplain.h"
|
||||
#include "globe.h"
|
||||
#include "homebrew.h"
|
||||
#include "invert.h"
|
||||
#include "jpeg.h"
|
||||
#include "magik.h"
|
||||
#include "meme.h"
|
||||
#include "mirror.h"
|
||||
#include "motivate.h"
|
||||
#include "reddit.h"
|
||||
#include "resize.h"
|
||||
#include "reverse.h"
|
||||
#include "scott.h"
|
||||
#include "snapchat.h"
|
||||
#include "sonic.h"
|
||||
#include "speed.h"
|
||||
#include "spin.h"
|
||||
#include "squish.h"
|
||||
#include "swirl.h"
|
||||
#include "tile.h"
|
||||
#include "togif.h"
|
||||
#include "uncanny.h"
|
||||
#include "uncaption.h"
|
||||
#include "wall.h"
|
||||
#include "watermark.h"
|
||||
#include "whisper.h"
|
||||
#include "zamn.h"
|
||||
|
||||
template <typename T>
|
||||
T GetArgument(ArgumentMap map, string key) {
|
||||
try {
|
||||
return std::get<T>(map.at(key));
|
||||
} catch (std::bad_variant_access&) {
|
||||
throw "Invalid requested type from variant.";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T GetArgumentWithFallback(ArgumentMap map, string key, T fallback) {
|
||||
try {
|
||||
return std::get<T>(map.at(key));
|
||||
} catch (...) { // this is, not great...
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
#define MAP_HAS(ARRAY, KEY) (ARRAY.count(KEY) > 0)
|
||||
#define MAP_GET(ARRAY, KEY, TYPE) \
|
||||
(MAP_HAS(ARRAY, KEY) ? get<TYPE>(ARRAY.at(KEY)) \
|
||||
: NULL) // C++ has forced my hand
|
||||
#define MAP_GET_FALLBACK(ARRAY, KEY, TYPE, FALLBACK) \
|
||||
(MAP_HAS(ARRAY, KEY) ? get<TYPE>(ARRAY.at(KEY)) : FALLBACK)
|
||||
|
||||
#define ARG_TYPES std::variant<string, bool, int, float>
|
||||
|
||||
const std::unordered_map<std::string, std::string> fontPaths{
|
||||
{"futura", "assets/fonts/caption.otf"},
|
||||
{"helvetica", "assets/fonts/caption2.ttf"},
|
||||
{"roboto", "assets/fonts/reddit.ttf"}};
|
||||
|
||||
const std::map<std::string,
|
||||
char* (*)(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize)>
|
||||
FunctionMap = {{"blur", &Blur},
|
||||
{"bounce", &Bounce},
|
||||
{"caption", &Caption},
|
||||
{"captionTwo", &CaptionTwo},
|
||||
{"circle", &Circle},
|
||||
{"colors", &Colors},
|
||||
{"crop", &Crop},
|
||||
{"deepfry", &Deepfry},
|
||||
{"explode", &Explode},
|
||||
{"flag", &Flag},
|
||||
{"flip", &Flip},
|
||||
{"freeze", &Freeze},
|
||||
{"gamexplain", Gamexplain},
|
||||
{"globe", Globe},
|
||||
{"invert", Invert},
|
||||
{"jpeg", Jpeg},
|
||||
{"magik", Magik},
|
||||
{"meme", Meme},
|
||||
{"mirror", Mirror},
|
||||
{"motivate", Motivate},
|
||||
{"reddit", Reddit},
|
||||
{"resize", Resize},
|
||||
{"reverse", Reverse},
|
||||
{"scott", Scott},
|
||||
{"snapchat", Snapchat},
|
||||
{"speed", &Speed},
|
||||
{"spin", Spin},
|
||||
{"squish", Squish},
|
||||
{"swirl", Swirl},
|
||||
{"tile", Tile},
|
||||
{"togif", ToGif},
|
||||
{"uncanny", Uncanny},
|
||||
{"uncaption", &Uncaption},
|
||||
{"wall", Wall},
|
||||
{"watermark", &Watermark},
|
||||
{"whisper", Whisper},
|
||||
{"zamn", Zamn}};
|
||||
|
||||
const std::map<std::string,
|
||||
char* (*)(string type, string* outType, ArgumentMap Arguments, size_t* DataSize)>
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <variant>
|
||||
|
||||
using std::map;
|
||||
using std::string;
|
||||
using std::variant;
|
||||
|
||||
typedef variant<char*, string, float, bool, int> ArgumentVariant;
|
||||
typedef map<string, ArgumentVariant> ArgumentMap;
|
||||
|
||||
#include "blur.h"
|
||||
#include "bounce.h"
|
||||
#include "caption.h"
|
||||
#include "caption2.h"
|
||||
#include "circle.h"
|
||||
#include "colors.h"
|
||||
#include "crop.h"
|
||||
#include "deepfry.h"
|
||||
#include "explode.h"
|
||||
#include "flag.h"
|
||||
#include "flip.h"
|
||||
#include "freeze.h"
|
||||
#include "gamexplain.h"
|
||||
#include "globe.h"
|
||||
#include "homebrew.h"
|
||||
#include "invert.h"
|
||||
#include "jpeg.h"
|
||||
#include "magik.h"
|
||||
#include "meme.h"
|
||||
#include "mirror.h"
|
||||
#include "motivate.h"
|
||||
#include "reddit.h"
|
||||
#include "resize.h"
|
||||
#include "reverse.h"
|
||||
#include "scott.h"
|
||||
#include "snapchat.h"
|
||||
#include "sonic.h"
|
||||
#include "speed.h"
|
||||
#include "spin.h"
|
||||
#include "squish.h"
|
||||
#include "swirl.h"
|
||||
#include "tile.h"
|
||||
#include "togif.h"
|
||||
#include "uncanny.h"
|
||||
#include "uncaption.h"
|
||||
#include "wall.h"
|
||||
#include "watermark.h"
|
||||
#include "whisper.h"
|
||||
#include "zamn.h"
|
||||
|
||||
template <typename T>
|
||||
T GetArgument(ArgumentMap map, string key) {
|
||||
try {
|
||||
return std::get<T>(map.at(key));
|
||||
} catch (std::bad_variant_access&) {
|
||||
throw "Invalid requested type from variant.";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T GetArgumentWithFallback(ArgumentMap map, string key, T fallback) {
|
||||
try {
|
||||
return std::get<T>(map.at(key));
|
||||
} catch (...) { // this is, not great...
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
#define MAP_HAS(ARRAY, KEY) (ARRAY.count(KEY) > 0)
|
||||
#define MAP_GET(ARRAY, KEY, TYPE) \
|
||||
(MAP_HAS(ARRAY, KEY) ? get<TYPE>(ARRAY.at(KEY)) \
|
||||
: NULL) // C++ has forced my hand
|
||||
#define MAP_GET_FALLBACK(ARRAY, KEY, TYPE, FALLBACK) \
|
||||
(MAP_HAS(ARRAY, KEY) ? get<TYPE>(ARRAY.at(KEY)) : FALLBACK)
|
||||
|
||||
#define ARG_TYPES std::variant<string, bool, int, float>
|
||||
|
||||
const std::unordered_map<std::string, std::string> fontPaths{
|
||||
{"futura", "assets/fonts/caption.otf"},
|
||||
{"helvetica", "assets/fonts/caption2.ttf"},
|
||||
{"roboto", "assets/fonts/reddit.ttf"}};
|
||||
|
||||
const std::map<std::string,
|
||||
ArgumentMap (*)(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize)>
|
||||
FunctionMap = {{"blur", &Blur},
|
||||
{"bounce", &Bounce},
|
||||
{"caption", &Caption},
|
||||
{"captionTwo", &CaptionTwo},
|
||||
{"circle", &Circle},
|
||||
{"colors", &Colors},
|
||||
{"crop", &Crop},
|
||||
{"deepfry", &Deepfry},
|
||||
{"explode", &Explode},
|
||||
{"flag", &Flag},
|
||||
{"flip", &Flip},
|
||||
{"freeze", &Freeze},
|
||||
{"gamexplain", Gamexplain},
|
||||
{"globe", Globe},
|
||||
{"invert", Invert},
|
||||
{"jpeg", Jpeg},
|
||||
{"magik", Magik},
|
||||
{"meme", Meme},
|
||||
{"mirror", Mirror},
|
||||
{"motivate", Motivate},
|
||||
{"reddit", Reddit},
|
||||
{"resize", Resize},
|
||||
{"reverse", Reverse},
|
||||
{"scott", Scott},
|
||||
{"snapchat", Snapchat},
|
||||
{"speed", &Speed},
|
||||
{"spin", Spin},
|
||||
{"squish", Squish},
|
||||
{"swirl", Swirl},
|
||||
{"tile", Tile},
|
||||
{"togif", ToGif},
|
||||
{"uncanny", Uncanny},
|
||||
{"uncaption", &Uncaption},
|
||||
{"wall", Wall},
|
||||
{"watermark", &Watermark},
|
||||
{"whisper", Whisper},
|
||||
{"zamn", Zamn}};
|
||||
|
||||
const std::map<std::string,
|
||||
ArgumentMap (*)(string type, string* outType, ArgumentMap Arguments, size_t* DataSize)>
|
||||
NoInputFunctionMap = {{"homebrew", Homebrew}, {"sonic", Sonic}};
|
105
natives/crop.cc
105
natives/crop.cc
|
@ -1,51 +1,56 @@
|
|||
#include <map>
|
||||
#include <string>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Crop(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
[[maybe_unused]] ArgumentMap Arguments, size_t *DataSize) {
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
VImage::new_from_buffer(BufferData, BufferLength, "",
|
||||
type == "gif" ? options->set("n", -1) : options)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
vector<VImage> img;
|
||||
int finalHeight = 0;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
int frameWidth = img_frame.width();
|
||||
int frameHeight = img_frame.height();
|
||||
bool widthOrHeight = frameWidth / frameHeight >= 1;
|
||||
int size = widthOrHeight ? frameHeight : frameWidth;
|
||||
// img_frame.crop(frameWidth - size, frameHeight - size, size, size);
|
||||
VImage result = img_frame.smartcrop(
|
||||
size, size,
|
||||
VImage::option()->set("interesting", VIPS_INTERESTING_CENTRE));
|
||||
finalHeight = size;
|
||||
img.push_back(result);
|
||||
}
|
||||
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, finalHeight);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
return (char *)buf;
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Crop(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
[[maybe_unused]] ArgumentMap Arguments, size_t *DataSize) {
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
VImage::new_from_buffer(BufferData, BufferLength, "",
|
||||
type == "gif" ? options->set("n", -1) : options)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
vector<VImage> img;
|
||||
int finalHeight = 0;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
int frameWidth = img_frame.width();
|
||||
int frameHeight = img_frame.height();
|
||||
bool widthOrHeight = frameWidth / frameHeight >= 1;
|
||||
int size = widthOrHeight ? frameHeight : frameWidth;
|
||||
// img_frame.crop(frameWidth - size, frameHeight - size, size, size);
|
||||
VImage result = img_frame.smartcrop(
|
||||
size, size,
|
||||
VImage::option()->set("interesting", VIPS_INTERESTING_CENTRE));
|
||||
finalHeight = size;
|
||||
img.push_back(result);
|
||||
}
|
||||
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, finalHeight);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = width;
|
||||
output["height"] = finalHeight;
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Crop(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Crop(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,61 +1,66 @@
|
|||
#include <map>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Deepfry(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, [[maybe_unused]] ArgumentMap Arguments,
|
||||
size_t *DataSize) {
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int totalHeight = in.height();
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
VImage fried = (in * 1.3 - (255.0 * 1.3 - 255.0)) * 1.5;
|
||||
|
||||
VImage final;
|
||||
if (totalHeight > 65500 && type == "gif") {
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
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;
|
||||
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;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif" ? VImage::option()->set("dither", 0) : 0);
|
||||
|
||||
return (char *)buf;
|
||||
#include <map>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Deepfry(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, [[maybe_unused]] ArgumentMap Arguments,
|
||||
size_t *DataSize) {
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int totalHeight = in.height();
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
VImage fried = (in * 1.3 - (255.0 * 1.3 - 255.0)) * 1.5;
|
||||
|
||||
VImage final;
|
||||
if (totalHeight > 65500 && type == "gif") {
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
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;
|
||||
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;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif" ? VImage::option()->set("dither", 0) : 0);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = width;
|
||||
output["height"] = pageHeight;
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Deepfry(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Deepfry(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,52 +1,57 @@
|
|||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Explode(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
bool implode = GetArgumentWithFallback<bool>(Arguments, "implode", false);
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option();
|
||||
|
||||
VImage in =
|
||||
VImage::new_from_buffer(
|
||||
BufferData, BufferLength, "",
|
||||
type == "gif" ? options->set("n", -1)->set("access", "sequential")
|
||||
: options)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
if (!in.has_alpha()) in = in.bandjoin(255);
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
string distortPath = basePath + "assets/images/" +
|
||||
(implode ? "linearimplode.png" : "linearexplode.png");
|
||||
VImage distort =
|
||||
(VImage::new_from_file(distortPath.c_str())
|
||||
.resize(width / 500.0, VImage::option()
|
||||
->set("vscale", pageHeight / 500.0)
|
||||
->set("kernel", VIPS_KERNEL_CUBIC)) /
|
||||
65535);
|
||||
|
||||
VImage distortImage = (distort[0] * width).bandjoin(distort[1] * pageHeight);
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
VImage mapped = img_frame.mapim(distortImage);
|
||||
img.push_back(mapped);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
return (char *)buf;
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Explode(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
bool implode = GetArgumentWithFallback<bool>(Arguments, "implode", false);
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option();
|
||||
|
||||
VImage in =
|
||||
VImage::new_from_buffer(
|
||||
BufferData, BufferLength, "",
|
||||
type == "gif" ? options->set("n", -1)->set("access", "sequential")
|
||||
: options)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
if (!in.has_alpha()) in = in.bandjoin(255);
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
string distortPath = basePath + "assets/images/" +
|
||||
(implode ? "linearimplode.png" : "linearexplode.png");
|
||||
VImage distort =
|
||||
(VImage::new_from_file(distortPath.c_str())
|
||||
.resize(width / 500.0, VImage::option()
|
||||
->set("vscale", pageHeight / 500.0)
|
||||
->set("kernel", VIPS_KERNEL_CUBIC)) /
|
||||
65535);
|
||||
|
||||
VImage distortImage = (distort[0] * width).bandjoin(distort[1] * pageHeight);
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
VImage mapped = img_frame.mapim(distortImage);
|
||||
img.push_back(mapped);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = width;
|
||||
output["height"] = pageHeight;
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Explode(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Explode(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
101
natives/flag.cc
101
natives/flag.cc
|
@ -1,49 +1,54 @@
|
|||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Flag(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t *DataSize) {
|
||||
string overlay = GetArgument<string>(Arguments, "overlay");
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
string assetPath = basePath + overlay;
|
||||
VImage overlayInput = VImage::new_from_file(assetPath.c_str());
|
||||
VImage overlayImage = overlayInput.resize(
|
||||
(double)width / (double)overlayInput.width(),
|
||||
VImage::option()->set(
|
||||
"vscale", (double)pageHeight / (double)overlayInput.height()));
|
||||
if (!overlayImage.has_alpha()) {
|
||||
overlayImage = overlayImage.bandjoin(127);
|
||||
} else {
|
||||
// this is a pretty cool line, just saying
|
||||
overlayImage = overlayImage * vector<double>{1, 1, 1, 0.5};
|
||||
}
|
||||
VImage replicated = overlayImage.replicate(1, nPages);
|
||||
VImage final = in.composite2(replicated, VIPS_BLEND_MODE_OVER);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
return (char *)buf;
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Flag(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t *DataSize) {
|
||||
string overlay = GetArgument<string>(Arguments, "overlay");
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
string assetPath = basePath + overlay;
|
||||
VImage overlayInput = VImage::new_from_file(assetPath.c_str());
|
||||
VImage overlayImage = overlayInput.resize(
|
||||
(double)width / (double)overlayInput.width(),
|
||||
VImage::option()->set(
|
||||
"vscale", (double)pageHeight / (double)overlayInput.height()));
|
||||
if (!overlayImage.has_alpha()) {
|
||||
overlayImage = overlayImage.bandjoin(127);
|
||||
} else {
|
||||
// this is a pretty cool line, just saying
|
||||
overlayImage = overlayImage * vector<double>{1, 1, 1, 0.5};
|
||||
}
|
||||
VImage replicated = overlayImage.replicate(1, nPages);
|
||||
VImage final = in.composite2(replicated, VIPS_BLEND_MODE_OVER);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = width;
|
||||
output["height"] = pageHeight;
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Flag(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Flag(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,48 +1,53 @@
|
|||
#include <map>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Flip(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t *DataSize) {
|
||||
bool flop = GetArgument<bool>(Arguments, "flop");
|
||||
|
||||
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 out;
|
||||
if (flop) {
|
||||
out = in.flip(VIPS_DIRECTION_HORIZONTAL);
|
||||
} else if (type == "gif") {
|
||||
// libvips gif handling is both a blessing and a curse
|
||||
vector<VImage> img;
|
||||
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);
|
||||
}
|
||||
|
||||
void *buf;
|
||||
out.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
return (char *)buf;
|
||||
#include <map>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Flip(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t *DataSize) {
|
||||
bool flop = GetArgumentWithFallback<bool>(Arguments, "flop", false);
|
||||
|
||||
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 out;
|
||||
if (flop) {
|
||||
out = in.flip(VIPS_DIRECTION_HORIZONTAL);
|
||||
} else if (type == "gif") {
|
||||
// libvips gif handling is both a blessing and a curse
|
||||
vector<VImage> img;
|
||||
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);
|
||||
}
|
||||
|
||||
void *buf;
|
||||
out.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = out.width();
|
||||
output["height"] = vips_image_get_page_height(in.get_image());
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Flip(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Flip(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,83 +1,107 @@
|
|||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Freeze(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
bool loop = GetArgumentWithFallback<bool>(Arguments, "loop", false);
|
||||
int frame = GetArgumentWithFallback<int>(Arguments, "frame", -1);
|
||||
|
||||
char *fileData = (char *)malloc(BufferLength);
|
||||
memcpy(fileData, BufferData, BufferLength);
|
||||
|
||||
char *match = (char *)"\x21\xFF\x0BNETSCAPE2.0\x03\x01";
|
||||
char *descriptor = (char *)"\x2C\x00\x00\x00\x00";
|
||||
char *lastPos;
|
||||
|
||||
bool none = true;
|
||||
|
||||
if (loop) {
|
||||
char *newData = (char *)malloc(BufferLength + 19);
|
||||
memcpy(newData, fileData, BufferLength);
|
||||
lastPos = (char *)memchr(newData, '\x2C', BufferLength);
|
||||
while (lastPos != NULL) {
|
||||
if (memcmp(lastPos, descriptor, 5) != 0) {
|
||||
lastPos = (char *)memchr(lastPos + 1, '\x2C',
|
||||
(BufferLength - (lastPos - newData)) - 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(lastPos + 19, lastPos, (BufferLength - (lastPos - newData)));
|
||||
memcpy(lastPos, match, 16);
|
||||
memcpy(lastPos + 16, "\x00\x00\x00", 3);
|
||||
|
||||
none = false;
|
||||
*DataSize = BufferLength + 19;
|
||||
break;
|
||||
}
|
||||
if (none) *DataSize = BufferLength;
|
||||
|
||||
return newData;
|
||||
} else if (frame >= 0 && !loop) {
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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 pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
int framePos = clamp(frame, 0, (int)nPages);
|
||||
VImage out = in.crop(0, 0, in.width(), pageHeight * (framePos + 1));
|
||||
out.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
out.set("loop", 1);
|
||||
|
||||
void *buf;
|
||||
out.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
return (char *)buf;
|
||||
} else {
|
||||
lastPos = (char *)memchr(fileData, '\x21', BufferLength);
|
||||
while (lastPos != NULL) {
|
||||
if (memcmp(lastPos, match, 16) != 0) {
|
||||
lastPos = (char *)memchr(lastPos + 1, '\x21',
|
||||
(BufferLength - (lastPos - fileData)) - 1);
|
||||
continue;
|
||||
}
|
||||
memcpy(lastPos, lastPos + 19, (BufferLength - (lastPos - fileData)) - 19);
|
||||
*DataSize = BufferLength - 19;
|
||||
none = false;
|
||||
break;
|
||||
}
|
||||
if (none) *DataSize = BufferLength;
|
||||
|
||||
return fileData;
|
||||
}
|
||||
}
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Freeze(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
bool loop = GetArgumentWithFallback<bool>(Arguments, "loop", false);
|
||||
int frame = GetArgumentWithFallback<int>(Arguments, "frame", -1);
|
||||
|
||||
char *fileData = (char *)malloc(BufferLength);
|
||||
memcpy(fileData, BufferData, BufferLength);
|
||||
|
||||
char *match = (char *)"\x21\xFF\x0BNETSCAPE2.0\x03\x01";
|
||||
char *descriptor = (char *)"\x2C\x00\x00\x00\x00";
|
||||
char *lastPos;
|
||||
|
||||
bool none = true;
|
||||
|
||||
if (loop) {
|
||||
char *newData = (char *)malloc(BufferLength + 19);
|
||||
memcpy(newData, fileData, BufferLength);
|
||||
lastPos = (char *)memchr(newData, '\x2C', BufferLength);
|
||||
while (lastPos != NULL) {
|
||||
if (memcmp(lastPos, descriptor, 5) != 0) {
|
||||
lastPos = (char *)memchr(lastPos + 1, '\x2C',
|
||||
(BufferLength - (lastPos - newData)) - 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(lastPos + 19, lastPos, (BufferLength - (lastPos - newData)));
|
||||
memcpy(lastPos, match, 16);
|
||||
memcpy(lastPos + 16, "\x00\x00\x00", 3);
|
||||
|
||||
none = false;
|
||||
*DataSize = BufferLength + 19;
|
||||
break;
|
||||
}
|
||||
if (none) *DataSize = BufferLength;
|
||||
|
||||
VImage in =
|
||||
VImage::new_from_buffer(newData, *DataSize, "",
|
||||
VImage::option()->set("access", "sequential"));
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = newData;
|
||||
output["width"] = in.width();
|
||||
output["height"] = vips_image_get_page_height(in.get_image());
|
||||
|
||||
return output;
|
||||
} else if (frame >= 0 && !loop) {
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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 pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
int framePos = clamp(frame, 0, (int)nPages);
|
||||
VImage out = in.crop(0, 0, in.width(), pageHeight * (framePos + 1));
|
||||
out.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
out.set("loop", 1);
|
||||
|
||||
void *buf;
|
||||
out.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = out.width();
|
||||
output["height"] = vips_image_get_page_height(in.get_image());
|
||||
|
||||
return output;
|
||||
|
||||
} else {
|
||||
lastPos = (char *)memchr(fileData, '\x21', BufferLength);
|
||||
while (lastPos != NULL) {
|
||||
if (memcmp(lastPos, match, 16) != 0) {
|
||||
lastPos = (char *)memchr(lastPos + 1, '\x21',
|
||||
(BufferLength - (lastPos - fileData)) - 1);
|
||||
continue;
|
||||
}
|
||||
memcpy(lastPos, lastPos + 19, (BufferLength - (lastPos - fileData)) - 19);
|
||||
*DataSize = BufferLength - 19;
|
||||
none = false;
|
||||
break;
|
||||
}
|
||||
if (none) *DataSize = BufferLength;
|
||||
|
||||
VImage in =
|
||||
VImage::new_from_buffer(fileData, *DataSize, "",
|
||||
VImage::option()->set("access", "sequential"));
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = fileData;
|
||||
output["width"] = in.width();
|
||||
output["height"] = vips_image_get_page_height(in.get_image());
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Freeze(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Freeze(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,50 +1,55 @@
|
|||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Gamexplain(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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 assetPath = basePath + "assets/images/gamexplain.png";
|
||||
VImage tmpl = VImage::new_from_file(assetPath.c_str());
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
VImage resized =
|
||||
img_frame
|
||||
.resize(1181.0 / (double)width,
|
||||
VImage::option()->set("vscale", 571.0 / (double)pageHeight))
|
||||
.embed(10, 92, 1200, 675, VImage::option()->set("extend", "white"));
|
||||
VImage composited = resized.composite2(tmpl, VIPS_BLEND_MODE_OVER);
|
||||
img.push_back(composited);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, 675);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
return (char *)buf;
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Gamexplain(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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 assetPath = basePath + "assets/images/gamexplain.png";
|
||||
VImage tmpl = VImage::new_from_file(assetPath.c_str());
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
VImage resized =
|
||||
img_frame
|
||||
.resize(1181.0 / (double)width,
|
||||
VImage::option()->set("vscale", 571.0 / (double)pageHeight))
|
||||
.embed(10, 92, 1200, 675, VImage::option()->set("extend", "white"));
|
||||
VImage composited = resized.composite2(tmpl, VIPS_BLEND_MODE_OVER);
|
||||
img.push_back(composited);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, 675);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = final.width();
|
||||
output["height"] = vips_image_get_page_height(in.get_image());
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Gamexplain(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Gamexplain(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
149
natives/globe.cc
149
natives/globe.cc
|
@ -1,73 +1,78 @@
|
|||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Globe(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t *DataSize) {
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option();
|
||||
|
||||
VImage in =
|
||||
VImage::new_from_buffer(
|
||||
BufferData, BufferLength, "",
|
||||
type == "gif" ? options->set("n", -1)->set("access", "sequential")
|
||||
: options)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
if (!in.has_alpha()) in = in.bandjoin(255);
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = type == "gif" ? vips_image_get_n_pages(in.get_image()) : 30;
|
||||
|
||||
double size = min(width, pageHeight);
|
||||
|
||||
string diffPath = basePath + "assets/images/globediffuse.png";
|
||||
VImage diffuse = VImage::new_from_file(diffPath.c_str())
|
||||
.resize(size / 500.0, VImage::option()->set(
|
||||
"kernel", VIPS_KERNEL_CUBIC)) /
|
||||
255;
|
||||
|
||||
string specPath = basePath + "assets/images/globespec.png";
|
||||
VImage specular = VImage::new_from_file(specPath.c_str())
|
||||
.resize(size / 500.0, VImage::option()->set(
|
||||
"kernel", VIPS_KERNEL_CUBIC));
|
||||
|
||||
string distortPath = basePath + "assets/images/spheremap.png";
|
||||
VImage distort =
|
||||
(VImage::new_from_file(distortPath.c_str())
|
||||
.resize(size / 500.0,
|
||||
VImage::option()->set("kernel", VIPS_KERNEL_CUBIC)) /
|
||||
65535) *
|
||||
size;
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
VImage resized = img_frame.resize(
|
||||
size / (double)width,
|
||||
VImage::option()->set("vscale", size / (double)pageHeight));
|
||||
VImage rolled = img_frame.wrap(
|
||||
VImage::option()->set("x", width * i / nPages)->set("y", 0));
|
||||
VImage extracted = rolled.extract_band(0, VImage::option()->set("n", 3));
|
||||
VImage mapped = extracted.mapim(distort);
|
||||
VImage composited = mapped * diffuse + specular;
|
||||
VImage frame = composited.bandjoin(diffuse > 0.0);
|
||||
img.push_back(frame);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, size);
|
||||
if (type != "gif") {
|
||||
vector<int> delay(30, 50);
|
||||
final.set("delay", delay);
|
||||
}
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(".gif", &buf, DataSize);
|
||||
|
||||
return (char *)buf;
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Globe(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t *DataSize) {
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option();
|
||||
|
||||
VImage in =
|
||||
VImage::new_from_buffer(
|
||||
BufferData, BufferLength, "",
|
||||
type == "gif" ? options->set("n", -1)->set("access", "sequential")
|
||||
: options)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
if (!in.has_alpha()) in = in.bandjoin(255);
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = type == "gif" ? vips_image_get_n_pages(in.get_image()) : 30;
|
||||
|
||||
double size = min(width, pageHeight);
|
||||
|
||||
string diffPath = basePath + "assets/images/globediffuse.png";
|
||||
VImage diffuse = VImage::new_from_file(diffPath.c_str())
|
||||
.resize(size / 500.0, VImage::option()->set(
|
||||
"kernel", VIPS_KERNEL_CUBIC)) /
|
||||
255;
|
||||
|
||||
string specPath = basePath + "assets/images/globespec.png";
|
||||
VImage specular = VImage::new_from_file(specPath.c_str())
|
||||
.resize(size / 500.0, VImage::option()->set(
|
||||
"kernel", VIPS_KERNEL_CUBIC));
|
||||
|
||||
string distortPath = basePath + "assets/images/spheremap.png";
|
||||
VImage distort =
|
||||
(VImage::new_from_file(distortPath.c_str())
|
||||
.resize(size / 500.0,
|
||||
VImage::option()->set("kernel", VIPS_KERNEL_CUBIC)) /
|
||||
65535) *
|
||||
size;
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
VImage resized = img_frame.resize(
|
||||
size / (double)width,
|
||||
VImage::option()->set("vscale", size / (double)pageHeight));
|
||||
VImage rolled = img_frame.wrap(
|
||||
VImage::option()->set("x", width * i / nPages)->set("y", 0));
|
||||
VImage extracted = rolled.extract_band(0, VImage::option()->set("n", 3));
|
||||
VImage mapped = extracted.mapim(distort);
|
||||
VImage composited = mapped * diffuse + specular;
|
||||
VImage frame = composited.bandjoin(diffuse > 0.0);
|
||||
img.push_back(frame);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, size);
|
||||
if (type != "gif") {
|
||||
vector<int> delay(30, 50);
|
||||
final.set("delay", delay);
|
||||
}
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(".gif", &buf, DataSize);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = final.width();
|
||||
output["height"] = vips_image_get_page_height(in.get_image());
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Globe(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Globe(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,37 +1,42 @@
|
|||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Homebrew(string type, string *outType, ArgumentMap Arguments,
|
||||
size_t *DataSize) {
|
||||
string caption = GetArgument<string>(Arguments, "caption");
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
string assetPath = basePath + "assets/images/hbc.png";
|
||||
VImage bg = VImage::new_from_file(assetPath.c_str());
|
||||
|
||||
VImage text = VImage::text(
|
||||
".", VImage::option()->set("fontfile",
|
||||
(basePath + "assets/fonts/hbc.ttf").c_str()));
|
||||
text = VImage::text(
|
||||
("<span letter_spacing=\"-5120\" color=\"white\">" + caption + "</span>")
|
||||
.c_str(),
|
||||
VImage::option()
|
||||
->set("rgba", true)
|
||||
->set("align", VIPS_ALIGN_CENTRE)
|
||||
->set("font", "PF Square Sans Pro, Twemoji Color Font 96")
|
||||
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str()));
|
||||
|
||||
VImage out = bg.composite2(text, VIPS_BLEND_MODE_OVER,
|
||||
VImage::option()
|
||||
->set("x", 400 - (text.width() / 2))
|
||||
->set("y", 300 - (text.height() / 2) - 8));
|
||||
|
||||
void *buf;
|
||||
out.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
return (char *)buf;
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Homebrew(string type, string *outType, ArgumentMap Arguments,
|
||||
size_t *DataSize) {
|
||||
string caption = GetArgument<string>(Arguments, "caption");
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
string assetPath = basePath + "assets/images/hbc.png";
|
||||
VImage bg = VImage::new_from_file(assetPath.c_str());
|
||||
|
||||
VImage text = VImage::text(
|
||||
".", VImage::option()->set("fontfile",
|
||||
(basePath + "assets/fonts/hbc.ttf").c_str()));
|
||||
text = VImage::text(
|
||||
("<span letter_spacing=\"-5120\" color=\"white\">" + caption + "</span>")
|
||||
.c_str(),
|
||||
VImage::option()
|
||||
->set("rgba", true)
|
||||
->set("align", VIPS_ALIGN_CENTRE)
|
||||
->set("font", "PF Square Sans Pro, Twemoji Color Font 96")
|
||||
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str()));
|
||||
|
||||
VImage out = bg.composite2(text, VIPS_BLEND_MODE_OVER,
|
||||
VImage::option()
|
||||
->set("x", 400 - (text.width() / 2))
|
||||
->set("y", 300 - (text.height() / 2) - 8));
|
||||
|
||||
void *buf;
|
||||
out.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = bg.width();
|
||||
output["height"] = vips_image_get_page_height(bg.get_image());
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char *Homebrew(string type, string *outType, ArgumentMap Arguments, size_t *DataSize);
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Homebrew(string type, string *outType, ArgumentMap Arguments, size_t *DataSize);
|
|
@ -1,28 +1,33 @@
|
|||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Invert(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, [[maybe_unused]] ArgumentMap Arguments,
|
||||
size_t *DataSize) {
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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);
|
||||
|
||||
VImage noAlpha =
|
||||
in.extract_band(0, VImage::option()->set("n", in.bands() - 1));
|
||||
VImage inverted = noAlpha.invert();
|
||||
VImage out = inverted.bandjoin(in.extract_band(3));
|
||||
|
||||
void *buf;
|
||||
out.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
return (char *)buf;
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Invert(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, [[maybe_unused]] ArgumentMap Arguments,
|
||||
size_t *DataSize) {
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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);
|
||||
|
||||
VImage noAlpha =
|
||||
in.extract_band(0, VImage::option()->set("n", in.bands() - 1));
|
||||
VImage inverted = noAlpha.invert();
|
||||
VImage out = inverted.bandjoin(in.extract_band(3));
|
||||
|
||||
void *buf;
|
||||
out.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = out.width();
|
||||
output["height"] = vips_image_get_page_height(in.get_image());
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Invert(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Invert(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
158
natives/jpeg.cc
158
natives/jpeg.cc
|
@ -1,75 +1,83 @@
|
|||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Jpeg(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t *DataSize) {
|
||||
int quality = GetArgumentWithFallback<int>(Arguments, "quality", 0);
|
||||
|
||||
void *buf;
|
||||
|
||||
if (type == "gif") {
|
||||
VImage in = VImage::new_from_buffer(
|
||||
BufferData, BufferLength, "",
|
||||
VImage::option()->set("access", "sequential")->set("n", -1))
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
if (!in.has_alpha()) in = in.bandjoin(255);
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int totalHeight = in.height();
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
VImage final;
|
||||
|
||||
if (totalHeight > 65500) {
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
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", quality)->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;
|
||||
size_t jpgLength;
|
||||
in.write_to_buffer(
|
||||
".jpg", &jpgBuf, &jpgLength,
|
||||
VImage::option()->set("Q", quality)->set("strip", true));
|
||||
final = VImage::new_from_buffer(jpgBuf, jpgLength, "");
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
final.set("delay", in.get_array_int("delay"));
|
||||
}
|
||||
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif" ? VImage::option()->set("dither", 0) : 0);
|
||||
} else {
|
||||
VImage in = VImage::new_from_buffer(BufferData, BufferLength, "");
|
||||
void *jpgBuf;
|
||||
in.write_to_buffer(".jpg", &jpgBuf, DataSize,
|
||||
VImage::option()->set("Q", quality)->set("strip", true));
|
||||
if (*outType == "gif") {
|
||||
VImage gifIn = VImage::new_from_buffer((char *)jpgBuf, *DataSize, "");
|
||||
gifIn.write_to_buffer(
|
||||
".gif", &buf, DataSize,
|
||||
VImage::option()->set("Q", quality)->set("strip", true));
|
||||
} else {
|
||||
*outType = "jpg";
|
||||
buf = jpgBuf;
|
||||
}
|
||||
}
|
||||
|
||||
return (char *)buf;
|
||||
}
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Jpeg(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t *DataSize) {
|
||||
int quality = GetArgumentWithFallback<int>(Arguments, "quality", 0);
|
||||
|
||||
void *buf;
|
||||
ArgumentMap output;
|
||||
|
||||
|
||||
if (type == "gif") {
|
||||
VImage in = VImage::new_from_buffer(
|
||||
BufferData, BufferLength, "",
|
||||
VImage::option()->set("access", "sequential")->set("n", -1))
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
if (!in.has_alpha()) in = in.bandjoin(255);
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int totalHeight = in.height();
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
VImage final;
|
||||
|
||||
if (totalHeight > 65500) {
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
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", quality)->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;
|
||||
size_t jpgLength;
|
||||
in.write_to_buffer(
|
||||
".jpg", &jpgBuf, &jpgLength,
|
||||
VImage::option()->set("Q", quality)->set("strip", true));
|
||||
final = VImage::new_from_buffer(jpgBuf, jpgLength, "");
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
final.set("delay", in.get_array_int("delay"));
|
||||
}
|
||||
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif" ? VImage::option()->set("dither", 0) : 0);
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = width;
|
||||
output["height"] = pageHeight;
|
||||
} else {
|
||||
VImage in = VImage::new_from_buffer(BufferData, BufferLength, "");
|
||||
void *jpgBuf;
|
||||
in.write_to_buffer(".jpg", &jpgBuf, DataSize,
|
||||
VImage::option()->set("Q", quality)->set("strip", true));
|
||||
if (*outType == "gif") {
|
||||
VImage gifIn = VImage::new_from_buffer((char *)jpgBuf, *DataSize, "");
|
||||
gifIn.write_to_buffer(
|
||||
".gif", &buf, DataSize,
|
||||
VImage::option()->set("Q", quality)->set("strip", true));
|
||||
} else {
|
||||
*outType = "jpg";
|
||||
buf = jpgBuf;
|
||||
}
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = in.width();
|
||||
output["height"] = vips_image_get_page_height(in.get_image());
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Jpeg(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Jpeg(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
108
natives/magik.cc
108
natives/magik.cc
|
@ -1,52 +1,58 @@
|
|||
#include <Magick++.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Magick;
|
||||
|
||||
char *Magik(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
[[maybe_unused]] ArgumentMap Arguments, size_t *DataSize) {
|
||||
Blob blob;
|
||||
|
||||
list<Image> frames;
|
||||
list<Image> coalesced;
|
||||
list<Image> blurred;
|
||||
try {
|
||||
readImages(&frames, Blob(BufferData, BufferLength));
|
||||
} catch (Magick::WarningCoder &warning) {
|
||||
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.scale(Geometry("350x350"));
|
||||
image.liquidRescale(Geometry("175x175"));
|
||||
image.liquidRescale(Geometry("350x350"));
|
||||
image.magick(*outType);
|
||||
blurred.push_back(image);
|
||||
}
|
||||
|
||||
optimizeTransparency(blurred.begin(), blurred.end());
|
||||
|
||||
if (*outType == "gif") {
|
||||
for (Image &image : blurred) {
|
||||
image.quantizeDitherMethod(FloydSteinbergDitherMethod);
|
||||
image.quantize();
|
||||
}
|
||||
}
|
||||
|
||||
writeImages(blurred.begin(), blurred.end(), &blob);
|
||||
|
||||
*DataSize = blob.length();
|
||||
|
||||
char *data = (char *)malloc(*DataSize);
|
||||
memcpy(data, blob.data(), *DataSize);
|
||||
return data;
|
||||
#include <Magick++.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Magick;
|
||||
|
||||
ArgumentMap Magik(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
[[maybe_unused]] ArgumentMap Arguments, size_t *DataSize) {
|
||||
Blob blob;
|
||||
|
||||
list<Image> frames;
|
||||
list<Image> coalesced;
|
||||
list<Image> blurred;
|
||||
try {
|
||||
readImages(&frames, Blob(BufferData, BufferLength));
|
||||
} catch (Magick::WarningCoder &warning) {
|
||||
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.scale(Geometry("350x350"));
|
||||
image.liquidRescale(Geometry("175x175"));
|
||||
image.liquidRescale(Geometry("350x350"));
|
||||
image.magick(*outType);
|
||||
blurred.push_back(image);
|
||||
}
|
||||
|
||||
optimizeTransparency(blurred.begin(), blurred.end());
|
||||
|
||||
if (*outType == "gif") {
|
||||
for (Image &image : blurred) {
|
||||
image.quantizeDitherMethod(FloydSteinbergDitherMethod);
|
||||
image.quantize();
|
||||
}
|
||||
}
|
||||
|
||||
writeImages(blurred.begin(), blurred.end(), &blob);
|
||||
|
||||
*DataSize = blob.length();
|
||||
|
||||
char *data = (char *)malloc(*DataSize);
|
||||
memcpy(data, blob.data(), *DataSize);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = data;
|
||||
output["width"] = (int)blurred.front().columns();
|
||||
output["height"] = (int)blurred.front().rows();
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Magik(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Magik(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
281
natives/meme.cc
281
natives/meme.cc
|
@ -1,139 +1,144 @@
|
|||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Meme(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t *DataSize) {
|
||||
string top = GetArgument<string>(Arguments, "top");
|
||||
string bottom = GetArgument<string>(Arguments, "bottom");
|
||||
string font = GetArgument<string>(Arguments, "font");
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
int size = width / 9;
|
||||
int dividedWidth = width / 1000;
|
||||
int rad = 1;
|
||||
vector<double> zeroVec = {0, 0, 0, 0};
|
||||
|
||||
string font_string =
|
||||
(font == "roboto" ? "Roboto Condensed" : font) + ", Twemoji Color Font " +
|
||||
(font != "impact" ? "bold" : "normal") + " " + to_string(size);
|
||||
|
||||
VImage mask = VImage::black(rad * 2 + 1, rad * 2 + 1) + 128;
|
||||
mask.draw_circle({255}, rad, rad, rad, VImage::option()->set("fill", true));
|
||||
|
||||
VImage altMask;
|
||||
|
||||
if (dividedWidth >= 1) {
|
||||
altMask = VImage::black(dividedWidth * 2 + 1, dividedWidth * 2 + 1) + 128;
|
||||
altMask.draw_circle({255}, dividedWidth, dividedWidth, dividedWidth,
|
||||
VImage::option()->set("fill", true));
|
||||
}
|
||||
|
||||
auto findResult = fontPaths.find(font);
|
||||
if (findResult != fontPaths.end()) {
|
||||
VImage::text(".", VImage::option()->set(
|
||||
"fontfile", (basePath + findResult->second).c_str()));
|
||||
}
|
||||
|
||||
VImage topText;
|
||||
if (top != "") {
|
||||
VImage topIn = VImage::text(
|
||||
("<span foreground=\"white\">" + top + "</span>").c_str(),
|
||||
VImage::option()
|
||||
->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", width));
|
||||
|
||||
topIn = topIn.embed(rad + 10, rad + 10, (topIn.width() + 2 * rad) + 20,
|
||||
(topIn.height() + 2 * rad) + 20);
|
||||
|
||||
VImage topOutline =
|
||||
topIn.morph(mask, VIPS_OPERATION_MORPHOLOGY_DILATE)
|
||||
.gaussblur(0.5, VImage::option()->set("min_ampl", 0.1));
|
||||
if (dividedWidth >= 1) {
|
||||
topOutline = topOutline.morph(altMask, VIPS_OPERATION_MORPHOLOGY_DILATE);
|
||||
}
|
||||
topOutline = (topOutline == zeroVec);
|
||||
VImage topInvert = topOutline.extract_band(3).invert();
|
||||
topOutline =
|
||||
topOutline
|
||||
.extract_band(0, VImage::option()->set("n", topOutline.bands() - 1))
|
||||
.bandjoin(topInvert);
|
||||
topText = topOutline.composite2(topIn, VIPS_BLEND_MODE_OVER);
|
||||
}
|
||||
|
||||
VImage bottomText;
|
||||
if (bottom != "") {
|
||||
VImage bottomIn = VImage::text(
|
||||
("<span foreground=\"white\">" + bottom + "</span>").c_str(),
|
||||
VImage::option()
|
||||
->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", width));
|
||||
bottomIn =
|
||||
bottomIn.embed(rad + 10, rad + 10, (bottomIn.width() + 2 * rad) + 20,
|
||||
(bottomIn.height() + 2 * rad) + 20);
|
||||
VImage bottomOutline =
|
||||
bottomIn.morph(mask, VIPS_OPERATION_MORPHOLOGY_DILATE)
|
||||
.gaussblur(0.5, VImage::option()->set("min_ampl", 0.1));
|
||||
if (dividedWidth >= 1) {
|
||||
bottomOutline =
|
||||
bottomOutline.morph(altMask, VIPS_OPERATION_MORPHOLOGY_DILATE);
|
||||
}
|
||||
bottomOutline = (bottomOutline == zeroVec);
|
||||
VImage bottomInvert = bottomOutline.extract_band(3).invert();
|
||||
bottomOutline = bottomOutline
|
||||
.extract_band(0, VImage::option()->set(
|
||||
"n", bottomOutline.bands() - 1))
|
||||
.bandjoin(bottomInvert);
|
||||
bottomText = bottomOutline.composite2(bottomIn, VIPS_BLEND_MODE_OVER);
|
||||
}
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
if (top != "") {
|
||||
img_frame = img_frame.composite2(
|
||||
topText, VIPS_BLEND_MODE_OVER,
|
||||
VImage::option()->set("x", (width / 2) - (topText.width() / 2)));
|
||||
}
|
||||
if (bottom != "") {
|
||||
img_frame = img_frame.composite2(
|
||||
bottomText, VIPS_BLEND_MODE_OVER,
|
||||
VImage::option()
|
||||
->set("x", (width / 2) - (bottomText.width() / 2))
|
||||
->set("y", pageHeight - bottomText.height()));
|
||||
}
|
||||
img.push_back(img_frame);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
return (char *)buf;
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Meme(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t *DataSize) {
|
||||
string top = GetArgument<string>(Arguments, "top");
|
||||
string bottom = GetArgument<string>(Arguments, "bottom");
|
||||
string font = GetArgument<string>(Arguments, "font");
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
int size = width / 9;
|
||||
int dividedWidth = width / 1000;
|
||||
int rad = 1;
|
||||
vector<double> zeroVec = {0, 0, 0, 0};
|
||||
|
||||
string font_string =
|
||||
(font == "roboto" ? "Roboto Condensed" : font) + ", Twemoji Color Font " +
|
||||
(font != "impact" ? "bold" : "normal") + " " + to_string(size);
|
||||
|
||||
VImage mask = VImage::black(rad * 2 + 1, rad * 2 + 1) + 128;
|
||||
mask.draw_circle({255}, rad, rad, rad, VImage::option()->set("fill", true));
|
||||
|
||||
VImage altMask;
|
||||
|
||||
if (dividedWidth >= 1) {
|
||||
altMask = VImage::black(dividedWidth * 2 + 1, dividedWidth * 2 + 1) + 128;
|
||||
altMask.draw_circle({255}, dividedWidth, dividedWidth, dividedWidth,
|
||||
VImage::option()->set("fill", true));
|
||||
}
|
||||
|
||||
auto findResult = fontPaths.find(font);
|
||||
if (findResult != fontPaths.end()) {
|
||||
VImage::text(".", VImage::option()->set(
|
||||
"fontfile", (basePath + findResult->second).c_str()));
|
||||
}
|
||||
|
||||
VImage topText;
|
||||
if (top != "") {
|
||||
VImage topIn = VImage::text(
|
||||
("<span foreground=\"white\">" + top + "</span>").c_str(),
|
||||
VImage::option()
|
||||
->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", width));
|
||||
|
||||
topIn = topIn.embed(rad + 10, rad + 10, (topIn.width() + 2 * rad) + 20,
|
||||
(topIn.height() + 2 * rad) + 20);
|
||||
|
||||
VImage topOutline =
|
||||
topIn.morph(mask, VIPS_OPERATION_MORPHOLOGY_DILATE)
|
||||
.gaussblur(0.5, VImage::option()->set("min_ampl", 0.1));
|
||||
if (dividedWidth >= 1) {
|
||||
topOutline = topOutline.morph(altMask, VIPS_OPERATION_MORPHOLOGY_DILATE);
|
||||
}
|
||||
topOutline = (topOutline == zeroVec);
|
||||
VImage topInvert = topOutline.extract_band(3).invert();
|
||||
topOutline =
|
||||
topOutline
|
||||
.extract_band(0, VImage::option()->set("n", topOutline.bands() - 1))
|
||||
.bandjoin(topInvert);
|
||||
topText = topOutline.composite2(topIn, VIPS_BLEND_MODE_OVER);
|
||||
}
|
||||
|
||||
VImage bottomText;
|
||||
if (bottom != "") {
|
||||
VImage bottomIn = VImage::text(
|
||||
("<span foreground=\"white\">" + bottom + "</span>").c_str(),
|
||||
VImage::option()
|
||||
->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", width));
|
||||
bottomIn =
|
||||
bottomIn.embed(rad + 10, rad + 10, (bottomIn.width() + 2 * rad) + 20,
|
||||
(bottomIn.height() + 2 * rad) + 20);
|
||||
VImage bottomOutline =
|
||||
bottomIn.morph(mask, VIPS_OPERATION_MORPHOLOGY_DILATE)
|
||||
.gaussblur(0.5, VImage::option()->set("min_ampl", 0.1));
|
||||
if (dividedWidth >= 1) {
|
||||
bottomOutline =
|
||||
bottomOutline.morph(altMask, VIPS_OPERATION_MORPHOLOGY_DILATE);
|
||||
}
|
||||
bottomOutline = (bottomOutline == zeroVec);
|
||||
VImage bottomInvert = bottomOutline.extract_band(3).invert();
|
||||
bottomOutline = bottomOutline
|
||||
.extract_band(0, VImage::option()->set(
|
||||
"n", bottomOutline.bands() - 1))
|
||||
.bandjoin(bottomInvert);
|
||||
bottomText = bottomOutline.composite2(bottomIn, VIPS_BLEND_MODE_OVER);
|
||||
}
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
if (top != "") {
|
||||
img_frame = img_frame.composite2(
|
||||
topText, VIPS_BLEND_MODE_OVER,
|
||||
VImage::option()->set("x", (width / 2) - (topText.width() / 2)));
|
||||
}
|
||||
if (bottom != "") {
|
||||
img_frame = img_frame.composite2(
|
||||
bottomText, VIPS_BLEND_MODE_OVER,
|
||||
VImage::option()
|
||||
->set("x", (width / 2) - (bottomText.width() / 2))
|
||||
->set("y", pageHeight - bottomText.height()));
|
||||
}
|
||||
img.push_back(img_frame);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = width;
|
||||
output["height"] = pageHeight;
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Meme(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Meme(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,64 +1,69 @@
|
|||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Mirror(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
bool vertical = GetArgumentWithFallback<bool>(Arguments, "vertical", false);
|
||||
bool first = GetArgumentWithFallback<bool>(Arguments, "first", false);
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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);
|
||||
|
||||
VImage out;
|
||||
|
||||
if (vertical) {
|
||||
if (type == "gif") {
|
||||
// once again, libvips gif handling is both a blessing and a curse
|
||||
vector<VImage> img;
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
bool isOdd = pageHeight % 2;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
int x = (i * pageHeight) + (first ? 0 : (pageHeight / 2));
|
||||
VImage cropped = in.crop(0, x, in.width(), pageHeight / 2);
|
||||
VImage flipped = cropped.flip(VIPS_DIRECTION_VERTICAL);
|
||||
VImage final = VImage::arrayjoin(
|
||||
{first ? cropped : flipped, first ? flipped : cropped},
|
||||
VImage::option()->set("across", 1));
|
||||
img.push_back(final);
|
||||
}
|
||||
out = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
out.set(VIPS_META_PAGE_HEIGHT, pageHeight - (isOdd ? 1 : 0));
|
||||
} else {
|
||||
VImage cropped = in.extract_area(0, 0, in.width(), in.height() / 2);
|
||||
VImage flipped = cropped.flip(VIPS_DIRECTION_VERTICAL);
|
||||
out = VImage::arrayjoin({cropped, flipped},
|
||||
VImage::option()->set("across", 1));
|
||||
}
|
||||
} else {
|
||||
if (first) {
|
||||
VImage cropped = in.extract_area(0, 0, in.width() / 2, in.height());
|
||||
VImage flipped = cropped.flip(VIPS_DIRECTION_HORIZONTAL);
|
||||
out = VImage::arrayjoin({cropped, flipped});
|
||||
} else {
|
||||
int size = in.width() / 2;
|
||||
VImage cropped = in.extract_area(size, 0, size, in.height());
|
||||
VImage flipped = cropped.flip(VIPS_DIRECTION_HORIZONTAL);
|
||||
out = VImage::arrayjoin({flipped, cropped});
|
||||
}
|
||||
}
|
||||
|
||||
void *buf;
|
||||
out.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
return (char *)buf;
|
||||
}
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Mirror(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
bool vertical = GetArgumentWithFallback<bool>(Arguments, "vertical", false);
|
||||
bool first = GetArgumentWithFallback<bool>(Arguments, "first", false);
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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);
|
||||
|
||||
VImage out;
|
||||
|
||||
if (vertical) {
|
||||
if (type == "gif") {
|
||||
// once again, libvips gif handling is both a blessing and a curse
|
||||
vector<VImage> img;
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
bool isOdd = pageHeight % 2;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
int x = (i * pageHeight) + (first ? 0 : (pageHeight / 2));
|
||||
VImage cropped = in.crop(0, x, in.width(), pageHeight / 2);
|
||||
VImage flipped = cropped.flip(VIPS_DIRECTION_VERTICAL);
|
||||
VImage final = VImage::arrayjoin(
|
||||
{first ? cropped : flipped, first ? flipped : cropped},
|
||||
VImage::option()->set("across", 1));
|
||||
img.push_back(final);
|
||||
}
|
||||
out = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
out.set(VIPS_META_PAGE_HEIGHT, pageHeight - (isOdd ? 1 : 0));
|
||||
} else {
|
||||
VImage cropped = in.extract_area(0, 0, in.width(), in.height() / 2);
|
||||
VImage flipped = cropped.flip(VIPS_DIRECTION_VERTICAL);
|
||||
out = VImage::arrayjoin({cropped, flipped},
|
||||
VImage::option()->set("across", 1));
|
||||
}
|
||||
} else {
|
||||
if (first) {
|
||||
VImage cropped = in.extract_area(0, 0, in.width() / 2, in.height());
|
||||
VImage flipped = cropped.flip(VIPS_DIRECTION_HORIZONTAL);
|
||||
out = VImage::arrayjoin({cropped, flipped});
|
||||
} else {
|
||||
int size = in.width() / 2;
|
||||
VImage cropped = in.extract_area(size, 0, size, in.height());
|
||||
VImage flipped = cropped.flip(VIPS_DIRECTION_HORIZONTAL);
|
||||
out = VImage::arrayjoin({flipped, cropped});
|
||||
}
|
||||
}
|
||||
|
||||
void *buf;
|
||||
out.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = in.width();
|
||||
output["height"] = vips_image_get_page_height(in.get_image());
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Mirror(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Mirror(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,123 +1,128 @@
|
|||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Motivate(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
string top_text = GetArgument<string>(Arguments, "top");
|
||||
string bottom_text = GetArgument<string>(Arguments, "bottom");
|
||||
string font = GetArgument<string>(Arguments, "font");
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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();
|
||||
int size = width / 5;
|
||||
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) + ", Twemoji Color Font";
|
||||
|
||||
auto findResult = fontPaths.find(font);
|
||||
if (findResult != fontPaths.end()) {
|
||||
VImage::text(".", VImage::option()->set(
|
||||
"fontfile", (basePath + findResult->second).c_str()));
|
||||
}
|
||||
|
||||
VImage topImage;
|
||||
if (top_text != "") {
|
||||
string topText = "<span foreground=\"white\" background=\"black\">" +
|
||||
top_text + "</span>";
|
||||
|
||||
topImage = VImage::text(
|
||||
topText.c_str(),
|
||||
VImage::option()
|
||||
->set("rgba", true)
|
||||
->set("align", VIPS_ALIGN_CENTRE)
|
||||
->set("font", (font_string + " " + to_string(size)).c_str())
|
||||
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str())
|
||||
->set("width", textWidth));
|
||||
}
|
||||
|
||||
VImage bottomImage;
|
||||
if (bottom_text != "") {
|
||||
string bottomText = "<span foreground=\"white\" background=\"black\">" +
|
||||
bottom_text + "</span>";
|
||||
|
||||
bottomImage = VImage::text(
|
||||
bottomText.c_str(),
|
||||
VImage::option()
|
||||
->set("rgba", true)
|
||||
->set("align", VIPS_ALIGN_CENTRE)
|
||||
->set("font", (font_string + " " + to_string(size * 0.4)).c_str())
|
||||
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str())
|
||||
->set("width", textWidth));
|
||||
}
|
||||
|
||||
vector<VImage> img;
|
||||
int height;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
|
||||
int borderSize = max(2, width / 66);
|
||||
int borderSize2 = borderSize * 0.5;
|
||||
VImage bordered =
|
||||
img_frame.embed(borderSize, borderSize, width + (borderSize * 2),
|
||||
pageHeight + (borderSize * 2),
|
||||
VImage::option()->set("extend", "black"));
|
||||
VImage bordered2 = bordered.embed(borderSize2, borderSize2,
|
||||
bordered.width() + (borderSize2 * 2),
|
||||
bordered.height() + (borderSize2 * 2),
|
||||
VImage::option()->set("extend", "white"));
|
||||
|
||||
int addition = width / 8;
|
||||
int sideAddition = pageHeight * 0.4;
|
||||
|
||||
VImage bordered3 = bordered2.embed(
|
||||
sideAddition / 2, addition / 2, bordered2.width() + sideAddition,
|
||||
bordered2.height() + addition,
|
||||
VImage::option()->set("extend", "black"));
|
||||
VImage frame;
|
||||
if (top_text != "") {
|
||||
frame = bordered3.join(
|
||||
topImage.gravity(VIPS_COMPASS_DIRECTION_NORTH, bordered3.width(),
|
||||
topImage.height() + (size / 4),
|
||||
VImage::option()->set("extend", "black")),
|
||||
VIPS_DIRECTION_VERTICAL,
|
||||
VImage::option()->set("background", 0x000000)->set("expand", true));
|
||||
}
|
||||
if (bottom_text != "") {
|
||||
if (top_text == "") frame = bordered3;
|
||||
frame = frame.join(
|
||||
bottomImage.gravity(VIPS_COMPASS_DIRECTION_NORTH, bordered3.width(),
|
||||
bottomImage.height() + (size / 4),
|
||||
VImage::option()->set("extend", "black")),
|
||||
VIPS_DIRECTION_VERTICAL,
|
||||
VImage::option()->set("background", 0x000000)->set("expand", true));
|
||||
}
|
||||
height = frame.height();
|
||||
img.push_back(frame);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1))
|
||||
.extract_band(0, VImage::option()->set("n", 3));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, height);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif" ? VImage::option()->set("dither", 1) : 0);
|
||||
|
||||
return (char *)buf;
|
||||
}
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Motivate(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
string top_text = GetArgument<string>(Arguments, "top");
|
||||
string bottom_text = GetArgument<string>(Arguments, "bottom");
|
||||
string font = GetArgument<string>(Arguments, "font");
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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();
|
||||
int size = width / 5;
|
||||
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) + ", Twemoji Color Font";
|
||||
|
||||
auto findResult = fontPaths.find(font);
|
||||
if (findResult != fontPaths.end()) {
|
||||
VImage::text(".", VImage::option()->set(
|
||||
"fontfile", (basePath + findResult->second).c_str()));
|
||||
}
|
||||
|
||||
VImage topImage;
|
||||
if (top_text != "") {
|
||||
string topText = "<span foreground=\"white\" background=\"black\">" +
|
||||
top_text + "</span>";
|
||||
|
||||
topImage = VImage::text(
|
||||
topText.c_str(),
|
||||
VImage::option()
|
||||
->set("rgba", true)
|
||||
->set("align", VIPS_ALIGN_CENTRE)
|
||||
->set("font", (font_string + " " + to_string(size)).c_str())
|
||||
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str())
|
||||
->set("width", textWidth));
|
||||
}
|
||||
|
||||
VImage bottomImage;
|
||||
if (bottom_text != "") {
|
||||
string bottomText = "<span foreground=\"white\" background=\"black\">" +
|
||||
bottom_text + "</span>";
|
||||
|
||||
bottomImage = VImage::text(
|
||||
bottomText.c_str(),
|
||||
VImage::option()
|
||||
->set("rgba", true)
|
||||
->set("align", VIPS_ALIGN_CENTRE)
|
||||
->set("font", (font_string + " " + to_string(size * 0.4)).c_str())
|
||||
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str())
|
||||
->set("width", textWidth));
|
||||
}
|
||||
|
||||
vector<VImage> img;
|
||||
int height;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
|
||||
int borderSize = max(2, width / 66);
|
||||
int borderSize2 = borderSize * 0.5;
|
||||
VImage bordered =
|
||||
img_frame.embed(borderSize, borderSize, width + (borderSize * 2),
|
||||
pageHeight + (borderSize * 2),
|
||||
VImage::option()->set("extend", "black"));
|
||||
VImage bordered2 = bordered.embed(borderSize2, borderSize2,
|
||||
bordered.width() + (borderSize2 * 2),
|
||||
bordered.height() + (borderSize2 * 2),
|
||||
VImage::option()->set("extend", "white"));
|
||||
|
||||
int addition = width / 8;
|
||||
int sideAddition = pageHeight * 0.4;
|
||||
|
||||
VImage bordered3 = bordered2.embed(
|
||||
sideAddition / 2, addition / 2, bordered2.width() + sideAddition,
|
||||
bordered2.height() + addition,
|
||||
VImage::option()->set("extend", "black"));
|
||||
VImage frame;
|
||||
if (top_text != "") {
|
||||
frame = bordered3.join(
|
||||
topImage.gravity(VIPS_COMPASS_DIRECTION_NORTH, bordered3.width(),
|
||||
topImage.height() + (size / 4),
|
||||
VImage::option()->set("extend", "black")),
|
||||
VIPS_DIRECTION_VERTICAL,
|
||||
VImage::option()->set("background", 0x000000)->set("expand", true));
|
||||
}
|
||||
if (bottom_text != "") {
|
||||
if (top_text == "") frame = bordered3;
|
||||
frame = frame.join(
|
||||
bottomImage.gravity(VIPS_COMPASS_DIRECTION_NORTH, bordered3.width(),
|
||||
bottomImage.height() + (size / 4),
|
||||
VImage::option()->set("extend", "black")),
|
||||
VIPS_DIRECTION_VERTICAL,
|
||||
VImage::option()->set("background", 0x000000)->set("expand", true));
|
||||
}
|
||||
height = frame.height();
|
||||
img.push_back(frame);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1))
|
||||
.extract_band(0, VImage::option()->set("n", 3));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, height);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif" ? VImage::option()->set("dither", 1) : 0);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = in.width();
|
||||
output["height"] = vips_image_get_page_height(in.get_image());
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Motivate(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Motivate(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,124 +1,130 @@
|
|||
#include <napi.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "../common.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Magick++.h>
|
||||
#endif
|
||||
#include <vips/vips8>
|
||||
|
||||
using namespace std;
|
||||
|
||||
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 ProcessImage(const Napi::CallbackInfo& info) {
|
||||
Napi::Env env = info.Env();
|
||||
Napi::Object result = Napi::Object::New(env);
|
||||
|
||||
try {
|
||||
string command = info[0].As<Napi::String>().Utf8Value();
|
||||
Napi::Object obj = info[1].As<Napi::Object>();
|
||||
string type =
|
||||
obj.Has("type") ? obj.Get("type").As<Napi::String>().Utf8Value() : "png";
|
||||
|
||||
Napi::Array properties = obj.GetPropertyNames();
|
||||
|
||||
ArgumentMap Arguments;
|
||||
|
||||
for (unsigned int i = 0; i < properties.Length(); i++) {
|
||||
string property =
|
||||
properties.Get(uint32_t(i)).As<Napi::String>().Utf8Value();
|
||||
|
||||
if (property == "data") {
|
||||
continue;
|
||||
}
|
||||
|
||||
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 {
|
||||
throw "Unimplemented value type passed to image native.";
|
||||
// Arguments[property] = val;
|
||||
}
|
||||
}
|
||||
|
||||
string outType = GetArgument<bool>(Arguments, "togif") ? "gif" : type;
|
||||
|
||||
size_t length = 0;
|
||||
char* buf;
|
||||
if (obj.Has("data")) {
|
||||
Napi::Buffer<char> data = obj.Has("data")
|
||||
? obj.Get("data").As<Napi::Buffer<char>>()
|
||||
: Napi::Buffer<char>::New(env, 0);
|
||||
buf = FunctionMap.at(command)(type, &outType, data.Data(), data.Length(),
|
||||
Arguments, &length);
|
||||
} else {
|
||||
buf = NoInputFunctionMap.at(command)(type, &outType, Arguments, &length);
|
||||
}
|
||||
|
||||
vips_error_clear();
|
||||
vips_thread_shutdown();
|
||||
|
||||
result.Set("data",
|
||||
Napi::Buffer<char>::New(env, buf, length,
|
||||
[]([[maybe_unused]] Napi::Env env,
|
||||
void* data) { free(data); }));
|
||||
result.Set("type", outType);
|
||||
} catch (std::exception const& err) {
|
||||
Napi::Error::New(env, err.what()).ThrowAsJavaScriptException();
|
||||
} catch (...) {
|
||||
Napi::Error::New(env, "Unknown error").ThrowAsJavaScriptException();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Napi::Object Init(Napi::Env env, Napi::Object exports) {
|
||||
#ifdef _WIN32
|
||||
Magick::InitializeMagick("");
|
||||
#endif
|
||||
if (vips_init("")) vips_error_exit(NULL);
|
||||
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 : NoInputFunctionMap) {
|
||||
Napi::HandleScope scope(env);
|
||||
arr[i] = Napi::String::New(env, imap.first);
|
||||
i++;
|
||||
}
|
||||
|
||||
exports.Set(Napi::String::New(env, "funcs"), arr);
|
||||
|
||||
return exports;
|
||||
}
|
||||
|
||||
NODE_API_MODULE(addon, Init)
|
||||
#include <napi.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "../common.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Magick++.h>
|
||||
#endif
|
||||
#include <vips/vips8>
|
||||
|
||||
using namespace std;
|
||||
|
||||
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 ProcessImage(const Napi::CallbackInfo& info) {
|
||||
Napi::Env env = info.Env();
|
||||
Napi::Object result = Napi::Object::New(env);
|
||||
|
||||
try {
|
||||
string command = info[0].As<Napi::String>().Utf8Value();
|
||||
Napi::Object obj = info[1].As<Napi::Object>();
|
||||
string type =
|
||||
obj.Has("type") ? obj.Get("type").As<Napi::String>().Utf8Value() : "png";
|
||||
|
||||
Napi::Array properties = obj.GetPropertyNames();
|
||||
|
||||
ArgumentMap Arguments;
|
||||
|
||||
for (unsigned int i = 0; i < properties.Length(); i++) {
|
||||
string property =
|
||||
properties.Get(uint32_t(i)).As<Napi::String>().Utf8Value();
|
||||
|
||||
if (property == "data") {
|
||||
continue;
|
||||
}
|
||||
|
||||
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 {
|
||||
throw "Unimplemented value type passed to image native.";
|
||||
// Arguments[property] = val;
|
||||
}
|
||||
}
|
||||
|
||||
string outType = GetArgument<bool>(Arguments, "togif") ? "gif" : type;
|
||||
|
||||
size_t length = 0;
|
||||
ArgumentMap outMap;
|
||||
if (obj.Has("data")) {
|
||||
Napi::Buffer<char> data = obj.Has("data")
|
||||
? obj.Get("data").As<Napi::Buffer<char>>()
|
||||
: Napi::Buffer<char>::New(env, 0);
|
||||
outMap = FunctionMap.at(command)(type, &outType, data.Data(), data.Length(),
|
||||
Arguments, &length);
|
||||
} else {
|
||||
outMap = NoInputFunctionMap.at(command)(type, &outType, Arguments, &length);
|
||||
}
|
||||
|
||||
vips_error_clear();
|
||||
vips_thread_shutdown();
|
||||
|
||||
char* buf = GetArgument<char*>(outMap, "buf");
|
||||
int width = GetArgument<int>(outMap, "width");
|
||||
int height = GetArgument<int>(outMap, "height");
|
||||
|
||||
result.Set("data",
|
||||
Napi::Buffer<char>::New(env, buf, length,
|
||||
[]([[maybe_unused]] Napi::Env env,
|
||||
void* data) { free(data); }));
|
||||
result.Set("type", outType);
|
||||
result.Set("width", width);
|
||||
result.Set("height", height);
|
||||
} catch (std::exception const& err) {
|
||||
Napi::Error::New(env, err.what()).ThrowAsJavaScriptException();
|
||||
} catch (...) {
|
||||
Napi::Error::New(env, "Unknown error").ThrowAsJavaScriptException();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Napi::Object Init(Napi::Env env, Napi::Object exports) {
|
||||
#ifdef _WIN32
|
||||
Magick::InitializeMagick("");
|
||||
#endif
|
||||
if (vips_init("")) vips_error_exit(NULL);
|
||||
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 : NoInputFunctionMap) {
|
||||
Napi::HandleScope scope(env);
|
||||
arr[i] = Napi::String::New(env, imap.first);
|
||||
i++;
|
||||
}
|
||||
|
||||
exports.Set(Napi::String::New(env, "funcs"), arr);
|
||||
|
||||
return exports;
|
||||
}
|
||||
|
||||
NODE_API_MODULE(addon, Init)
|
||||
|
|
|
@ -1,67 +1,72 @@
|
|||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Reddit(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
string text = GetArgumentWithFallback<string>(Arguments, "text", "");
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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 assetPath = basePath + "assets/images/reddit.png";
|
||||
VImage tmpl = VImage::new_from_file(assetPath.c_str());
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
string captionText = "<span foreground=\"white\">" + text + "</span>";
|
||||
|
||||
VImage textImage = VImage::text(
|
||||
".", VImage::option()->set(
|
||||
"fontfile", (basePath + "assets/fonts/reddit.ttf").c_str()));
|
||||
textImage = VImage::text(
|
||||
captionText.c_str(),
|
||||
VImage::option()
|
||||
->set("rgba", true)
|
||||
->set("font", "Roboto, Twemoji Color Font 62")
|
||||
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str())
|
||||
->set("align", VIPS_ALIGN_LOW));
|
||||
|
||||
VImage composited =
|
||||
tmpl.composite2(textImage, VIPS_BLEND_MODE_OVER,
|
||||
VImage::option()->set("x", 375)->set(
|
||||
"y", (tmpl.height() - textImage.height()) - 64));
|
||||
VImage watermark =
|
||||
composited.resize((double)width / (double)composited.width());
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
VImage frame = img_frame.join(watermark, VIPS_DIRECTION_VERTICAL,
|
||||
VImage::option()->set("expand", true));
|
||||
img.push_back(frame);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight + watermark.height());
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
return (char *)buf;
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Reddit(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
string text = GetArgument<string>(Arguments, "caption");
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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 assetPath = basePath + "assets/images/reddit.png";
|
||||
VImage tmpl = VImage::new_from_file(assetPath.c_str());
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
string captionText = "<span foreground=\"white\">" + text + "</span>";
|
||||
|
||||
VImage textImage = VImage::text(
|
||||
".", VImage::option()->set(
|
||||
"fontfile", (basePath + "assets/fonts/reddit.ttf").c_str()));
|
||||
textImage = VImage::text(
|
||||
captionText.c_str(),
|
||||
VImage::option()
|
||||
->set("rgba", true)
|
||||
->set("font", "Roboto, Twemoji Color Font 62")
|
||||
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str())
|
||||
->set("align", VIPS_ALIGN_LOW));
|
||||
|
||||
VImage composited =
|
||||
tmpl.composite2(textImage, VIPS_BLEND_MODE_OVER,
|
||||
VImage::option()->set("x", 375)->set(
|
||||
"y", (tmpl.height() - textImage.height()) - 64));
|
||||
VImage watermark =
|
||||
composited.resize((double)width / (double)composited.width());
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
VImage frame = img_frame.join(watermark, VIPS_DIRECTION_VERTICAL,
|
||||
VImage::option()->set("expand", true));
|
||||
img.push_back(frame);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight + watermark.height());
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = width;
|
||||
output["height"] = pageHeight + watermark.height();
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Reddit(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Reddit(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,54 +1,59 @@
|
|||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Resize(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
bool stretch = GetArgumentWithFallback<bool>(Arguments, "stretch", false);
|
||||
bool wide = GetArgumentWithFallback<bool>(Arguments, "wide", false);
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
VImage::new_from_buffer(BufferData, BufferLength, "",
|
||||
type == "gif" ? options->set("n", -1) : options)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
|
||||
VImage out;
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
int finalHeight;
|
||||
if (stretch) {
|
||||
out =
|
||||
in.resize(512.0 / (double)width,
|
||||
VImage::option()->set("vscale", 512.0 / (double)pageHeight));
|
||||
finalHeight = 512;
|
||||
} else if (wide) {
|
||||
out = in.resize(9.5, VImage::option()->set("vscale", 0.5));
|
||||
finalHeight = pageHeight / 2;
|
||||
} else {
|
||||
// Pain. Pain. Pain. Pain. Pain.
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
VImage resized = img_frame.resize(0.1).resize(
|
||||
10, VImage::option()->set("kernel", VIPS_KERNEL_NEAREST));
|
||||
img.push_back(resized);
|
||||
finalHeight = resized.height();
|
||||
}
|
||||
out = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
}
|
||||
out.set(VIPS_META_PAGE_HEIGHT, finalHeight);
|
||||
|
||||
void *buf;
|
||||
out.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
return (char *)buf;
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Resize(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
bool stretch = GetArgumentWithFallback<bool>(Arguments, "stretch", false);
|
||||
bool wide = GetArgumentWithFallback<bool>(Arguments, "wide", false);
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
VImage::new_from_buffer(BufferData, BufferLength, "",
|
||||
type == "gif" ? options->set("n", -1) : options)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
|
||||
VImage out;
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
int finalHeight;
|
||||
if (stretch) {
|
||||
out =
|
||||
in.resize(512.0 / (double)width,
|
||||
VImage::option()->set("vscale", 512.0 / (double)pageHeight));
|
||||
finalHeight = 512;
|
||||
} else if (wide) {
|
||||
out = in.resize(9.5, VImage::option()->set("vscale", 0.5));
|
||||
finalHeight = pageHeight / 2;
|
||||
} else {
|
||||
// Pain. Pain. Pain. Pain. Pain.
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
VImage resized = img_frame.resize(0.1).resize(
|
||||
10, VImage::option()->set("kernel", VIPS_KERNEL_NEAREST));
|
||||
img.push_back(resized);
|
||||
finalHeight = resized.height();
|
||||
}
|
||||
out = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
}
|
||||
out.set(VIPS_META_PAGE_HEIGHT, finalHeight);
|
||||
|
||||
void *buf;
|
||||
out.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = width;
|
||||
output["height"] = finalHeight;
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Resize(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Resize(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,59 +1,64 @@
|
|||
#include <algorithm>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Reverse(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
bool soos = GetArgumentWithFallback<bool>(Arguments, "soos", false);
|
||||
|
||||
VOption *options =
|
||||
VImage::option()->set("access", "sequential")->set("n", -1);
|
||||
|
||||
VImage in = VImage::new_from_buffer(BufferData, BufferLength, "", options)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
vector<VImage> split;
|
||||
// todo: find a better way of getting individual frames (or at least getting
|
||||
// the frames in reverse order)
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame = in.crop(0, i * pageHeight, width, pageHeight);
|
||||
split.push_back(img_frame);
|
||||
}
|
||||
|
||||
vector<int> delays = in.get_array_int("delay");
|
||||
if (soos) {
|
||||
vector<VImage> copy = split;
|
||||
vector<int> copy2 = delays;
|
||||
reverse(copy.begin(), copy.end());
|
||||
reverse(copy2.begin(), copy2.end());
|
||||
copy.pop_back();
|
||||
copy2.pop_back();
|
||||
copy.erase(copy.begin());
|
||||
copy2.erase(copy2.begin());
|
||||
split.insert(split.end(), copy.begin(), copy.end());
|
||||
delays.insert(delays.end(), copy2.begin(), copy2.end());
|
||||
} else {
|
||||
reverse(split.begin(), split.end());
|
||||
reverse(delays.begin(), delays.end());
|
||||
}
|
||||
|
||||
VImage final = VImage::arrayjoin(split, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
final.set("delay", delays);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(".gif", &buf, DataSize,
|
||||
VImage::option()->set("dither", 0));
|
||||
|
||||
*outType = "gif";
|
||||
|
||||
return (char *)buf;
|
||||
#include <algorithm>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Reverse(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
bool soos = GetArgumentWithFallback<bool>(Arguments, "soos", false);
|
||||
|
||||
VOption *options =
|
||||
VImage::option()->set("access", "sequential")->set("n", -1);
|
||||
|
||||
VImage in = VImage::new_from_buffer(BufferData, BufferLength, "", options)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
vector<VImage> split;
|
||||
// todo: find a better way of getting individual frames (or at least getting
|
||||
// the frames in reverse order)
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame = in.crop(0, i * pageHeight, width, pageHeight);
|
||||
split.push_back(img_frame);
|
||||
}
|
||||
|
||||
vector<int> delays = in.get_array_int("delay");
|
||||
if (soos) {
|
||||
vector<VImage> copy = split;
|
||||
vector<int> copy2 = delays;
|
||||
reverse(copy.begin(), copy.end());
|
||||
reverse(copy2.begin(), copy2.end());
|
||||
copy.pop_back();
|
||||
copy2.pop_back();
|
||||
copy.erase(copy.begin());
|
||||
copy2.erase(copy2.begin());
|
||||
split.insert(split.end(), copy.begin(), copy.end());
|
||||
delays.insert(delays.end(), copy2.begin(), copy2.end());
|
||||
} else {
|
||||
reverse(split.begin(), split.end());
|
||||
reverse(delays.begin(), delays.end());
|
||||
}
|
||||
|
||||
VImage final = VImage::arrayjoin(split, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
final.set("delay", delays);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(".gif", &buf, DataSize,
|
||||
VImage::option()->set("dither", 0));
|
||||
|
||||
*outType = "gif";
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = width;
|
||||
output["height"] = pageHeight;
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Reverse(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Reverse(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
114
natives/scott.cc
114
natives/scott.cc
|
@ -1,55 +1,61 @@
|
|||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Scott(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t *DataSize) {
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
string assetPath = basePath + "assets/images/scott.png";
|
||||
VImage bg = VImage::new_from_file(assetPath.c_str());
|
||||
|
||||
string distortPath = basePath + "assets/images/scottmap.png";
|
||||
VImage distort = VImage::new_from_file(distortPath.c_str());
|
||||
|
||||
VImage distortImage =
|
||||
((distort[1] / 255) * 414).bandjoin((distort[0] / 255) * 233);
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
VImage resized = img_frame.resize(
|
||||
415 / (double)width,
|
||||
VImage::option()->set("vscale", 234 / (double)pageHeight));
|
||||
VImage mapped = resized.mapim(distortImage)
|
||||
.extract_band(0, VImage::option()->set("n", 3))
|
||||
.bandjoin(distort[2]);
|
||||
VImage offset = mapped.embed(127, 181, 864, 481);
|
||||
VImage composited = bg.composite2(offset, VIPS_BLEND_MODE_OVER);
|
||||
img.push_back(composited);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, 481);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif" ? VImage::option()->set("dither", 1) : 0);
|
||||
return (char *)buf;
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Scott(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t *DataSize) {
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
string assetPath = basePath + "assets/images/scott.png";
|
||||
VImage bg = VImage::new_from_file(assetPath.c_str());
|
||||
|
||||
string distortPath = basePath + "assets/images/scottmap.png";
|
||||
VImage distort = VImage::new_from_file(distortPath.c_str());
|
||||
|
||||
VImage distortImage =
|
||||
((distort[1] / 255) * 414).bandjoin((distort[0] / 255) * 233);
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
VImage resized = img_frame.resize(
|
||||
415 / (double)width,
|
||||
VImage::option()->set("vscale", 234 / (double)pageHeight));
|
||||
VImage mapped = resized.mapim(distortImage)
|
||||
.extract_band(0, VImage::option()->set("n", 3))
|
||||
.bandjoin(distort[2]);
|
||||
VImage offset = mapped.embed(127, 181, 864, 481);
|
||||
VImage composited = bg.composite2(offset, VIPS_BLEND_MODE_OVER);
|
||||
img.push_back(composited);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, 481);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif" ? VImage::option()->set("dither", 1) : 0);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = width;
|
||||
output["height"] = pageHeight;
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Scott(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Scott(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,72 +1,77 @@
|
|||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Snapchat(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
string caption = GetArgument<string>(Arguments, "caption");
|
||||
float pos = GetArgumentWithFallback<float>(Arguments, "pos", 0.5);
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
int size = width / 20;
|
||||
int textWidth = width - ((width / 25) * 2);
|
||||
|
||||
string font_string = "Helvetica Neue, Twemoji Color Font " + to_string(size);
|
||||
|
||||
VImage textIn = VImage::text(
|
||||
".", VImage::option()->set(
|
||||
"fontfile", (basePath + "assets/fonts/caption2.ttf").c_str()));
|
||||
textIn = VImage::text(
|
||||
("<span foreground=\"white\" background=\"#000000B2\">" + caption +
|
||||
"</span>")
|
||||
.c_str(),
|
||||
VImage::option()
|
||||
->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));
|
||||
int bgHeight = textIn.height() + (width / 25);
|
||||
textIn = ((textIn == (vector<double>){0, 0, 0, 0}).bandand())
|
||||
.ifthenelse({0, 0, 0, 178}, textIn)
|
||||
.embed((width / 2) - (textIn.width() / 2),
|
||||
(bgHeight / 2) - (textIn.height() / 2), width, bgHeight,
|
||||
VImage::option()
|
||||
->set("extend", "background")
|
||||
->set("background", (vector<double>){0, 0, 0, 178}));
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
img_frame = img_frame.composite2(
|
||||
textIn, VIPS_BLEND_MODE_OVER,
|
||||
VImage::option()->set("x", 0)->set("y", pageHeight * pos));
|
||||
img.push_back(img_frame);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
return (char *)buf;
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Snapchat(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
string caption = GetArgument<string>(Arguments, "caption");
|
||||
float pos = GetArgumentWithFallback<float>(Arguments, "pos", 0.5);
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
int size = width / 20;
|
||||
int textWidth = width - ((width / 25) * 2);
|
||||
|
||||
string font_string = "Helvetica Neue, Twemoji Color Font " + to_string(size);
|
||||
|
||||
VImage textIn = VImage::text(
|
||||
".", VImage::option()->set(
|
||||
"fontfile", (basePath + "assets/fonts/caption2.ttf").c_str()));
|
||||
textIn = VImage::text(
|
||||
("<span foreground=\"white\" background=\"#000000B2\">" + caption +
|
||||
"</span>")
|
||||
.c_str(),
|
||||
VImage::option()
|
||||
->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));
|
||||
int bgHeight = textIn.height() + (width / 25);
|
||||
textIn = ((textIn == (vector<double>){0, 0, 0, 0}).bandand())
|
||||
.ifthenelse({0, 0, 0, 178}, textIn)
|
||||
.embed((width / 2) - (textIn.width() / 2),
|
||||
(bgHeight / 2) - (textIn.height() / 2), width, bgHeight,
|
||||
VImage::option()
|
||||
->set("extend", "background")
|
||||
->set("background", (vector<double>){0, 0, 0, 178}));
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
img_frame = img_frame.composite2(
|
||||
textIn, VIPS_BLEND_MODE_OVER,
|
||||
VImage::option()->set("x", 0)->set("y", pageHeight * pos));
|
||||
img.push_back(img_frame);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = width;
|
||||
output["height"] = pageHeight;
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Snapchat(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Snapchat(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,35 +1,40 @@
|
|||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Sonic(string type, string *outType, ArgumentMap Arguments,
|
||||
size_t *DataSize) {
|
||||
string text = GetArgument<string>(Arguments, "text");
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
string assetPath = basePath + "assets/images/sonic.jpg";
|
||||
VImage bg = VImage::new_from_file(assetPath.c_str());
|
||||
|
||||
VImage textImage =
|
||||
VImage::text(
|
||||
("<span foreground=\"white\">" + text + "</span>").c_str(),
|
||||
VImage::option()
|
||||
->set("rgba", true)
|
||||
->set("align", VIPS_ALIGN_CENTRE)
|
||||
->set("font", "Verdana, Twemoji Color Font")
|
||||
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str())
|
||||
->set("width", 542)
|
||||
->set("height", 390))
|
||||
.gravity(VIPS_COMPASS_DIRECTION_CENTRE, 542, 390);
|
||||
|
||||
VImage out = bg.composite2(textImage, VIPS_BLEND_MODE_OVER,
|
||||
VImage::option()->set("x", 391)->set("y", 84));
|
||||
|
||||
void *buf;
|
||||
out.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
return (char *)buf;
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Sonic(string type, string *outType, ArgumentMap Arguments,
|
||||
size_t *DataSize) {
|
||||
string text = GetArgument<string>(Arguments, "text");
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
string assetPath = basePath + "assets/images/sonic.jpg";
|
||||
VImage bg = VImage::new_from_file(assetPath.c_str());
|
||||
|
||||
VImage textImage =
|
||||
VImage::text(
|
||||
("<span foreground=\"white\">" + text + "</span>").c_str(),
|
||||
VImage::option()
|
||||
->set("rgba", true)
|
||||
->set("align", VIPS_ALIGN_CENTRE)
|
||||
->set("font", "Verdana, Twemoji Color Font")
|
||||
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str())
|
||||
->set("width", 542)
|
||||
->set("height", 390))
|
||||
.gravity(VIPS_COMPASS_DIRECTION_CENTRE, 542, 390);
|
||||
|
||||
VImage out = bg.composite2(textImage, VIPS_BLEND_MODE_OVER,
|
||||
VImage::option()->set("x", 391)->set("y", 84));
|
||||
|
||||
void *buf;
|
||||
out.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = out.width();
|
||||
output["height"] = vips_image_get_page_height(out.get_image());
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char *Sonic(string type, string *outType, ArgumentMap Arguments, size_t *DataSize);
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Sonic(string type, string *outType, ArgumentMap Arguments, size_t *DataSize);
|
209
natives/speed.cc
209
natives/speed.cc
|
@ -1,102 +1,109 @@
|
|||
#include <iostream>
|
||||
#include <map>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
void *memset16(void *m, uint16_t val, size_t count) {
|
||||
uint16_t *buf = (uint16_t *)m;
|
||||
|
||||
while (count--) *buf++ = val;
|
||||
return m;
|
||||
}
|
||||
|
||||
char *vipsRemove(char *data, size_t length, size_t *DataSize, int speed) {
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in = VImage::new_from_buffer(data, length, "", options->set("n", -1))
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
if (!in.has_alpha()) in = in.bandjoin(255);
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i += speed) {
|
||||
VImage img_frame = in.crop(0, i * pageHeight, width, pageHeight);
|
||||
img.push_back(img_frame);
|
||||
}
|
||||
VImage out = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
out.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
|
||||
void *buf;
|
||||
out.write_to_buffer(".gif", &buf, DataSize);
|
||||
|
||||
return (char *)buf;
|
||||
}
|
||||
|
||||
char *Speed([[maybe_unused]] string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
bool slow = GetArgumentWithFallback<bool>(Arguments, "slow", false);
|
||||
int speed = GetArgumentWithFallback<int>(Arguments, "speed", 2);
|
||||
|
||||
char *fileData = (char *)malloc(BufferLength);
|
||||
memcpy(fileData, BufferData, BufferLength);
|
||||
|
||||
char *match = (char *)"\x00\x21\xF9\x04";
|
||||
|
||||
vector<uint16_t> old_delays;
|
||||
bool removeFrames = false;
|
||||
char *lastPos;
|
||||
|
||||
// int amount = 0;
|
||||
|
||||
lastPos = (char *)memchr(fileData, '\x00', BufferLength);
|
||||
while (lastPos != NULL) {
|
||||
if (memcmp(lastPos, match, 4) != 0) {
|
||||
lastPos = (char *)memchr(lastPos + 1, '\x00',
|
||||
(BufferLength - (lastPos - fileData)) - 1);
|
||||
continue;
|
||||
}
|
||||
//++amount;
|
||||
uint16_t old_delay;
|
||||
memcpy(&old_delay, lastPos + 5, 2);
|
||||
old_delays.push_back(old_delay);
|
||||
lastPos = (char *)memchr(lastPos + 1, '\x00',
|
||||
(BufferLength - (lastPos - fileData)) - 1);
|
||||
}
|
||||
|
||||
int currentFrame = 0;
|
||||
lastPos = (char *)memchr(fileData, '\x00', BufferLength);
|
||||
while (lastPos != NULL) {
|
||||
if (memcmp(lastPos, match, 4) != 0) {
|
||||
lastPos = (char *)memchr(lastPos + 1, '\x00',
|
||||
(BufferLength - (lastPos - fileData)) - 1);
|
||||
continue;
|
||||
}
|
||||
uint16_t new_delay = slow ? old_delays[currentFrame] * speed
|
||||
: old_delays[currentFrame] / speed;
|
||||
if (!slow && new_delay <= 1) {
|
||||
removeFrames = true;
|
||||
break;
|
||||
}
|
||||
|
||||
memset16(lastPos + 5, new_delay, 1);
|
||||
|
||||
lastPos = (char *)memchr(lastPos + 1, '\x00',
|
||||
(BufferLength - (lastPos - fileData)) - 1);
|
||||
++currentFrame;
|
||||
}
|
||||
|
||||
if (removeFrames) {
|
||||
fileData = vipsRemove(BufferData, BufferLength, DataSize, speed);
|
||||
} else {
|
||||
*DataSize = BufferLength;
|
||||
}
|
||||
|
||||
return fileData;
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
void *memset16(void *m, uint16_t val, size_t count) {
|
||||
uint16_t *buf = (uint16_t *)m;
|
||||
|
||||
while (count--) *buf++ = val;
|
||||
return m;
|
||||
}
|
||||
|
||||
ArgumentMap vipsHandle(char *data, size_t length, size_t *DataSize, int speed, bool removeFrames) {
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in = VImage::new_from_buffer(data, length, "", options->set("n", -1))
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
if (!in.has_alpha()) in = in.bandjoin(255);
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
VImage out;
|
||||
if (removeFrames) {
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i += speed) {
|
||||
VImage img_frame = in.crop(0, i * pageHeight, width, pageHeight);
|
||||
img.push_back(img_frame);
|
||||
}
|
||||
out = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
out.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
} else {
|
||||
out = in;
|
||||
}
|
||||
|
||||
void *buf;
|
||||
out.write_to_buffer(".gif", &buf, DataSize);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = width;
|
||||
output["height"] = pageHeight;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
ArgumentMap Speed([[maybe_unused]] string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
bool slow = GetArgumentWithFallback<bool>(Arguments, "slow", false);
|
||||
int speed = GetArgumentWithFallback<int>(Arguments, "speed", 2);
|
||||
|
||||
char *fileData = (char *)malloc(BufferLength);
|
||||
memcpy(fileData, BufferData, BufferLength);
|
||||
|
||||
char *match = (char *)"\x00\x21\xF9\x04";
|
||||
|
||||
vector<uint16_t> old_delays;
|
||||
bool removeFrames = false;
|
||||
char *lastPos;
|
||||
|
||||
// int amount = 0;
|
||||
|
||||
lastPos = (char *)memchr(fileData, '\x00', BufferLength);
|
||||
while (lastPos != NULL) {
|
||||
if (memcmp(lastPos, match, 4) != 0) {
|
||||
lastPos = (char *)memchr(lastPos + 1, '\x00',
|
||||
(BufferLength - (lastPos - fileData)) - 1);
|
||||
continue;
|
||||
}
|
||||
//++amount;
|
||||
uint16_t old_delay;
|
||||
memcpy(&old_delay, lastPos + 5, 2);
|
||||
old_delays.push_back(old_delay);
|
||||
lastPos = (char *)memchr(lastPos + 1, '\x00',
|
||||
(BufferLength - (lastPos - fileData)) - 1);
|
||||
}
|
||||
|
||||
int currentFrame = 0;
|
||||
lastPos = (char *)memchr(fileData, '\x00', BufferLength);
|
||||
while (lastPos != NULL) {
|
||||
if (memcmp(lastPos, match, 4) != 0) {
|
||||
lastPos = (char *)memchr(lastPos + 1, '\x00',
|
||||
(BufferLength - (lastPos - fileData)) - 1);
|
||||
continue;
|
||||
}
|
||||
uint16_t new_delay = slow ? old_delays[currentFrame] * speed
|
||||
: old_delays[currentFrame] / speed;
|
||||
if (!slow && new_delay <= 1) {
|
||||
removeFrames = true;
|
||||
break;
|
||||
}
|
||||
|
||||
memset16(lastPos + 5, new_delay, 1);
|
||||
|
||||
lastPos = (char *)memchr(lastPos + 1, '\x00',
|
||||
(BufferLength - (lastPos - fileData)) - 1);
|
||||
++currentFrame;
|
||||
}
|
||||
|
||||
// TODO: this is cursed, fix it later
|
||||
ArgumentMap output = vipsHandle(BufferData, BufferLength, DataSize, speed, removeFrames);
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Speed(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Speed(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
150
natives/spin.cc
150
natives/spin.cc
|
@ -1,72 +1,78 @@
|
|||
#include <Magick++.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Magick;
|
||||
|
||||
char *Spin(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
[[maybe_unused]] ArgumentMap Arguments, size_t *DataSize) {
|
||||
int delay = GetArgumentWithFallback<int>(Arguments, "delay", 0);
|
||||
|
||||
Blob blob;
|
||||
|
||||
list<Image> frames;
|
||||
list<Image> coalesced;
|
||||
list<Image> mid;
|
||||
try {
|
||||
readImages(&frames, Blob(BufferData, BufferLength));
|
||||
} catch (Magick::WarningCoder &warning) {
|
||||
cerr << "Coder Warning: " << warning.what() << endl;
|
||||
} catch (Magick::Warning &warning) {
|
||||
cerr << "Warning: " << warning.what() << endl;
|
||||
}
|
||||
coalesceImages(&coalesced, frames.begin(), frames.end());
|
||||
|
||||
if (type != "gif") {
|
||||
list<Image>::iterator it = coalesced.begin();
|
||||
for (int i = 0; i < 29; ++i) {
|
||||
coalesced.push_back(*it);
|
||||
}
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (Image &image : coalesced) {
|
||||
image.virtualPixelMethod(Magick::TransparentVirtualPixelMethod);
|
||||
image.scale(Geometry("256x256"));
|
||||
image.alphaChannel(Magick::SetAlphaChannel);
|
||||
double rotation[1] = {(double)360 * i / coalesced.size()};
|
||||
image.distort(Magick::ScaleRotateTranslateDistortion, 1, rotation);
|
||||
image.magick("GIF");
|
||||
mid.push_back(image);
|
||||
i++;
|
||||
}
|
||||
|
||||
for_each(mid.begin(), mid.end(),
|
||||
gifDisposeMethodImage(Magick::BackgroundDispose));
|
||||
|
||||
optimizeTransparency(mid.begin(), mid.end());
|
||||
if (delay != 0) {
|
||||
for_each(mid.begin(), mid.end(), animationDelayImage(delay));
|
||||
} else if (type != "gif") {
|
||||
for_each(mid.begin(), mid.end(), animationDelayImage(5));
|
||||
}
|
||||
|
||||
for (Image &image : mid) {
|
||||
image.quantizeDitherMethod(FloydSteinbergDitherMethod);
|
||||
image.quantize();
|
||||
}
|
||||
|
||||
writeImages(mid.begin(), mid.end(), &blob);
|
||||
|
||||
*outType = "gif";
|
||||
*DataSize = blob.length();
|
||||
|
||||
char *data = (char *)malloc(*DataSize);
|
||||
memcpy(data, blob.data(), *DataSize);
|
||||
return data;
|
||||
}
|
||||
#include <Magick++.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Magick;
|
||||
|
||||
ArgumentMap Spin(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
[[maybe_unused]] ArgumentMap Arguments, size_t *DataSize) {
|
||||
int delay = GetArgumentWithFallback<int>(Arguments, "delay", 0);
|
||||
|
||||
Blob blob;
|
||||
|
||||
list<Image> frames;
|
||||
list<Image> coalesced;
|
||||
list<Image> mid;
|
||||
try {
|
||||
readImages(&frames, Blob(BufferData, BufferLength));
|
||||
} catch (Magick::WarningCoder &warning) {
|
||||
cerr << "Coder Warning: " << warning.what() << endl;
|
||||
} catch (Magick::Warning &warning) {
|
||||
cerr << "Warning: " << warning.what() << endl;
|
||||
}
|
||||
coalesceImages(&coalesced, frames.begin(), frames.end());
|
||||
|
||||
if (type != "gif") {
|
||||
list<Image>::iterator it = coalesced.begin();
|
||||
for (int i = 0; i < 29; ++i) {
|
||||
coalesced.push_back(*it);
|
||||
}
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (Image &image : coalesced) {
|
||||
image.virtualPixelMethod(Magick::TransparentVirtualPixelMethod);
|
||||
image.scale(Geometry("256x256"));
|
||||
image.alphaChannel(Magick::SetAlphaChannel);
|
||||
double rotation[1] = {(double)360 * i / coalesced.size()};
|
||||
image.distort(Magick::ScaleRotateTranslateDistortion, 1, rotation);
|
||||
image.magick("GIF");
|
||||
mid.push_back(image);
|
||||
i++;
|
||||
}
|
||||
|
||||
for_each(mid.begin(), mid.end(),
|
||||
gifDisposeMethodImage(Magick::BackgroundDispose));
|
||||
|
||||
optimizeTransparency(mid.begin(), mid.end());
|
||||
if (delay != 0) {
|
||||
for_each(mid.begin(), mid.end(), animationDelayImage(delay));
|
||||
} else if (type != "gif") {
|
||||
for_each(mid.begin(), mid.end(), animationDelayImage(5));
|
||||
}
|
||||
|
||||
for (Image &image : mid) {
|
||||
image.quantizeDitherMethod(FloydSteinbergDitherMethod);
|
||||
image.quantize();
|
||||
}
|
||||
|
||||
writeImages(mid.begin(), mid.end(), &blob);
|
||||
|
||||
*outType = "gif";
|
||||
*DataSize = blob.length();
|
||||
|
||||
char *data = (char *)malloc(*DataSize);
|
||||
memcpy(data, blob.data(), *DataSize);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = data;
|
||||
output["width"] = (int)mid.front().columns();
|
||||
output["height"] = (int)mid.front().rows();
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Spin(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Spin(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,52 +1,57 @@
|
|||
#include <math.h>
|
||||
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Squish(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, [[maybe_unused]] ArgumentMap Arguments,
|
||||
size_t *DataSize) {
|
||||
VOption *options = VImage::option();
|
||||
|
||||
VImage in =
|
||||
VImage::new_from_buffer(
|
||||
BufferData, BufferLength, "",
|
||||
type == "gif" ? options->set("n", -1)->set("access", "sequential")
|
||||
: options)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
if (!in.has_alpha()) in = in.bandjoin(255);
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = type == "gif" ? vips_image_get_n_pages(in.get_image()) : 30;
|
||||
double mult = (2 * M_PI) / nPages;
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
double newWidth = (sin(i * mult) / 4) + 0.75;
|
||||
double newHeight = (cos(i * mult) / 4) + 0.75;
|
||||
VImage resized =
|
||||
img_frame.resize(newWidth, VImage::option()->set("vscale", newHeight))
|
||||
.gravity(VIPS_COMPASS_DIRECTION_CENTRE, width, pageHeight);
|
||||
img.push_back(resized);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
if (type != "gif") {
|
||||
vector<int> delay(30, 50);
|
||||
final.set("delay", delay);
|
||||
}
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(".gif", &buf, DataSize);
|
||||
|
||||
*outType = "gif";
|
||||
|
||||
return (char *)buf;
|
||||
#include <math.h>
|
||||
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Squish(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, [[maybe_unused]] ArgumentMap Arguments,
|
||||
size_t *DataSize) {
|
||||
VOption *options = VImage::option();
|
||||
|
||||
VImage in =
|
||||
VImage::new_from_buffer(
|
||||
BufferData, BufferLength, "",
|
||||
type == "gif" ? options->set("n", -1)->set("access", "sequential")
|
||||
: options)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
if (!in.has_alpha()) in = in.bandjoin(255);
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = type == "gif" ? vips_image_get_n_pages(in.get_image()) : 30;
|
||||
double mult = (2 * M_PI) / nPages;
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
double newWidth = (sin(i * mult) / 4) + 0.75;
|
||||
double newHeight = (cos(i * mult) / 4) + 0.75;
|
||||
VImage resized =
|
||||
img_frame.resize(newWidth, VImage::option()->set("vscale", newHeight))
|
||||
.gravity(VIPS_COMPASS_DIRECTION_CENTRE, width, pageHeight);
|
||||
img.push_back(resized);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
if (type != "gif") {
|
||||
vector<int> delay(30, 50);
|
||||
final.set("delay", delay);
|
||||
}
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(".gif", &buf, DataSize);
|
||||
|
||||
*outType = "gif";
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = final.width();
|
||||
output["height"] = vips_image_get_page_height(final.get_image());
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Squish(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Squish(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
155
natives/swirl.cc
155
natives/swirl.cc
|
@ -1,76 +1,81 @@
|
|||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Swirl(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
[[maybe_unused]] ArgumentMap Arguments, size_t *DataSize) {
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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 pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
int width = in.width();
|
||||
double newWidth = width * 3;
|
||||
double newHeight = pageHeight * 3;
|
||||
vector<double> divSize = {newWidth / 2, newHeight / 2};
|
||||
|
||||
VImage index = VImage::xyz(newWidth, newHeight);
|
||||
VImage center = index - divSize;
|
||||
VImage polar = center
|
||||
.copy(VImage::option()
|
||||
->set("format", VIPS_FORMAT_COMPLEX)
|
||||
->set("bands", 1))
|
||||
.polar()
|
||||
.copy(VImage::option()
|
||||
->set("format", VIPS_FORMAT_FLOAT)
|
||||
->set("bands", 2));
|
||||
|
||||
int size = min(width, pageHeight) / 2;
|
||||
|
||||
VImage test = (1 - polar.extract_band(0) / size);
|
||||
VImage degrees = test.cast(VIPS_FORMAT_FLOAT).pow(2);
|
||||
|
||||
VImage angle = polar.extract_band(1) + degrees * 180;
|
||||
|
||||
VImage distortion = polar.extract_band(0)
|
||||
.bandjoin(angle)
|
||||
.copy(VImage::option()
|
||||
->set("format", VIPS_FORMAT_COMPLEX)
|
||||
->set("bands", 1))
|
||||
.rect()
|
||||
.copy(VImage::option()
|
||||
->set("format", VIPS_FORMAT_FLOAT)
|
||||
->set("bands", 2)) +
|
||||
divSize;
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
|
||||
VImage distort =
|
||||
img_frame
|
||||
.gravity(VIPS_COMPASS_DIRECTION_CENTRE, newWidth, newHeight,
|
||||
VImage::option()->set("extend", VIPS_EXTEND_COPY))
|
||||
.mapim(distortion,
|
||||
VImage::option()->set(
|
||||
"interpolate", VInterpolate::new_from_name("bicubic")));
|
||||
VImage frame = distort.crop(width, pageHeight, width, pageHeight);
|
||||
img.push_back(frame);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
return (char *)buf;
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Swirl(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
[[maybe_unused]] ArgumentMap Arguments, size_t *DataSize) {
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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 pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
int width = in.width();
|
||||
double newWidth = width * 3;
|
||||
double newHeight = pageHeight * 3;
|
||||
vector<double> divSize = {newWidth / 2, newHeight / 2};
|
||||
|
||||
VImage index = VImage::xyz(newWidth, newHeight);
|
||||
VImage center = index - divSize;
|
||||
VImage polar = center
|
||||
.copy(VImage::option()
|
||||
->set("format", VIPS_FORMAT_COMPLEX)
|
||||
->set("bands", 1))
|
||||
.polar()
|
||||
.copy(VImage::option()
|
||||
->set("format", VIPS_FORMAT_FLOAT)
|
||||
->set("bands", 2));
|
||||
|
||||
int size = min(width, pageHeight) / 2;
|
||||
|
||||
VImage test = (1 - polar.extract_band(0) / size);
|
||||
VImage degrees = test.cast(VIPS_FORMAT_FLOAT).pow(2);
|
||||
|
||||
VImage angle = polar.extract_band(1) + degrees * 180;
|
||||
|
||||
VImage distortion = polar.extract_band(0)
|
||||
.bandjoin(angle)
|
||||
.copy(VImage::option()
|
||||
->set("format", VIPS_FORMAT_COMPLEX)
|
||||
->set("bands", 1))
|
||||
.rect()
|
||||
.copy(VImage::option()
|
||||
->set("format", VIPS_FORMAT_FLOAT)
|
||||
->set("bands", 2)) +
|
||||
divSize;
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
|
||||
VImage distort =
|
||||
img_frame
|
||||
.gravity(VIPS_COMPASS_DIRECTION_CENTRE, newWidth, newHeight,
|
||||
VImage::option()->set("extend", VIPS_EXTEND_COPY))
|
||||
.mapim(distortion,
|
||||
VImage::option()->set(
|
||||
"interpolate", VInterpolate::new_from_name("bicubic")));
|
||||
VImage frame = distort.crop(width, pageHeight, width, pageHeight);
|
||||
img.push_back(frame);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = final.width();
|
||||
output["height"] = vips_image_get_page_height(final.get_image());
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Swirl(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Swirl(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
134
natives/tile.cc
134
natives/tile.cc
|
@ -1,65 +1,71 @@
|
|||
#include <Magick++.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Magick;
|
||||
|
||||
char *Tile(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
[[maybe_unused]] ArgumentMap Arguments, size_t *DataSize) {
|
||||
Blob blob;
|
||||
|
||||
list<Image> frames;
|
||||
list<Image> coalesced;
|
||||
list<Image> mid;
|
||||
try {
|
||||
readImages(&frames, Blob(BufferData, BufferLength));
|
||||
} catch (Magick::WarningCoder &warning) {
|
||||
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) {
|
||||
list<Image> duplicated;
|
||||
Image appended;
|
||||
list<Image> montage;
|
||||
Image frame;
|
||||
image.magick(*outType);
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
duplicated.push_back(image);
|
||||
}
|
||||
appendImages(&appended, duplicated.begin(), duplicated.end());
|
||||
appended.repage();
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
montage.push_back(appended);
|
||||
}
|
||||
appendImages(&frame, montage.begin(), montage.end(), true);
|
||||
frame.repage();
|
||||
frame.scale(Geometry("800x800>"));
|
||||
frame.animationDelay(image.animationDelay());
|
||||
mid.push_back(frame);
|
||||
}
|
||||
|
||||
optimizeTransparency(mid.begin(), mid.end());
|
||||
|
||||
if (*outType == "gif") {
|
||||
for (Image &image : mid) {
|
||||
image.quantizeDitherMethod(FloydSteinbergDitherMethod);
|
||||
image.quantize();
|
||||
}
|
||||
}
|
||||
|
||||
writeImages(mid.begin(), mid.end(), &blob);
|
||||
|
||||
*DataSize = blob.length();
|
||||
|
||||
char *data = (char *)malloc(*DataSize);
|
||||
memcpy(data, blob.data(), *DataSize);
|
||||
return data;
|
||||
#include <Magick++.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Magick;
|
||||
|
||||
ArgumentMap Tile(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
[[maybe_unused]] ArgumentMap Arguments, size_t *DataSize) {
|
||||
Blob blob;
|
||||
|
||||
list<Image> frames;
|
||||
list<Image> coalesced;
|
||||
list<Image> mid;
|
||||
try {
|
||||
readImages(&frames, Blob(BufferData, BufferLength));
|
||||
} catch (Magick::WarningCoder &warning) {
|
||||
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) {
|
||||
list<Image> duplicated;
|
||||
Image appended;
|
||||
list<Image> montage;
|
||||
Image frame;
|
||||
image.magick(*outType);
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
duplicated.push_back(image);
|
||||
}
|
||||
appendImages(&appended, duplicated.begin(), duplicated.end());
|
||||
appended.repage();
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
montage.push_back(appended);
|
||||
}
|
||||
appendImages(&frame, montage.begin(), montage.end(), true);
|
||||
frame.repage();
|
||||
frame.scale(Geometry("800x800>"));
|
||||
frame.animationDelay(image.animationDelay());
|
||||
mid.push_back(frame);
|
||||
}
|
||||
|
||||
optimizeTransparency(mid.begin(), mid.end());
|
||||
|
||||
if (*outType == "gif") {
|
||||
for (Image &image : mid) {
|
||||
image.quantizeDitherMethod(FloydSteinbergDitherMethod);
|
||||
image.quantize();
|
||||
}
|
||||
}
|
||||
|
||||
writeImages(mid.begin(), mid.end(), &blob);
|
||||
|
||||
*DataSize = blob.length();
|
||||
|
||||
char *data = (char *)malloc(*DataSize);
|
||||
memcpy(data, blob.data(), *DataSize);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = data;
|
||||
output["width"] = (int)mid.front().columns();
|
||||
output["height"] = (int)mid.front().rows();
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Tile(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Tile(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,28 +1,38 @@
|
|||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *ToGif(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
[[maybe_unused]] ArgumentMap Arguments, size_t *DataSize) {
|
||||
if (type == "gif") {
|
||||
*DataSize = BufferLength;
|
||||
char *data = (char *)malloc(BufferLength);
|
||||
memcpy(data, BufferData, BufferLength);
|
||||
return data;
|
||||
} else {
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in = VImage::new_from_buffer(
|
||||
BufferData, BufferLength, "",
|
||||
type == "webp" ? options->set("n", -1) : options);
|
||||
|
||||
void *buf;
|
||||
in.write_to_buffer(".gif", &buf, DataSize);
|
||||
*outType = "gif";
|
||||
|
||||
return (char *)buf;
|
||||
}
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap ToGif(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
[[maybe_unused]] ArgumentMap Arguments, size_t *DataSize) {
|
||||
if (type == "gif") {
|
||||
*DataSize = BufferLength;
|
||||
char *data = (char *)malloc(BufferLength);
|
||||
memcpy(data, BufferData, BufferLength);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = data;
|
||||
|
||||
return output;
|
||||
|
||||
} else {
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in = VImage::new_from_buffer(
|
||||
BufferData, BufferLength, "",
|
||||
type == "webp" ? options->set("n", -1) : options);
|
||||
|
||||
void *buf;
|
||||
in.write_to_buffer(".gif", &buf, DataSize);
|
||||
*outType = "gif";
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = in.width();
|
||||
output["height"] = vips_image_get_page_height(in.get_image());
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* ToGif(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap ToGif(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,101 +1,106 @@
|
|||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Uncanny(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
string caption = GetArgument<string>(Arguments, "caption");
|
||||
string caption2 = GetArgument<string>(Arguments, "caption2");
|
||||
string font = GetArgument<string>(Arguments, "font");
|
||||
string path = GetArgument<string>(Arguments, "path");
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
VImage::new_from_buffer(BufferData, BufferLength, "",
|
||||
type == "gif" ? options->set("n", -1) : options)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB)
|
||||
.extract_band(0, VImage::option()->set("n", 3));
|
||||
|
||||
VImage base = VImage::black(1280, 720, VImage::option()->set("bands", 3));
|
||||
|
||||
string font_string = (font == "roboto" ? "Roboto Condensed" : font) +
|
||||
", Twemoji Color Font " +
|
||||
(font != "impact" ? "bold" : "normal") + " 72";
|
||||
|
||||
string captionText =
|
||||
"<span background=\"black\" foreground=\"white\">" + caption + "</span>";
|
||||
string caption2Text =
|
||||
"<span background=\"black\" foreground=\"red\">" + caption2 + "</span>";
|
||||
|
||||
auto findResult = fontPaths.find(font);
|
||||
if (findResult != fontPaths.end()) {
|
||||
VImage::text(".", VImage::option()->set(
|
||||
"fontfile", (basePath + findResult->second).c_str()));
|
||||
}
|
||||
|
||||
VImage text = VImage::text(
|
||||
captionText.c_str(),
|
||||
VImage::option()
|
||||
->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", 588)
|
||||
->set("height", 90));
|
||||
VImage captionImage =
|
||||
text.extract_band(0, VImage::option()->set("n", 3))
|
||||
.gravity(VIPS_COMPASS_DIRECTION_CENTRE, 640, text.height() + 40,
|
||||
VImage::option()->set("extend", "black"));
|
||||
|
||||
VImage text2 = VImage::text(
|
||||
caption2Text.c_str(),
|
||||
VImage::option()
|
||||
->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", 588)
|
||||
->set("height", 90));
|
||||
VImage caption2Image =
|
||||
text2.extract_band(0, VImage::option()->set("n", 3))
|
||||
.gravity(VIPS_COMPASS_DIRECTION_CENTRE, 640, text.height() + 40,
|
||||
VImage::option()->set("extend", "black"));
|
||||
|
||||
base = base.insert(captionImage, 0, 0).insert(caption2Image, 640, 0);
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
VImage uncanny = VImage::new_from_file((basePath + path).c_str());
|
||||
|
||||
base = base.insert(uncanny, 0, 130);
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
VImage resized = img_frame.resize(690.0 / (double)width);
|
||||
if (resized.height() > 590) {
|
||||
double vscale = 590.0 / (double)resized.height();
|
||||
resized = resized.resize(vscale, VImage::option()->set("vscale", vscale));
|
||||
}
|
||||
VImage composited = base.insert(resized, 935 - (resized.width() / 2),
|
||||
425 - (resized.height() / 2));
|
||||
img.push_back(composited);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, 720);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif" ? VImage::option()->set("reoptimise", 1) : 0);
|
||||
|
||||
return (char *)buf;
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Uncanny(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
string caption = GetArgument<string>(Arguments, "caption");
|
||||
string caption2 = GetArgument<string>(Arguments, "caption2");
|
||||
string font = GetArgument<string>(Arguments, "font");
|
||||
string path = GetArgument<string>(Arguments, "path");
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
VImage::new_from_buffer(BufferData, BufferLength, "",
|
||||
type == "gif" ? options->set("n", -1) : options)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB)
|
||||
.extract_band(0, VImage::option()->set("n", 3));
|
||||
|
||||
VImage base = VImage::black(1280, 720, VImage::option()->set("bands", 3));
|
||||
|
||||
string font_string = (font == "roboto" ? "Roboto Condensed" : font) +
|
||||
", Twemoji Color Font " +
|
||||
(font != "impact" ? "bold" : "normal") + " 72";
|
||||
|
||||
string captionText =
|
||||
"<span background=\"black\" foreground=\"white\">" + caption + "</span>";
|
||||
string caption2Text =
|
||||
"<span background=\"black\" foreground=\"red\">" + caption2 + "</span>";
|
||||
|
||||
auto findResult = fontPaths.find(font);
|
||||
if (findResult != fontPaths.end()) {
|
||||
VImage::text(".", VImage::option()->set(
|
||||
"fontfile", (basePath + findResult->second).c_str()));
|
||||
}
|
||||
|
||||
VImage text = VImage::text(
|
||||
captionText.c_str(),
|
||||
VImage::option()
|
||||
->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", 588)
|
||||
->set("height", 90));
|
||||
VImage captionImage =
|
||||
text.extract_band(0, VImage::option()->set("n", 3))
|
||||
.gravity(VIPS_COMPASS_DIRECTION_CENTRE, 640, text.height() + 40,
|
||||
VImage::option()->set("extend", "black"));
|
||||
|
||||
VImage text2 = VImage::text(
|
||||
caption2Text.c_str(),
|
||||
VImage::option()
|
||||
->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", 588)
|
||||
->set("height", 90));
|
||||
VImage caption2Image =
|
||||
text2.extract_band(0, VImage::option()->set("n", 3))
|
||||
.gravity(VIPS_COMPASS_DIRECTION_CENTRE, 640, text.height() + 40,
|
||||
VImage::option()->set("extend", "black"));
|
||||
|
||||
base = base.insert(captionImage, 0, 0).insert(caption2Image, 640, 0);
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
VImage uncanny = VImage::new_from_file((basePath + path).c_str());
|
||||
|
||||
base = base.insert(uncanny, 0, 130);
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
VImage resized = img_frame.resize(690.0 / (double)width);
|
||||
if (resized.height() > 590) {
|
||||
double vscale = 590.0 / (double)resized.height();
|
||||
resized = resized.resize(vscale, VImage::option()->set("vscale", vscale));
|
||||
}
|
||||
VImage composited = base.insert(resized, 935 - (resized.width() / 2),
|
||||
425 - (resized.height() / 2));
|
||||
img.push_back(composited);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, 720);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif" ? VImage::option()->set("reoptimise", 1) : 0);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = final.width();
|
||||
output["height"] = vips_image_get_page_height(final.get_image());
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Uncanny(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Uncanny(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,54 +1,59 @@
|
|||
#include <map>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Uncaption(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
float tolerance = GetArgumentWithFallback<float>(Arguments, "tolerance", 0.5);
|
||||
|
||||
VOption *options = VImage::option();
|
||||
|
||||
VImage in =
|
||||
VImage::new_from_buffer(
|
||||
BufferData, BufferLength, "",
|
||||
type == "gif" ? options->set("n", -1)->set("access", "sequential")
|
||||
: options)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
if (!in.has_alpha()) in = in.bandjoin(255);
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
VImage first =
|
||||
in.crop(0, 0, 3, pageHeight).colourspace(VIPS_INTERPRETATION_B_W) >
|
||||
(255 * tolerance);
|
||||
int top, captionWidth, captionHeight;
|
||||
first.find_trim(&top, &captionWidth, &captionHeight);
|
||||
|
||||
vector<VImage> img;
|
||||
int newHeight = pageHeight - top;
|
||||
if (top == pageHeight) {
|
||||
newHeight = pageHeight;
|
||||
top = 0;
|
||||
}
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame = in.crop(0, (i * pageHeight) + top, width, newHeight);
|
||||
img.push_back(img_frame);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, newHeight);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
return (char *)buf;
|
||||
}
|
||||
#include <map>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Uncaption(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
float tolerance = GetArgumentWithFallback<float>(Arguments, "tolerance", 0.5);
|
||||
|
||||
VOption *options = VImage::option();
|
||||
|
||||
VImage in =
|
||||
VImage::new_from_buffer(
|
||||
BufferData, BufferLength, "",
|
||||
type == "gif" ? options->set("n", -1)->set("access", "sequential")
|
||||
: options)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||
if (!in.has_alpha()) in = in.bandjoin(255);
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
VImage first =
|
||||
in.crop(0, 0, 3, pageHeight).colourspace(VIPS_INTERPRETATION_B_W) >
|
||||
(255 * tolerance);
|
||||
int top, captionWidth, captionHeight;
|
||||
first.find_trim(&top, &captionWidth, &captionHeight);
|
||||
|
||||
vector<VImage> img;
|
||||
int newHeight = pageHeight - top;
|
||||
if (top == pageHeight) {
|
||||
newHeight = pageHeight;
|
||||
top = 0;
|
||||
}
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame = in.crop(0, (i * pageHeight) + top, width, newHeight);
|
||||
img.push_back(img_frame);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, newHeight);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = final.width();
|
||||
output["height"] = vips_image_get_page_height(final.get_image());
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Uncaption(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Uncaption(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
120
natives/wall.cc
120
natives/wall.cc
|
@ -1,58 +1,64 @@
|
|||
#include <Magick++.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Magick;
|
||||
|
||||
char *Wall(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
[[maybe_unused]] ArgumentMap Arguments, size_t *DataSize) {
|
||||
Blob blob;
|
||||
|
||||
list<Image> frames;
|
||||
list<Image> coalesced;
|
||||
list<Image> mid;
|
||||
try {
|
||||
readImages(&frames, Blob(BufferData, BufferLength));
|
||||
} catch (Magick::WarningCoder &warning) {
|
||||
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.resize(Geometry("128x128"));
|
||||
image.virtualPixelMethod(Magick::TileVirtualPixelMethod);
|
||||
image.matteColor("none");
|
||||
image.backgroundColor("none");
|
||||
image.scale(Geometry("512x512"));
|
||||
double arguments[16] = {0, 0, 57, 42, 0, 128, 63, 130,
|
||||
128, 0, 140, 60, 128, 128, 140, 140};
|
||||
image.distort(Magick::PerspectiveDistortion, 16, arguments);
|
||||
image.scale(Geometry("800x800>"));
|
||||
image.magick(*outType);
|
||||
mid.push_back(image);
|
||||
}
|
||||
|
||||
optimizeTransparency(mid.begin(), mid.end());
|
||||
|
||||
if (*outType == "gif") {
|
||||
for (Image &image : mid) {
|
||||
image.quantizeDitherMethod(FloydSteinbergDitherMethod);
|
||||
image.quantize();
|
||||
}
|
||||
}
|
||||
|
||||
writeImages(mid.begin(), mid.end(), &blob);
|
||||
|
||||
*DataSize = blob.length();
|
||||
|
||||
char *data = (char *)malloc(*DataSize);
|
||||
memcpy(data, blob.data(), *DataSize);
|
||||
return data;
|
||||
#include <Magick++.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Magick;
|
||||
|
||||
ArgumentMap Wall(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
[[maybe_unused]] ArgumentMap Arguments, size_t *DataSize) {
|
||||
Blob blob;
|
||||
|
||||
list<Image> frames;
|
||||
list<Image> coalesced;
|
||||
list<Image> mid;
|
||||
try {
|
||||
readImages(&frames, Blob(BufferData, BufferLength));
|
||||
} catch (Magick::WarningCoder &warning) {
|
||||
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.resize(Geometry("128x128"));
|
||||
image.virtualPixelMethod(Magick::TileVirtualPixelMethod);
|
||||
image.matteColor("none");
|
||||
image.backgroundColor("none");
|
||||
image.scale(Geometry("512x512"));
|
||||
double arguments[16] = {0, 0, 57, 42, 0, 128, 63, 130,
|
||||
128, 0, 140, 60, 128, 128, 140, 140};
|
||||
image.distort(Magick::PerspectiveDistortion, 16, arguments);
|
||||
image.scale(Geometry("800x800>"));
|
||||
image.magick(*outType);
|
||||
mid.push_back(image);
|
||||
}
|
||||
|
||||
optimizeTransparency(mid.begin(), mid.end());
|
||||
|
||||
if (*outType == "gif") {
|
||||
for (Image &image : mid) {
|
||||
image.quantizeDitherMethod(FloydSteinbergDitherMethod);
|
||||
image.quantize();
|
||||
}
|
||||
}
|
||||
|
||||
writeImages(mid.begin(), mid.end(), &blob);
|
||||
|
||||
*DataSize = blob.length();
|
||||
|
||||
char *data = (char *)malloc(*DataSize);
|
||||
memcpy(data, blob.data(), *DataSize);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = data;
|
||||
output["width"] = (int)mid.front().columns();
|
||||
output["height"] = (int)mid.front().rows();
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Wall(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Wall(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,154 +1,159 @@
|
|||
#include <map>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Watermark(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
string water = GetArgument<string>(Arguments, "water");
|
||||
int gravity = GetArgument<int>(Arguments, "gravity");
|
||||
|
||||
bool resize = GetArgumentWithFallback<bool>(Arguments, "resize", false);
|
||||
|
||||
float yscale = GetArgumentWithFallback<float>(Arguments, "yscale", false);
|
||||
|
||||
bool append = GetArgumentWithFallback<bool>(Arguments, "append", false);
|
||||
|
||||
bool alpha = GetArgumentWithFallback<bool>(Arguments, "alpha", false);
|
||||
bool flip = GetArgumentWithFallback<bool>(Arguments, "flip", false);
|
||||
|
||||
bool mc = MAP_HAS(Arguments, "mc");
|
||||
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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 watermark = VImage::new_from_file(merged.c_str());
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
if (flip) {
|
||||
watermark = watermark.flip(VIPS_DIRECTION_HORIZONTAL);
|
||||
}
|
||||
|
||||
if (resize && append) {
|
||||
watermark = watermark.resize((double)width / (double)watermark.width());
|
||||
} 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;
|
||||
switch (gravity) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
x = (width / 2) - (watermark.width() / 2);
|
||||
break;
|
||||
case 3:
|
||||
x = width - watermark.width();
|
||||
break;
|
||||
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 addedHeight = 0;
|
||||
VImage contentAlpha;
|
||||
VImage frameAlpha;
|
||||
VImage bg;
|
||||
VImage frame;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
if (append) {
|
||||
VImage appended = img_frame.join(watermark, VIPS_DIRECTION_VERTICAL,
|
||||
VImage::option()->set("expand", true));
|
||||
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 (*outType == "jpg" || *outType == "jpeg") {
|
||||
*outType = "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 final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight + addedHeight);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
return (char *)buf;
|
||||
}
|
||||
#include <map>
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Watermark(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
string water = GetArgument<string>(Arguments, "water");
|
||||
int gravity = GetArgument<int>(Arguments, "gravity");
|
||||
|
||||
bool resize = GetArgumentWithFallback<bool>(Arguments, "resize", false);
|
||||
|
||||
float yscale = GetArgumentWithFallback<float>(Arguments, "yscale", false);
|
||||
|
||||
bool append = GetArgumentWithFallback<bool>(Arguments, "append", false);
|
||||
|
||||
bool alpha = GetArgumentWithFallback<bool>(Arguments, "alpha", false);
|
||||
bool flip = GetArgumentWithFallback<bool>(Arguments, "flip", false);
|
||||
|
||||
bool mc = MAP_HAS(Arguments, "mc");
|
||||
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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 watermark = VImage::new_from_file(merged.c_str());
|
||||
|
||||
int width = in.width();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
if (flip) {
|
||||
watermark = watermark.flip(VIPS_DIRECTION_HORIZONTAL);
|
||||
}
|
||||
|
||||
if (resize && append) {
|
||||
watermark = watermark.resize((double)width / (double)watermark.width());
|
||||
} 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;
|
||||
switch (gravity) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
x = (width / 2) - (watermark.width() / 2);
|
||||
break;
|
||||
case 3:
|
||||
x = width - watermark.width();
|
||||
break;
|
||||
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 addedHeight = 0;
|
||||
VImage contentAlpha;
|
||||
VImage frameAlpha;
|
||||
VImage bg;
|
||||
VImage frame;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
if (append) {
|
||||
VImage appended = img_frame.join(watermark, VIPS_DIRECTION_VERTICAL,
|
||||
VImage::option()->set("expand", true));
|
||||
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 (*outType == "jpg" || *outType == "jpeg") {
|
||||
*outType = "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 final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight + addedHeight);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = final.width();
|
||||
output["height"] = vips_image_get_page_height(final.get_image());
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Watermark(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Watermark(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,86 +1,91 @@
|
|||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Whisper(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
string caption = GetArgument<string>(Arguments, "caption");
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
int size = width / 6;
|
||||
int dividedWidth = width / 175;
|
||||
int rad = 1;
|
||||
|
||||
string font_string = "Upright, Twemoji Color Font " + to_string(size);
|
||||
|
||||
VImage mask;
|
||||
if (dividedWidth >= 1) {
|
||||
mask = VImage::black(dividedWidth * 2 + 1, dividedWidth * 2 + 1) + 128;
|
||||
mask.draw_circle({255}, dividedWidth, dividedWidth, dividedWidth,
|
||||
VImage::option()->set("fill", true));
|
||||
} else {
|
||||
mask = VImage::black(rad * 2 + 1, rad * 2 + 1) + 128;
|
||||
mask.draw_circle({255}, rad, rad, rad, VImage::option()->set("fill", true));
|
||||
}
|
||||
|
||||
VImage textIn = VImage::text(
|
||||
".", VImage::option()->set(
|
||||
"fontfile", (basePath + "assets/fonts/whisper.otf").c_str()));
|
||||
textIn = VImage::text(
|
||||
("<span foreground=\"white\">" + caption + "</span>").c_str(),
|
||||
VImage::option()
|
||||
->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", width));
|
||||
|
||||
textIn = textIn.embed(rad + 10, rad + 10, (textIn.width() + 2 * rad) + 20,
|
||||
(textIn.height() + 2 * rad) + 20);
|
||||
|
||||
VImage outline = textIn.morph(mask, VIPS_OPERATION_MORPHOLOGY_DILATE)
|
||||
.gaussblur(0.5, VImage::option()->set("min_ampl", 0.1));
|
||||
outline = (outline == (vector<double>){0, 0, 0, 0});
|
||||
VImage invert = outline.extract_band(3).invert();
|
||||
outline =
|
||||
outline.extract_band(0, VImage::option()->set("n", outline.bands() - 1))
|
||||
.bandjoin(invert);
|
||||
VImage textImg = outline.composite2(textIn, VIPS_BLEND_MODE_OVER);
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
img_frame = img_frame.composite2(
|
||||
textImg, VIPS_BLEND_MODE_OVER,
|
||||
VImage::option()
|
||||
->set("x", (width / 2) - (textImg.width() / 2))
|
||||
->set("y", (pageHeight / 2) - (textImg.height() / 2)));
|
||||
img.push_back(img_frame);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
return (char *)buf;
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Whisper(string type, string *outType, char *BufferData,
|
||||
size_t BufferLength, ArgumentMap Arguments, size_t *DataSize) {
|
||||
string caption = GetArgument<string>(Arguments, "caption");
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
int size = width / 6;
|
||||
int dividedWidth = width / 175;
|
||||
int rad = 1;
|
||||
|
||||
string font_string = "Upright, Twemoji Color Font " + to_string(size);
|
||||
|
||||
VImage mask;
|
||||
if (dividedWidth >= 1) {
|
||||
mask = VImage::black(dividedWidth * 2 + 1, dividedWidth * 2 + 1) + 128;
|
||||
mask.draw_circle({255}, dividedWidth, dividedWidth, dividedWidth,
|
||||
VImage::option()->set("fill", true));
|
||||
} else {
|
||||
mask = VImage::black(rad * 2 + 1, rad * 2 + 1) + 128;
|
||||
mask.draw_circle({255}, rad, rad, rad, VImage::option()->set("fill", true));
|
||||
}
|
||||
|
||||
VImage textIn = VImage::text(
|
||||
".", VImage::option()->set(
|
||||
"fontfile", (basePath + "assets/fonts/whisper.otf").c_str()));
|
||||
textIn = VImage::text(
|
||||
("<span foreground=\"white\">" + caption + "</span>").c_str(),
|
||||
VImage::option()
|
||||
->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", width));
|
||||
|
||||
textIn = textIn.embed(rad + 10, rad + 10, (textIn.width() + 2 * rad) + 20,
|
||||
(textIn.height() + 2 * rad) + 20);
|
||||
|
||||
VImage outline = textIn.morph(mask, VIPS_OPERATION_MORPHOLOGY_DILATE)
|
||||
.gaussblur(0.5, VImage::option()->set("min_ampl", 0.1));
|
||||
outline = (outline == (vector<double>){0, 0, 0, 0});
|
||||
VImage invert = outline.extract_band(3).invert();
|
||||
outline =
|
||||
outline.extract_band(0, VImage::option()->set("n", outline.bands() - 1))
|
||||
.bandjoin(invert);
|
||||
VImage textImg = outline.composite2(textIn, VIPS_BLEND_MODE_OVER);
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
img_frame = img_frame.composite2(
|
||||
textImg, VIPS_BLEND_MODE_OVER,
|
||||
VImage::option()
|
||||
->set("x", (width / 2) - (textImg.width() / 2))
|
||||
->set("y", (pageHeight / 2) - (textImg.height() / 2)));
|
||||
img.push_back(img_frame);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, pageHeight);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(
|
||||
("." + *outType).c_str(), &buf, DataSize,
|
||||
*outType == "gif"
|
||||
? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||
: 0);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = width;
|
||||
output["height"] = pageHeight;
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Whisper(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Whisper(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -1,47 +1,52 @@
|
|||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
char *Zamn(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t *DataSize) {
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
string assetPath = basePath + "assets/images/zamn.png";
|
||||
VImage tmpl = VImage::new_from_file(assetPath.c_str());
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
VImage composited = tmpl.insert(
|
||||
img_frame.extract_band(0, VImage::option()->set("n", 3))
|
||||
.bandjoin(255)
|
||||
.resize(
|
||||
303.0 / (double)width,
|
||||
VImage::option()->set("vscale", 438.0 / (double)pageHeight)),
|
||||
310, 76);
|
||||
img.push_back(composited);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, 516);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
return (char *)buf;
|
||||
#include <vips/vips8>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vips;
|
||||
|
||||
ArgumentMap Zamn(string type, string *outType, char *BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t *DataSize) {
|
||||
string basePath = GetArgument<string>(Arguments, "basePath");
|
||||
|
||||
VOption *options = VImage::option()->set("access", "sequential");
|
||||
|
||||
VImage in =
|
||||
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();
|
||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||
int nPages = vips_image_get_n_pages(in.get_image());
|
||||
|
||||
string assetPath = basePath + "assets/images/zamn.png";
|
||||
VImage tmpl = VImage::new_from_file(assetPath.c_str());
|
||||
|
||||
vector<VImage> img;
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
VImage img_frame =
|
||||
type == "gif" ? in.crop(0, i * pageHeight, width, pageHeight) : in;
|
||||
VImage composited = tmpl.insert(
|
||||
img_frame.extract_band(0, VImage::option()->set("n", 3))
|
||||
.bandjoin(255)
|
||||
.resize(
|
||||
303.0 / (double)width,
|
||||
VImage::option()->set("vscale", 438.0 / (double)pageHeight)),
|
||||
310, 76);
|
||||
img.push_back(composited);
|
||||
}
|
||||
VImage final = VImage::arrayjoin(img, VImage::option()->set("across", 1));
|
||||
final.set(VIPS_META_PAGE_HEIGHT, 516);
|
||||
|
||||
void *buf;
|
||||
final.write_to_buffer(("." + *outType).c_str(), &buf, DataSize);
|
||||
|
||||
ArgumentMap output;
|
||||
output["buf"] = (char *)buf;
|
||||
output["width"] = final.width();
|
||||
output["height"] = vips_image_get_page_height(final.get_image());
|
||||
|
||||
return output;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
char* Zamn(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
ArgumentMap Zamn(string type, string* outType, char* BufferData, size_t BufferLength,
|
||||
ArgumentMap Arguments, size_t* DataSize);
|
|
@ -50,7 +50,9 @@ export default function run(object) {
|
|||
const result = img.image(object.cmd, objectWithFixedType);
|
||||
const returnObject = {
|
||||
buffer: result.data,
|
||||
fileExtension: result.type
|
||||
fileExtension: result.type,
|
||||
width: result.width,
|
||||
height: result.height
|
||||
};
|
||||
resolve(returnObject);
|
||||
} catch (e) {
|
||||
|
|
|
@ -135,7 +135,9 @@ function waitForWorker(worker) {
|
|||
worker.once("message", (data) => {
|
||||
resolve({
|
||||
buffer: Buffer.from([...data.buffer]),
|
||||
type: data.fileExtension
|
||||
type: data.fileExtension,
|
||||
width: data.width,
|
||||
height: data.height
|
||||
});
|
||||
});
|
||||
worker.once("error", reject);
|
||||
|
|
Loading…
Reference in a new issue