How Switching from Front‑End to Back‑End Image Generation Boosted Performance for Game Account Listings
This article explains how moving large‑image generation for game account listings from a front‑end Puppeteer‑based approach to a back‑end Java AWT solution dramatically reduced processing time, improved user experience, and created a modular, maintainable system for multiple games.
1 Background
In the ZhaiZhai game account business (e.g., Honor of Kings), key metrics such as total heroes, skins, and featured skins are important, but the old list‑page images were user‑uploaded or generated by simple rules, failing to highlight these core features.
Although detailed verification reports appear on the product detail page, users must click from the list page, creating a long conversion path and reducing information reach efficiency.
Therefore we generate a large image containing the key account information and display it both on the list and detail pages.
List page large image:
Detail page large image:
2 From Front‑End to Back‑End Image Generation
2.1 Considerations and Implementation on the Front End
Initially the large image was generated on the front end because browsers can render complex layouts quickly and development cost is low.
The front end obtains all material data (small‑image URLs, text, etc.) from a back‑end API, renders them on a page, and then uses a Puppeteer service to screenshot the page.
Front end creates a page, fetches material data, draws images and text.
The page URL is sent to a Puppeteer service, which launches a browser instance, visits the page, and captures a screenshot.
2.2 Problems with Front‑End Generation
After launch, the front‑end approach often timed out (average 2‑3 s, sometimes >5 s). With simple 12‑image compositions the timeout already occurred; with 600+ images for detailed pages the issue worsened.
Analysis showed the Puppeteer screenshot step consumes most time: allocating resources, launching a browser process, loading the page, rendering and capturing.
2.3 Improvement – Move Generation to the Back End
To eliminate the performance bottleneck we evaluated generating images on the back end using Java AWT APIs, avoiding the overhead of launching a browser.
Two criteria were measured: execution time and UI compliance. Local tests showed the back‑end solution creates the same image in about 20 ms (versus 2‑3 s front‑end) and meets UI acceptance even with 500+ images.
Front‑end generated image:
Back‑end generated image:
3 Back‑End Image Generation Implementation
The target large image consists of a modular layout: a basic information module followed by a skin‑category module, which itself contains a title and individual skin units.
Key operations include drawing images, text, scaling, and translating. Java’s BufferedImage and Graphics2D are the core classes.
3.1 Java Image‑Processing API
BufferedImage acts as a canvas storing pixel data; Graphics2D provides drawing capabilities.
3.1.1 Creating BufferedImage
/** Read local file */
BufferedImage imageFromFile = ImageIO.read(new File("local_path"));
/** Read image from URL */
BufferedImage imageFromUrl = ImageIO.read(new URL("url_path"));
/** Create blank canvas */
BufferedImage combinedImage = new BufferedImage(100, 200, BufferedImage.TYPE_INT_RGB);3.1.2 Drawing Images and Text
public static void main(String[] args) throws IOException {
BufferedImage backGroundImage = ImageIO.read(new File("input_path"));
BufferedImage combinedImage = new BufferedImage(backGroundImage.getWidth(),
backGroundImage.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = combinedImage.createGraphics();
try {
graphics.drawImage(backGroundImage, 0, 0, null);
graphics.setFont(new Font("Microsoft YaHei", Font.BOLD, 20));
graphics.setColor(Color.WHITE);
graphics.drawString("text content", 20, 20);
} finally {
graphics.dispose();
}
File output = new File("output_path");
ImageIO.write(combinedImage, "jpg", output);
}3.1.3 Image Scaling
public static void main(String[] args) throws IOException {
BufferedImage originImage = ImageIO.read(new File("file_path"));
BufferedImage scaleImage = getScaleImage(originImage, 0.7, 0.7);
File output = new File("output_path");
ImageIO.write(scaleImage, "jpg", output);
}
public static BufferedImage getScaleImage(BufferedImage originImage,
double scaleFactorWidth, double scaleFactorHeight) {
if (originImage == null || scaleFactorWidth <= 0 || scaleFactorHeight <= 0) {
return originImage;
}
int scaledWidth = (int) (originImage.getWidth() * scaleFactorWidth);
int scaledHeight = (int) (originImage.getHeight() * scaleFactorHeight);
BufferedImage scaledImage = new BufferedImage(scaledWidth, scaledHeight,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = scaledImage.createGraphics();
try {
g2d.drawImage(originImage, 0, 0, scaledWidth, scaledHeight, null);
} finally {
g2d.dispose();
}
return scaledImage;
}3.2 Basic Information Section
The original UI mockup is drawn onto the canvas, then text is placed at specific coordinates.
Resulting image:
3.3 Modular Skin‑Category Assembly
Each skin unit consists of a badge, background image, text, and overlay. The rendering steps are:
Draw the skin background.
Draw the overlay on top.
Draw the badge at the designated position.
Draw the text.
Static small images are cached locally to avoid repeated network requests.
3.3.1 Drawing Titles
Title images are drawn directly to the target position, skipping font calculations.
Title example:
3.3.2 Generating Skin Units
Each unit combines four elements; the combined units are placed according to configured coordinates.
Unit example:
3.3.3 Assembling Category Modules
All generated skin units are laid out to form the category image.
Category example:
3.3.4 Stretching Background and Border
The background adapts to the total height of the skin images for each account.
Background example:
3.3.5 Stitching Category Images into the Final Large Image
Repeating the steps for each category produces the final composite.
Final composite example:
4 Summary
4.1 Performance Gains
Average generation time dropped from 2‑3 s (front‑end + Puppeteer) to milliseconds for simple images and around 2 s for extremely complex images with 500+ skins, eliminating timeout issues.
4.2 User Experience
Users now receive core account information instantly while browsing product listings.
4.3 Extensibility and Maintainability
Modularizing image composition into reusable services and configuring layouts per game decouples business logic from rendering, greatly speeding up onboarding of new game categories.
The solution is already deployed for Honor of Kings, Genshin Impact, Naruto, and Gunfire Games.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Zhuanzhuan Tech
A platform for Zhuanzhuan R&D and industry peers to learn and exchange technology, regularly sharing frontline experience and cutting‑edge topics. We welcome practical discussions and sharing; contact waterystone with any questions.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
