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

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