1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00
joplin/Tools/generate-images.js
Giacomo Rossetto 4167ecafd2
Desktop: Support Windows tiles (#3063)
* Add vector assets

Useful for future tile designs, they contain suggested content guides

* Add tile files

Images and manifest

* Make build script retrieve new files

* Automate Windows Tiles icon generation

* Fix alignment bug

* Replace handcraftet tiles with automatically generetad ones
2020-05-10 15:01:53 +01:00

339 lines
7.6 KiB
JavaScript

require('app-module-path').addPath(`${__dirname}/../ReactNativeClient`);
const dirname = require('path').dirname;
const sharp = require('sharp');
const fs = require('fs-extra');
const { execCommand } = require('./tool-utils.js');
const { fileExtension } = require('lib/path-utils');
const sources = [
{
id: 1,
name: 'Square_1024x1024.png',
},
{
id: 2,
name: 'RoundedCorners_16x16.png',
},
{
id: 3,
name: 'RoundedCorners_64x64.png',
},
{
id: 4,
name: 'RoundedCorners_1024x1024.png',
},
{
id: 5,
name: 'Joplin.ico',
},
{
id: 6,
name: '../JoplinLetter.png',
},
];
function sourceById(id) {
for (const s of sources) {
if (s.id === id) return s;
}
throw new Error(`Invalid source ID: ${id}`);
}
const operations = [
// ============================================================================
// iOS icons
// ============================================================================
{
source: 1,
dest: 'ReactNativeClient/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_marketing1024x1024.png',
width: 1024,
height: 1024,
},
{
source: 1,
dest: 'ReactNativeClient/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_app76x76.png',
width: 76,
height: 76,
},
{
source: 1,
dest: 'ReactNativeClient/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_app76x76@2x.png',
width: 152,
height: 152,
},
{
source: 1,
dest: 'ReactNativeClient/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_notification20x20.png',
width: 20,
height: 20,
},
{
source: 1,
dest: 'ReactNativeClient/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_notification20x20@2x.png',
width: 40,
height: 40,
},
{
source: 1,
dest: 'ReactNativeClient/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_pro_app83.5x83.5@2x.png',
width: 167,
height: 167,
},
{
source: 1,
dest: 'ReactNativeClient/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_settings29x29.png',
width: 29,
height: 29,
},
{
source: 1,
dest: 'ReactNativeClient/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_settings29x29@2x.png',
width: 58,
height: 58,
},
{
source: 1,
dest: 'ReactNativeClient/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_spotlight40x40.png',
width: 40,
height: 40,
},
{
source: 1,
dest: 'ReactNativeClient/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_spotlight40x40@2x.png',
width: 80,
height: 80,
},
{
source: 1,
dest: 'ReactNativeClient/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_app60x60@2x.png',
width: 120,
height: 120,
},
{
source: 1,
dest: 'ReactNativeClient/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_app60x60@3x.png',
width: 180,
height: 180,
},
{
source: 1,
dest: 'ReactNativeClient/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_notification20x20@2x.png',
width: 40,
height: 40,
},
{
source: 1,
dest: 'ReactNativeClient/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_notification20x20@3x.png',
width: 60,
height: 60,
},
{
source: 1,
dest: 'ReactNativeClient/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_settings29x29@2x.png',
width: 58,
height: 58,
},
{
source: 1,
dest: 'ReactNativeClient/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_settings29x29@3x.png',
width: 87,
height: 87,
},
{
source: 1,
dest: 'ReactNativeClient/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_spotlight40x40@2x.png',
width: 80,
height: 80,
},
{
source: 1,
dest: 'ReactNativeClient/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_spotlight40x40@3x.png',
width: 120,
height: 120,
},
// ============================================================================
// macOS icons
// ============================================================================
{
source: 2,
dest: 'Assets/macOs.iconset/icon_16x16.png',
width: 16,
height: 16,
},
{
source: 3,
dest: 'Assets/macOs.iconset/icon_16x16@2x.png',
width: 32,
height: 32,
},
{
source: 3,
dest: 'Assets/macOs.iconset/icon_32x32.png',
width: 32,
height: 32,
},
{
source: 3,
dest: 'Assets/macOs.iconset/icon_32x32@2x.png',
width: 64,
height: 64,
},
{
source: 4,
dest: 'Assets/macOs.iconset/icon_128x128.png',
width: 128,
height: 128,
},
{
source: 4,
dest: 'Assets/macOs.iconset/icon_128x128@2x.png',
width: 256,
height: 256,
},
{
source: 4,
dest: 'Assets/macOs.iconset/icon_256x256.png',
width: 256,
height: 256,
},
{
source: 4,
dest: 'Assets/macOs.iconset/icon_256x256@2x.png',
width: 512,
height: 512,
},
{
source: 4,
dest: 'Assets/macOs.iconset/icon_512x512.png',
width: 512,
height: 512,
},
{
source: 4,
dest: 'Assets/macOs.iconset/icon_512x512@2x.png',
width: 1024,
height: 1024,
},
{
source: 5,
dest: 'Tools/PortableAppsLauncher/App/AppInfo/appicon.ico',
},
{
source: 2,
dest: 'Tools/PortableAppsLauncher/App/AppInfo/appicon_16.png',
},
{
source: 3,
dest: 'Tools/PortableAppsLauncher/App/AppInfo/appicon_32.png',
width: 32,
height: 32,
},
{
source: 4,
dest: 'Tools/PortableAppsLauncher/App/AppInfo/appicon_75.png',
width: 75,
height: 75,
},
{
source: 4,
dest: 'Tools/PortableAppsLauncher/App/AppInfo/appicon_128.png',
width: 128,
height: 128,
},
{
source: 4,
dest: 'Tools/PortableAppsLauncher/App/AppInfo/Launcher/splash.jpg',
width: 144,
height: 144,
},
// ============================================================================
// Windows tiles
// ============================================================================
{
source: 6,
dest: 'ElectronClient/build-win/icons/Square150x150Logo.png',
width: 150,
height: 150,
iconWidth: 99,
iconHeight: 75,
},
{
source: 6,
dest: 'ElectronClient/build-win/icons/SmallTile.png',
width: 70,
height: 70,
iconWidth: 46,
iconHeight: 46,
},
];
async function main() {
const rootDir = dirname(__dirname);
const sourceImageDir = `${rootDir}/Assets/ImageSources`;
for (const operation of operations) {
const source = sourceById(operation.source);
const sourcePath = `${sourceImageDir}/${source.name}`;
const destPath = `${rootDir}/${operation.dest}`;
const sourceExt = fileExtension(sourcePath).toLowerCase();
const destExt = fileExtension(destPath).toLowerCase();
if ((operation.width && operation.height) || (sourceExt !== destExt)) {
let s = sharp(sourcePath);
if (operation.width && operation.height) {
if (operation.iconWidth && operation.iconHeight) {
s = s.resize(operation.iconWidth, operation.iconHeight, {
fit: 'contain',
background: { r: 0, g: 0, b: 0, alpha: 0 },
}).extend({
top: Math.floor((operation.height - operation.iconHeight) / 2),
bottom: Math.ceil((operation.height - operation.iconHeight) / 2),
left: Math.floor((operation.width - operation.iconWidth) / 2),
right: Math.ceil((operation.width - operation.iconWidth) / 2),
background: { r: 0, g: 0, b: 0, alpha: 0 },
});
} else {
s = s.resize(operation.width, operation.height, { fit: 'fill' });
}
}
if (destExt === 'jpg') {
s.jpeg({ quality: 90 });
} else if (destExt === 'png') {
s.png();
} else {
throw new Error(`Unsupported extension: ${destExt}`);
}
s = s.toFile(destPath);
} else {
await fs.copyFile(sourcePath, destPath);
}
}
if (process && process.platform === 'darwin') {
const icnsDest = `${rootDir}/Assets/macOs.icns`;
const icnsSource = `${rootDir}/Assets/macOs.iconset`;
console.info(`iconutil -c icns -o "${icnsDest}" "${icnsSource}"`);
await execCommand(`iconutil -c icns -o "${icnsDest}" "${icnsSource}"`);
}
}
main().catch((error) => {
console.error(error);
process.exit(1);
});