feat: add high-DPI scale to chart image downloads#39285
feat: add high-DPI scale to chart image downloads#39285eschutho wants to merge 3 commits intoapache:masterfrom
Conversation
Code Review Agent Run #9a4123Actionable Suggestions - 0Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
| import { addWarningToast } from 'src/components/MessageToasts/actions'; | ||
|
|
||
| const IMAGE_DOWNLOAD_QUALITY = 0.95; | ||
| const IMAGE_DOWNLOAD_SCALE = window.devicePixelRatio || 2; |
There was a problem hiding this comment.
🟠 Architect Review — HIGH
The IMAGE_DOWNLOAD_SCALE constant uses window.devicePixelRatio || 2, so on standard displays where devicePixelRatio is 1 (truthy) the scale remains 1× and does not satisfy the stated requirement that all users get at least 2× output resolution.
Suggestion: Change the scale computation to enforce a 2× lower bound, for example const IMAGE_DOWNLOAD_SCALE = Math.max(window.devicePixelRatio || 1, 2);, so both standard and HiDPI displays meet the intended minimum resolution.
| import { addWarningToast } from 'src/components/MessageToasts/actions'; | ||
|
|
||
| const IMAGE_DOWNLOAD_QUALITY = 0.95; | ||
| const IMAGE_DOWNLOAD_SCALE = window.devicePixelRatio || 2; |
There was a problem hiding this comment.
Suggestion: The scale calculation does not enforce the intended minimum 2× output: when devicePixelRatio is 1 (standard displays), the current expression resolves to 1, so image downloads remain low-resolution. Use a max check so scale is never below 2. [logic error]
Severity Level: Major ⚠️
- ⚠️ Dashboard 'Download as image' exports low-resolution JPEGs on 1×.
- ⚠️ Per-chart image downloads lower resolution than promised 2×.
- ⚠️ PR promise of minimum 2× scale not met.| const IMAGE_DOWNLOAD_SCALE = window.devicePixelRatio || 2; | |
| const IMAGE_DOWNLOAD_SCALE = Math.max(window.devicePixelRatio || 1, 2); |
Steps of Reproduction ✅
1. Open any Superset dashboard in a desktop browser on a standard display where
`window.devicePixelRatio === 1` (e.g., 100% zoom on many non-HiDPI monitors).
2. Trigger a dashboard-wide image download from the main menu: this calls
`useDownloadMenuItems` in
`superset-frontend/src/dashboard/components/menu/DownloadMenuItems/index.tsx:43-48`, whose
`onDownloadImage` handler at lines 75-77 invokes
`downloadAsImage(SCREENSHOT_NODE_SELECTOR, dashboardTitle, true)(e)`.
3. Alternatively, trigger a per-chart image download from a slice header menu: this
executes the `MenuKeys.DownloadAsImage` case in
`superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx:49-71`, which
calls `downloadAsImage(getScreenshotNodeSelector(props.slice.slice_id),
props.slice.slice_name, true, theme)(domEvent)`.
4. In both flows, `downloadAsImage` is the default export from
`superset-frontend/src/utils/downloadAsImage.tsx:266-324`; inside this file
`IMAGE_DOWNLOAD_SCALE` is defined at line 28 as `const IMAGE_DOWNLOAD_SCALE =
window.devicePixelRatio || 2;` and passed to `domToImage.toJpeg` at lines 299-304. On a
standard display (`devicePixelRatio === 1`), this expression evaluates to `1` (since `1`
is truthy and the `|| 2` fallback is not used), so the exported JPEG uses a scale of 1×
instead of the PR's intended minimum 2×, producing lower-resolution images than specified.Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** superset-frontend/src/utils/downloadAsImage.tsx
**Line:** 28:28
**Comment:**
*Logic Error: The scale calculation does not enforce the intended minimum 2× output: when `devicePixelRatio` is `1` (standard displays), the current expression resolves to `1`, so image downloads remain low-resolution. Use a max check so scale is never below 2.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.|
Yes, the suggestion is valid — it adjusts the fallback to 1 and applies Math.max to guarantee a minimum scale of 2, addressing the issue where standard displays (devicePixelRatio=1) would otherwise get 1x resolution. |
Add IMAGE_DOWNLOAD_SCALE constant using window.devicePixelRatio (|| 2 fallback) and pass it as the `scale` option to both dom-to-image-more toJpeg calls. This doubles image resolution for retina displays and ensures a minimum 2x output for all users. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
✅ Deploy Preview for superset-docs-preview ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
a8f82f0 to
00ab3a3
Compare
Change IMAGE_DOWNLOAD_SCALE from `window.devicePixelRatio || 2` to `Math.max(window.devicePixelRatio || 1, 2)` so that standard displays (devicePixelRatio=1) also get 2x output. The previous expression evaluated to 1 on standard displays since 1 is truthy. Add tests covering the standard display (dpr=1→2) and zero (dpr=0→2) cases, and rename the prior fallback test accordingly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
🎪 Showtime deployed environment on GHA for fc24d4b • Environment: http://35.89.121.178:8080 (admin/admin) |
- Run prettier on downloadAsImage.tsx to fix pre-commit CI failure - Replace isolateModulesAsync scale tests (jest.mock inside async callbacks is hoisted and doesn't capture scale) with simpler capturedScale pattern using mockImplementation, and a pure formula test verifying Math.max(dpr || 1, 2) behaviour Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Code Review Agent Run #4253c3Actionable Suggestions - 0Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #39285 +/- ##
=======================================
Coverage 64.42% 64.42%
=======================================
Files 2553 2553
Lines 132588 132589 +1
Branches 30758 30759 +1
=======================================
+ Hits 85416 85417 +1
Misses 45686 45686
Partials 1486 1486
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Summary
IMAGE_DOWNLOAD_SCALE = window.devicePixelRatio || 2constant indownloadAsImage.tsxscaleto bothdomToImage.toJpeg()calls (regular and ag-grid paths)Why
The
dom-to-image-morelibrary defaults to 1× (CSS pixels only) when noscaleis provided. Downloaded chart images were lower resolution than what's visible on screen, especially on retina/HiDPI displays.Test plan