Skip to content

Commit

Permalink
Remove font-scanner in frontend (#247)
Browse files Browse the repository at this point in the history
* Remove font-scanner in frontend

* Fix eslint

* Fix eslint

* Remove text to svg
  • Loading branch information
dkdkwizard committed Jan 3, 2023
1 parent d44f4d6 commit d1e40bb
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 327 deletions.
174 changes: 2 additions & 172 deletions electron-main.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,20 @@ const { app, ipcMain, BrowserWindow, dialog } = require('electron');
app.commandLine.appendSwitch('ignore-gpu-blacklist');
app.allowRendererProcessReuse = false;

const FontScanner = require('font-scanner');
const TextToSVG = require('text-to-svg');
const path = require('path');
const url = require('url');
const fs = require('fs');
const os = require('os');
const exec = require('child_process').exec;
const Store = require('electron-store');
const Sentry = require('@sentry/electron');

const BackendManager = require('./src/node/backend-manager.js');
const fontHelper = require('./src/node/font-helper');
const MonitorManager = require('./src/node/monitor-manager.js');
const MenuManager = require('./src/node/menu-manager.js');
const UpdateManager = require('./src/node/update-manager.js');
const UglyNotify = require('./src/node/ugly-notify.js');
const events = require('./src/node/ipc-events');
const TTC2TTF = require('./src/node/ttc2ttf.js');
const { getDeeplinkUrl, handleDeepLinkUrl } = require('./src/node/deep-link-helper');

Sentry.init({ dsn: 'https://bbd96134db9147658677dcf024ae5a83@o28957.ingest.sentry.io/5617300' });
Expand Down Expand Up @@ -352,12 +349,6 @@ ipcMain.on(events.CHECK_BACKEND_STATUS, () => {
console.error('Recv async-status request but main window not exist');
}
});
var fontsListCache = [];
ipcMain.on(events.GET_AVAILABLE_FONTS, (event, arg) => {
const fonts = FontScanner.getAvailableFontsSync();
fontsListCache = fonts;
event.returnValue = fonts;
});

