UNPKG

@sync-in/server

Version:

The secure, open-source platform for file storage, sharing, collaboration, and sync

134 lines (133 loc) 4.54 kB
/* * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com> * This file is part of Sync-in | The open source file sync and share solution * See the LICENSE file for licensing details */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: Object.getOwnPropertyDescriptor(all, name).get }); } _export(exports, { get convertImageToBase64 () { return convertImageToBase64; }, get generateAvatar () { return generateAvatar; }, get generateThumbnail () { return generateThumbnail; }, get pngMimeType () { return pngMimeType; }, get svgMimeType () { return svgMimeType; }, get webpMimeType () { return webpMimeType; } }); const _promises = /*#__PURE__*/ _interop_require_default(require("node:fs/promises")); const _nodeos = /*#__PURE__*/ _interop_require_default(require("node:os")); const _nodepath = /*#__PURE__*/ _interop_require_default(require("node:path")); const _nodeutil = require("node:util"); const _sharp = /*#__PURE__*/ _interop_require_default(require("sharp")); const _texttosvg = /*#__PURE__*/ _interop_require_default(require("text-to-svg" // Sharp settings )); function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // Sharp settings _sharp.default.cache(false); _sharp.default.concurrency(Math.min(2, _nodeos.default.cpus()?.length || 1)); const pngMimeType = 'image/png'; const svgMimeType = 'image/svg+xml'; const webpMimeType = 'image/webp'; const avatarSize = 256; const fontPath = _nodepath.default.join(__dirname, 'fonts', 'avatar.ttf'); const loadTextToSVG = (0, _nodeutil.promisify)(_texttosvg.default.load.bind(_texttosvg.default)); let textToSvgCache = null; async function generateThumbnail(filePath, size) { return (0, _sharp.default)(filePath, { failOn: 'none', sequentialRead: true, limitInputPixels: 268e6 // protects against extremely large images }).rotate().resize({ width: size, height: size, fit: 'inside', kernel: 'nearest', withoutEnlargement: true, fastShrinkOnLoad: true // true by default, added for clarity }).webp({ quality: 80, effort: 0, alphaQuality: 90 }); } async function generateAvatar(initials) { const tts = await getTextToSvg(); const { backgroundColor, foregroundColor } = randomColor(); const fontSize = fitFontSize(tts, initials, avatarSize * 0.8, 170); const d = tts.getD(initials, { x: avatarSize / 2, y: avatarSize / 2.1, fontSize, anchor: 'center middle' }); const svg = ` <svg width="${avatarSize}" height="${avatarSize}" viewBox="0 0 ${avatarSize} ${avatarSize}" xmlns="http://www.w3.org/2000/svg"> <rect width="100%" height="100%" fill="${backgroundColor}"/> <path d="${d}" fill="${foregroundColor}" /> </svg>`.trim(); return (0, _sharp.default)(Buffer.from(svg, 'utf8')).png(); } async function convertImageToBase64(imgPath) { const base64String = await _promises.default.readFile(imgPath, { encoding: 'base64' }); return `data:image/png;base64,${base64String}`; } function randomColor() { let color = ''; while(color.length < 6){ /* sometimes the returned value does not have * the 6 digits needed, so we do it again until * it does */ color = Math.floor(Math.random() * 16777215).toString(16); } const red = parseInt(color.substring(0, 2), 16); const green = parseInt(color.substring(2, 4), 16); const blue = parseInt(color.substring(4, 6), 16); const brightness = red * 0.299 + green * 0.587 + blue * 0.114; return { backgroundColor: `#${color}`, foregroundColor: brightness > 180 ? '#000000' : '#ffffff' }; } function fitFontSize(tts, text, box, start = 170) { // Heuristic to make the text occupy ~80% of the available width let size = start; // Lower bound to prevent infinite loops when the font renders very small while(size > 20){ const m = tts.getMetrics(text, { fontSize: size, anchor: 'center middle' }); if (m.width <= box) break; size -= 4; } return size; } function getTextToSvg() { return textToSvgCache ??= loadTextToSVG(fontPath); } //# sourceMappingURL=image.js.map