Fix #640: generate an icon with a white background automatically

This commit is contained in:
pietervdvn 2022-02-06 01:57:33 +01:00
parent 508ef8a970
commit 278fce8726
4 changed files with 103 additions and 83 deletions

View file

@ -277,8 +277,6 @@
],
"id": "bike_repair_station-opening_hours"
},
{
"question": {
"en": "Who maintains this cycle pump?",
@ -331,7 +329,6 @@
"render": "<a href='tel:{phone}'>{phone}</a>",
"id": "bike_repair_station-phone"
},
{
"id": "bike_repair_station-bike-chain-tool",
"question": {

View file

@ -9,52 +9,52 @@
"orientation": "portrait-primary, landscape-primary",
"icons": [
{
"src": "assets/generated/svg_mapcomplete_logo72.png",
"src": "./assets/generated/svg_mapcomplete_logo72.png",
"sizes": "72x72",
"type": "image/png"
},
{
"src": "assets/generated/svg_mapcomplete_logo96.png",
"src": "./assets/generated/svg_mapcomplete_logo96.png",
"sizes": "96x96",
"type": "image/png"
},
{
"src": "assets/generated/svg_mapcomplete_logo120.png",
"src": "./assets/generated/svg_mapcomplete_logo120.png",
"sizes": "120x120",
"type": "image/png"
},
{
"src": "assets/generated/svg_mapcomplete_logo128.png",
"src": "./assets/generated/svg_mapcomplete_logo128.png",
"sizes": "128x128",
"type": "image/png"
},
{
"src": "assets/generated/svg_mapcomplete_logo144.png",
"src": "./assets/generated/svg_mapcomplete_logo144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "assets/generated/svg_mapcomplete_logo152.png",
"src": "./assets/generated/svg_mapcomplete_logo152.png",
"sizes": "152x152",
"type": "image/png"
},
{
"src": "assets/generated/svg_mapcomplete_logo180.png",
"src": "./assets/generated/svg_mapcomplete_logo180.png",
"sizes": "180x180",
"type": "image/png"
},
{
"src": "assets/generated/svg_mapcomplete_logo192.png",
"src": "./assets/generated/svg_mapcomplete_logo192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "assets/generated/svg_mapcomplete_logo384.png",
"src": "./assets/generated/svg_mapcomplete_logo384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src": "assets/generated/svg_mapcomplete_logo512.png",
"src": "./assets/generated/svg_mapcomplete_logo512.png",
"sizes": "512x512",
"type": "image/png"
},

View file

@ -7,7 +7,6 @@ import * as all_known_layouts from "../assets/generated/known_layers_and_themes.
import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson";
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
import xml2js from 'xml2js';
import {exec} from "child_process";
const sharp = require('sharp');
const template = readFileSync("theme.html", "utf8");
@ -18,9 +17,7 @@ function enc(str: string): string {
return encodeURIComponent(str.toLowerCase());
}
const alreadyWritten = []
async function createIcon(iconPath: string, size: number) {
async function createIcon(iconPath: string, size: number, alreadyWritten: string[]) {
let name = iconPath.split(".").slice(0, -1).join(".");
if (name.startsWith("./")) {
name = name.substr(2)
@ -53,7 +50,7 @@ async function createIcon(iconPath: string, size: number) {
return newname;
}
async function createManifest(layout: LayoutConfig) {
async function createManifest(layout: LayoutConfig, alreadyWritten: string[]) {
const name = layout.id;
Translation.forcedLanguage = "en"
@ -64,6 +61,7 @@ async function createManifest(layout: LayoutConfig) {
if (icon.endsWith(".svg") || icon.startsWith("<svg") || icon.startsWith("<?xml")) {
// This is an svg. Lets create the needed pngs and do some checkes!
const whiteBackgroundPath = "./assets/generated/theme_"+layout.id+"_white_background.svg"
{
const svgResult = await xml2js.parseStringPromise(readFileSync(icon, "UTF8"))
const svg = svgResult.svg
@ -82,7 +80,11 @@ async function createManifest(layout: LayoutConfig) {
}))//*/
}
const builder = new xml2js.Builder();
const withRect = {rect: {"$":{width, height, style: "fill:#ffffff;"}}, ...svg}
const xml = builder.buildObject({svg: withRect});
writeFileSync(whiteBackgroundPath, xml)
}
let path = layout.icon;
@ -94,9 +96,10 @@ async function createManifest(layout: LayoutConfig) {
const sizes = [72, 96, 120, 128, 144, 152, 180, 192, 384, 512];
for (const size of sizes) {
const name = await createIcon(path, size);
const name = await createIcon(path, size, alreadyWritten);
createIcon(whiteBackgroundPath, size, alreadyWritten)
icons.push({
src: name,
src: "./"+name,
sizes: size + "x" + size,
type: "image/png"
})
@ -133,7 +136,6 @@ async function createManifest(layout: LayoutConfig) {
};
}
async function createLandingPage(layout: LayoutConfig, manifest) {
Locale.language.setData(layout.language[0]);
@ -176,7 +178,7 @@ async function createLandingPage(layout: LayoutConfig, manifest) {
if (icon.type !== "image/png") {
continue;
}
apple_icons.push(`<link rel="apple-touch-icon" sizes="${icon.sizes}" href="${icon.src}">`)
apple_icons.push(`<link rel="apple-touch-icon" sizes="${icon.sizes}" href="./assets/generated/generated_theme_${layout.id}_white_background${icon.sizes.substr(icon.sizes.indexOf("x")+ 1)}.png">`)
}
let themeSpecific = [
@ -211,65 +213,78 @@ async function createIndexFor(theme: LayoutConfig) {
appendFileSync(filename, codeTemplate)
}
const generatedDir = "./assets/generated";
if (!existsSync(generatedDir)) {
mkdirSync(generatedDir)
function createDir(path){
if (!existsSync(path)) {
mkdirSync(path)
}
}
const blacklist = ["", "test", ".", "..", "manifest", "index", "land", "preferences", "account", "openstreetmap", "custom", "theme"]
// @ts-ignore
const all: LayoutConfigJson[] = all_known_layouts.themes;
const args = process.argv
const theme = args[2]
if(theme !== undefined){
console.warn("Only generating layout "+theme)
}
for (const i in all) {
const layoutConfigJson: LayoutConfigJson = all[i]
if(theme !== undefined && layoutConfigJson.id !== theme){
continue
async function main(): Promise<void>{
const alreadyWritten = []
createDir("./assets/generated")
createDir("./assets/generated/layers")
createDir("./assets/generated/themes")
createDir("./assets/generated/white_background")
const blacklist = ["", "test", ".", "..", "manifest", "index", "land", "preferences", "account", "openstreetmap", "custom", "theme"]
// @ts-ignore
const all: LayoutConfigJson[] = all_known_layouts.themes;
const args = process.argv
const theme = args[2]
if(theme !== undefined){
console.warn("Only generating layout "+theme)
}
const layout = new LayoutConfig(layoutConfigJson, true, "generating layouts")
const layoutName = layout.id
if (blacklist.indexOf(layoutName.toLowerCase()) >= 0) {
console.log(`Skipping a layout with name${layoutName}, it is on the blacklist`);
continue;
}
const err = err => {
if (err !== null) {
console.log("Could not write manifest for ", layoutName, " because ", err)
for (const i in all) {
const layoutConfigJson: LayoutConfigJson = all[i]
if(theme !== undefined && layoutConfigJson.id !== theme){
continue
}
};
createManifest(layout).then(manifObj => {
const layout = new LayoutConfig(layoutConfigJson, true, "generating layouts")
const layoutName = layout.id
if (blacklist.indexOf(layoutName.toLowerCase()) >= 0) {
console.log(`Skipping a layout with name${layoutName}, it is on the blacklist`);
continue;
}
const err = err => {
if (err !== null) {
console.log("Could not write manifest for ", layoutName, " because ", err)
}
};
await createManifest(layout, alreadyWritten).then(manifObj => {
const manif = JSON.stringify(manifObj, undefined, 2);
const manifestLocation = encodeURIComponent(layout.id.toLowerCase()) + ".webmanifest";
writeFile(manifestLocation, manif, err);
// Create a landing page for the given theme
createLandingPage(layout, manifObj).then(landing => {
writeFile(enc(layout.id) + ".html", landing, err)
});
createIndexFor(layout)
}).catch(e => console.log("Could not generate the manifest: ", e))
}
await createManifest(new LayoutConfig({
icon: "assets/svg/mapcomplete_logo.svg",
id: "index",
layers: [],
maintainer: "Pieter Vander Vennet",
socialImage: "assets/SocialImage.png",
startLat: 0,
startLon: 0,
startZoom: 0,
title: {en: "MapComplete"},
version: Constants.vNumber,
description: {en: "A thematic map viewer and editor based on OpenStreetMap"}
}), alreadyWritten).then(manifObj => {
const manif = JSON.stringify(manifObj, undefined, 2);
const manifestLocation = encodeURIComponent(layout.id.toLowerCase()) + ".webmanifest";
writeFile(manifestLocation, manif, err);
// Create a landing page for the given theme
createLandingPage(layout, manifObj).then(landing => {
writeFile(enc(layout.id) + ".html", landing, err)
});
createIndexFor(layout)
}).catch(e => console.log("Could not generate the manifest: ", e))
writeFileSync("index.manifest", manif)
})
}
createManifest(new LayoutConfig({
icon: "assets/svg/mapcomplete_logo.svg",
id: "index",
layers: [],
maintainer: "Pieter Vander Vennet",
socialImage: "assets/SocialImage.png",
startLat: 0,
startLon: 0,
startZoom: 0,
title: {en: "MapComplete"},
version: Constants.vNumber,
description: {en: "A thematic map viewer and editor based on OpenStreetMap"}
})).then(manifObj => {
const manif = JSON.stringify(manifObj, undefined, 2);
writeFileSync("index.manifest", manif)
})
console.log("All done!");
main().then(() => {
console.log("All done!")
})

20
test.ts
View file

@ -1,7 +1,15 @@
import {AllKnownLayouts} from "./Customizations/AllKnownLayouts";
import List from "./UI/Base/List";
import Link from "./UI/Base/Link";
import {FixedUiElement} from "./UI/Base/FixedUiElement";
import xml2js from 'xml2js';
import {readFileSync} from "fs";
const allHidden = AllKnownLayouts.layoutsList.filter(l => l.hideFromOverview)
new List(allHidden.map(th => new Link(new FixedUiElement(th.id), "theme.html?layout=" + th.id))).AttachTo("maindiv")
const xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" +
"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"375px\" height=\"375px\" viewBox=\"0 0 375 375\" version=\"1.1\">\n" +
" <g id=\"surface1\">\n" +
" <path style=\" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;\" d=\"M 54.046875 233.558594 C 75.683594 233.558594 93.1875 215.566406 93.1875 193.296875 C 93.1875 171.148438 75.683594 153.148438 54.046875 153.148438 C 32.496094 153.148438 15 171.148438 15 193.296875 C 15 215.558594 32.496094 233.558594 54.046875 233.558594 Z M 273.269531 302.675781 C 275.09375 301.386719 277.5 301.777344 278.828125 303.554688 L 286.066406 313.84375 C 287.296875 315.628906 286.921875 318.195312 285.195312 319.589844 L 232.09375 359.242188 C 230.378906 360.53125 227.878906 360.128906 226.523438 358.359375 L 219.308594 348.066406 C 218.070312 346.28125 218.460938 343.726562 220.175781 342.335938 Z M 213.246094 251.550781 L 192.1875 213.578125 L 181.132812 221.878906 L 202.191406 260.054688 Z M 164.113281 162.847656 L 82.214844 15 L 66.546875 15.105469 L 152.960938 171.253906 Z M 241.222656 241.074219 C 245.851562 237.613281 256.441406 232.5 262.5 232.5 L 337.5 232.5 C 352.304688 232.5 360 247.394531 360 262.53125 C 360 277.753906 352.304688 285 337.5 285 L 270 285 L 188.730469 348.765625 C 160.171875 369.90625 142.859375 346.679688 142.859375 346.679688 L 79.238281 281.210938 C 68.566406 268.066406 70.875 243.046875 83.671875 231.96875 L 171.710938 167.488281 C 180.457031 159.988281 193.441406 161.167969 200.851562 170.0625 C 208.171875 179.0625 207.015625 192.515625 198.253906 200.03125 L 141.890625 242.460938 L 182.386719 283.589844 Z M 241.222656 241.074219 \"/>\n" +
" </g>\n" +
"</svg>"
xml2js.parseStringPromise(xml).then(svgResult => {
const svg = svgResult.svg
const builder = new xml2js.Builder();
console.log(builder.buildObject(svg))
})