Skip to content

fix: crop SVG export to the visible canvas - #215

Closed
MiMoHo wants to merge 1 commit into
FossifyOrg:mainfrom
MiMoHo:fix/issue-26
Closed

fix: crop SVG export to the visible canvas#215
MiMoHo wants to merge 1 commit into
FossifyOrg:mainfrom
MiMoHo:fix/issue-26

Conversation

@MiMoHo

@MiMoHo MiMoHo commented Jul 3, 2026

Copy link
Copy Markdown

Type of change(s)

  • Bug fix

What changed and why

The raster (PNG/JPG) export path goes through MyCanvas.getBitmap(), which draws the canvas via onDraw() and therefore bakes in the current pan/zoom (canvas.translate(mPosX, mPosY) + canvas.scale(mScaleFactor, mScaleFactor, mCenter)). The output is correctly cropped to what is visible at save time.

The SVG export path (Svg.saveToOutputStream -> writeSvg) instead wrote each path's raw recorded coordinates with the viewport width/height and no transform. As a result a saved SVG reflected the launch-time coordinate space rather than the currently visible viewport, so it appeared wrongly cropped after the canvas had been moved or zoomed, exactly as the reporter describes.

This change reproduces, in the SVG writer, the same pan/zoom matrix that onDraw applies (scale-about-center then translate) and bakes it into every exported coordinate via Matrix.mapPoints. Stroke widths are multiplied by the current scale factor to match the raster output (where canvas.scale also scales stroke widths). The <path> elements stay direct children of <svg> (flat structure), so the app's own parseSvg loader is unchanged and re-opening a saved SVG round-trips exactly. The background <rect> is intentionally left untransformed since it fills the whole viewport in both raster and SVG. When there is no pan and scaleFactor == 1, the matrix is identity and the stroke-width multiplier is 1, so the output is byte-identical to before (backward compatible).

Tests performed

  • detekt, lint, unit tests and the build all pass locally (CI-equivalent).
  • Source-verified: SVG export now applies the same canvas Matrix transform to each drawn action's coordinates that the raster (PNG/JPG) export already uses, so the exported SVG is cropped to the visible/moved canvas instead of the initial bounds.
  • Note: verified via CI + code review; the draw-move-export flow was not scripted end-to-end.

Closes the following issue(s)

Checklist

  • I read the contribution guidelines.
  • I manually tested my changes on device/emulator (verified via CI + source review; see Tests performed).
  • I updated the "Unreleased" section in CHANGELOG.md (if applicable).
  • I have self-reviewed my pull request (no typos, formatting errors, etc.).
  • I understand every change in this pull request.

Coded with Opus 4.8 ultracode.

The raster (PNG/JPG) export goes through MyCanvas.getBitmap(), which
draws via onDraw() and therefore bakes in the current pan/zoom
(canvas.translate(mPosX, mPosY) + canvas.scale(mScaleFactor, ..., mCenter)).
The SVG export, however, wrote each path's raw recorded coordinates with
no transform, so a saved SVG reflected the launch-time viewport instead
of what was visible, appearing wrongly cropped after the canvas was
moved or zoomed.

Reproduce the same pan/zoom matrix that onDraw applies and bake it into
every exported coordinate, and scale stroke-width by the current scale
factor to match the raster output. The SVG structure stays flat so the
existing loader round-trips unchanged, and with no pan and scaleFactor==1
the matrix is identity, keeping output byte-identical to before.

Closes FossifyOrg#26
@MiMoHo
MiMoHo requested a review from naveensingh as a code owner July 3, 2026 21:44
@MiMoHo MiMoHo closed this Jul 3, 2026
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.

SVG export does not crop correctly

1 participant