Browse Source

Rework 'make generate-images' (#12316)

* Rework 'make generate-images'

- Remove external dependencies and replace it with a node script that
  does does the same.
- Move detail removal from gitea-sm.png to favicon.png
- Remove favicon.ico and its generation, it is unused and we already serve
  favicon.png in its place.

Fixes: https://github.com/go-gitea/gitea/issues/12314

* use proper centering value for preserveAspectRatio

* fix lint

* use fabric

* better linting fix

* fix typo

* mention detail-remove class in docs
pull/11585/merge
silverwind GitHub 1 week ago
parent
commit
7cf23399a0
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 90 additions and 32 deletions
  1. +4
    -0
      .eslintrc
  2. +2
    -28
      Makefile
  3. +2
    -1
      assets/logo.svg
  4. +80
    -0
      build/generate-images.js
  5. +2
    -3
      docs/content/doc/advanced/hacking-on-gitea.en-us.md
  6. BIN
      public/img/apple-touch-icon.png
  7. BIN
      public/img/avatar_default.png
  8. BIN
      public/img/favicon.ico
  9. BIN
      public/img/favicon.png
  10. BIN
      public/img/gitea-192.png
  11. BIN
      public/img/gitea-512.png
  12. BIN
      public/img/gitea-lg.png
  13. BIN
      public/img/gitea-sm.png

+ 4
- 0
.eslintrc View File

@@ -33,6 +33,10 @@ overrides:
worker: true
rules:
no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, status, statusbar, stop, toolbar, top]
- files: ["build/generate-images.js"]
rules:
import/no-unresolved: [0]
import/no-extraneous-dependencies: [0]

rules:
accessor-pairs: [2]


+ 2
- 28
Makefile View File

@@ -648,34 +648,8 @@ update-translations:

