You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

generate-images.js 2.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import imageminZopfli from 'imagemin-zopfli';
  2. import {optimize} from 'svgo';
  3. import {fabric} from 'fabric';
  4. import fs from 'fs';
  5. import {resolve, dirname} from 'path';
  6. import {fileURLToPath} from 'url';
  7. const {readFile, writeFile} = fs.promises;
  8. const __dirname = dirname(fileURLToPath(import.meta.url));
  9. const logoFile = resolve(__dirname, '../assets/logo.svg');
  10. const faviconFile = resolve(__dirname, '../assets/favicon.svg');
  11. function exit(err) {
  12. if (err) console.error(err);
  13. process.exit(err ? 1 : 0);
  14. }
  15. function loadSvg(svg) {
  16. return new Promise((resolve) => {
  17. fabric.loadSVGFromString(svg, (objects, options) => {
  18. resolve({objects, options});
  19. });
  20. });
  21. }
  22. async function generate(svg, outputFile, {size, bg}) {
  23. if (outputFile.endsWith('.svg')) {
  24. const {data} = optimize(svg, {
  25. plugins: [
  26. 'preset-default',
  27. 'removeDimensions',
  28. {
  29. name: 'addAttributesToSVGElement',
  30. params: {attributes: [{width: size}, {height: size}]}
  31. },
  32. ],
  33. });
  34. await writeFile(outputFile, data);
  35. return;
  36. }
  37. const {objects, options} = await loadSvg(svg);
  38. const canvas = new fabric.Canvas();
  39. canvas.setDimensions({width: size, height: size});
  40. const ctx = canvas.getContext('2d');
  41. ctx.scale(options.width ? (size / options.width) : 1, options.height ? (size / options.height) : 1);
  42. if (bg) {
  43. canvas.add(new fabric.Rect({
  44. left: 0,
  45. top: 0,
  46. height: size * (1 / (size / options.height)),
  47. width: size * (1 / (size / options.width)),
  48. fill: 'white',
  49. }));
  50. }
  51. canvas.add(fabric.util.groupSVGElements(objects, options));
  52. canvas.renderAll();
  53. let png = Buffer.from([]);
  54. for await (const chunk of canvas.createPNGStream()) {
  55. png = Buffer.concat([png, chunk]);
  56. }
  57. png = await imageminZopfli({more: true})(png);
  58. await writeFile(outputFile, png);
  59. }
  60. async function main() {
  61. const gitea = process.argv.slice(2).includes('gitea');
  62. const logoSvg = await readFile(logoFile, 'utf8');
  63. const faviconSvg = await readFile(faviconFile, 'utf8');
  64. await Promise.all([
  65. generate(logoSvg, resolve(__dirname, '../public/img/logo.svg'), {size: 32}),
  66. generate(logoSvg, resolve(__dirname, '../public/img/logo.png'), {size: 512}),
  67. generate(faviconSvg, resolve(__dirname, '../public/img/favicon.svg'), {size: 32}),
  68. generate(faviconSvg, resolve(__dirname, '../public/img/favicon.png'), {size: 180}),
  69. generate(logoSvg, resolve(__dirname, '../public/img/avatar_default.png'), {size: 200}),
  70. generate(logoSvg, resolve(__dirname, '../public/img/apple-touch-icon.png'), {size: 180, bg: true}),
  71. gitea && generate(logoSvg, resolve(__dirname, '../public/img/gitea.svg'), {size: 32}),
  72. ]);
  73. }
  74. main().then(exit).catch(exit);