-
-
Notifications
You must be signed in to change notification settings - Fork 197
/
Copy pathassets-generation-service.ts
124 lines (106 loc) · 4.73 KB
/
assets-generation-service.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import * as Jimp from "jimp";
import * as Color from "color";
import { exported } from "../../common/decorators";
import { AssetConstants } from '../../constants';
export const enum Operations {
OverlayWith = "overlayWith",
Blank = "blank",
Resize = "resize"
}
export class AssetsGenerationService implements IAssetsGenerationService {
private get propertiesToEnumerate(): IDictionary<string[]> {
return {
icon: ["icons"],
splash: ["splashBackgrounds", "splashCenterImages", "splashImages"]
};
}
constructor(private $logger: ILogger,
private $projectDataService: IProjectDataService) {
}
@exported("assetsGenerationService")
public async generateIcons(resourceGenerationData: IResourceGenerationData): Promise<void> {
this.$logger.info("Generating icons ...");
await this.generateImagesForDefinitions(resourceGenerationData, this.propertiesToEnumerate.icon);
this.$logger.info("Icons generation completed.");
}
@exported("assetsGenerationService")
public async generateSplashScreens(splashesGenerationData: ISplashesGenerationData): Promise<void> {
this.$logger.info("Generating splash screens ...");
await this.generateImagesForDefinitions(splashesGenerationData, this.propertiesToEnumerate.splash);
this.$logger.info("Splash screens generation completed.");
}
private async generateImagesForDefinitions(generationData: ISplashesGenerationData, propertiesToEnumerate: string[]): Promise<void> {
generationData.background = generationData.background || "white";
const assetsStructure = await this.$projectDataService.getAssetsStructure(generationData);
const assetItems = _(assetsStructure)
.filter((assetGroup: IAssetGroup, platform: string) =>
!generationData.platform || platform.toLowerCase() === generationData.platform.toLowerCase()
)
.map((assetGroup: IAssetGroup) =>
_.filter(assetGroup, (assetSubGroup: IAssetSubGroup, imageTypeKey: string) =>
assetSubGroup && propertiesToEnumerate.indexOf(imageTypeKey) !== -1
)
)
.flatten<IAssetSubGroup>()
.map(assetSubGroup => assetSubGroup.images)
.flatten<IAssetItem>()
.filter(assetItem => !!assetItem.filename)
.value();
for (const assetItem of assetItems) {
const operation = assetItem.resizeOperation || Operations.Resize;
let tempScale: number = null;
if (assetItem.scale) {
if (_.isNumber(assetItem.scale)) {
tempScale = assetItem.scale;
} else {
const splittedElements = `${assetItem.scale}`.split(AssetConstants.sizeDelimiter);
tempScale = splittedElements && splittedElements.length && splittedElements[0] && +splittedElements[0];
}
}
const scale = tempScale || AssetConstants.defaultScale;
const outputPath = assetItem.path;
const width = assetItem.width * scale;
const height = assetItem.height * scale;
switch (operation) {
case Operations.OverlayWith:
const overlayImageScale = assetItem.overlayImageScale || AssetConstants.defaultOverlayImageScale;
const imageResize = Math.round(Math.min(width, height) * overlayImageScale);
const image = await this.resize(generationData.imagePath, imageResize, imageResize);
await this.generateImage(generationData.background, width, height, outputPath, image);
break;
case Operations.Blank:
await this.generateImage(generationData.background, width, height, outputPath);
break;
case Operations.Resize:
const resizedImage = await this.resize(generationData.imagePath, width, height);
resizedImage.write(outputPath);
break;
default:
throw new Error(`Invalid image generation operation: ${operation}`);
}
}
}
private async resize(imagePath: string, width: number, height: number): Promise<Jimp> {
const image = await Jimp.read(imagePath);
return image.scaleToFit(width, height);
}
private generateImage(background: string, width: number, height: number, outputPath: string, overlayImage?: Jimp): void {
// Typescript declarations for Jimp are not updated to define the constructor with backgroundColor so we workaround it by casting it to <any> for this case only.
const J = <any>Jimp;
const backgroundColor = this.getRgbaNumber(background);
let image = new J(width, height, backgroundColor);
if (overlayImage) {
const centeredWidth = (width - overlayImage.bitmap.width) / 2;
const centeredHeight = (height - overlayImage.bitmap.height) / 2;
image = image.composite(overlayImage, centeredWidth, centeredHeight);
}
image.write(outputPath);
}
private getRgbaNumber(colorString: string): number {
const color = new Color(colorString);
const colorRgb = color.rgb();
const alpha = Math.round(colorRgb.alpha() * 255);
return Jimp.rgbaToInt(colorRgb.red(), colorRgb.green(), colorRgb.blue(), alpha);
}
}
$injector.register("assetsGenerationService", AssetsGenerationService);