Skip to content

Commit 1f3ed71

Browse files
authored
feat: backport of PWA icon image lazy generation (#21263)
This commit is a backport of #16994 (limited to PWA icon handling) Fixes #21253
1 parent 42c5458 commit 1f3ed71

File tree

2 files changed

+68
-51
lines changed

2 files changed

+68
-51
lines changed

flow-server/src/main/java/com/vaadin/flow/server/PwaIcon.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
package com.vaadin.flow.server;
1010

1111
import javax.imageio.ImageIO;
12+
import java.awt.Color;
13+
import java.awt.Graphics2D;
14+
import java.awt.Image;
1215
import java.awt.image.BufferedImage;
1316
import java.io.ByteArrayOutputStream;
1417
import java.io.IOException;
@@ -56,6 +59,8 @@ public enum Domain {
5659
private final Map<String, String> attributes = new HashMap<>();
5760
private String tag = "link";
5861

62+
private PwaRegistry registry;
63+
5964
PwaIcon(int width, int height, String baseName) {
6065
this(width, height, baseName, Domain.HEADER);
6166
}
@@ -202,6 +207,10 @@ public Domain getDomain() {
202207
return domain;
203208
}
204209

210+
public void setRegistry(PwaRegistry registry) {
211+
this.registry = registry;
212+
}
213+
205214
/**
206215
* Sets the image presenting the icon.
207216
*
@@ -227,6 +236,11 @@ public void setImage(BufferedImage image) {
227236
* output stream to write the icon image to
228237
*/
229238
public void write(OutputStream outputStream) {
239+
if (data == null) {
240+
// New image with wanted size
241+
// Store byte array and hashcode of image (GeneratedImage)
242+
setImage(drawIconImage(getBaseImage()));
243+
}
230244
try {
231245
outputStream.write(data);
232246
} catch (IOException ioe) {
@@ -236,4 +250,49 @@ public void write(OutputStream outputStream) {
236250
}
237251
}
238252

253+
// visible for test
254+
protected BufferedImage getBaseImage() {
255+
return registry.getBaseImage();
256+
}
257+
258+
private BufferedImage drawIconImage(BufferedImage baseImage) {
259+
// Pick top-left pixel as fill color if needed for image
260+
// resizing
261+
int bgColor = baseImage.getRGB(0, 0);
262+
263+
BufferedImage bimage = new BufferedImage(this.getWidth(),
264+
this.getHeight(), BufferedImage.TYPE_INT_ARGB);
265+
// Draw the image on to the buffered image
266+
Graphics2D graphics = bimage.createGraphics();
267+
268+
// fill bg with fill-color
269+
graphics.setBackground(new Color(bgColor, true));
270+
graphics.clearRect(0, 0, this.getWidth(), this.getHeight());
271+
272+
// calculate ratio (bigger ratio) for resize
273+
float ratio = (float) baseImage.getWidth()
274+
/ (float) this.getWidth() > (float) baseImage.getHeight()
275+
/ (float) this.getHeight()
276+
? (float) baseImage.getWidth()
277+
/ (float) this.getWidth()
278+
: (float) baseImage.getHeight()
279+
/ (float) this.getHeight();
280+
281+
// Forbid upscaling of image
282+
ratio = ratio > 1.0f ? ratio : 1.0f;
283+
284+
// calculate sizes with ratio
285+
int newWidth = Math.round(baseImage.getHeight() / ratio);
286+
int newHeight = Math.round(baseImage.getWidth() / ratio);
287+
288+
// draw rescaled img in the center of created image
289+
graphics.drawImage(
290+
baseImage.getScaledInstance(newWidth, newHeight,
291+
Image.SCALE_SMOOTH),
292+
(this.getWidth() - newWidth) / 2,
293+
(this.getHeight() - newHeight) / 2, null);
294+
graphics.dispose();
295+
return bimage;
296+
}
297+
239298
}

flow-server/src/main/java/com/vaadin/flow/server/PwaRegistry.java

Lines changed: 9 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@
1111
import javax.imageio.ImageIO;
1212
import javax.servlet.ServletContext;
1313

14-
import java.awt.Color;
15-
import java.awt.Graphics2D;
16-
import java.awt.Image;
1714
import java.awt.image.BufferedImage;
1815
import java.io.BufferedReader;
1916
import java.io.IOException;
@@ -75,6 +72,7 @@ public class PwaRegistry implements Serializable {
7572
private long offlineHash;
7673
private List<PwaIcon> icons = new ArrayList<>();
7774
private final PwaConfiguration pwaConfiguration;
75+
private BufferedImage baseImage;
7876

7977
/**
8078
* Creates a new PwaRegistry instance.
@@ -109,6 +107,10 @@ public PwaRegistry(PWA pwa, ServletContext servletContext)
109107
initializeResources(servletContext);
110108
}
111109

110+
BufferedImage getBaseImage() {
111+
return baseImage;
112+
}
113+
112114
private void initializeResources(ServletContext servletContext)
113115
throws MalformedURLException, IOException {
114116
if (!pwaConfiguration.isEnabled()) {
@@ -126,17 +128,13 @@ private void initializeResources(ServletContext servletContext)
126128

127129
// Load base logo from servlet context if available
128130
// fall back to local image if unavailable
129-
BufferedImage baseImage = getBaseImage(logo);
131+
baseImage = getBaseImage(logo);
130132

131133
if (baseImage == null) {
132134
getLogger().error("Image is not found or can't be loaded: " + logo);
133135
} else {
134-
// Pick top-left pixel as fill color if needed for image
135-
// resizing
136-
int bgColor = baseImage.getRGB(0, 0);
137-
138136
// initialize icons
139-
icons = initializeIcons(baseImage, bgColor);
137+
icons = initializeIcons();
140138
}
141139

142140
// Load offline page as string, from servlet context if
@@ -171,54 +169,14 @@ private URL getResourceUrl(ServletContext context, String path)
171169
return resourceUrl;
172170
}
173171

174-
private List<PwaIcon> initializeIcons(BufferedImage baseImage,
175-
int bgColor) {
172+
private List<PwaIcon> initializeIcons() {
176173
for (PwaIcon icon : getIconTemplates(pwaConfiguration.getIconPath())) {
177-
// New image with wanted size
178-
icon.setImage(drawIconImage(baseImage, bgColor, icon));
179-
// Store byte array and hashcode of image (GeneratedImage)
174+
icon.setRegistry(this);
180175
icons.add(icon);
181176
}
182177
return icons;
183178
}
184179

185-
private BufferedImage drawIconImage(BufferedImage baseImage, int bgColor,
186-
PwaIcon icon) {
187-
BufferedImage bimage = new BufferedImage(icon.getWidth(),
188-
icon.getHeight(), BufferedImage.TYPE_INT_ARGB);
189-
// Draw the image on to the buffered image
190-
Graphics2D graphics = bimage.createGraphics();
191-
192-
// fill bg with fill-color
193-
graphics.setBackground(new Color(bgColor, true));
194-
graphics.clearRect(0, 0, icon.getWidth(), icon.getHeight());
195-
196-
// calculate ratio (bigger ratio) for resize
197-
float ratio = (float) baseImage.getWidth()
198-
/ (float) icon.getWidth() > (float) baseImage.getHeight()
199-
/ (float) icon.getHeight()
200-
? (float) baseImage.getWidth()
201-
/ (float) icon.getWidth()
202-
: (float) baseImage.getHeight()
203-
/ (float) icon.getHeight();
204-
205-
// Forbid upscaling of image
206-
ratio = ratio > 1.0f ? ratio : 1.0f;
207-
208-
// calculate sizes with ratio
209-
int newWidth = Math.round(baseImage.getHeight() / ratio);
210-
int newHeight = Math.round(baseImage.getWidth() / ratio);
211-
212-
// draw rescaled img in the center of created image
213-
graphics.drawImage(
214-
baseImage.getScaledInstance(newWidth, newHeight,
215-
Image.SCALE_SMOOTH),
216-
(icon.getWidth() - newWidth) / 2,
217-
(icon.getHeight() - newHeight) / 2, null);
218-
graphics.dispose();
219-
return bimage;
220-
}
221-
222180
/**
223181
* Creates manifest.webmanifest json object.
224182
*

0 commit comments

Comments
 (0)