Merged
Conversation
added 11 commits
March 11, 2026 15:21
watermark.service.ts was sending String(1) instead of String(opts.opacity) for the 'opacity' FormData field. The opacity slider in the UI had no effect — every request went to the backend with opacity=1 regardless of the setting. Changed to String(opts.opacity ?? 0.5) to pass the actual value.
buildTextTileSvg and buildLogoTileSvg used `dto.rotate ?? -30` as fallback for the pattern rotation. When a user set rotate=0 explicitly, the tile would still be rendered at -30 degrees — inconsistent with single-placement mode which correctly used `dto.rotate ?? 0`. Changed both tile builders to use `dto.rotate ?? 0` so the default is no rotation, matching user expectations and the single-placement behaviour.
Backend (watermark.controller.ts):
FileFieldsInterceptor now has limits: { fileSize: 25 * 1024 * 1024 }.
Large uploads are rejected by Multer before Sharp ever touches them,
avoiding memory exhaustion from large in-memory buffers.
Frontend (watermark-uploader.component.ts/.html):
setMainFile() and setLogoFile() now check file.size > MAX_FILE_BYTES
(25 MB) before accepting the file. Shows an inline alert under the
respective dropzone. formatBytes() helper formats the error message.
Prevents the confusing Multer 413/500 response from reaching the user.
…imited
Sharp image processing is CPU-intensive. Without @TierRateLimit() the
/watermark/apply endpoint was completely unguarded against request floods.
watermark.controller.ts: @TierRateLimit() added to POST apply.
watermark.module.ts:
- ApiKeyModule imported (required for ApiKeyGuard resolution)
- MulterModule.register limit raised from 15 MB to 25 MB to align with
the FileFieldsInterceptor limits added in the previous commit.
The previous implementation resolved the default logo path relative to process.cwd() which is the repo root in development but the dist output dir in production Docker containers — making the path wrong in both cases. Replaced with __dirname-relative paths: __dirname/assets/watermark/default-logo.png (dist layout) __dirname/../assets/watermark/default-logo.png (fallback) __dirname always points to the directory containing the compiled JS file, which is consistent across local and container environments.
When the backend returns a 400/413/500, Angular's responseType:'blob' still delivers a Blob to the next() handler instead of routing to error(). The component would then call URL.createObjectURL() on a JSON payload and display a broken image with no error message. watermark.service.ts now wraps the HTTP call in an Observable that inspects the response blob's content-type. If it is not image/* the blob is read as text, parsed as JSON, and re-thrown as a proper Error so the component's catchError / error handler can display the message to the user.
…inates
The drag overlay was positioned in CSS pixels (relative to the rendered
preview div) but the x,y values were sent directly to the backend as
image pixel coordinates. A 4000x3000 image rendered at 800x300 CSS px
would produce a 5x offset between where the overlay appeared and where
the watermark was actually placed.
Changes:
watermark-uploader.component.ts:
- Added @ViewChild previewImg to access the rendered <img> element
- naturalWidth/naturalHeight tracked via onImageLoad() handler
- scaleX / scaleY computed as naturalSize / renderedSize
- startDrag: converts stored image-px coords → CSS px for drag offset
- onPointerMove: converts CSS-px drag result → image-px for form/backend
watermark-uploader.component.html:
- #previewImg template ref + (load)=onImageLoad added to <img>
- Overlay left/top now divided by scaleX/scaleY so the draggable dot
stays visually in sync with where the backend will place the mark
…English All German strings in watermark.controller.ts and apply-watermark.dto.ts replaced with English equivalents to be consistent with the rest of the API documentation. Affects Swagger UI display and BadRequestException messages.
Adding @TierRateLimit() brought ApiKeyGuard into the module, which requires
TypeORM / DataSource. The test module was importing WatermarkModule directly
and had no database context, causing the suite to fail.
Rewrote the spec to wire only what it needs:
- MulterModule.register (memory storage)
- WatermarkController + WatermarkService directly
- ApiKeyGuard overridden with { canActivate: () => true }
286/286 tests pass.
…osite error
Sharp requires that composite overlays are never larger than the base image
and that top/left coordinates keep the overlay fully within bounds.
Two failure modes fixed:
1. Logo scale=1 (frontend default) or a logo larger than the input image:
targetWidth was uncapped, producing an overlay wider than the base image.
Fix: cap targetWidth to min(calculated, imageWidth) before scaling.
2. After anchor/position calculation top or left could be negative or push
the overlay past the image edge (e.g. margin=0, bottom-right on a logo
that fills the full width).
Fix: clamp top to [0, imageH - wmH]
and left to [0, imageW - wmW] after resolving position.
scaleLogoToWidth now accepts an optional maxHeight and passes it to
Sharp.resize() with withoutEnlargement:true so the logo is never upscaled.
Also translated the two remaining German BadRequestException messages.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.