User signal
A product walkthrough reported that generated images cannot be downloaded, with QR Code Generator called out as an example.
Original feedback: 生成的图片无法下载 比如二维码.
Current implementation to inspect
QR Code Generator renders to a canvas and stores canvas.toDataURL("image/png") in component state. The PNG action calls downloadDataUrl(dataUrl, "qr-code.png"). SVG uses buildQrSvg(...) and downloadSvg(...).
The browser helpers currently create a detached <a>, set href and download, then call a.click(). For SVG, the object URL is revoked immediately after click().
Relevant files:
src/features/tools/qr-code-generator/page.tsx
src/features/tools/qr-code-generator/browser-actions.ts
Suspected cause
Some browsers are stricter about programmatic downloads:
- a detached anchor click can be ignored;
- object URLs may be revoked too early before the download is consumed;
canvas.toDataURL can be less reliable than canvas.toBlob for large images or browser-specific download handling;
- the UI currently shows success after calling the helper, even if the browser blocked or ignored the download.
Recommended implementation
- Replace detached-anchor helpers with a robust
downloadBlob / downloadUrl helper:
- append the anchor to
document.body;
- set
rel="noopener" where appropriate;
- call
click() inside the user-triggered action;
- remove the anchor in
finally;
- defer
URL.revokeObjectURL(url) with setTimeout or after download initiation.
- Prefer
canvas.toBlob for PNG export; fall back to data URL only when needed.
- Return an explicit result from the download helper so the action does not announce false success.
- Add browser-level Playwright coverage using
page.waitForEvent("download") for QR PNG and SVG.
- Audit other generated-image/download tools for the same pattern.
Reproduction matrix
/en/qr-code-generator
- generate default QR;
- download PNG;
- download SVG;
- repeat after changing size/color;
- repeat with logo enabled;
- test Chrome, Edge, Safari where possible.
Acceptance criteria
- QR PNG download produces a non-empty
.png file in Chromium/Chrome.
- QR SVG download produces a non-empty
.svg file in Chromium/Chrome.
- The success toast is only shown after a download helper returns success.
- Object URLs are not revoked synchronously before the browser can consume them.
- Add focused unit tests for helper behavior and Playwright download smoke for QR export.
User signal
A product walkthrough reported that generated images cannot be downloaded, with QR Code Generator called out as an example.
Original feedback:
生成的图片无法下载 比如二维码.Current implementation to inspect
QR Code Generator renders to a canvas and stores
canvas.toDataURL("image/png")in component state. The PNG action callsdownloadDataUrl(dataUrl, "qr-code.png"). SVG usesbuildQrSvg(...)anddownloadSvg(...).The browser helpers currently create a detached
<a>, sethrefanddownload, then calla.click(). For SVG, the object URL is revoked immediately afterclick().Relevant files:
src/features/tools/qr-code-generator/page.tsxsrc/features/tools/qr-code-generator/browser-actions.tsSuspected cause
Some browsers are stricter about programmatic downloads:
canvas.toDataURLcan be less reliable thancanvas.toBlobfor large images or browser-specific download handling;Recommended implementation
downloadBlob/downloadUrlhelper:document.body;rel="noopener"where appropriate;click()inside the user-triggered action;finally;URL.revokeObjectURL(url)withsetTimeoutor after download initiation.canvas.toBlobfor PNG export; fall back to data URL only when needed.page.waitForEvent("download")for QR PNG and SVG.Reproduction matrix
/en/qr-code-generatorAcceptance criteria
.pngfile in Chromium/Chrome..svgfile in Chromium/Chrome.