Load fonts directly from assets directory, fix image buffer issues
This commit is contained in:
parent
273e5b94d7
commit
4f66519aa7
22 changed files with 188 additions and 111 deletions
24
Dockerfile
24
Dockerfile
|
@ -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 \
|
RUN --mount=type=cache,id=pnpm-store,target=/root/.pnpm-store \
|
||||||
npm install -g pnpm@6.27.1
|
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
|
# liblqr needs to be built manually for magick to work
|
||||||
# and because alpine doesn't have it in their repos
|
# and because alpine doesn't have it in their repos
|
||||||
RUN git clone https://github.com/carlobaldassi/liblqr \
|
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 update-ms-fonts && fc-cache -f
|
||||||
|
|
||||||
RUN adduser esmBot -s /bin/sh -D
|
RUN adduser esmBot -s /bin/sh -D
|
||||||
|
USER esmBot
|
||||||
|
|
||||||
WORKDIR /home/esmBot/.internal
|
WORKDIR /home/esmBot/.internal
|
||||||
|
|
||||||
COPY ./assets/caption.otf /usr/share/fonts/caption.otf
|
COPY --chown=esmBot:esmBot ./package.json package.json
|
||||||
COPY ./assets/caption2.ttf /usr/share/fonts/caption2.ttf
|
COPY --chown=esmBot:esmBot ./pnpm-lock.yaml pnpm-lock.yaml
|
||||||
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
|
|
||||||
RUN pnpm install
|
RUN pnpm install
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN rm .env
|
RUN rm .env
|
||||||
|
@ -81,6 +67,4 @@ RUN mkdir /home/esmBot/.internal/logs \
|
||||||
&& chown esmBot:esmBot /home/esmBot/.internal/logs \
|
&& chown esmBot:esmBot /home/esmBot/.internal/logs \
|
||||||
&& chmod 777 /home/esmBot/.internal/logs
|
&& chmod 777 /home/esmBot/.internal/logs
|
||||||
|
|
||||||
USER esmBot
|
|
||||||
|
|
||||||
ENTRYPOINT ["node", "app.js"]
|
ENTRYPOINT ["node", "app.js"]
|
||||||
|
|
BIN
assets/fonts/twemoji.otf
Normal file
BIN
assets/fonts/twemoji.otf
Normal file
Binary file not shown.
|
@ -77,13 +77,13 @@ class ImageCommand extends Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { arrayBuffer, type } = await runImageJob(imageParams);
|
const { buffer, type } = await runImageJob(imageParams);
|
||||||
if (type === "nogif" && this.constructor.requiresGIF) {
|
if (type === "nogif" && this.constructor.requiresGIF) {
|
||||||
return "That isn't a GIF!";
|
return "That isn't a GIF!";
|
||||||
}
|
}
|
||||||
this.success = true;
|
this.success = true;
|
||||||
return {
|
return {
|
||||||
file: Buffer.from(arrayBuffer),
|
file: buffer,
|
||||||
name: `${this.constructor.command}.${type}`
|
name: `${this.constructor.command}.${type}`
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -17,7 +17,7 @@ class UncannyCommand extends ImageCommand {
|
||||||
return {
|
return {
|
||||||
caption: text1?.trim() ? textEncode(text1) : random(prompts),
|
caption: text1?.trim() ? textEncode(text1) : random(prompts),
|
||||||
caption2: textEncode(text2),
|
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"
|
font: typeof this.options.font === "string" && this.constructor.allowedFonts.includes(this.options.font.toLowerCase()) ? this.options.font.toLowerCase() : "helvetica"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ Choose the distro you're using below for insallation instructions.
|
||||||
|
|
||||||
### 2. Install libvips.
|
### 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
|
!!! note
|
||||||
Alpine, Arch, and RHEL **(not Fedora!)** users can skip this step, since these distros now have 8.13.0 packaged.
|
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 install
|
||||||
pnpm build
|
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"
|
??? 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.
|
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"
|
??? 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.
|
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.
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include "common.h"
|
||||||
#include <napi.h>
|
#include <napi.h>
|
||||||
|
|
||||||
#include <vips/vips8>
|
#include <vips/vips8>
|
||||||
|
@ -15,6 +16,7 @@ Napi::Value Caption(const Napi::CallbackInfo &info) {
|
||||||
string caption = obj.Get("caption").As<Napi::String>().Utf8Value();
|
string caption = obj.Get("caption").As<Napi::String>().Utf8Value();
|
||||||
string font = obj.Get("font").As<Napi::String>().Utf8Value();
|
string font = obj.Get("font").As<Napi::String>().Utf8Value();
|
||||||
string type = obj.Get("type").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");
|
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 nPages = vips_image_get_n_pages(in.get_image());
|
||||||
int textWidth = width - ((width / 25) * 2);
|
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") + " " +
|
(font != "impact" ? "bold" : "normal") + " " +
|
||||||
to_string(size);
|
to_string(size);
|
||||||
|
|
||||||
string captionText = "<span background=\"white\">" + caption + "</span>";
|
string captionText = "<span background=\"white\">" + caption + "</span>";
|
||||||
|
|
||||||
VImage text =
|
VImage text;
|
||||||
VImage::text(captionText.c_str(), VImage::option()
|
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("rgba", true)
|
||||||
->set("align", VIPS_ALIGN_CENTRE)
|
->set("align", VIPS_ALIGN_CENTRE)
|
||||||
->set("font", font_string.c_str())
|
->set("font", font_string.c_str())
|
||||||
|
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str())
|
||||||
->set("width", textWidth));
|
->set("width", textWidth));
|
||||||
VImage captionImage =
|
VImage captionImage =
|
||||||
((text == (vector<double>){0, 0, 0, 0}).bandand())
|
((text == (vector<double>){0, 0, 0, 0}).bandand())
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include "common.h"
|
||||||
#include <napi.h>
|
#include <napi.h>
|
||||||
|
|
||||||
#include <vips/vips8>
|
#include <vips/vips8>
|
||||||
|
@ -16,6 +17,7 @@ Napi::Value CaptionTwo(const Napi::CallbackInfo &info) {
|
||||||
bool top = obj.Get("top").As<Napi::Boolean>().Value();
|
bool top = obj.Get("top").As<Napi::Boolean>().Value();
|
||||||
string font = obj.Get("font").As<Napi::String>().Utf8Value();
|
string font = obj.Get("font").As<Napi::String>().Utf8Value();
|
||||||
string type = obj.Get("type").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");
|
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 nPages = vips_image_get_n_pages(in.get_image());
|
||||||
int textWidth = width - ((width / 25) * 2);
|
int textWidth = width - ((width / 25) * 2);
|
||||||
|
|
||||||
string font_string =
|
string font_string = "Twemoji Color Emoji, " +
|
||||||
(font == "roboto" ? "Roboto Condensed" : font) + " " + to_string(size);
|
(font == "roboto" ? "Roboto Condensed" : font) + " " +
|
||||||
|
to_string(size);
|
||||||
|
|
||||||
string captionText = "<span background=\"white\">" + caption + "</span>";
|
string captionText = "<span background=\"white\">" + caption + "</span>";
|
||||||
|
|
||||||
VImage text =
|
VImage text;
|
||||||
VImage::text(captionText.c_str(), VImage::option()
|
auto findResult = fontPaths.find(font);
|
||||||
->set("rgba", true)
|
if (findResult != fontPaths.end()) {
|
||||||
->set("font", font_string.c_str())
|
text = VImage::text(
|
||||||
->set("align", VIPS_ALIGN_LOW)
|
".", VImage::option()->set("fontfile",
|
||||||
->set("width", textWidth));
|
(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 =
|
VImage captionImage =
|
||||||
((text == (vector<double>){0, 0, 0, 0}).bandand())
|
((text == (vector<double>){0, 0, 0, 0}).bandand())
|
||||||
.ifthenelse(255, text)
|
.ifthenelse(255, text)
|
||||||
|
|
10
natives/common.h
Normal file
10
natives/common.h
Normal 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"}
|
||||||
|
};
|
|
@ -17,14 +17,18 @@ Napi::Value Homebrew(const Napi::CallbackInfo &info) {
|
||||||
string assetPath = basePath + "assets/images/hbc.png";
|
string assetPath = basePath + "assets/images/hbc.png";
|
||||||
VImage bg = VImage::new_from_file(assetPath.c_str());
|
VImage bg = VImage::new_from_file(assetPath.c_str());
|
||||||
|
|
||||||
VImage text =
|
VImage text = VImage::text(
|
||||||
VImage::text(("<span letter_spacing=\"-5120\" color=\"white\">" +
|
".", VImage::option()->set(
|
||||||
caption + "</span>")
|
"fontfile", (basePath + "assets/fonts/hbc.ttf").c_str()));
|
||||||
.c_str(),
|
text = VImage::text(
|
||||||
VImage::option()
|
("<span letter_spacing=\"-5120\" color=\"white\">" + caption +
|
||||||
->set("rgba", true)
|
"</span>")
|
||||||
->set("align", VIPS_ALIGN_CENTRE)
|
.c_str(),
|
||||||
->set("font", "PF Square Sans Pro 96"));
|
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 out = bg.composite2(text, VIPS_BLEND_MODE_OVER,
|
||||||
VImage::option()
|
VImage::option()
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include "common.h"
|
||||||
#include <napi.h>
|
#include <napi.h>
|
||||||
|
|
||||||
#include <vips/vips8>
|
#include <vips/vips8>
|
||||||
|
@ -16,6 +17,7 @@ Napi::Value Meme(const Napi::CallbackInfo &info) {
|
||||||
string bottom = obj.Get("bottom").As<Napi::String>().Utf8Value();
|
string bottom = obj.Get("bottom").As<Napi::String>().Utf8Value();
|
||||||
string font = obj.Get("font").As<Napi::String>().Utf8Value();
|
string font = obj.Get("font").As<Napi::String>().Utf8Value();
|
||||||
string type = obj.Get("type").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");
|
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(), "",
|
VImage::new_from_buffer(data.Data(), data.Length(), "",
|
||||||
type == "gif" ? options->set("n", -1) : options)
|
type == "gif" ? options->set("n", -1) : options)
|
||||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||||
if (!in.has_alpha()) in = in.bandjoin(255);
|
if (!in.has_alpha())
|
||||||
|
in = in.bandjoin(255);
|
||||||
|
|
||||||
int width = in.width();
|
int width = in.width();
|
||||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||||
|
@ -33,7 +36,8 @@ Napi::Value Meme(const Napi::CallbackInfo &info) {
|
||||||
int rad = 1;
|
int rad = 1;
|
||||||
vector<double> zeroVec = {0, 0, 0, 0};
|
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") + " " +
|
(font != "impact" ? "bold" : "normal") + " " +
|
||||||
to_string(size);
|
to_string(size);
|
||||||
|
|
||||||
|
@ -48,6 +52,13 @@ Napi::Value Meme(const Napi::CallbackInfo &info) {
|
||||||
VImage::option()->set("fill", true));
|
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;
|
VImage topText;
|
||||||
if (top != "") {
|
if (top != "") {
|
||||||
VImage topIn = VImage::text(
|
VImage topIn = VImage::text(
|
||||||
|
@ -56,6 +67,7 @@ Napi::Value Meme(const Napi::CallbackInfo &info) {
|
||||||
->set("rgba", true)
|
->set("rgba", true)
|
||||||
->set("align", VIPS_ALIGN_CENTRE)
|
->set("align", VIPS_ALIGN_CENTRE)
|
||||||
->set("font", font_string.c_str())
|
->set("font", font_string.c_str())
|
||||||
|
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str())
|
||||||
->set("width", width));
|
->set("width", width));
|
||||||
|
|
||||||
topIn = topIn.embed(rad + 10, rad + 10, (topIn.width() + 2 * rad) + 20,
|
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);
|
topOutline = (topOutline == zeroVec);
|
||||||
VImage topInvert = topOutline.extract_band(3).invert();
|
VImage topInvert = topOutline.extract_band(3).invert();
|
||||||
topOutline = topOutline
|
topOutline =
|
||||||
.extract_band(0, VImage::option()->set(
|
topOutline
|
||||||
"n", topOutline.bands() - 1))
|
.extract_band(0,
|
||||||
.bandjoin(topInvert);
|
VImage::option()->set("n", topOutline.bands() - 1))
|
||||||
|
.bandjoin(topInvert);
|
||||||
topText = topOutline.composite2(topIn, VIPS_BLEND_MODE_OVER);
|
topText = topOutline.composite2(topIn, VIPS_BLEND_MODE_OVER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +98,7 @@ Napi::Value Meme(const Napi::CallbackInfo &info) {
|
||||||
->set("rgba", true)
|
->set("rgba", true)
|
||||||
->set("align", VIPS_ALIGN_CENTRE)
|
->set("align", VIPS_ALIGN_CENTRE)
|
||||||
->set("font", font_string.c_str())
|
->set("font", font_string.c_str())
|
||||||
|
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str())
|
||||||
->set("width", width));
|
->set("width", width));
|
||||||
bottomIn =
|
bottomIn =
|
||||||
bottomIn.embed(rad + 10, rad + 10, (bottomIn.width() + 2 * rad) + 20,
|
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;
|
size_t length;
|
||||||
final.write_to_buffer(
|
final.write_to_buffer(
|
||||||
("." + type).c_str(), &buf, &length,
|
("." + type).c_str(), &buf, &length,
|
||||||
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1) : 0);
|
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||||
|
: 0);
|
||||||
|
|
||||||
result.Set("data", Napi::Buffer<char>::Copy(env, (char *)buf, length));
|
result.Set("data", Napi::Buffer<char>::Copy(env, (char *)buf, length));
|
||||||
result.Set("type", type);
|
result.Set("type", type);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include "common.h"
|
||||||
#include <napi.h>
|
#include <napi.h>
|
||||||
|
|
||||||
#include <vips/vips8>
|
#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 bottom_text = obj.Get("bottom").As<Napi::String>().Utf8Value();
|
||||||
string font = obj.Get("font").As<Napi::String>().Utf8Value();
|
string font = obj.Get("font").As<Napi::String>().Utf8Value();
|
||||||
string type = obj.Get("type").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");
|
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 nPages = vips_image_get_n_pages(in.get_image());
|
||||||
int textWidth = width - ((width / 25) * 2);
|
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;
|
VImage topImage;
|
||||||
if (top_text != "") {
|
if (top_text != "") {
|
||||||
|
@ -45,6 +55,7 @@ Napi::Value Motivate(const Napi::CallbackInfo &info) {
|
||||||
->set("rgba", true)
|
->set("rgba", true)
|
||||||
->set("align", VIPS_ALIGN_CENTRE)
|
->set("align", VIPS_ALIGN_CENTRE)
|
||||||
->set("font", (font_string + " " + to_string(size)).c_str())
|
->set("font", (font_string + " " + to_string(size)).c_str())
|
||||||
|
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str())
|
||||||
->set("width", textWidth));
|
->set("width", textWidth));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +70,7 @@ Napi::Value Motivate(const Napi::CallbackInfo &info) {
|
||||||
->set("rgba", true)
|
->set("rgba", true)
|
||||||
->set("align", VIPS_ALIGN_CENTRE)
|
->set("align", VIPS_ALIGN_CENTRE)
|
||||||
->set("font", (font_string + " " + to_string(size * 0.4)).c_str())
|
->set("font", (font_string + " " + to_string(size * 0.4)).c_str())
|
||||||
|
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str())
|
||||||
->set("width", textWidth));
|
->set("width", textWidth));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +108,8 @@ Napi::Value Motivate(const Napi::CallbackInfo &info) {
|
||||||
VImage::option()->set("background", 0x000000)->set("expand", true));
|
VImage::option()->set("background", 0x000000)->set("expand", true));
|
||||||
}
|
}
|
||||||
if (bottom_text != "") {
|
if (bottom_text != "") {
|
||||||
if (top_text == "") frame = bordered3;
|
if (top_text == "")
|
||||||
|
frame = bordered3;
|
||||||
frame = frame.join(
|
frame = frame.join(
|
||||||
bottomImage.gravity(VIPS_COMPASS_DIRECTION_NORTH, bordered3.width(),
|
bottomImage.gravity(VIPS_COMPASS_DIRECTION_NORTH, bordered3.width(),
|
||||||
bottomImage.height() + (size / 4),
|
bottomImage.height() + (size / 4),
|
||||||
|
|
|
@ -22,7 +22,8 @@ Napi::Value Reddit(const Napi::CallbackInfo &info) {
|
||||||
VImage::new_from_buffer(data.Data(), data.Length(), "",
|
VImage::new_from_buffer(data.Data(), data.Length(), "",
|
||||||
type == "gif" ? options->set("n", -1) : options)
|
type == "gif" ? options->set("n", -1) : options)
|
||||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||||
if (!in.has_alpha()) in = in.bandjoin(255);
|
if (!in.has_alpha())
|
||||||
|
in = in.bandjoin(255);
|
||||||
|
|
||||||
string assetPath = basePath + "assets/images/reddit.png";
|
string assetPath = basePath + "assets/images/reddit.png";
|
||||||
VImage tmpl = VImage::new_from_file(assetPath.c_str());
|
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>";
|
string captionText = "<span foreground=\"white\">" + text + "</span>";
|
||||||
|
|
||||||
VImage textImage =
|
VImage textImage = VImage::text(
|
||||||
VImage::text(captionText.c_str(), VImage::option()
|
".", VImage::option()->set(
|
||||||
->set("rgba", true)
|
"fontfile", (basePath + "assets/fonts/reddit.ttf").c_str()));
|
||||||
->set("font", "Roboto 62")
|
textImage = VImage::text(
|
||||||
->set("align", VIPS_ALIGN_LOW));
|
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 =
|
VImage composited =
|
||||||
tmpl.composite2(textImage, VIPS_BLEND_MODE_OVER,
|
tmpl.composite2(textImage, VIPS_BLEND_MODE_OVER,
|
||||||
|
@ -61,7 +67,8 @@ Napi::Value Reddit(const Napi::CallbackInfo &info) {
|
||||||
size_t length;
|
size_t length;
|
||||||
final.write_to_buffer(
|
final.write_to_buffer(
|
||||||
("." + type).c_str(), &buf, &length,
|
("." + type).c_str(), &buf, &length,
|
||||||
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1) : 0);
|
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||||
|
: 0);
|
||||||
|
|
||||||
result.Set("data", Napi::Buffer<char>::Copy(env, (char *)buf, length));
|
result.Set("data", Napi::Buffer<char>::Copy(env, (char *)buf, length));
|
||||||
result.Set("type", type);
|
result.Set("type", type);
|
||||||
|
|
|
@ -16,6 +16,7 @@ Napi::Value Snapchat(const Napi::CallbackInfo &info) {
|
||||||
float pos =
|
float pos =
|
||||||
obj.Has("pos") ? obj.Get("pos").As<Napi::Number>().FloatValue() : 0.5;
|
obj.Has("pos") ? obj.Get("pos").As<Napi::Number>().FloatValue() : 0.5;
|
||||||
string type = obj.Get("type").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");
|
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(), "",
|
VImage::new_from_buffer(data.Data(), data.Length(), "",
|
||||||
type == "gif" ? options->set("n", -1) : options)
|
type == "gif" ? options->set("n", -1) : options)
|
||||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||||
if (!in.has_alpha()) in = in.bandjoin(255);
|
if (!in.has_alpha())
|
||||||
|
in = in.bandjoin(255);
|
||||||
|
|
||||||
int width = in.width();
|
int width = in.width();
|
||||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||||
|
@ -31,17 +33,22 @@ Napi::Value Snapchat(const Napi::CallbackInfo &info) {
|
||||||
int size = width / 20;
|
int size = width / 20;
|
||||||
int textWidth = width - ((width / 25) * 2);
|
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 textIn = VImage::text(
|
||||||
VImage::text(("<span foreground=\"white\" background=\"#000000B2\">" +
|
".", VImage::option()->set(
|
||||||
caption + "</span>")
|
"fontfile", (basePath + "assets/fonts/caption2.ttf").c_str()));
|
||||||
.c_str(),
|
textIn = VImage::text(
|
||||||
VImage::option()
|
("<span foreground=\"white\" background=\"#000000B2\">" + caption +
|
||||||
->set("rgba", true)
|
"</span>")
|
||||||
->set("align", VIPS_ALIGN_CENTRE)
|
.c_str(),
|
||||||
->set("font", font_string.c_str())
|
VImage::option()
|
||||||
->set("width", textWidth));
|
->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);
|
int bgHeight = textIn.height() + (width / 25);
|
||||||
textIn =
|
textIn =
|
||||||
((textIn == (vector<double>){0, 0, 0, 0}).bandand())
|
((textIn == (vector<double>){0, 0, 0, 0}).bandand())
|
||||||
|
@ -68,7 +75,8 @@ Napi::Value Snapchat(const Napi::CallbackInfo &info) {
|
||||||
size_t length;
|
size_t length;
|
||||||
final.write_to_buffer(
|
final.write_to_buffer(
|
||||||
("." + type).c_str(), &buf, &length,
|
("." + type).c_str(), &buf, &length,
|
||||||
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1) : 0);
|
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||||
|
: 0);
|
||||||
|
|
||||||
result.Set("data", Napi::Buffer<char>::Copy(env, (char *)buf, length));
|
result.Set("data", Napi::Buffer<char>::Copy(env, (char *)buf, length));
|
||||||
result.Set("type", type);
|
result.Set("type", type);
|
||||||
|
|
|
@ -18,13 +18,16 @@ Napi::Value Sonic(const Napi::CallbackInfo &info) {
|
||||||
VImage bg = VImage::new_from_file(assetPath.c_str());
|
VImage bg = VImage::new_from_file(assetPath.c_str());
|
||||||
|
|
||||||
VImage textImage =
|
VImage textImage =
|
||||||
VImage::text(("<span foreground=\"white\">" + text + "</span>").c_str(),
|
VImage::text(
|
||||||
VImage::option()
|
("<span foreground=\"white\">" + text + "</span>").c_str(),
|
||||||
->set("rgba", true)
|
VImage::option()
|
||||||
->set("align", VIPS_ALIGN_CENTRE)
|
->set("rgba", true)
|
||||||
->set("font", "Bitstream Vera Sans")
|
->set("align", VIPS_ALIGN_CENTRE)
|
||||||
->set("width", 542)
|
->set("font", "Twemoji Color Font, Bitstream Vera Sans")
|
||||||
->set("height", 390))
|
->set("fontfile",
|
||||||
|
(basePath + "assets/fonts/twemoji.otf").c_str())
|
||||||
|
->set("width", 542)
|
||||||
|
->set("height", 390))
|
||||||
.gravity(VIPS_COMPASS_DIRECTION_CENTRE, 542, 390);
|
.gravity(VIPS_COMPASS_DIRECTION_CENTRE, 542, 390);
|
||||||
|
|
||||||
VImage out = bg.composite2(textImage, VIPS_BLEND_MODE_OVER,
|
VImage out = bg.composite2(textImage, VIPS_BLEND_MODE_OVER,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include "common.h"
|
||||||
#include <napi.h>
|
#include <napi.h>
|
||||||
|
|
||||||
#include <vips/vips8>
|
#include <vips/vips8>
|
||||||
|
@ -17,6 +18,7 @@ Napi::Value Uncanny(const Napi::CallbackInfo &info) {
|
||||||
string font = obj.Get("font").As<Napi::String>().Utf8Value();
|
string font = obj.Get("font").As<Napi::String>().Utf8Value();
|
||||||
string type = obj.Get("type").As<Napi::String>().Utf8Value();
|
string type = obj.Get("type").As<Napi::String>().Utf8Value();
|
||||||
string path = obj.Get("path").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");
|
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));
|
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";
|
(font != "impact" ? "bold" : "normal") + " 72";
|
||||||
|
|
||||||
string captionText = "<span background=\"black\" foreground=\"white\">" +
|
string captionText = "<span background=\"black\" foreground=\"white\">" +
|
||||||
|
@ -36,25 +39,36 @@ Napi::Value Uncanny(const Napi::CallbackInfo &info) {
|
||||||
string caption2Text =
|
string caption2Text =
|
||||||
"<span background=\"black\" foreground=\"red\">" + caption2 + "</span>";
|
"<span background=\"black\" foreground=\"red\">" + caption2 + "</span>";
|
||||||
|
|
||||||
VImage text =
|
auto findResult = fontPaths.find(font);
|
||||||
VImage::text(captionText.c_str(), VImage::option()
|
if (findResult != fontPaths.end()) {
|
||||||
->set("rgba", true)
|
VImage::text(
|
||||||
->set("align", VIPS_ALIGN_CENTRE)
|
".", VImage::option()->set("fontfile",
|
||||||
->set("font", font_string.c_str())
|
(basePath + findResult->second).c_str()));
|
||||||
->set("width", 588)
|
}
|
||||||
->set("height", 90));
|
|
||||||
|
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 =
|
VImage captionImage =
|
||||||
text.extract_band(0, VImage::option()->set("n", 3))
|
text.extract_band(0, VImage::option()->set("n", 3))
|
||||||
.gravity(VIPS_COMPASS_DIRECTION_CENTRE, 640, text.height() + 40,
|
.gravity(VIPS_COMPASS_DIRECTION_CENTRE, 640, text.height() + 40,
|
||||||
VImage::option()->set("extend", "black"));
|
VImage::option()->set("extend", "black"));
|
||||||
|
|
||||||
VImage text2 = VImage::text(caption2Text.c_str(),
|
VImage text2 = VImage::text(
|
||||||
VImage::option()
|
caption2Text.c_str(),
|
||||||
->set("rgba", true)
|
VImage::option()
|
||||||
->set("align", VIPS_ALIGN_CENTRE)
|
->set("rgba", true)
|
||||||
->set("font", font_string.c_str())
|
->set("align", VIPS_ALIGN_CENTRE)
|
||||||
->set("width", 588)
|
->set("font", font_string.c_str())
|
||||||
->set("height", 90));
|
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str())
|
||||||
|
->set("width", 588)
|
||||||
|
->set("height", 90));
|
||||||
VImage caption2Image =
|
VImage caption2Image =
|
||||||
text2.extract_band(0, VImage::option()->set("n", 3))
|
text2.extract_band(0, VImage::option()->set("n", 3))
|
||||||
.gravity(VIPS_COMPASS_DIRECTION_CENTRE, 640, text.height() + 40,
|
.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 pageHeight = vips_image_get_page_height(in.get_image());
|
||||||
int nPages = vips_image_get_n_pages(in.get_image());
|
int nPages = vips_image_get_n_pages(in.get_image());
|
||||||
|
|
||||||
VImage uncanny = VImage::new_from_file(path.c_str());
|
VImage uncanny = VImage::new_from_file((basePath + path).c_str());
|
||||||
|
|
||||||
base = base.insert(uncanny, 0, 130);
|
base = base.insert(uncanny, 0, 130);
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ Napi::Value Whisper(const Napi::CallbackInfo &info) {
|
||||||
Napi::Buffer<char> data = obj.Get("data").As<Napi::Buffer<char>>();
|
Napi::Buffer<char> data = obj.Get("data").As<Napi::Buffer<char>>();
|
||||||
string caption = obj.Get("caption").As<Napi::String>().Utf8Value();
|
string caption = obj.Get("caption").As<Napi::String>().Utf8Value();
|
||||||
string type = obj.Get("type").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");
|
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(), "",
|
VImage::new_from_buffer(data.Data(), data.Length(), "",
|
||||||
type == "gif" ? options->set("n", -1) : options)
|
type == "gif" ? options->set("n", -1) : options)
|
||||||
.colourspace(VIPS_INTERPRETATION_sRGB);
|
.colourspace(VIPS_INTERPRETATION_sRGB);
|
||||||
if (!in.has_alpha()) in = in.bandjoin(255);
|
if (!in.has_alpha())
|
||||||
|
in = in.bandjoin(255);
|
||||||
|
|
||||||
int width = in.width();
|
int width = in.width();
|
||||||
int pageHeight = vips_image_get_page_height(in.get_image());
|
int pageHeight = vips_image_get_page_height(in.get_image());
|
||||||
|
@ -30,7 +32,7 @@ Napi::Value Whisper(const Napi::CallbackInfo &info) {
|
||||||
int dividedWidth = width / 175;
|
int dividedWidth = width / 175;
|
||||||
int rad = 1;
|
int rad = 1;
|
||||||
|
|
||||||
string font_string = "Upright " + to_string(size);
|
string font_string = "Twemoji Color Font, Upright " + to_string(size);
|
||||||
|
|
||||||
VImage mask;
|
VImage mask;
|
||||||
if (dividedWidth >= 1) {
|
if (dividedWidth >= 1) {
|
||||||
|
@ -44,11 +46,15 @@ Napi::Value Whisper(const Napi::CallbackInfo &info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
VImage textIn = VImage::text(
|
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(),
|
("<span foreground=\"white\">" + caption + "</span>").c_str(),
|
||||||
VImage::option()
|
VImage::option()
|
||||||
->set("rgba", true)
|
->set("rgba", true)
|
||||||
->set("align", VIPS_ALIGN_CENTRE)
|
->set("align", VIPS_ALIGN_CENTRE)
|
||||||
->set("font", font_string.c_str())
|
->set("font", font_string.c_str())
|
||||||
|
->set("fontfile", (basePath + "assets/fonts/twemoji.otf").c_str())
|
||||||
->set("width", width));
|
->set("width", width));
|
||||||
|
|
||||||
textIn = textIn.embed(rad + 10, rad + 10, (textIn.width() + 2 * rad) + 20,
|
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;
|
size_t length;
|
||||||
final.write_to_buffer(
|
final.write_to_buffer(
|
||||||
("." + type).c_str(), &buf, &length,
|
("." + type).c_str(), &buf, &length,
|
||||||
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1) : 0);
|
type == "gif" ? VImage::option()->set("dither", 0)->set("reoptimise", 1)
|
||||||
|
: 0);
|
||||||
|
|
||||||
result.Set("data", Napi::Buffer<char>::Copy(env, (char *)buf, length));
|
result.Set("data", Napi::Buffer<char>::Copy(env, (char *)buf, length));
|
||||||
result.Set("type", type);
|
result.Set("type", type);
|
||||||
|
|
|
@ -140,7 +140,7 @@ class ImageConnection {
|
||||||
type = contentType;
|
type = contentType;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return { arrayBuffer: await req.body.arrayBuffer(), type };
|
return { buffer: Buffer.from(await req.body.arrayBuffer()), type };
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCount() {
|
async getCount() {
|
||||||
|
|
Loading…
Reference in a new issue