|
|
|
|
@@ -33,7 +33,7 @@ import marketing.heyday.hartmann.fotodocumentation.core.model.Picture;
|
|
|
|
|
*
|
|
|
|
|
* created: 2 Feb 2026
|
|
|
|
|
*/
|
|
|
|
|
@java.lang.SuppressWarnings("java:S818")
|
|
|
|
|
@SuppressWarnings({"java:S818", "squid:S818", "squid:S109"})
|
|
|
|
|
public class PdfUtils {
|
|
|
|
|
private static final Log LOG = LogFactory.getLog(PdfUtils.class);
|
|
|
|
|
|
|
|
|
|
@@ -51,10 +51,10 @@ public class PdfUtils {
|
|
|
|
|
private static final Color COLOR_RED = new Color(244, 67, 54);
|
|
|
|
|
private static final Color COLOR_HIGHLIGHT = new Color(41, 98, 175);
|
|
|
|
|
|
|
|
|
|
private static final float PAGE_MARGIN = 40f;
|
|
|
|
|
private static final float CIRCLE_RADIUS = 8f;
|
|
|
|
|
private static final float HIGHLIGHT_RADIUS = 12f;
|
|
|
|
|
private static final float CIRCLE_SPACING = 30f;
|
|
|
|
|
private static final float PAGE_MARGIN = 40F;
|
|
|
|
|
private static final float CIRCLE_RADIUS = 8F;
|
|
|
|
|
private static final float HIGHLIGHT_RADIUS = 12F;
|
|
|
|
|
private static final float CIRCLE_SPACING = 30F;
|
|
|
|
|
|
|
|
|
|
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd.MM.yyyy HH:mm", Locale.GERMAN);
|
|
|
|
|
|
|
|
|
|
@@ -71,10 +71,10 @@ public class PdfUtils {
|
|
|
|
|
float pageWidth = page.getMediaBox().getWidth();
|
|
|
|
|
float pageHeight = page.getMediaBox().getHeight();
|
|
|
|
|
float contentWidth = pageWidth - 2 * PAGE_MARGIN;
|
|
|
|
|
float halfWidth = contentWidth / 2f;
|
|
|
|
|
float halfWidth = contentWidth / 2F;
|
|
|
|
|
|
|
|
|
|
try (PDPageContentStream cs = new PDPageContentStream(document, page)) {
|
|
|
|
|
float yPosition = pageHeight - 50f;
|
|
|
|
|
float yPosition = pageHeight - 50F;
|
|
|
|
|
|
|
|
|
|
// Customer name on the first page
|
|
|
|
|
if (firstPage) {
|
|
|
|
|
@@ -84,15 +84,15 @@ public class PdfUtils {
|
|
|
|
|
cs.newLineAtOffset(PAGE_MARGIN, yPosition);
|
|
|
|
|
cs.showText(nullSafe(customer.getName()));
|
|
|
|
|
cs.endText();
|
|
|
|
|
yPosition -= 60f;
|
|
|
|
|
yPosition -= 60F;
|
|
|
|
|
firstPage = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Left side: image (50% of content width)
|
|
|
|
|
float imageX = PAGE_MARGIN;
|
|
|
|
|
float imageY = yPosition;
|
|
|
|
|
float imageMaxWidth = halfWidth - 10f;
|
|
|
|
|
float imageMaxHeight = pageHeight - 2 * PAGE_MARGIN - 40f;
|
|
|
|
|
float imageMaxWidth = halfWidth - 10F;
|
|
|
|
|
float imageMaxHeight = pageHeight - 2 * PAGE_MARGIN - 40F;
|
|
|
|
|
|
|
|
|
|
if (picture.getImage() != null) {
|
|
|
|
|
try {
|
|
|
|
|
@@ -110,8 +110,8 @@ public class PdfUtils {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Right side: metadata (top-aligned with image)
|
|
|
|
|
float rightX = PAGE_MARGIN + halfWidth + 10f;
|
|
|
|
|
float rightY = imageY - 32f;
|
|
|
|
|
float rightX = PAGE_MARGIN + halfWidth + 10F;
|
|
|
|
|
float rightY = imageY - 32F;
|
|
|
|
|
|
|
|
|
|
// Date (no label, bold, size 44)
|
|
|
|
|
String dateStr = picture.getPictureDate() != null ? DATE_FORMAT.format(picture.getPictureDate()) + " UHR": "";
|
|
|
|
|
@@ -121,27 +121,27 @@ public class PdfUtils {
|
|
|
|
|
cs.newLineAtOffset(rightX, rightY);
|
|
|
|
|
cs.showText(dateStr);
|
|
|
|
|
cs.endText();
|
|
|
|
|
rightY -= 54f;
|
|
|
|
|
rightY -= 54F;
|
|
|
|
|
|
|
|
|
|
// Customer number
|
|
|
|
|
float kundenNummerY = rightY;
|
|
|
|
|
rightY = drawLabel(cs, fontBold, "KUNDENNUMMER", rightX, rightY);
|
|
|
|
|
rightY = drawValue(cs, fontRegular, nullSafe(customer.getCustomerNumber()), rightX, rightY);
|
|
|
|
|
rightY -= 10f;
|
|
|
|
|
rightY -= 10F;
|
|
|
|
|
|
|
|
|
|
// Evaluation card with circles
|
|
|
|
|
float circlesX = rightX + 140f;
|
|
|
|
|
float circlesX = rightX + 140F;
|
|
|
|
|
drawEvaluationCard(cs, fontBold, circlesX, kundenNummerY, picture.getEvaluation());
|
|
|
|
|
|
|
|
|
|
// ZIP
|
|
|
|
|
rightY = drawLabel(cs, fontBold, "PLZ", rightX, rightY);
|
|
|
|
|
rightY = drawValue(cs, fontRegular, nullSafe(customer.getZip()), rightX, rightY);
|
|
|
|
|
rightY -= 10f;
|
|
|
|
|
rightY -= 10F;
|
|
|
|
|
|
|
|
|
|
// City
|
|
|
|
|
rightY = drawLabel(cs, fontBold, "ORT", rightX, rightY);
|
|
|
|
|
rightY = drawValue(cs, fontRegular, nullSafe(customer.getCity()), rightX, rightY);
|
|
|
|
|
rightY -= 10f;
|
|
|
|
|
rightY -= 10F;
|
|
|
|
|
|
|
|
|
|
// Comment
|
|
|
|
|
rightY = drawLabel(cs, fontBold, "KOMMENTAR", rightX, rightY);
|
|
|
|
|
@@ -177,7 +177,7 @@ public class PdfUtils {
|
|
|
|
|
cs.newLineAtOffset(x, y);
|
|
|
|
|
cs.showText(label);
|
|
|
|
|
cs.endText();
|
|
|
|
|
return y - 14f;
|
|
|
|
|
return y - 14F;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private float drawValue(PDPageContentStream cs, PDFont font, String value, float x, float y) throws IOException {
|
|
|
|
|
@@ -187,7 +187,7 @@ public class PdfUtils {
|
|
|
|
|
cs.newLineAtOffset(x, y);
|
|
|
|
|
cs.showText(value);
|
|
|
|
|
cs.endText();
|
|
|
|
|
return y - 14f;
|
|
|
|
|
return y - 14F;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void drawWrappedText(PDPageContentStream cs, PDFont font, String text, float x, float y, float maxWidth) throws IOException {
|
|
|
|
|
@@ -203,13 +203,13 @@ public class PdfUtils {
|
|
|
|
|
|
|
|
|
|
for (String word : words) {
|
|
|
|
|
String testLine = line.isEmpty() ? word : line + " " + word;
|
|
|
|
|
float textWidth = font.getStringWidth(testLine) / 1000f * 10f;
|
|
|
|
|
float textWidth = font.getStringWidth(testLine) / 1000F * 10F;
|
|
|
|
|
if (textWidth > maxWidth && !line.isEmpty()) {
|
|
|
|
|
cs.beginText();
|
|
|
|
|
cs.newLineAtOffset(x, currentY);
|
|
|
|
|
cs.showText(line.toString());
|
|
|
|
|
cs.endText();
|
|
|
|
|
currentY -= 14f;
|
|
|
|
|
currentY -= 14F;
|
|
|
|
|
line = new StringBuilder(word);
|
|
|
|
|
} else {
|
|
|
|
|
line = new StringBuilder(testLine);
|
|
|
|
|
@@ -227,10 +227,10 @@ public class PdfUtils {
|
|
|
|
|
int eval = evaluation != null ? evaluation : 0;
|
|
|
|
|
Color[] colors = { COLOR_GREEN, COLOR_YELLOW, COLOR_RED };
|
|
|
|
|
|
|
|
|
|
float cardPadding = 10f;
|
|
|
|
|
float cardPadding = 10F;
|
|
|
|
|
float cardWidth = 2 * CIRCLE_SPACING + 2 * HIGHLIGHT_RADIUS + 2 * cardPadding;
|
|
|
|
|
float labelHeight = 14f;
|
|
|
|
|
float cardHeight = labelHeight + 2 * HIGHLIGHT_RADIUS + 2 * cardPadding + 4f;
|
|
|
|
|
float labelHeight = 14F;
|
|
|
|
|
float cardHeight = labelHeight + 2 * HIGHLIGHT_RADIUS + 2 * cardPadding + 4F;
|
|
|
|
|
float cardX = x - HIGHLIGHT_RADIUS - cardPadding;
|
|
|
|
|
float cardY = y - cardHeight + cardPadding;
|
|
|
|
|
|
|
|
|
|
@@ -238,7 +238,7 @@ public class PdfUtils {
|
|
|
|
|
cs.setStrokingColor(new Color(0xDD, 0xDD, 0xDD));
|
|
|
|
|
cs.setNonStrokingColor(new Color(0xF8, 0xF8, 0xF8));
|
|
|
|
|
cs.setLineWidth(1f);
|
|
|
|
|
drawRoundedRect(cs, cardX, cardY, cardWidth, cardHeight, 6f);
|
|
|
|
|
drawRoundedRect(cs, cardX, cardY, cardWidth, cardHeight, 6F);
|
|
|
|
|
cs.fillAndStroke();
|
|
|
|
|
|
|
|
|
|
// Draw "BEWERTUNG" label above circles
|
|
|
|
|
@@ -252,14 +252,14 @@ public class PdfUtils {
|
|
|
|
|
cs.endText();
|
|
|
|
|
|
|
|
|
|
// Draw circles below the label
|
|
|
|
|
float circleY = labelY - cardPadding - HIGHLIGHT_RADIUS - 2f;
|
|
|
|
|
float circleY = labelY - cardPadding - HIGHLIGHT_RADIUS - 2F;
|
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
|
float cx = x + i * CIRCLE_SPACING;
|
|
|
|
|
|
|
|
|
|
// Highlight circle if this matches the evaluation (1=green, 2=yellow, 3=red)
|
|
|
|
|
if (eval == i + 1) {
|
|
|
|
|
cs.setStrokingColor(COLOR_HIGHLIGHT);
|
|
|
|
|
cs.setLineWidth(2f);
|
|
|
|
|
cs.setLineWidth(2F);
|
|
|
|
|
drawCircle(cs, cx, circleY, HIGHLIGHT_RADIUS);
|
|
|
|
|
cs.stroke();
|
|
|
|
|
}
|
|
|
|
|
|