quote-api / methods /generate.js
rippanteq7's picture
Update methods/generate.js
2938874 verified
const {
QuoteGenerate
} = require('../utils')
const { createCanvas, loadImage } = require('canvas')
const sharp = require('sharp')
const normalizeColor = (color) => {
const canvas = createCanvas(0, 0)
const canvasCtx = canvas.getContext('2d')
canvasCtx.fillStyle = color
color = canvasCtx.fillStyle
return color
}
const colorLuminance = (hex, lum) => {
hex = String(hex).replace(/[^0-9a-f]/gi, '')
if (hex.length < 6) {
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]
}
lum = lum || 0
// convert to decimal and change luminosity
let rgb = '#'
let c
let i
for (i = 0; i < 3; i++) {
c = parseInt(hex.substr(i * 2, 2), 16)
c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16)
rgb += ('00' + c).substr(c.length)
}
return rgb
}
const imageAlpha = (image, alpha) => {
const canvas = createCanvas(image.width, image.height)
const canvasCtx = canvas.getContext('2d')
canvasCtx.globalAlpha = alpha
canvasCtx.drawImage(image, 0, 0)
return canvas
}
module.exports = async (parm) => {
// console.log(JSON.stringify(parm, null, 2))
if (!parm) return { error: 'query_empty' }
if (!parm.messages || parm.messages.length < 1) return { error: 'messages_empty' }
let botToken = parm.botToken || process.env.BOT_TOKEN
const quoteGenerate = new QuoteGenerate(botToken)
const quoteImages = []
let backgroundColor = parm.backgroundColor || '//#292232'
let backgroundColorOne
let backgroundColorTwo
const backgroundColorSplit = backgroundColor.split('/')
if (backgroundColorSplit && backgroundColorSplit.length > 1 && backgroundColorSplit[0] !== '') {
backgroundColorOne = normalizeColor(backgroundColorSplit[0])
backgroundColorTwo = normalizeColor(backgroundColorSplit[1])
} else if (backgroundColor.startsWith('//')) {
backgroundColor = normalizeColor(backgroundColor.replace('//', ''))
backgroundColorOne = colorLuminance(backgroundColor, 0.35)
backgroundColorTwo = colorLuminance(backgroundColor, -0.15)
} else {
backgroundColor = normalizeColor(backgroundColor)
backgroundColorOne = backgroundColor
backgroundColorTwo = backgroundColor
}
for (const key in parm.messages) {
const message = parm.messages[key]
if (message) {
const canvasQuote = await quoteGenerate.generate(
backgroundColorOne,
backgroundColorTwo,
message,
parm.width,
parm.height,
parseFloat(parm.scale),
parm.emojiBrand
)
quoteImages.push(canvasQuote)
}
}
if (quoteImages.length === 0) {
return {
error: 'empty_messages'
}
}
let canvasQuote
if (quoteImages.length > 1) {
let width = 0
let height = 0
for (let index = 0; index < quoteImages.length; index++) {
if (quoteImages[index].width > width) width = quoteImages[index].width
height += quoteImages[index].height
}
const quoteMargin = 5 * parm.scale
const canvas = createCanvas(width, height + (quoteMargin * quoteImages.length))
const canvasCtx = canvas.getContext('2d')
let imageY = 0
for (let index = 0; index < quoteImages.length; index++) {
canvasCtx.drawImage(quoteImages[index], 0, imageY)
imageY += quoteImages[index].height + quoteMargin
}
canvasQuote = canvas
} else {
canvasQuote = quoteImages[0]
}
let quoteImage
let { type, format, ext } = parm
if (!type && ext) type = 'png'
if (type !== 'image' && type !== 'stories' && canvasQuote.height > 1024 * 2) type = 'png'
if (type === 'quote') {
const downPadding = 75
const maxWidth = 512
const maxHeight = 512
const imageQuoteSharp = sharp(canvasQuote.toBuffer())
if (canvasQuote.height > canvasQuote.width) imageQuoteSharp.resize({ height: maxHeight })
else imageQuoteSharp.resize({ width: maxWidth })
const canvasImage = await loadImage(await imageQuoteSharp.toBuffer())
const canvasPadding = createCanvas(canvasImage.width, canvasImage.height + downPadding)
const canvasPaddingCtx = canvasPadding.getContext('2d')
canvasPaddingCtx.drawImage(canvasImage, 0, 0)
const imageSharp = sharp(canvasPadding.toBuffer())
if (canvasPadding.height >= canvasPadding.width) imageSharp.resize({ height: maxHeight })
else imageSharp.resize({ width: maxWidth })
if (format === 'png') quoteImage = await imageSharp.png().toBuffer()
else quoteImage = await imageSharp.webp({ lossless: true, force: true }).toBuffer()
} else if (type === 'image') {
const heightPadding = 75 * parm.scale
const widthPadding = 95 * parm.scale
const canvasImage = await loadImage(canvasQuote.toBuffer())
const canvasPic = createCanvas(canvasImage.width + widthPadding, canvasImage.height + heightPadding)
const canvasPicCtx = canvasPic.getContext('2d')
// radial gradient background (top left)
const gradient = canvasPicCtx.createRadialGradient(
canvasPic.width / 2,
canvasPic.height / 2,
0,
canvasPic.width / 2,
canvasPic.height / 2,
canvasPic.width / 2
)
const patternColorOne = colorLuminance(backgroundColorTwo, 0.15)
const patternColorTwo = colorLuminance(backgroundColorOne, 0.15)
gradient.addColorStop(0, patternColorOne)
gradient.addColorStop(1, patternColorTwo)
canvasPicCtx.fillStyle = gradient
canvasPicCtx.fillRect(0, 0, canvasPic.width, canvasPic.height)
const canvasPatternImage = await loadImage('./assets/pattern_02.png')
// const canvasPatternImage = await loadImage('./assets/pattern_ny.png');
const pattern = canvasPicCtx.createPattern(imageAlpha(canvasPatternImage, 0.3), 'repeat')
canvasPicCtx.fillStyle = pattern
canvasPicCtx.fillRect(0, 0, canvasPic.width, canvasPic.height)
// Add shadow effect to the canvas image
canvasPicCtx.shadowOffsetX = 8
canvasPicCtx.shadowOffsetY = 8
canvasPicCtx.shadowBlur = 13
canvasPicCtx.shadowColor = 'rgba(0, 0, 0, 0.5)'
// Draw the image to the canvas with padding centered
canvasPicCtx.drawImage(canvasImage, widthPadding / 2, heightPadding / 2)
canvasPicCtx.shadowOffsetX = 0
canvasPicCtx.shadowOffsetY = 0
canvasPicCtx.shadowBlur = 0
canvasPicCtx.shadowColor = 'rgba(0, 0, 0, 0)'
// write text button right
canvasPicCtx.fillStyle = `rgba(0, 0, 0, 0.3)`
canvasPicCtx.font = `${8 * parm.scale}px Noto Sans`
canvasPicCtx.textAlign = 'right'
canvasPicCtx.fillText('@QuotLyBot', canvasPic.width - 25, canvasPic.height - 25)
quoteImage = await sharp(canvasPic.toBuffer()).png({ lossless: true, force: true }).toBuffer()
} else if (type === 'stories') {
const canvasPic = createCanvas(720, 1280)
const canvasPicCtx = canvasPic.getContext('2d')
// radial gradient background (top left)
const gradient = canvasPicCtx.createRadialGradient(
canvasPic.width / 2,
canvasPic.height / 2,
0,
canvasPic.width / 2,
canvasPic.height / 2,
canvasPic.width / 2
)
const patternColorOne = colorLuminance(backgroundColorTwo, 0.25)
const patternColorTwo = colorLuminance(backgroundColorOne, 0.15)
gradient.addColorStop(0, patternColorOne)
gradient.addColorStop(1, patternColorTwo)
canvasPicCtx.fillStyle = gradient
canvasPicCtx.fillRect(0, 0, canvasPic.width, canvasPic.height)
const canvasPatternImage = await loadImage('./assets/pattern_02.png')
const pattern = canvasPicCtx.createPattern(imageAlpha(canvasPatternImage, 0.3), 'repeat')
canvasPicCtx.fillStyle = pattern
canvasPicCtx.fillRect(0, 0, canvasPic.width, canvasPic.height)
// Add shadow effect to the canvas image
canvasPicCtx.shadowOffsetX = 8
canvasPicCtx.shadowOffsetY = 8
canvasPicCtx.shadowBlur = 13
canvasPicCtx.shadowColor = 'rgba(0, 0, 0, 0.5)'
let canvasImage = await loadImage(canvasQuote.toBuffer())
// мінімальний відступ від країв картинки
const minPadding = 110
// resize canvasImage if it is larger than canvasPic + minPadding
if (canvasImage.width > canvasPic.width - minPadding * 2 || canvasImage.height > canvasPic.height - minPadding * 2) {
canvasImage = await sharp(canvasQuote.toBuffer()).resize({
width: canvasPic.width - minPadding * 2,
height: canvasPic.height - minPadding * 2,
fit: 'contain',
background: { r: 0, g: 0, b: 0, alpha: 0 }
}).toBuffer()
canvasImage = await loadImage(canvasImage)
}
// розмістити canvasImage в центрі по горизонталі і вертикалі
const imageX = (canvasPic.width - canvasImage.width) / 2
const imageY = (canvasPic.height - canvasImage.height) / 2
canvasPicCtx.drawImage(canvasImage, imageX, imageY)
canvasPicCtx.shadowOffsetX = 0
canvasPicCtx.shadowOffsetY = 0
canvasPicCtx.shadowBlur = 0
// write text vertical left center text
canvasPicCtx.fillStyle = `rgba(0, 0, 0, 0.4)`
canvasPicCtx.font = `${16 * parm.scale}px Noto Sans`
canvasPicCtx.textAlign = 'center'
canvasPicCtx.translate(70, canvasPic.height / 2)
canvasPicCtx.rotate(-Math.PI / 2)
if (parm.watermark) canvasPicCtx.fillText(parm.watermark || '@QuotLyBot', 0, 0)
quoteImage = await sharp(canvasPic.toBuffer()).png({ lossless: true, force: true }).toBuffer()
} else {
quoteImage = canvasQuote.toBuffer()
}
const imageMetadata = await sharp(quoteImage).metadata()
const width = imageMetadata.width
const height = imageMetadata.height
let image
if (ext) image = quoteImage
else image = quoteImage.toString('base64')
return {
image,
type,
width,
height,
ext
}
}