Load fonts directly from assets directory, fix image buffer issues

This commit is contained in:
Essem 2022-09-22 23:44:54 -05:00
parent 273e5b94d7
commit 4f66519aa7
No known key found for this signature in database
GPG Key ID: 7D497397CC3A2A8C
22 changed files with 188 additions and 111 deletions

View File

@ -12,15 +12,6 @@ RUN apk add --no-cache git cmake msttcorefonts-installer python3 alpine-sdk ffmp
RUN --mount=type=cache,id=pnpm-store,target=/root/.pnpm-store \
npm install -g pnpm@6.27.1
# gets latest version of twemoji
RUN mkdir /tmp/twemoji \
&& cd /tmp/twemoji \
&& package=$(wget --quiet -O - https://fedora.mirror.liteserver.nl/linux/development/rawhide/Everything/aarch64/os/Packages/t/ | grep -Po '(?<=href=")twitter-twemoji-fonts-[^"]*' | tail -1) \
&& wget https://fedora.mirror.liteserver.nl/linux/development/rawhide/Everything/aarch64/os/Packages/t/$package \
&& rpm2cpio $package | cpio -ivd \
&& cp ./usr/share/fonts/twemoji/Twemoji.ttf /usr/share/fonts/Twemoji.ttf \
&& rm -r /tmp/twemoji
# liblqr needs to be built manually for magick to work
# and because alpine doesn't have it in their repos
RUN git clone https://github.com/carlobaldassi/liblqr \
@ -53,17 +44,12 @@ RUN git clone https://github.com/ImageMagick/ImageMagick.git ImageMagick \
RUN update-ms-fonts && fc-cache -f
RUN adduser esmBot -s /bin/sh -D
USER esmBot
WORKDIR /home/esmBot/.internal
COPY ./assets/caption.otf /usr/share/fonts/caption.otf
COPY ./assets/caption2.ttf /usr/share/fonts/caption2.ttf
COPY ./assets/hbc.ttf /usr/share/fonts/hbc.ttf
COPY ./assets/reddit.ttf /usr/share/fonts/reddit.ttf
COPY ./assets/whisper.otf /usr/share/fonts/whisper.otf
RUN fc-cache -fv
COPY --chown=node:node ./package.json package.json
COPY --chown=node:node ./pnpm-lock.yaml pnpm-lock.yaml
COPY --chown=esmBot:esmBot ./package.json package.json
COPY --chown=esmBot:esmBot ./pnpm-lock.yaml pnpm-lock.yaml
RUN pnpm install
COPY . .
RUN rm .env
@ -81,6 +67,4 @@ RUN mkdir /home/esmBot/.internal/logs \
&& chown esmBot:esmBot /home/esmBot/.internal/logs \
&& chmod 777 /home/esmBot/.internal/logs
USER esmBot
ENTRYPOINT ["node", "app.js"]

BIN
assets/fonts/twemoji.otf Normal file

Binary file not shown.

View File

@ -77,13 +77,13 @@ class ImageCommand extends Command {
}
try {
const { arrayBuffer, type } = await runImageJob(imageParams);
const { buffer, type } = await runImageJob(imageParams);
if (type === "nogif" && this.constructor.requiresGIF) {
return "That isn't a GIF!";
}
this.success = true;
return {
file: Buffer.from(arrayBuffer),
file: buffer,
name: `${this.constructor.command}.${type}`
};
} catch (e) {

View File

@ -17,7 +17,7 @@ class UncannyCommand extends ImageCommand {
return {
caption: text1?.trim() ? textEncode(text1) : random(prompts),
caption2: textEncode(text2),
path: `./assets/images/uncanny/${typeof this.options.phase === "string" && names.includes(this.options.phase.toLowerCase()) ? this.options.phase.toLowerCase() : random(names.filter((val) => val !== "goated"))}.png`,
path: `assets/images/uncanny/${typeof this.options.phase === "string" && names.includes(this.options.phase.toLowerCase()) ? this.options.phase.toLowerCase() : random(names.filter((val) => val !== "goated"))}.png`,
font: typeof this.options.font === "string" && this.constructor.allowedFonts.includes(this.options.font.toLowerCase()) ? this.options.font.toLowerCase() : "helvetica"
};
}

View File

@ -43,7 +43,7 @@ Choose the distro you're using below for insallation instructions.
### 2. Install libvips.
[libvips](https://github.com/libvips/libvips) is the core of esmBot's image processing commands. The latest version (8.13.0) is recommended because it contains fixes to GIF handling and support for the freeze command; however, this version isn't packaged for most distros yet. To fix this, you'll need to build libvips from source.
[libvips](https://github.com/libvips/libvips) is the core of esmBot's image processing commands. Version 8.13.0 or higher is recommended because it contains fixes to GIF handling and support for the freeze command; however, this version isn't packaged for most distros yet. To fix this, you'll need to build libvips from source.
!!! note
Alpine, Arch, and RHEL **(not Fedora!)** users can skip this step, since these distros now have 8.13.0 packaged.
@ -120,11 +120,6 @@ pnpm i -g node-gyp
pnpm install
pnpm build
```
You'll also need to copy over some fonts for the image commands:
```sh
sudo cp assets/*.ttf assets/*.otf /usr/local/share/fonts
fc-cache -fv
```
***
@ -225,13 +220,6 @@ pm2 start app.js
??? faq "Gifs from Tenor result in a "no decode delegate for this image format" or "improper image header" error"
Tenor GIFs are actually stored as MP4s, which libvips can't decode most of the time. You'll need to get a Tenor API key from [here](https://developers.google.com/tenor/guides/quickstart) and put it in the `TENOR` variable in .env.
??? faq "Emojis are missing in some commands"
Your system doesn't have an emoji font installed. You can install Google's emoji set with `sudo apt-get install fonts-noto-color-emoji` on Debian/Ubuntu systems, `doas apk add font-noto-emoji` on Alpine, and `sudo pacman -S noto-fonts-emoji` on Arch/Manjaro.
If you want to use the same set that Discord and the main bot uses (Twemoji) on Fedora, then you can run `sudo dnf remove google-noto-emoji-color-fonts && sudo dnf install twitter-twemoji-fonts`.
If you want to install Twemoji on another distro then it's slightly more difficult. Go [here](https://koji.fedoraproject.org/koji/packageinfo?packageID=26306) and choose the latest build, then download the `noarch` RPM file. You'll then have to extract this file; most graphical tools (e.g. 7-Zip, Ark, The Unarchiver) should be able to extract this just fine, but on the command line you'll have to use the `rpm2cpio` tool. The font file should be inside the archive at `usr/share/fonts/Twemoji/Twemoji.ttf`; copy this to `/usr/share/fonts/Twemoji.ttf` (note the / at the beginning). After this, run `fc-cache -fv` and you should be good to go!
??? faq "Sound/music commands do nothing"
Make sure Lavalink is running and started up completely. The bot skips loading sound commands if Lavalink is not present, so make sure it's running when the bot starts as well.

View File

@ -1,3 +1,4 @@
#include "common.h"
#include <napi.h>
#include <vips/vips8>
@ -15,6 +16,7 @@ Napi::Value Caption(const Napi::CallbackInfo &info) {
string caption = obj.Get("caption").As<Napi::String>().Utf8Value();
string font = obj.Get("font").As<Napi::String>().Utf8Value();
string type = obj.Get("type").As<Napi::String>().Utf8Value();
string basePath = obj.Get("basePath").As<Napi::String>().Utf8Value();
VOption *options = VImage::option()->set("access", "sequential");
@ -31,17 +33,27 @@ Napi::Value Caption(const Napi::CallbackInfo &info) {
int nPages = vips_image_get_n_pages(in.get_image());
int textWidth = width - ((width / 25) * 2);
string font_string = (font == "roboto" ? "Roboto Condensed" : font) + " " +
string font_string = "Twemoji Color Emoji, " +
(font == "roboto" ? "Roboto Condensed" : font) + " " +
(font != "impact" ? "bold" : "normal") + " " +
to_string(size);
string captionText = "<span background=\"white\">" + caption + "</span>";
VImage text =
VImage::text(captionText.c_str(), VImage::option()
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())

View File

@ -1,3 +1,4 @@
#include "common.h"
#include <napi.h>
#include <vips/vips8>
@ -16,6 +17,7 @@ Napi::Value CaptionTwo(const Napi::CallbackInfo &info) {
bool top = obj.Get("top").As<Napi::Boolean>().Value();
string font = obj.Get("font").As<Napi::String>().Utf8Value();
string type = obj.Get("type").As<Napi::String>().Utf8Value();
string basePath = obj.Get("basePath").As<Napi::String>().Utf8Value();
VOption *options = VImage::option()->set("access", "sequential");
@ -32,17 +34,27 @@ Napi::Value CaptionTwo(const Napi::CallbackInfo &info) {
int nPages = vips_image_get_n_pages(in.get_image());
int textWidth = width - ((width / 25) * 2);
string font_string =
(font == "roboto" ? "Roboto Condensed" : font) + " " + to_string(size);
string font_string = "Twemoji Color Emoji, " +
(font == "roboto" ? "Roboto Condensed" : font) + " " +
to_string(size);
string captionText = "<span background=\"white\">" + caption + "</span>";
VImage text =
VImage::text(captionText.c_str(), VImage::option()
->set("rgba", true)
->set("font", font_string.c_str())
->set("align", VIPS_ALIGN_LOW)
->set("width", textWidth));
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)

10
natives/common.h Normal file
View File

@ -0,0 +1,10 @@
#pragma once
#include <string>
#include <unordered_map>
const std::unordered_map<std::string, std::string> fontPaths {
{"futura", "assets/fonts/caption.otf"},
{"helvetica", "assets/fonts/caption2.ttf"},
{"roboto", "assets/fonts/reddit.ttf"}
};

View File

@ -17,14 +17,18 @@ Napi::Value Homebrew(const Napi::CallbackInfo &info) {
string assetPath = basePath + "assets/images/hbc.png";
VImage bg = VImage::new_from_file(assetPath.c_str());
VImage 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 96"));
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", "Twemoji Color Font, PF Square Sans Pro 96")
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str()));
VImage out = bg.composite2(text, VIPS_BLEND_MODE_OVER,
VImage::option()

View File

@ -1,3 +1,4 @@
#include "common.h"
#include <napi.h>
#include <vips/vips8>
@ -16,6 +17,7 @@ Napi::Value Meme(const Napi::CallbackInfo &info) {
string bottom = obj.Get("bottom").As<Napi::String>().Utf8Value();
string font = obj.Get("font").As<Napi::String>().Utf8Value();
string type = obj.Get("type").As<Napi::String>().Utf8Value();
string basePath = obj.Get("basePath").As<Napi::String>().Utf8Value();
VOption *options = VImage::option()->set("access", "sequential");
@ -23,7 +25,8 @@ Napi::Value Meme(const Napi::CallbackInfo &info) {
VImage::new_from_buffer(data.Data(), data.Length(), "",
type == "gif" ? options->set("n", -1) : options)
.colourspace(VIPS_INTERPRETATION_sRGB);
if (!in.has_alpha()) in = in.bandjoin(255);
if (!in.has_alpha())
in = in.bandjoin(255);
int width = in.width();
int pageHeight = vips_image_get_page_height(in.get_image());
@ -33,7 +36,8 @@ Napi::Value Meme(const Napi::CallbackInfo &info) {
int rad = 1;
vector<double> zeroVec = {0, 0, 0, 0};
string font_string = (font == "roboto" ? "Roboto Condensed" : font) + " " +
string font_string = "Twemoji Color Font, " +
(font == "roboto" ? "Roboto Condensed" : font) + " " +
(font != "impact" ? "bold" : "normal") + " " +
to_string(size);
@ -48,6 +52,13 @@ Napi::Value Meme(const Napi::CallbackInfo &info) {
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(
@ -56,6 +67,7 @@ Napi::Value Meme(const Napi::CallbackInfo &info) {
->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,
@ -70,10 +82,11 @@ Napi::Value Meme(const Napi::CallbackInfo &info) {
}
topOutline = (topOutline == zeroVec);
VImage topInvert = topOutline.extract_band(3).invert();
topOutline = topOutline
.extract_band(0, VImage::option()->set(
"n", topOutline.bands() - 1))
.bandjoin(topInvert);
topOutline =
topOutline
.extract_band(0,
VImage::option()->set("n", topOutline.bands() - 1))
.bandjoin(topInvert);
topText = topOutline.composite2(topIn, VIPS_BLEND_MODE_OVER);
}
@ -85,6 +98,7 @@ Napi::Value Meme(const Napi::CallbackInfo &info) {
->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,
@ -130,7 +144,8 @@ Napi::Value Meme(const Napi::CallbackInfo &info) {
size_t length;
final.write_to_buffer(
("." + type).c_str(), &buf, &length,
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1) : 0);
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1)
: 0);
result.Set("data", Napi::Buffer<char>::Copy(env, (char *)buf, length));
result.Set("type", type);

View File

@ -1,3 +1,4 @@
#include "common.h"
#include <napi.h>
#include <vips/vips8>
@ -16,6 +17,7 @@ Napi::Value Motivate(const Napi::CallbackInfo &info) {
string bottom_text = obj.Get("bottom").As<Napi::String>().Utf8Value();
string font = obj.Get("font").As<Napi::String>().Utf8Value();
string type = obj.Get("type").As<Napi::String>().Utf8Value();
string basePath = obj.Get("basePath").As<Napi::String>().Utf8Value();
VOption *options = VImage::option()->set("access", "sequential");
@ -32,7 +34,15 @@ Napi::Value Motivate(const Napi::CallbackInfo &info) {
int nPages = vips_image_get_n_pages(in.get_image());
int textWidth = width - ((width / 25) * 2);
string font_string = font == "roboto" ? "Roboto Condensed" : font;
string font_string =
"Twemoji Color Font, " + (font == "roboto" ? "Roboto Condensed" : 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 != "") {
@ -45,6 +55,7 @@ Napi::Value Motivate(const Napi::CallbackInfo &info) {
->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));
}
@ -59,6 +70,7 @@ Napi::Value Motivate(const Napi::CallbackInfo &info) {
->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));
}
@ -96,7 +108,8 @@ Napi::Value Motivate(const Napi::CallbackInfo &info) {
VImage::option()->set("background", 0x000000)->set("expand", true));
}
if (bottom_text != "") {
if (top_text == "") frame = bordered3;
if (top_text == "")
frame = bordered3;
frame = frame.join(
bottomImage.gravity(VIPS_COMPASS_DIRECTION_NORTH, bordered3.width(),
bottomImage.height() + (size / 4),

View File

@ -8,7 +8,7 @@ using namespace vips;
Napi::Value Reddit(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
Napi::Object result = Napi::Object::New(env);
try {
Napi::Object obj = info[0].As<Napi::Object>();
Napi::Buffer<char> data = obj.Get("data").As<Napi::Buffer<char>>();
@ -22,7 +22,8 @@ Napi::Value Reddit(const Napi::CallbackInfo &info) {
VImage::new_from_buffer(data.Data(), data.Length(), "",
type == "gif" ? options->set("n", -1) : options)
.colourspace(VIPS_INTERPRETATION_sRGB);
if (!in.has_alpha()) in = in.bandjoin(255);
if (!in.has_alpha())
in = in.bandjoin(255);
string assetPath = basePath + "assets/images/reddit.png";
VImage tmpl = VImage::new_from_file(assetPath.c_str());
@ -33,11 +34,16 @@ Napi::Value Reddit(const Napi::CallbackInfo &info) {
string captionText = "<span foreground=\"white\">" + text + "</span>";
VImage textImage =
VImage::text(captionText.c_str(), VImage::option()
->set("rgba", true)
->set("font", "Roboto 62")
->set("align", VIPS_ALIGN_LOW));
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", "Twemoji Color Font, Roboto 62")
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str())
->set("align", VIPS_ALIGN_LOW));
VImage composited =
tmpl.composite2(textImage, VIPS_BLEND_MODE_OVER,
@ -61,7 +67,8 @@ Napi::Value Reddit(const Napi::CallbackInfo &info) {
size_t length;
final.write_to_buffer(
("." + type).c_str(), &buf, &length,
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1) : 0);
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1)
: 0);
result.Set("data", Napi::Buffer<char>::Copy(env, (char *)buf, length));
result.Set("type", type);

View File

@ -16,6 +16,7 @@ Napi::Value Snapchat(const Napi::CallbackInfo &info) {
float pos =
obj.Has("pos") ? obj.Get("pos").As<Napi::Number>().FloatValue() : 0.5;
string type = obj.Get("type").As<Napi::String>().Utf8Value();
string basePath = obj.Get("basePath").As<Napi::String>().Utf8Value();
VOption *options = VImage::option()->set("access", "sequential");
@ -23,7 +24,8 @@ Napi::Value Snapchat(const Napi::CallbackInfo &info) {
VImage::new_from_buffer(data.Data(), data.Length(), "",
type == "gif" ? options->set("n", -1) : options)
.colourspace(VIPS_INTERPRETATION_sRGB);
if (!in.has_alpha()) in = in.bandjoin(255);
if (!in.has_alpha())
in = in.bandjoin(255);
int width = in.width();
int pageHeight = vips_image_get_page_height(in.get_image());
@ -31,17 +33,22 @@ Napi::Value Snapchat(const Napi::CallbackInfo &info) {
int size = width / 20;
int textWidth = width - ((width / 25) * 2);
string font_string = "Helvetica Neue " + to_string(size);
string font_string =
"Twemoji Color Font, Helvetica Neue " + to_string(size);
VImage 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("width", textWidth));
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())
@ -68,7 +75,8 @@ Napi::Value Snapchat(const Napi::CallbackInfo &info) {
size_t length;
final.write_to_buffer(
("." + type).c_str(), &buf, &length,
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1) : 0);
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1)
: 0);
result.Set("data", Napi::Buffer<char>::Copy(env, (char *)buf, length));
result.Set("type", type);

View File

@ -18,13 +18,16 @@ Napi::Value Sonic(const Napi::CallbackInfo &info) {
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", "Bitstream Vera Sans")
->set("width", 542)
->set("height", 390))
VImage::text(
("<span foreground=\"white\">" + text + "</span>").c_str(),
VImage::option()
->set("rgba", true)
->set("align", VIPS_ALIGN_CENTRE)
->set("font", "Twemoji Color Font, Bitstream Vera Sans")
->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,

View File

@ -1,3 +1,4 @@
#include "common.h"
#include <napi.h>
#include <vips/vips8>
@ -17,6 +18,7 @@ Napi::Value Uncanny(const Napi::CallbackInfo &info) {
string font = obj.Get("font").As<Napi::String>().Utf8Value();
string type = obj.Get("type").As<Napi::String>().Utf8Value();
string path = obj.Get("path").As<Napi::String>().Utf8Value();
string basePath = obj.Get("basePath").As<Napi::String>().Utf8Value();
VOption *options = VImage::option()->set("access", "sequential");
@ -28,7 +30,8 @@ Napi::Value Uncanny(const Napi::CallbackInfo &info) {
VImage base = VImage::black(1280, 720, VImage::option()->set("bands", 3));
string font_string = (font == "roboto" ? "Roboto Condensed" : font) + " " +
string font_string = "Twemoji Color Font, " +
(font == "roboto" ? "Roboto Condensed" : font) + " " +
(font != "impact" ? "bold" : "normal") + " 72";
string captionText = "<span background=\"black\" foreground=\"white\">" +
@ -36,25 +39,36 @@ Napi::Value Uncanny(const Napi::CallbackInfo &info) {
string caption2Text =
"<span background=\"black\" foreground=\"red\">" + caption2 + "</span>";
VImage text =
VImage::text(captionText.c_str(), VImage::option()
->set("rgba", true)
->set("align", VIPS_ALIGN_CENTRE)
->set("font", font_string.c_str())
->set("width", 588)
->set("height", 90));
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("width", 588)
->set("height", 90));
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,
@ -66,7 +80,7 @@ Napi::Value Uncanny(const Napi::CallbackInfo &info) {
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(path.c_str());
VImage uncanny = VImage::new_from_file((basePath + path).c_str());
base = base.insert(uncanny, 0, 130);

View File

@ -14,6 +14,7 @@ Napi::Value Whisper(const Napi::CallbackInfo &info) {
Napi::Buffer<char> data = obj.Get("data").As<Napi::Buffer<char>>();
string caption = obj.Get("caption").As<Napi::String>().Utf8Value();
string type = obj.Get("type").As<Napi::String>().Utf8Value();
string basePath = obj.Get("basePath").As<Napi::String>().Utf8Value();
VOption *options = VImage::option()->set("access", "sequential");
@ -21,7 +22,8 @@ Napi::Value Whisper(const Napi::CallbackInfo &info) {
VImage::new_from_buffer(data.Data(), data.Length(), "",
type == "gif" ? options->set("n", -1) : options)
.colourspace(VIPS_INTERPRETATION_sRGB);
if (!in.has_alpha()) in = in.bandjoin(255);
if (!in.has_alpha())
in = in.bandjoin(255);
int width = in.width();
int pageHeight = vips_image_get_page_height(in.get_image());
@ -30,7 +32,7 @@ Napi::Value Whisper(const Napi::CallbackInfo &info) {
int dividedWidth = width / 175;
int rad = 1;
string font_string = "Upright " + to_string(size);
string font_string = "Twemoji Color Font, Upright " + to_string(size);
VImage mask;
if (dividedWidth >= 1) {
@ -44,11 +46,15 @@ Napi::Value Whisper(const Napi::CallbackInfo &info) {
}
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,
@ -82,7 +88,8 @@ Napi::Value Whisper(const Napi::CallbackInfo &info) {
size_t length;
final.write_to_buffer(
("." + type).c_str(), &buf, &length,
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1) : 0);
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1)
: 0);
result.Set("data", Napi::Buffer<char>::Copy(env, (char *)buf, length));
result.Set("type", type);

View File

@ -140,7 +140,7 @@ class ImageConnection {
type = contentType;
break;
}
return { arrayBuffer: await req.body.arrayBuffer(), type };
return { buffer: Buffer.from(await req.body.arrayBuffer()), type };
}
async getCount() {