ipcMain.on(events.SVG_URL_TO_IMG_URL, (e, data) => {
const { svgUrl: url, imgWidth: width, imgHeight: height, bb, imageRatio, id, strokeWidth } = data;
Expand All @@ -371,51 +362,7 @@ ipcMain.on(events.SVG_URL_TO_IMG_URL_DONE, (e, data) => {
mainWindow.send(`${events.SVG_URL_TO_IMG_URL_DONE}_${id}`, imageUrl);
});

function findFontsSync(arg) {
const availableFonts = FontScanner.getAvailableFontsSync();
const matchFamily = availableFonts.filter(font => font.family === arg.family);
const match = matchFamily.filter(font => {
result = true
Object.getOwnPropertyNames(arg).forEach(a => {
if (arg[a] !== font[a]) {
result = false;
}
});
return result;
});
return match;
}

function findFontSync(arg) {
arg.style = arg.style || 'Regular';
const availableFonts = FontScanner.getAvailableFontsSync();
let font = availableFonts[0];
let match = availableFonts.filter(font => font.family === arg.family);
font = match[0] || font;
if (arg.italic != null) {
match = match.filter(font => font.italic === arg.italic);
font = match[0] || font;
}
match = match.filter(font => font.style === arg.style);
font = match[0] || font;
if (arg.weight != null) {
match = match.filter(font => font.weight === arg.weight);
}
font = match[0] || font;
return font;
};

ipcMain.on(events.FIND_FONTS, (event, arg) => {
// FontScanner.findFontsSync({ family: 'Arial' });
const fonts = findFontsSync(arg);
event.returnValue = fonts;
});

ipcMain.on(events.FIND_FONT, (event, arg) => {
// FontScanner.findFontSync({ family: 'Arial', weight: 700 })
const font = findFontSync(arg);
event.returnValue = font;
});
fontHelper.registerEvents();

ipcMain.on('save-dialog', function (event, title, allFiles, extensionName, extensions, filename, file) {
const isMac = process.platform === 'darwin';
Expand Down Expand Up @@ -461,123 +408,6 @@ ipcMain.on('save-dialog', function (event, title, allFiles, extensionName, exten
event.returnValue = filePath;
})

ipcMain.on(events.REQUEST_PATH_D_OF_TEXT, async (event, { text, x, y, fontFamily, fontSize, fontStyle, letterSpacing, key }) => {
const substitutedFamily = (function () {

// Escape for Whitelists
const whiteList = ['標楷體'];
const whiteKeyWords = ['華康', 'Adobe', '文鼎'];
if (whiteList.indexOf(fontFamily) >= 0) {
return fontFamily;
}
for (let i = 0; i < whiteKeyWords.length; i++) {
let keyword = whiteKeyWords[i];
if (fontFamily.indexOf(keyword) >= 0) {
return fontFamily;
}
}
//if only contain basic character (123abc!@#$...), don't substitute.
//because my Mac cannot substituteFont properly handing font like 'Windings'
//but we have to subsittue text if text contain both English and Chinese
const textOnlyContainBasicLatin = Array.from(text).every(char => {
return char.charCodeAt(0) <= 0x007F;
});
if (textOnlyContainBasicLatin) {
return fontFamily;
}

const originFont = findFontSync({
family: fontFamily,
style: fontStyle
});

// array of used family which are in the text

const originPostscriptName = originFont.postscriptName;
const fontList = Array.from(text).map(char =>
FontScanner.substituteFontSync(originPostscriptName, char)
);
let familyList = fontList.map(font => font.family);
let postscriptList = fontList.map(font => font.postscriptName)
// make unique
familyList = [...new Set(familyList)];
postscriptList = [...new Set(postscriptList)];

if (familyList.length === 1) {
return familyList[0];
} else {
// Test all found fonts if they contain all

let fontIndex;
for (let i = 0; i < postscriptList.length; ++i) {
let allFit = true;
for (let j = 0; j < text.length; ++j) {
if (fontList[j].postscriptName === postscriptList[i]) {
continue;
}
const foundfont = FontScanner.substituteFontSync(postscriptList[i], text[j]).family;
if (familyList[i] !== foundfont) {
allFit = false;
break;
}
}
if (allFit) {
console.log(`Find ${familyList[i]} fit for all char`);
return familyList[i];
}
}
console.log('Cannot find a font fit for all')
return (familyList.filter(family => family !== fontFamily))[0];
}
})();

// Font Manager won't return PingFang Semibold if input PingFang Bold
if (substitutedFamily && substitutedFamily.indexOf('PingFang') > -1) {
switch (fontStyle) {
case 'Bold':
fontStyle = 'Semibold';
break;
case 'Italic':
fontStyle = 'Regular';
break;
case 'Bold Italic':
fontStyle = 'Semibold';
break;
default:
break;
}
}
console.log('fontstyle', fontStyle);
let font = findFontSync({
family: substitutedFamily,
style: fontStyle
});
let fontPath = font.path;
if (fontFamily.indexOf("華康") >= 0 && (fontPath.toLowerCase().indexOf("arial") > 0 || fontPath.toLowerCase().indexOf("meiryo") > 0)) {
// This is a hotfix for 華康系列 fonts, because fontScanner does not support
for (var i in fontsListCache) {
const fontInfo = fontsListCache[i];
if (fontInfo.family == fontFamily) {
fontPath = fontInfo.path;
font = fontInfo;
}
}
}
console.log("New Font path ", fontPath);
if (fontPath.toLowerCase().endsWith('.ttc') || fontPath.toLowerCase().endsWith('.ttcf')) {
fontPath = await TTC2TTF(fontPath, font.postscriptName);
}
const pathD = TextToSVG.loadSync(fontPath).getD(text, {
fontSize: Number(fontSize),
anchor: 'left baseline',
x: x,
y: y,
letterSpacing: letterSpacing
});

event.sender.send(events.RESOLVE_PATH_D_OF_TEXT + key, pathD);
});

console.log('Running Beam Studio on ', os.arch());

app.setAsDefaultProtocolClient('beam-studio');
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
"sprintf-js": "^1.1.2",
"squirejs": "^0.2.1",
"sudo-prompt": "^9.0.0",
"text-to-svg": "^3.1.5",
"typescript": "^4.2.4",
"typings": "^2.1.1",
"ws": "^7.1.0"
Expand Down
11 changes: 6 additions & 5 deletions src/implementations/fontHelper.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import fontkit from 'fontkit';
import fontScanner from 'font-scanner';

import communicator from 'implementations/communicator';
import { FontDescriptor, FontHelper } from 'interfaces/IFont';

export default {
findFont(fontDescriptor: FontDescriptor): FontDescriptor {
return fontScanner.findFontSync(fontDescriptor);
return communicator.sendSync('FIND_FONT', fontDescriptor);
},
findFonts(fontDescriptor: FontDescriptor): FontDescriptor[] {
return fontScanner.findFontsSync(fontDescriptor);
return communicator.sendSync('FIND_FONTS', fontDescriptor);
},
getAvailableFonts() {
return fontScanner.getAvailableFontsSync();
return communicator.sendSync('GET_AVAILABLE_FONTS');
},
substituteFont(postscriptName: string, text: string) {
return fontScanner.substituteFontSync(postscriptName, text);
return communicator.sendSync('SUBSTITUTE_FONT', postscriptName, text);
},
getFontName(font: FontDescriptor): string {
let fontName = font.family;
Expand Down
73 changes: 73 additions & 0 deletions src/node/font-helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/* eslint-disable no-param-reassign */
/* eslint-disable @typescript-eslint/no-var-requires */
const fontScanner = require('font-scanner');
const { ipcMain } = require('electron');

const events = require('./ipc-events');

let fontsListCache = [];

const findFontsSync = (arg) => {
const availableFonts = fontsListCache || fontScanner.getAvailableFontsSync();
const matchFamily = availableFonts.filter((font) => font.family === arg.family);
const match = matchFamily.filter((font) => {
let result = true;
Object.getOwnPropertyNames(arg).forEach((a) => {
if (arg[a] !== font[a]) {
result = false;
}
});
return result;
});
return match;
};

const findFontSync = (arg) => {
if (arg.postscriptName) {
return fontScanner.findFontSync(arg);
}

arg.style = arg.style || 'Regular';
const availableFonts = fontsListCache || fontScanner.getAvailableFontsSync();
let font = availableFonts[0];
let match = availableFonts.filter((f) => f.family === arg.family);
font = match[0] || font;
if (arg.italic != null) {
match = match.filter((f) => f.italic === arg.italic);
font = match[0] || font;
}
match = match.filter((f) => f.style === arg.style);
font = match[0] || font;
if (arg.weight != null) {
match = match.filter((f) => f.weight === arg.weight);
}
font = match[0] || font;
return font;
};

const registerEvents = () => {
ipcMain.on(events.GET_AVAILABLE_FONTS, (event) => {
const fonts = fontScanner.getAvailableFontsSync();
fontsListCache = fonts;
event.returnValue = fonts;
});

ipcMain.on(events.FIND_FONTS, (event, arg) => {
const fonts = findFontsSync(arg);
event.returnValue = fonts;
});

ipcMain.on(events.FIND_FONT, (event, arg) => {
const font = findFontSync(arg);
event.returnValue = font;
});

ipcMain.on(events.SUBSTITUTE_FONT, (event, postscriptName, text) => {
const font = fontScanner.substituteFontSync(postscriptName, text);
event.returnValue = font;
});
};

module.exports = {
registerEvents,
};
53 changes: 26 additions & 27 deletions src/node/ipc-events.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,36 @@
module.exports = {
NOTIFY_LANGUAGE : 'NOTIFY_LANGUAGE',
NOTIFY_MACHINE_STATUS : 'NOTIFY_MACHINE_STATUS',
NOTIFY_LANGUAGE: 'NOTIFY_LANGUAGE',
NOTIFY_MACHINE_STATUS: 'NOTIFY_MACHINE_STATUS',

FRONTEND_READY : 'FRONTEND_READY',
BACKEND_UP : 'BACKEND_UP',
BACKEND_DOWN : 'BACKEND_DOWN',
CHECK_BACKEND_STATUS : 'CHECK_BACKEND_STATUS',
NOTIFY_BACKEND_STATUS : 'NOTIFY_BACKEND_STATUS',
FRONTEND_READY: 'FRONTEND_READY',
BACKEND_UP: 'BACKEND_UP',
BACKEND_DOWN: 'BACKEND_DOWN',
CHECK_BACKEND_STATUS: 'CHECK_BACKEND_STATUS',
NOTIFY_BACKEND_STATUS: 'NOTIFY_BACKEND_STATUS',

MENU_CLICK : 'MENU_CLICK',
UPDATE_CUSTOM_TITLEBAR : 'UPDATE_CUSTOM_TITLEBAR',
DISABLE_MENU_ITEM : 'DISABLE_MENU_ITEM',
ENABLE_MENU_ITEM : 'ENABLE_MENU_ITEM',
MENU_CLICK: 'MENU_CLICK',
UPDATE_CUSTOM_TITLEBAR: 'UPDATE_CUSTOM_TITLEBAR',
DISABLE_MENU_ITEM: 'DISABLE_MENU_ITEM',
ENABLE_MENU_ITEM: 'ENABLE_MENU_ITEM',

POPUP_MENU : 'POPUP_MENU_ITEM',
POPUP_MENU: 'POPUP_MENU_ITEM',

UPDATE_ACCOUNT : 'UPDATE_ACCOUNT',
UPDATE_ACCOUNT: 'UPDATE_ACCOUNT',

GET_AVAILABLE_FONTS : 'GET_AVAILABLE_FONTS',
FIND_FONTS : 'FIND_FONTS',
FIND_FONT : 'FIND_FONT',
REQUEST_PATH_D_OF_TEXT : 'REQUEST_PATH_D_OF_TEXT',
RESOLVE_PATH_D_OF_TEXT : 'RESOLVE_PATH_D_OF_TEXT',
GET_AVAILABLE_FONTS: 'GET_AVAILABLE_FONTS',
FIND_FONTS: 'FIND_FONTS',
FIND_FONT: 'FIND_FONT',
SUBSTITUTE_FONT: 'SUBSTITUTE_FONT',

SET_AS_DEFAULT : 'SET_AS_DEFAULT',
SET_AS_DEFAULT: 'SET_AS_DEFAULT',

CHECK_FOR_UPDATE : 'CHECK_FOR_UPDATE',
UPDATE_AVAILABLE : 'UPDATE_AVAILABLE',
DOWNLOAD_UPDATE : 'DOWNLOAD_UPDATE',
DOWNLOAD_PROGRESS : 'DOWNLOAD_PROGRESS',
UPDATE_DOWNLOADED : 'UPDATE_DOWNLOADED',
QUIT_AND_INSTALL : 'QUIT_AND_INSTALL',
CHECK_FOR_UPDATE: 'CHECK_FOR_UPDATE',
UPDATE_AVAILABLE: 'UPDATE_AVAILABLE',
DOWNLOAD_UPDATE: 'DOWNLOAD_UPDATE',
DOWNLOAD_PROGRESS: 'DOWNLOAD_PROGRESS',
UPDATE_DOWNLOADED: 'UPDATE_DOWNLOADED',
QUIT_AND_INSTALL: 'QUIT_AND_INSTALL',

SVG_URL_TO_IMG_URL : 'SVG_URL_TO_IMG_URL',
SVG_URL_TO_IMG_URL_DONE : 'SVG_URL_TO_IMG_URL_DONE'
SVG_URL_TO_IMG_URL: 'SVG_URL_TO_IMG_URL',
SVG_URL_TO_IMG_URL_DONE: 'SVG_URL_TO_IMG_URL_DONE',
};

0 comments on commit d1e40bb

Please sign in to comment.