mirror of
https://github.com/Blockzilla101/citation.git
synced 2025-04-18 18:34:41 -04:00
fix #4
This commit is contained in:
parent
0b3fef0fe4
commit
93abcdc48e
5 changed files with 326 additions and 1152 deletions
4
index.js
4
index.js
|
@ -1,5 +1,5 @@
|
||||||
const { Citation } = require('./src/citation')
|
const { Citation } = require('./src/citation')
|
||||||
const { registerFont } = require('canvas')
|
const { GlobalFonts } = require('@napi-rs/canvas')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
|
|
||||||
|
@ -11,6 +11,6 @@ if (!fs.existsSync(dataDir)) throw new Error(`${dataDir} is no where to be found
|
||||||
if (!fs.existsSync(fontFile)) throw new Error(`Font ${fontFile} is no where to be found`)
|
if (!fs.existsSync(fontFile)) throw new Error(`Font ${fontFile} is no where to be found`)
|
||||||
if (!fs.existsSync(logo)) throw new Error(`Logo ${logo} is no where to be found`)
|
if (!fs.existsSync(logo)) throw new Error(`Logo ${logo} is no where to be found`)
|
||||||
|
|
||||||
registerFont(fontFile, { family: 'BMmini' });
|
GlobalFonts.registerFromPath(path.join(__dirname, 'data', 'BMmini.ttf'), 'BMmini')
|
||||||
|
|
||||||
module.exports = { Citation }
|
module.exports = { Citation }
|
||||||
|
|
1346
package-lock.json
generated
1346
package-lock.json
generated
File diff suppressed because it is too large
Load diff
25
package.json
25
package.json
|
@ -1,14 +1,15 @@
|
||||||
{
|
{
|
||||||
"name": "@blockzilla101/citation",
|
"name": "@blockzilla101/citation",
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"canvas": "^2.6.1",
|
"@napi-rs/canvas": "^0.1.34",
|
||||||
"gif-encoder-2": "^1.0.5"
|
"args-parser": "^1.3.0",
|
||||||
},
|
"gif-encoder-2": "^1.0.5"
|
||||||
"author": "Blockzilla101",
|
},
|
||||||
"main": "index.js",
|
"author": "Blockzilla101",
|
||||||
"repository": {
|
"main": "index.js",
|
||||||
"type": "git",
|
"repository": {
|
||||||
"url": "https://github.com/Blockzilla101/citation"
|
"type": "git",
|
||||||
}
|
"url": "https://github.com/Blockzilla101/citation"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const { createCanvas, Canvas, loadImage, Image } = require('canvas');
|
// const { createCanvas, Canvas, loadImage, Image } = require('canvas');
|
||||||
|
const { createCanvas, loadImage, Image, Canvas } = require('@napi-rs/canvas')
|
||||||
const { text, textWrapped, line, dottedLine, barcode, rect, textFitsHeight, wrap, tint } = require('./util');
|
const { text, textWrapped, line, dottedLine, barcode, rect, textFitsHeight, wrap, tint } = require('./util');
|
||||||
const Encoder = require('gif-encoder-2');
|
const Encoder = require('gif-encoder-2');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
@ -146,9 +147,6 @@ module.exports.Citation = class {
|
||||||
this.#canvas = createCanvas(this.#width, this.#height);
|
this.#canvas = createCanvas(this.#width, this.#height);
|
||||||
this.#ctx = this.#canvas.getContext('2d');
|
this.#ctx = this.#canvas.getContext('2d');
|
||||||
|
|
||||||
this.#ctx.imageSmoothingEnabled = false;
|
|
||||||
this.#ctx.antialias = 'none';
|
|
||||||
|
|
||||||
if (!this.#logo) this.#logo = await loadImage(`${__dirname + '/../data'}/logo.png`);
|
if (!this.#logo) this.#logo = await loadImage(`${__dirname + '/../data'}/logo.png`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +159,8 @@ module.exports.Citation = class {
|
||||||
*/
|
*/
|
||||||
async render(out, gif = false, frameRate = 10, yPos = null) {
|
async render(out, gif = false, frameRate = 10, yPos = null) {
|
||||||
await this.#draw()
|
await this.#draw()
|
||||||
let data = gif ? await this.#animated(frameRate, yPos) : this.#canvas.toBuffer()
|
const b = this.#canvas.toBuffer('image/png');
|
||||||
|
let data = gif ? await this.#animated(frameRate, yPos) : b
|
||||||
if (out) {
|
if (out) {
|
||||||
fs.writeFileSync(out, data)
|
fs.writeFileSync(out, data)
|
||||||
}
|
}
|
||||||
|
@ -174,19 +173,19 @@ module.exports.Citation = class {
|
||||||
if (this.resizeReason) {
|
if (this.resizeReason) {
|
||||||
let wrapped = wrap(this.reason, this.font, this.moaFt, this.#ctx, this.#reasonMaxWidth)
|
let wrapped = wrap(this.reason, this.font, this.moaFt, this.#ctx, this.#reasonMaxWidth)
|
||||||
const ogHeight = this.#height
|
const ogHeight = this.#height
|
||||||
|
let newHeight = this.#height;
|
||||||
if (!textFitsHeight(wrapped, this.font, this.#ctx, this.#reasonMaxHeight)) {
|
if (!textFitsHeight(wrapped, this.font, this.#ctx, this.#reasonMaxHeight)) {
|
||||||
this.#ctx.font = this.font
|
this.#ctx.font = this.font
|
||||||
let metrics = this.#ctx.measureText(wrapped);
|
let metrics = this.#ctx.measureText(wrapped);
|
||||||
this.#canvas.height += (metrics.emHeightDescent - (metrics.emHeightAscent / 2)) - this.#reasonMaxHeight;
|
newHeight += (metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent + 2) * wrapped.split('\n').length - this.#reasonMaxHeight;
|
||||||
this.#height = this.#canvas.height
|
|
||||||
if (this.resizeLimit > ogHeight) {
|
if (this.resizeLimit > ogHeight) {
|
||||||
if (this.#height > this.resizeLimit) {
|
if (newHeight > this.resizeLimit) {
|
||||||
this.#canvas.height = this.resizeLimit
|
newHeight = this.resizeLimit
|
||||||
this.#height = this.resizeLimit
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.height = this.#canvas.height
|
this.#height = newHeight
|
||||||
|
await this.#createCanvas()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bg
|
// Bg
|
||||||
|
|
82
src/util.js
82
src/util.js
|
@ -1,6 +1,6 @@
|
||||||
const { NodeCanvasRenderingContext2D, createCanvas } = require('canvas');
|
const { createCanvas, SKRSContext2D } = require('@napi-rs/canvas');
|
||||||
|
|
||||||
/** @typedef {NodeCanvasRenderingContext2D} RenderingContext*/
|
/** @typedef {SKRSContext2D} RenderingContext*/
|
||||||
/** @typedef {string|CanvasGradient|CanvasPattern} Style*/
|
/** @typedef {string|CanvasGradient|CanvasPattern} Style*/
|
||||||
/** @typedef {"center"|"end"|"left"|"right"|"start"} TextAlignment*/
|
/** @typedef {"center"|"end"|"left"|"right"|"start"} TextAlignment*/
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ function line(startX, startY,endX, endY, style , ctx, width = 1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} text
|
* @param {string} fillText
|
||||||
* @param {number} x
|
* @param {number} x
|
||||||
* @param {number} y
|
* @param {number} y
|
||||||
* @param {string} font
|
* @param {string} font
|
||||||
|
@ -53,24 +53,27 @@ function line(startX, startY,endX, endY, style , ctx, width = 1) {
|
||||||
* @param {TextAlignment} [alignment="left"]
|
* @param {TextAlignment} [alignment="left"]
|
||||||
* @param {number} [maxWidth=0]
|
* @param {number} [maxWidth=0]
|
||||||
*/
|
*/
|
||||||
function text(text, x, y, font, style, ctx, alignment = 'left', maxWidth) {
|
function text(fillText, x, y, font, style, ctx, alignment = 'left', maxWidth) {
|
||||||
|
if (fillText.includes('\n')) {
|
||||||
|
const metrics = ctx.measureText(fillText)
|
||||||
|
const height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent + 2
|
||||||
|
|
||||||
|
let currY = y;
|
||||||
|
const lines = fillText.split('\n')
|
||||||
|
for (const line of lines) {
|
||||||
|
text(line, x, currY, font, style, ctx, alignment, maxWidth)
|
||||||
|
currY += height
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ctx.fillStyle = style
|
ctx.fillStyle = style
|
||||||
|
ctx.strokeStyle = style
|
||||||
ctx.font = font;
|
ctx.font = font;
|
||||||
ctx.textAlign = alignment
|
ctx.textAlign = alignment
|
||||||
if (typeof maxWidth !== 'undefined') {
|
|
||||||
const metrics = ctx.measureText(text);
|
|
||||||
const size = metrics.emHeightAscent + metrics.emHeightDescent;
|
|
||||||
|
|
||||||
if (maxWidth < 0) maxWidth = 0;
|
ctx.fillText(fillText, x, y, maxWidth);
|
||||||
let width = ctx.measureText(text).width;
|
|
||||||
while(width > maxWidth) {
|
|
||||||
if (width - maxWidth > maxWidth) text = text.substr(0, text.length - (width / size));
|
|
||||||
text = text.substr(0, text.length - 1);
|
|
||||||
|
|
||||||
width = ctx.measureText(text).width
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.fillText(text, x, y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -86,40 +89,31 @@ function text(text, x, y, font, style, ctx, alignment = 'left', maxWidth) {
|
||||||
*/
|
*/
|
||||||
function textWrapped(str, x, y, font, style, ctx, maxWidth, maxHeight, alignment = "left") {
|
function textWrapped(str, x, y, font, style, ctx, maxWidth, maxHeight, alignment = "left") {
|
||||||
let newStr = wrap(str, font, style, ctx, maxWidth)
|
let newStr = wrap(str, font, style, ctx, maxWidth)
|
||||||
|
|
||||||
if (typeof maxHeight !== 'undefined' && maxHeight > 0 && newStr.includes('\n')) {
|
|
||||||
let metrics = ctx.measureText(newStr);
|
|
||||||
let height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
|
|
||||||
while (height > maxHeight) {
|
|
||||||
newStr = newStr.substr(0, newStr.lastIndexOf('\n'));
|
|
||||||
metrics = ctx.measureText(newStr);
|
|
||||||
height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
text(newStr, x, y, font, style, ctx, alignment, maxWidth);
|
text(newStr, x, y, font, style, ctx, alignment, maxWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
function wrap(str, font, style, ctx, maxWidth) {
|
function wrap(str, font, style, ctx, maxWidth) {
|
||||||
let words = str.split(" ");
|
|
||||||
let lines = [];
|
|
||||||
let currentLine = words[0];
|
|
||||||
|
|
||||||
ctx.font = font;
|
ctx.font = font;
|
||||||
ctx.style = style;
|
ctx.fillStyle = style
|
||||||
|
|
||||||
for (let i = 1; i < words.length; i++) {
|
const lines = str.split('\n')
|
||||||
let word = words[i];
|
const newStr = []
|
||||||
let width = ctx.measureText(currentLine + " " + word).width;
|
for (const line of lines) {
|
||||||
if (width < maxWidth) {
|
const words = line.split(' ');
|
||||||
currentLine += " " + word;
|
let currStr = []
|
||||||
} else {
|
for (const word of words) {
|
||||||
lines.push(currentLine);
|
currStr.push(word)
|
||||||
currentLine = word;
|
if (ctx.measureText(currStr.join(' ')).width > maxWidth) {
|
||||||
|
const lastWord = currStr.pop()
|
||||||
|
newStr.push(currStr.join(' '))
|
||||||
|
currStr = []
|
||||||
|
currStr.push(lastWord)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
newStr.push(currStr.join(' ').trim())
|
||||||
}
|
}
|
||||||
lines.push(currentLine);
|
|
||||||
return lines.join('\n');
|
return newStr.join('\n').trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -173,7 +167,7 @@ function textFitsWidth(text, font, ctx, maxWidth) {
|
||||||
function textFitsHeight(text, font, ctx, maxHeight) {
|
function textFitsHeight(text, font, ctx, maxHeight) {
|
||||||
ctx.font = font;
|
ctx.font = font;
|
||||||
let metrics = ctx.measureText(text);
|
let metrics = ctx.measureText(text);
|
||||||
return metrics.emHeightDescent - (metrics.emHeightAscent / 2) <= maxHeight;
|
return (metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent + 2) * text.split('\n').length <= maxHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
function tint(image, color, opacity = 0.5) {
|
function tint(image, color, opacity = 0.5) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue