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.5KB

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