diff --git a/desktop/pom.xml b/desktop/pom.xml
index fe513dc6..6ecf5c6b 100644
--- a/desktop/pom.xml
+++ b/desktop/pom.xml
@@ -30,6 +30,16 @@
javafx-web
${javafx.version}
+
+ org.openjfx
+ javafx-swing
+ ${javafx.version}
+
+
+ com.twelvemonkeys.imageio
+ imageio-webp
+ 3.11.0
+
org.junit.jupiter
diff --git a/desktop/src/main/java/module-info.java b/desktop/src/main/java/module-info.java
index a13de731..93a6704e 100644
--- a/desktop/src/main/java/module-info.java
+++ b/desktop/src/main/java/module-info.java
@@ -2,6 +2,7 @@ module org.example.petshopdesktop {
requires javafx.controls;
requires javafx.fxml;
requires javafx.web;
+ requires javafx.swing;
requires java.desktop;
requires java.sql;
requires java.net.http;
diff --git a/desktop/src/main/java/org/example/petshopdesktop/util/DesktopImageSupport.java b/desktop/src/main/java/org/example/petshopdesktop/util/DesktopImageSupport.java
index e9521231..dba81e76 100644
--- a/desktop/src/main/java/org/example/petshopdesktop/util/DesktopImageSupport.java
+++ b/desktop/src/main/java/org/example/petshopdesktop/util/DesktopImageSupport.java
@@ -1,22 +1,55 @@
package org.example.petshopdesktop.util;
import javafx.application.Platform;
+import javafx.embed.swing.SwingFXUtils;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import org.example.petshopdesktop.api.ApiClient;
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
public final class DesktopImageSupport {
private static final Map IMAGE_CACHE = new ConcurrentHashMap<>();
private static final Map ORIENTATION_CACHE = new ConcurrentHashMap<>();
+ private static final AtomicBoolean PLUGINS_SCANNED = new AtomicBoolean(false);
private DesktopImageSupport() {
}
+ private static void ensurePlugins() {
+ if (PLUGINS_SCANNED.compareAndSet(false, true)) {
+ ImageIO.scanForPlugins();
+ }
+ }
+
+ private static boolean isWebP(byte[] data) {
+ return data.length >= 12
+ && data[0] == 'R' && data[1] == 'I' && data[2] == 'F' && data[3] == 'F'
+ && data[8] == 'W' && data[9] == 'E' && data[10] == 'B' && data[11] == 'P';
+ }
+
+ private static Image decodeImage(byte[] bytes) {
+ if (isWebP(bytes)) {
+ ensurePlugins();
+ try {
+ BufferedImage bi = ImageIO.read(new ByteArrayInputStream(bytes));
+ if (bi != null) {
+ return SwingFXUtils.toFXImage(bi, null);
+ }
+ } catch (Exception ignored) {
+ }
+ return null;
+ }
+ Image img = new Image(new ByteArrayInputStream(bytes));
+ return img.isError() ? null : img;
+ }
+
public static void loadImageInto(ImageView imageView, String imageUrl, double width, double height) {
imageView.setFitWidth(width);
imageView.setFitHeight(height);
@@ -34,8 +67,8 @@ public final class DesktopImageSupport {
try {
byte[] bytes = java.net.URI.create(imageUrl).toURL().openStream().readAllBytes();
int orientation = readExifOrientation(bytes);
- Image image = new Image(new ByteArrayInputStream(bytes));
- if (!image.isError()) {
+ Image image = decodeImage(bytes);
+ if (image != null) {
Platform.runLater(() -> {
imageView.setImage(image);
imageView.setRotate(exifOrientationToAngle(orientation));
@@ -58,8 +91,8 @@ public final class DesktopImageSupport {
try {
byte[] bytes = ApiClient.getInstance().getBytes(imageUrl);
int orientation = readExifOrientation(bytes);
- Image image = new Image(new ByteArrayInputStream(bytes));
- if (!image.isError()) {
+ Image image = decodeImage(bytes);
+ if (image != null) {
IMAGE_CACHE.put(imageUrl, image);
ORIENTATION_CACHE.put(imageUrl, orientation);
Platform.runLater(() -> {