Skip to content

Commit 8bad93c

Browse files
committed
MS Store packager uses new app image generator
1 parent ac5aec8 commit 8bad93c

8 files changed

Lines changed: 56 additions & 167 deletions

File tree

apps/pwabuilder-google-play/package-lock.json

Lines changed: 1 addition & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/pwabuilder-microsoft-store/Models/AppSettings.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public class AppSettings
7878
/// <summary>
7979
/// The URL of the image generator API.
8080
/// </summary>
81-
public string ImageGeneratorApiUrl { get; set; } = string.Empty;
81+
public required Uri ImageGeneratorApiUrl { get; set; }
8282

8383
/// <summary>
8484
/// App Insights connection string

apps/pwabuilder-microsoft-store/Models/ImageGeneratorServiceZipFile.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@ public ImageGeneratorServiceZipFile(ZipArchive zip)
3333
throw new NotSupportedException("Unable to find scale set type " + type);
3434
}
3535

36-
return zip.GetEntry($"windows11/{prefix}{scale.ToWindowsImageNamingConventionSuffix()}.png");
36+
return zip.GetEntry($"windows/{prefix}{scale.ToWindowsImageNamingConventionSuffix()}.png");
3737
}
3838

3939
public ZipArchiveEntry? GetTargetSize(ImageTargetSize size, ImageAltForm altForm)
4040
{
4141
// Square44x44Logo isn't a typo here - the image generator service uses those files names, then appends the actual size to the file name.
42-
return zip.GetEntry($"windows11/{altForm.ToWindowsImageNamingConventionString(size)}.png");
42+
return zip.GetEntry($"windows/{altForm.ToWindowsImageNamingConventionString(size)}.png");
4343
}
4444

4545
public void Dispose()

apps/pwabuilder-microsoft-store/Services/ImageGenerator.cs

Lines changed: 22 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ public ImageGenerator(
3131
IOptions<AppSettings> appSettings,
3232
ILogger<ImageGenerator> logger)
3333
{
34-
this.http = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.All });
34+
this.http = httpClientFactory.CreateClient();
3535
this.http.AddLatestEdgeUserAgent();
36-
this.imageGeneratorServiceUrl = new Uri(appSettings.Value.ImageGeneratorApiUrl);
36+
this.imageGeneratorServiceUrl = appSettings.Value.ImageGeneratorApiUrl;
3737
this.logger = logger;
3838
}
3939

@@ -50,7 +50,7 @@ public async Task<ImageGeneratorResult> Generate(WindowsAppPackageOptions option
5050
// 1. Generate images using PWABuilder's image generation service.
5151
// These will be used as a backup if the options and manifest are missing images.
5252
var imageOptions = options.Images ?? new WindowsImages();
53-
var generatedImagesZip = await InvokePwabuilderImageGeneratorService(imageOptions, manifest);
53+
using var generatedImagesZip = await InvokePwabuilderImageGeneratorService(imageOptions, manifest);
5454

5555
// 2. Assemble the image sources from the options, web manifest, and generated images zip.
5656
var imageSources = GetImageSources(imageOptions, manifest, generatedImagesZip);
@@ -70,8 +70,7 @@ private IEnumerable<ImageSource> GetImageSources(WindowsImages imageOptions, Web
7070
private async Task<ImageGeneratorServiceZipFile> InvokePwabuilderImageGeneratorService(WindowsImages imageOptions, WebAppManifestContext webManifest)
7171
{
7272
var baseImageBytes = await GetBaseImage(imageOptions, webManifest);
73-
var imagesZipUrl = await CreateWindows11ImagesZip(baseImageBytes, imageOptions.Padding, imageOptions.BackgroundColor);
74-
return await DownloadWindowsImagesZip(imagesZipUrl);
73+
return await CreateWindows11ImagesZip(baseImageBytes, imageOptions.Padding, imageOptions.BackgroundColor);
7574
}
7675

7776
private async Task<byte[]> GetBaseImage(WindowsImages imageOptions, WebAppManifestContext webManifest)
@@ -122,46 +121,35 @@ private async Task<byte[]> GetBaseImage(WindowsImages imageOptions, WebAppManife
122121
throw new InvalidOperationException($"Couldn't find a suitable base image from which to generate all Windows package images. Please ensure your web app manifest has a square PNG image 512x512 or larger. Base image sources: {string.Join(", ", imageSourceDescriptions)}");
123122
}
124123

125-
private async Task<Uri> CreateWindows11ImagesZip(byte[] image, double padding, string? backgroundColor)
124+
private async Task<ImageGeneratorServiceZipFile> CreateWindows11ImagesZip(byte[] image, double padding, string? backgroundColor)
126125
{
127-
// The image generation API documentation (https://github.com/pwa-builder/pwabuilder-Image-Generator/blob/master/README.md)
126+
// The image generation API documentation: https://github.com/pwa-builder/PWABuilder/blob/ac5aec8c3ad235cb7f2f54bfa64189ec73e947a6/apps/pwabuilder/Controllers/ImagesController.cs#L83
128127
// states the image generator takes the following parameters:
129-
// - fileName: bytes
130-
// - padding: double
128+
// - baseImage: bytes
129+
// - padding: double from 0 to 1
131130
// - color: The background color (named color or hex color) of the generated images. If null, the color will be chosen from (0,0) pixel of the source image
132131
// - platform: windows11
133-
// - colorChanged: if colorOption = "choose", this should be 1. Otherwise, omit.
134-
var fileContent = new StreamContent(new MemoryStream(image));
135-
fileContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("form-data") { Name = "file", FileName = "image.png" };
136-
fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
132+
var memStream = new MemoryStream(image);
133+
using var fileContent = new StreamContent(memStream);
134+
fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/png");
137135
var imageGeneratorArgs = new MultipartFormDataContent
138136
{
139-
{ fileContent, "fileName" },
140-
{ new StringContent(padding.ToString()), "padding" }, // For Windows 10 images, padding is honored. For Windows 11 images, padding is overriden by individual image sizes. See https://github.com/pwa-builder/pwabuilder-Image-Generator/blob/master/AppImageGenerator/App_Data/windows11Images.json
141-
{ new StringContent("windows11"), "platform" },
142-
{ new StringContent(backgroundColor ?? string.Empty), "color" }
137+
{ fileContent, "BaseImage", "image.png" },
138+
{ new StringContent(padding.ToString(System.Globalization.CultureInfo.InvariantCulture)), "Padding" },
139+
{ new StringContent("windows11"), "Platforms" },
140+
{ new StringContent(backgroundColor ?? "transparent"), "BackgroundColor" }
143141
};
144142

145-
var imagesResponse = await this.http.PostAsync(imageGeneratorServiceUrl, imageGeneratorArgs);
143+
using var imagesResponse = await this.http.PostAsync(imageGeneratorServiceUrl, imageGeneratorArgs);
146144
imagesResponse.EnsureSuccessStatusCode();
147-
var imagesResponseString = await imagesResponse.Content.ReadAsStringAsync(); // it should be a JSON string containing a ImageGeneratorServiceResult
148-
var imagesResult = JsonSerializer.Deserialize<ImageGeneratorServiceResult>(imagesResponseString, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
149-
if (imagesResult == null)
150-
{
151-
throw new InvalidOperationException("Unable to deserialize image generator result");
152-
}
153-
if (!Uri.TryCreate(imageGeneratorServiceUrl, imagesResult.Uri, out var imagesZipUri))
154-
{
155-
throw new Exception($"Unable to generate images for Windows package. The image URI returned from the image generator service, '{imagesResult.Uri}', is an invalid URI. Raw response: {imagesResponseString}");
156-
}
157145

158-
return imagesZipUri;
159-
}
146+
// Copy the response into a self-contained MemoryStream so that
147+
// the ZipArchive remains usable after the HTTP response is disposed.
148+
var zipMemoryStream = new MemoryStream();
149+
await imagesResponse.Content.CopyToAsync(zipMemoryStream);
150+
zipMemoryStream.Position = 0;
160151

161-
private async Task<ImageGeneratorServiceZipFile> DownloadWindowsImagesZip(Uri url)
162-
{
163-
var zipStream = await this.http.GetStreamAsync(url);
164-
var zipArchive = new ZipArchive(zipStream, ZipArchiveMode.Read, false);
152+
var zipArchive = new ZipArchive(zipMemoryStream, ZipArchiveMode.Read);
165153
return new ImageGeneratorServiceZipFile(zipArchive);
166154
}
167155

@@ -346,10 +334,5 @@ private async Task<List<string>> TryWriteImageSourcesToDirectory(IEnumerable<Ima
346334
return null;
347335
}
348336
}
349-
350-
private class ImageGeneratorServiceResult
351-
{
352-
public string? Uri { get; set; }
353-
}
354337
}
355338
}

apps/pwabuilder-microsoft-store/appsettings.Development.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
"PriPath": "bin\\Debug\\net10.0\\Resources\\resources.pri",
1919
"ReadmePath": "bin\\Debug\\net10.0\\Resources\\next-steps.html",
2020
"OutputDirectory": "%temp%",
21-
"WindowsSdkDirectory": "C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.26100.0\\x64",
21+
"WindowsSdkDirectory": "E:\\sdks\\windows-sdk\\bin\\10.0.26100.0\\x64",
2222
"UrlLoggerService": "",
23-
"ImageGeneratorApiUrl": "https://appimagegenerator-prod.azurewebsites.net/api/image",
23+
"ImageGeneratorApiUrl": "https://localhost:7217/api/images/generateStoreImages",
2424
"ApplicationInsightsConnectionString": ""
2525
}
2626
}
Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
11
{
2-
"ConnectionStrings": {
3-
"DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Database=_CHANGE_ME;Trusted_Connection=True;MultipleActiveResultSets=true"
4-
},
5-
"Logging": {
6-
"LogLevel": {
7-
"Default": "Information",
8-
"Microsoft": "Warning",
9-
"Microsoft.Hosting.Lifetime": "Information"
2+
"ConnectionStrings": {
3+
"DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Database=_CHANGE_ME;Trusted_Connection=True;MultipleActiveResultSets=true"
4+
},
5+
"Logging": {
6+
"LogLevel": {
7+
"Default": "Information",
8+
"Microsoft": "Warning",
9+
"Microsoft.Hosting.Lifetime": "Information"
10+
}
11+
},
12+
"AppSettings": {
13+
"PwaBuilderPath": "Resources\\cli\\pwabuilder\\pwa_builder.exe",
14+
"PwaInstallerPath": "Resources\\cli\\pwainstaller\\pwainstaller.exe",
15+
"InstallScriptPath": "Resources\\install.ps1",
16+
"ClassicWindowsAppPackagePath": "Resources\\ClassicWindowsAppPackage.appx",
17+
"SpartanWindowsAppPackagePath": "Resources\\SpartanWindowsAppPackage.appx",
18+
"SpartanInstallScriptPath": "Resources\\install-edgehtml.ps1",
19+
"SpartanReadmePath": "Resources\\next-steps-edgehtml.html",
20+
"StoreSupportedLanguagesPath": "Resources\\store-supported-languages.txt",
21+
"PriPath": "Resources\\resources.pri",
22+
"ReadmePath": "Resources\\next-steps.html",
23+
"OutputDirectory": "%temp%",
24+
"WindowsSdkDirectory": "C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.19041.0\\x64",
25+
"UrlLoggerService": "",
26+
"ImageGeneratorApiUrl": "/api/images/generateStoreImages",
27+
"ApplicationInsightsConnectionString": ""
1028
}
11-
},
12-
"AppSettings": {
13-
"PwaBuilderPath": "Resources\\cli\\pwabuilder\\pwa_builder.exe",
14-
"PwaInstallerPath": "Resources\\cli\\pwainstaller\\pwainstaller.exe",
15-
"InstallScriptPath": "Resources\\install.ps1",
16-
"ClassicWindowsAppPackagePath": "Resources\\ClassicWindowsAppPackage.appx",
17-
"SpartanWindowsAppPackagePath": "Resources\\SpartanWindowsAppPackage.appx",
18-
"SpartanInstallScriptPath": "Resources\\install-edgehtml.ps1",
19-
"SpartanReadmePath": "Resources\\next-steps-edgehtml.html",
20-
"StoreSupportedLanguagesPath": "Resources\\store-supported-languages.txt",
21-
"PriPath": "Resources\\resources.pri",
22-
"ReadmePath": "Resources\\next-steps.html",
23-
"OutputDirectory": "%temp%",
24-
"WindowsSdkDirectory": "C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.19041.0\\x64",
25-
"UrlLoggerService": "",
26-
"ImageGeneratorApiUrl": "https://appimagegenerator-prod.azurewebsites.net/api/image",
27-
"ApplicationInsightsConnectionString": ""
28-
}
29-
}
29+
}

apps/pwabuilder/Frontend/src/locales/en_US.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@
271271
"input_image": "Choose your base image",
272272
"input_image_help": "You should choose a 512x512 or larger square PNG/SVG/WEBP image. This image will be used to generate all the images for your chosen platforms.",
273273
"padding": "Padding",
274-
"padding_text": "0 is no padding, 1 is 100% of the source image. Google Play and iOS App Store both recommend full bleed icons with zero padding.",
274+
"padding_text": "0 is no padding, 1 is 100% of the source image. The Microsoft Store, Google Play, and iOS App Store recommend full bleed icons with zero padding.",
275275
"background_color": "Background Color",
276276
"best_guess": "Best guess",
277277
"transparent": "Transparent",

0 commit comments

Comments
 (0)