Erweiterungen
This commit is contained in:
@@ -41,8 +41,19 @@ import jakarta.annotation.security.RolesAllowed;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Iterator;
|
||||
import javax.imageio.IIOImage;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageWriteParam;
|
||||
import javax.imageio.ImageWriter;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
@@ -79,6 +90,8 @@ public class MessageDetailsView extends Main implements BeforeEnterObserver {
|
||||
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm");
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("dd.MM.yyyy");
|
||||
private static final int MAX_IMAGE_FILE_SIZE = 32 * 1024 * 1024; // 32 MB aligns with Spring settings
|
||||
private static final int TARGET_IMAGE_WIDTH = 1920;
|
||||
private static final float JPEG_COMPRESSION_QUALITY = 0.8f;
|
||||
|
||||
public MessageDetailsView(AppUserService appUserService, MessageService messageService,
|
||||
SecurityService securityService, MessageBroadcaster messageBroadcaster) {
|
||||
@@ -258,8 +271,8 @@ public class MessageDetailsView extends Main implements BeforeEnterObserver {
|
||||
|
||||
upload.addSucceededListener(event -> {
|
||||
try (InputStream inputStream = buffer.getInputStream()) {
|
||||
byte[] bytes = inputStream.readAllBytes();
|
||||
if (bytes.length == 0) {
|
||||
byte[] rawBytes = inputStream.readAllBytes();
|
||||
if (rawBytes.length == 0) {
|
||||
base64Ref.set(null);
|
||||
preview.setVisible(false);
|
||||
confirmButton.setEnabled(false);
|
||||
@@ -268,13 +281,9 @@ public class MessageDetailsView extends Main implements BeforeEnterObserver {
|
||||
return;
|
||||
}
|
||||
|
||||
String base64 = Base64.getEncoder().encodeToString(bytes);
|
||||
base64Ref.set(base64);
|
||||
|
||||
String mimeType = Optional.ofNullable(event.getMIMEType()).filter(value -> !value.isBlank())
|
||||
.orElseGet(() -> detectImageMimeType(bytes));
|
||||
String dataUrl = createDataUrlFromContent(base64, mimeType);
|
||||
if (dataUrl == null) {
|
||||
String processedBase64 = processImageToJpegBase64(rawBytes);
|
||||
if (processedBase64 == null) {
|
||||
base64Ref.set(null);
|
||||
preview.setVisible(false);
|
||||
confirmButton.setEnabled(false);
|
||||
Notification.show("Das Bild konnte nicht verarbeitet werden.", 3000,
|
||||
@@ -282,6 +291,8 @@ public class MessageDetailsView extends Main implements BeforeEnterObserver {
|
||||
return;
|
||||
}
|
||||
|
||||
base64Ref.set(processedBase64);
|
||||
String dataUrl = "data:image/jpeg;base64," + processedBase64;
|
||||
preview.setSrc(dataUrl);
|
||||
preview.setVisible(true);
|
||||
confirmButton.setEnabled(true);
|
||||
@@ -517,6 +528,96 @@ public class MessageDetailsView extends Main implements BeforeEnterObserver {
|
||||
return "image/png";
|
||||
}
|
||||
|
||||
private String processImageToJpegBase64(byte[] originalBytes) {
|
||||
try {
|
||||
BufferedImage original = ImageIO.read(new ByteArrayInputStream(originalBytes));
|
||||
if (original == null) {
|
||||
log.warn("Bild konnte nicht geladen werden (ImageIO liefert null)");
|
||||
return null;
|
||||
}
|
||||
|
||||
int originalWidth = original.getWidth();
|
||||
int originalHeight = original.getHeight();
|
||||
if (originalWidth <= 0 || originalHeight <= 0) {
|
||||
log.warn("Ungültige Bildmaße: {}x{}", originalWidth, originalHeight);
|
||||
return null;
|
||||
}
|
||||
|
||||
int targetWidth = Math.min(originalWidth, TARGET_IMAGE_WIDTH);
|
||||
int targetHeight = (int) Math.round((double) targetWidth / originalWidth * originalHeight);
|
||||
if (targetHeight <= 0) {
|
||||
targetHeight = originalHeight;
|
||||
}
|
||||
|
||||
BufferedImage scaled = scaleImage(original, targetWidth, targetHeight);
|
||||
byte[] jpegBytes = encodeJpeg(scaled, JPEG_COMPRESSION_QUALITY);
|
||||
if (jpegBytes == null || jpegBytes.length == 0) {
|
||||
log.warn("JPEG-Kodierung lieferte leeres Ergebnis");
|
||||
return null;
|
||||
}
|
||||
|
||||
return Base64.getEncoder().encodeToString(jpegBytes);
|
||||
} catch (IOException ex) {
|
||||
log.error("Fehler beim Skalieren/Konvertieren des Bildes", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private BufferedImage scaleImage(BufferedImage original, int targetWidth, int targetHeight) {
|
||||
if (original.getWidth() == targetWidth && original.getHeight() == targetHeight) {
|
||||
return ensureRgbFormat(original);
|
||||
}
|
||||
|
||||
BufferedImage output = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g2d = output.createGraphics();
|
||||
try {
|
||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2d.drawImage(original, 0, 0, targetWidth, targetHeight, null);
|
||||
} finally {
|
||||
g2d.dispose();
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
private BufferedImage ensureRgbFormat(BufferedImage image) {
|
||||
if (image.getType() == BufferedImage.TYPE_INT_RGB) {
|
||||
return image;
|
||||
}
|
||||
BufferedImage rgbImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g2d = rgbImage.createGraphics();
|
||||
try {
|
||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||
g2d.drawImage(image, 0, 0, null);
|
||||
} finally {
|
||||
g2d.dispose();
|
||||
}
|
||||
return rgbImage;
|
||||
}
|
||||
|
||||
private byte[] encodeJpeg(BufferedImage image, float quality) throws IOException {
|
||||
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpeg");
|
||||
if (!writers.hasNext()) {
|
||||
throw new IOException("Kein JPEG-Writer verfügbar");
|
||||
}
|
||||
ImageWriter writer = writers.next();
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ImageOutputStream ios = ImageIO.createImageOutputStream(baos)) {
|
||||
writer.setOutput(ios);
|
||||
|
||||
ImageWriteParam params = writer.getDefaultWriteParam();
|
||||
if (params.canWriteCompressed()) {
|
||||
params.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
||||
params.setCompressionQuality(Math.max(0f, Math.min(1f, quality)));
|
||||
}
|
||||
writer.write(null, new IIOImage(image, null, null), params);
|
||||
return baos.toByteArray();
|
||||
} finally {
|
||||
writer.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private UploadI18N createGermanUploadI18n() {
|
||||
UploadI18N i18n = new UploadI18N();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user