.PHONY: generate-images
generate-images:
$(eval TMPDIR := $(shell mktemp -d 2>/dev/null || mktemp -d -t 'gitea-temp'))
mkdir -p $(TMPDIR)/images
inkscape -f $(PWD)/assets/logo.svg -w 880 -h 880 -e $(PWD)/public/img/gitea-lg.png
inkscape -f $(PWD)/assets/logo.svg -w 512 -h 512 -e $(PWD)/public/img/gitea-512.png
inkscape -f $(PWD)/assets/logo.svg -w 192 -h 192 -e $(PWD)/public/img/gitea-192.png
inkscape -f $(PWD)/assets/logo.svg -w 120 -h 120 -jC -i layer1 -e $(TMPDIR)/images/sm-1.png
inkscape -f $(PWD)/assets/logo.svg -w 120 -h 120 -jC -i layer2 -e $(TMPDIR)/images/sm-2.png
composite -compose atop $(TMPDIR)/images/sm-2.png $(TMPDIR)/images/sm-1.png $(PWD)/public/img/gitea-sm.png
inkscape -f $(PWD)/assets/logo.svg -w 200 -h 200 -e $(PWD)/public/img/avatar_default.png
inkscape -f $(PWD)/assets/logo.svg -w 180 -h 180 -e $(PWD)/public/img/favicon.png
inkscape -f $(PWD)/assets/logo.svg -w 128 -h 128 -e $(TMPDIR)/images/128-raw.png
inkscape -f $(PWD)/assets/logo.svg -w 64 -h 64 -e $(TMPDIR)/images/64-raw.png
inkscape -f $(PWD)/assets/logo.svg -w 32 -h 32 -jC -i layer1 -e $(TMPDIR)/images/32-1.png
inkscape -f $(PWD)/assets/logo.svg -w 32 -h 32 -jC -i layer2 -e $(TMPDIR)/images/32-2.png
composite -compose atop $(TMPDIR)/images/32-2.png $(TMPDIR)/images/32-1.png $(TMPDIR)/images/32-raw.png
inkscape -f $(PWD)/assets/logo.svg -w 16 -h 16 -jC -i layer1 -e $(TMPDIR)/images/16-raw.png
zopflipng -m -y $(TMPDIR)/images/128-raw.png $(TMPDIR)/images/128.png
zopflipng -m -y $(TMPDIR)/images/64-raw.png $(TMPDIR)/images/64.png
zopflipng -m -y $(TMPDIR)/images/32-raw.png $(TMPDIR)/images/32.png
zopflipng -m -y $(TMPDIR)/images/16-raw.png $(TMPDIR)/images/16.png
rm -f $(TMPDIR)/images/*-*.png
convert $(TMPDIR)/images/16.png $(TMPDIR)/images/32.png \
$(TMPDIR)/images/64.png $(TMPDIR)/images/128.png \
$(PWD)/public/img/favicon.ico
convert -flatten $(PWD)/public/img/favicon.png $(PWD)/public/img/apple-touch-icon.png

rm -rf $(TMPDIR)/images
$(foreach file, $(shell find public/img -type f -name '*.png' ! -name 'loading.png'),zopflipng -m -y $(file) $(file);)
npm install --no-save --no-package-lock xmldom fabric imagemin-zopfli
node build/generate-images.js

.PHONY: pr\#%
pr\#%: clean-all


+ 2
- 1
assets/logo.svg View File

@@ -115,6 +115,7 @@
<g
inkscape:groupmode="layer"
id="layer3"
class="detail-remove"
inkscape:label="Layer 3"
style="display:inline">
<g
@@ -157,4 +158,4 @@
style="fill:none;stroke:#609926;stroke-width:2.68000007;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
</svg>
</svg>

+ 80
- 0
build/generate-images.js View File

@@ -0,0 +1,80 @@
#!/usr/bin/env node
'use strict';

const imageminZopfli = require('imagemin-zopfli');
const {fabric} = require('fabric');
const {DOMParser, XMLSerializer} = require('xmldom');
const {readFile, writeFile} = require('fs').promises;
const {resolve} = require('path');

function exit(err) {
if (err) console.error(err);
process.exit(err ? 1 : 0);
}

function loadSvg(svg) {
return new Promise((resolve) => {
fabric.loadSVGFromString(svg, (objects, options) => {
resolve({objects, options});
});
});
}

async function generate(svg, outputFile, {size, bg, removeDetail} = {}) {
const parser = new DOMParser();
const serializer = new XMLSerializer();
const document = parser.parseFromString(svg);

if (removeDetail) {
for (const el of Array.from(document.getElementsByTagName('g') || [])) {
for (const attribute of Array.from(el.attributes || [])) {
if (attribute.name === 'class' && attribute.value === 'detail-remove') {
el.parentNode.removeChild(el);
}
}
}
}

svg = serializer.serializeToString(document);

const {objects, options} = await loadSvg(svg);
const canvas = new fabric.Canvas();
canvas.setDimensions({width: size, height: size});
const ctx = canvas.getContext('2d');
ctx.scale(options.width ? (size / options.width) : 1, options.height ? (size / options.height) : 1);

if (bg) {
canvas.add(new fabric.Rect({
left: 0,
top: 0,
height: size * (1 / (size / options.height)),
width: size * (1 / (size / options.width)),
fill: 'white',
}));
}

canvas.add(fabric.util.groupSVGElements(objects, options));
canvas.renderAll();

let png = Buffer.from([]);
for await (const chunk of canvas.createPNGStream()) {
png = Buffer.concat([png, chunk]);
}

png = await imageminZopfli({more: true})(png);
await writeFile(outputFile, png);
}

async function main() {
const svg = await readFile(resolve(__dirname, '../assets/logo.svg'), 'utf8');
await generate(svg, resolve(__dirname, '../public/img/gitea-lg.png'), {size: 880});
await generate(svg, resolve(__dirname, '../public/img/gitea-512.png'), {size: 512});
await generate(svg, resolve(__dirname, '../public/img/gitea-192.png'), {size: 192});
await generate(svg, resolve(__dirname, '../public/img/gitea-sm.png'), {size: 120});
await generate(svg, resolve(__dirname, '../public/img/avatar_default.png'), {size: 200});
await generate(svg, resolve(__dirname, '../public/img/favicon.png'), {size: 180, removeDetail: true});
await generate(svg, resolve(__dirname, '../public/img/apple-touch-icon.png'), {size: 180, bg: true});
}

main().then(exit).catch(exit);


+ 2
- 3
docs/content/doc/advanced/hacking-on-gitea.en-us.md View File

@@ -155,10 +155,9 @@ Note: When working on frontend code, set `USE_SERVICE_WORKER` to `false` in `app

SVG icons are built using the `make svg` target which compiles the icon sources defined in `build/generate-svg.js` into the output directory `public/img/svg`. Custom icons can be added in the `web_src/svg` directory.

### Building Images
### Building the Logo

To build the images, ImageMagick, `inkscape` and `zopflipng` binaries must be available in
your `PATH` to run `make generate-images`.
The PNG versions of the logo are built from a single SVG source file `assets/logo.svg` using the `make generate-images` target. To run it, Node.js and npm must be available. The same process can also be used to generate a custom logo PNGs from a SVG source file. It's possible to remove parts of the SVG logo for the favicon build by adding a `detail-remove` class to the SVG nodes to be removed.

### Updating the API



BIN
public/img/apple-touch-icon.png View File

Before After
Width: 180  |  Height: 180  |  Size: 5.3KB Width: 180  |  Height: 180  |  Size: 5.5KB

BIN
public/img/avatar_default.png View File

Before After
Width: 200  |  Height: 200  |  Size: 6.1KB Width: 200  |  Height: 200  |  Size: 6.1KB

BIN
public/img/favicon.ico View File

Before After

BIN
public/img/favicon.png View File

Before After
Width: 180  |  Height: 180  |  Size: 5.4KB Width: 180  |  Height: 180  |  Size: 4.8KB

BIN
public/img/gitea-192.png View File

Before After
Width: 192  |  Height: 192  |  Size: 5.7KB Width: 192  |  Height: 192  |  Size: 5.7KB

BIN
public/img/gitea-512.png View File

Before After
Width: 512  |  Height: 512  |  Size: 17KB Width: 512  |  Height: 512  |  Size: 17KB

BIN
public/img/gitea-lg.png View File

Before After
Width: 880  |  Height: 880  |  Size: 33KB Width: 880  |  Height: 880  |  Size: 33KB

BIN
public/img/gitea-sm.png View File

Before After
Width: 120  |  Height: 120  |  Size: 3.3KB Width: 120  |  Height: 120  |  Size: 3.6KB

Loading…
Cancel
Save