Skip to content

feat: export at the resolution of the background image, and restore the size of the canvas - #216

Merged
tbolis merged 3 commits into
release/1.2.0from
feature/original-resolution
Nov 10, 2026
Merged

tbolis merged 3 commits into
release/1.2.0from
feature/original-resolution

Conversation

@tbolis

@tbolis tbolis commented Nov 10, 2026

Copy link
Copy Markdown
Owner

Refs #75 (not closed by this: the issue can be answered once it is released).

Problem

The canvas has the size of its container, and toDataURL() draws at that size. A photo which is shown smaller than it is loses pixels in the exported file, and drawing on an exported image again loses more each time.

Changes

  • toDataURL({ multiplier: "original" }): one pixel of the picture for each pixel of the background image, at any size of the canvas. It is 1 without a background image. An image scaled differently in the two directions is exported at the larger scale, so no pixel of it is lost.
  • getOriginalSize(): the size of the background image in pixels, or undefined without one (or while it loads). New type Types.SketchSize.
  • Showcase: an Original size button in the Canvas tab gives the canvas the size of the background image (the zoom is taken back first), and Download PNG and JSON has the resolution of the image. The canvas size sliders follow a size over 1000.
  • Fix: autoresize rounded its scale factors to two decimals, so the drawing and the background image were a little off their size, the error added up with every resize, and a canvas could not go back to the size it had. The factors are exact now. This changes an existing behavior, so it is in the CHANGELOG under Fixed.
  • README section "Keeping the resolution of an image", the method table, and the CHANGELOG.

Verification

  • 13 new tests in SketchField.spec.tsx: the multiplier (scaled, zoomed, smaller than the canvas, different scales in the two directions, flipped, no image, other options kept), getOriginalSize(), and the resize (several sizes and back, the size of the image through layout and through the width and height properties). The two resize tests fail with the rounding put back.
  • Whole suite: 463 passed on React 19 and on React 18. Format, lint, typecheck and yarn build pass.
  • In headless Chrome on the built showcase, with the 1539 x 673 sample image: Original size makes the canvas 1539 x 673 with the drawing in place, and the download is 1539 x 673. Fitted to a 1400 x 813 window, the download is 1539 x 893 (the width of the image).

Notes

  • The tests use jsdom with a canvas mock, so they check the multiplier and the scales which are passed to fabric, not the pixels of the file. The pixels were checked in Chrome only.
  • The showcase has no tests, so the button and the download are covered by the Chrome check only.
  • Browsers limit the area of a canvas (a phone about 16 million pixels, for example), and an export over the limit is empty. The README says so, there is no fallback.
  • feat: add the bucket fill tool #214 and fix: undo and redo of a move put the objects back where they were #215 also add a ## 1.2.0 heading to CHANGELOG.md, and feat: add the bucket fill tool #214 changes showcase files, so the second and third to merge need a conflict resolution.

…he size of the canvas

toDataURL({ multiplier: "original" }) draws the drawing with one pixel of the
picture for each pixel of the background image, at any size of the canvas, so a
drawing on a photo does not lose the resolution of the photo. getOriginalSize()
returns the size of that image, and the showcase has an Original size button
which gives the canvas that size, and downloads at that resolution.

The factors which scale the drawing when the canvas is resized were rounded to
two decimals, so the drawing was a little off its size, the error added up with
every resize, and a canvas could not go back to the size it had. They are exact
now.
Remove the comment above the resize factors, and replace the HTML table of the
options in the documentation of toDataURL with a reference to DataUrlOptions,
which describes each of them.
@tbolis
tbolis merged commit da1d76b into release/1.2.0 Nov 10, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant