Fix profile image squish and rotate isusse

This commit is contained in:
Alex
2026-04-13 00:07:58 -06:00
parent 227eb9cac8
commit 296f99900a

View File

@@ -14,7 +14,6 @@ import javafx.scene.image.Image;
import javafx.scene.input.MouseEvent; import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.paint.ImagePattern;
import javafx.scene.shape.Circle; import javafx.scene.shape.Circle;
import javafx.stage.Stage; import javafx.stage.Stage;
import org.example.petshopdesktop.api.endpoints.ChatApi; import org.example.petshopdesktop.api.endpoints.ChatApi;
@@ -31,6 +30,8 @@ import java.io.ByteArrayInputStream;
public class MainLayoutController { public class MainLayoutController {
private int avatarExifOrientation = 1;
private static final String NAV_BASE_STYLE = "-fx-background-color: transparent; " + private static final String NAV_BASE_STYLE = "-fx-background-color: transparent; " +
"-fx-text-fill: #cbd5e1; " + "-fx-text-fill: #cbd5e1; " +
"-fx-background-radius: 10; " + "-fx-background-radius: 10; " +
@@ -331,9 +332,11 @@ public class MainLayoutController {
try { try {
byte[] imageBytes = AuthApi.getInstance().getMyAvatarFile(); byte[] imageBytes = AuthApi.getInstance().getMyAvatarFile();
Image image = new Image(new ByteArrayInputStream(imageBytes), 52, 52, true, true); avatarExifOrientation = readExifOrientation(imageBytes);
Image image = new Image(new ByteArrayInputStream(imageBytes), 200, 200, true, true);
return image.isError() ? null : image; return image.isError() ? null : image;
} catch (Exception e) { } catch (Exception e) {
avatarExifOrientation = 1;
return null; return null;
} }
} }
@@ -342,19 +345,31 @@ public class MainLayoutController {
Circle border = new Circle(29); Circle border = new Circle(29);
border.setFill(Color.web("#dbe4ee")); border.setFill(Color.web("#dbe4ee"));
Circle circle = new Circle(26);
Label initials = new Label(initials(displayName));
initials.setStyle("-fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: 16px;");
if (avatarImage != null) { if (avatarImage != null) {
circle.setFill(new ImagePattern(avatarImage)); double imgW = avatarImage.getWidth();
initials.setVisible(false); double imgH = avatarImage.getHeight();
} else { double cropSize = Math.min(imgW, imgH);
circle.setFill(Color.web("#4ECDC4")); double cropX = (imgW - cropSize) / 2;
initials.setVisible(true); double cropY = (imgH - cropSize) / 2;
}
avatarPreview.getChildren().setAll(border, circle, initials); javafx.scene.image.ImageView imageView = new javafx.scene.image.ImageView(avatarImage);
imageView.setViewport(new javafx.geometry.Rectangle2D(cropX, cropY, cropSize, cropSize));
imageView.setFitWidth(52);
imageView.setFitHeight(52);
imageView.setPreserveRatio(false);
imageView.setRotate(exifOrientationToAngle(avatarExifOrientation));
Circle clip = new Circle(26, 26, 26);
imageView.setClip(clip);
avatarPreview.getChildren().setAll(border, imageView);
} else {
Circle circle = new Circle(26);
circle.setFill(Color.web("#4ECDC4"));
Label initials = new Label(initials(displayName));
initials.setStyle("-fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: 16px;");
avatarPreview.getChildren().setAll(border, circle, initials);
}
} }
private String initials(String displayName) { private String initials(String displayName) {
@@ -495,4 +510,56 @@ public class MainLayoutController {
} }
} }
private double exifOrientationToAngle(int orientation) {
return switch (orientation) {
case 3 -> 180;
case 6 -> 90;
case 8 -> -90;
default -> 0;
};
}
private int readExifOrientation(byte[] data) {
try {
if (data.length < 2 || (data[0] & 0xFF) != 0xFF || (data[1] & 0xFF) != 0xD8) return 1;
int offset = 2;
while (offset + 4 < data.length) {
if ((data[offset] & 0xFF) != 0xFF) break;
int marker = data[offset + 1] & 0xFF;
int segLen = ((data[offset + 2] & 0xFF) << 8) | (data[offset + 3] & 0xFF);
if (marker == 0xE1 && offset + 9 < data.length
&& data[offset + 4] == 'E' && data[offset + 5] == 'x'
&& data[offset + 6] == 'i' && data[offset + 7] == 'f'
&& data[offset + 8] == 0 && data[offset + 9] == 0) {
int tiff = offset + 10;
boolean le = data[tiff] == 'I';
int ifdOffset = readInt(data, tiff + 4, le);
int ifd = tiff + ifdOffset;
int entries = readShort(data, ifd, le);
for (int i = 0; i < entries; i++) {
int e = ifd + 2 + i * 12;
if (e + 9 < data.length && readShort(data, e, le) == 0x0112) {
return readShort(data, e + 8, le);
}
}
}
if (marker == 0xDA) break;
offset += 2 + segLen;
}
} catch (Exception ignored) {}
return 1;
}
private int readShort(byte[] data, int offset, boolean le) {
return le
? (data[offset] & 0xFF) | ((data[offset + 1] & 0xFF) << 8)
: ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
}
private int readInt(byte[] data, int offset, boolean le) {
return le
? (data[offset] & 0xFF) | ((data[offset + 1] & 0xFF) << 8) | ((data[offset + 2] & 0xFF) << 16) | ((data[offset + 3] & 0xFF) << 24)
: ((data[offset] & 0xFF) << 24) | ((data[offset + 1] & 0xFF) << 16) | ((data[offset + 2] & 0xFF) << 8) | (data[offset + 3] & 0xFF);
}
} }