update backend to support rotating and resizing about the centerpoint

This commit is contained in:
EthanHealy01 2025-09-17 01:08:23 +01:00
parent b94154dea7
commit 6cdbf55264
2 changed files with 45 additions and 18 deletions

View File

@ -239,34 +239,54 @@ public class StampController {
PDRectangle pageSize = page.getMediaBox(); PDRectangle pageSize = page.getMediaBox();
float x, y; float x, y;
if (overrideX >= 0 && overrideY >= 0) {
// Use override values if provided
x = overrideX;
y = overrideY;
} else {
x = calculatePositionX(pageSize, position, fontSize, font, fontSize, stampText, margin);
y =
calculatePositionY(
pageSize, position, calculateTextCapHeight(font, fontSize), margin);
}
// Split the stampText into multiple lines // Split the stampText into multiple lines
String[] lines = stampText.split("\\\\n"); String[] lines = stampText.split("\\r?\\n|\\\\n");
// Calculate dynamic line height based on font ascent and descent // Calculate dynamic line height based on font ascent and descent
float ascent = font.getFontDescriptor().getAscent(); float ascent = font.getFontDescriptor().getAscent();
float descent = font.getFontDescriptor().getDescent(); float descent = font.getFontDescriptor().getDescent();
float lineHeight = ((ascent - descent) / 1000) * fontSize; float lineHeight = ((ascent - descent) / 1000) * fontSize;
// Compute a single pivot for the entire text block to avoid line-by-line wobble
float capHeight = calculateTextCapHeight(font, fontSize);
float blockHeight = Math.max(lineHeight, lineHeight * Math.max(1, lines.length));
float maxWidth = 0f;
for (String ln : lines) {
maxWidth = Math.max(maxWidth, calculateTextWidth(ln, font, fontSize));
}
if (overrideX >= 0 && overrideY >= 0) {
// Use override values if provided
x = overrideX;
y = overrideY;
} else {
// Base positioning on the true multi-line block size
x = calculatePositionX(pageSize, position, maxWidth, null, 0, null, margin);
y = calculatePositionY(pageSize, position, blockHeight, margin);
}
// After anchoring the block, draw from the top line downward
float adjustedX = x;
float adjustedY = y;
float pivotX = adjustedX + maxWidth / 2f;
float pivotY = adjustedY + blockHeight / 2f;
// Apply rotation about the block center at the graphics state level
contentStream.saveGraphicsState();
contentStream.transform(Matrix.getTranslateInstance(pivotX, pivotY));
contentStream.transform(Matrix.getRotateInstance(Math.toRadians(rotation), 0, 0));
contentStream.transform(Matrix.getTranslateInstance(-pivotX, -pivotY));
contentStream.beginText(); contentStream.beginText();
for (int i = 0; i < lines.length; i++) { for (int i = 0; i < lines.length; i++) {
String line = lines[i]; String line = lines[i];
// Set the text matrix for each line with rotation // Start from top line: yTop = adjustedY + blockHeight - capHeight
contentStream.setTextMatrix( float yLine = adjustedY + blockHeight - capHeight - (i * lineHeight);
Matrix.getRotateInstance(Math.toRadians(rotation), x, y - (i * lineHeight))); contentStream.setTextMatrix(Matrix.getTranslateInstance(adjustedX, yLine));
contentStream.showText(line); contentStream.showText(line);
} }
contentStream.endText(); contentStream.endText();
contentStream.restoreGraphicsState();
} }
private void addImageStamp( private void addImageStamp(
@ -310,9 +330,17 @@ public class StampController {
} }
contentStream.saveGraphicsState(); contentStream.saveGraphicsState();
contentStream.transform(Matrix.getTranslateInstance(x, y)); // Rotate and scale about the center of the image
float centerX = x + (desiredPhysicalWidth / 2f);
float centerY = y + (desiredPhysicalHeight / 2f);
contentStream.transform(Matrix.getTranslateInstance(centerX, centerY));
contentStream.transform(Matrix.getRotateInstance(Math.toRadians(rotation), 0, 0)); contentStream.transform(Matrix.getRotateInstance(Math.toRadians(rotation), 0, 0));
contentStream.drawImage(xobject, 0, 0, desiredPhysicalWidth, desiredPhysicalHeight); contentStream.drawImage(
xobject,
-desiredPhysicalWidth / 2f,
-desiredPhysicalHeight / 2f,
desiredPhysicalWidth,
desiredPhysicalHeight);
contentStream.restoreGraphicsState(); contentStream.restoreGraphicsState();
} }

View File

@ -11,7 +11,6 @@ import StampPreview from "../components/tools/addStamp/StampPreview";
import LocalIcon from "../components/shared/LocalIcon"; import LocalIcon from "../components/shared/LocalIcon";
import styles from "../components/tools/addStamp/StampPreview.module.css"; import styles from "../components/tools/addStamp/StampPreview.module.css";
import { Tooltip } from "../components/shared/Tooltip"; import { Tooltip } from "../components/shared/Tooltip";
import FitText from "../components/shared/FitText";
import ButtonSelector from "../components/shared/ButtonSelector"; import ButtonSelector from "../components/shared/ButtonSelector";
const AddStamp = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => { const AddStamp = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {