From 2505a7ee9e18d1d22ebc6eef49900fcfb6235bea Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Sat, 13 Dec 2025 12:15:10 -0600 Subject: [PATCH] Implement db storage of image height/width, and add to ImageView. --- build.gradle | 3 +++ .../app/mealsmadeeasy/api/image/Image.java | 2 ++ .../api/image/S3ImageEntity.java | 24 +++++++++++++++++++ .../api/image/S3ImageService.java | 17 +++++++++++++ .../api/image/view/ImageView.java | 20 ++++++++++++++++ 5 files changed, 66 insertions(+) diff --git a/build.gradle b/build.gradle index 47bce9f..1d18ae5 100644 --- a/build.gradle +++ b/build.gradle @@ -64,6 +64,9 @@ dependencies { implementation 'io.minio:minio:8.5.11' + // https://mvnrepository.com/artifact/com.twelvemonkeys.imageio/imageio-webp + runtimeOnly 'com.twelvemonkeys.imageio:imageio-webp:3.12.0' + compileOnly 'org.jetbrains:annotations:24.1.0' // Custom testing diff --git a/src/main/java/app/mealsmadeeasy/api/image/Image.java b/src/main/java/app/mealsmadeeasy/api/image/Image.java index 7c956a9..7c26673 100644 --- a/src/main/java/app/mealsmadeeasy/api/image/Image.java +++ b/src/main/java/app/mealsmadeeasy/api/image/Image.java @@ -16,5 +16,7 @@ public interface Image { @Nullable String getCaption(); User getOwner(); boolean isPublic(); + int getHeight(); + int getWidth(); Set getViewers(); } diff --git a/src/main/java/app/mealsmadeeasy/api/image/S3ImageEntity.java b/src/main/java/app/mealsmadeeasy/api/image/S3ImageEntity.java index 5079afb..ba26784 100644 --- a/src/main/java/app/mealsmadeeasy/api/image/S3ImageEntity.java +++ b/src/main/java/app/mealsmadeeasy/api/image/S3ImageEntity.java @@ -35,6 +35,12 @@ public class S3ImageEntity implements Image { @Column(nullable = false) private String objectName; + @Column(nullable = false) + private int height; + + @Column(nullable = false) + private int width; + @ManyToOne(optional = false) @JoinColumn(name = "owner_id", nullable = false) private UserEntity owner; @@ -116,6 +122,24 @@ public class S3ImageEntity implements Image { this.objectName = objectName; } + @Override + public int getHeight() { + return this.height; + } + + public void setHeight(int height) { + this.height = height; + } + + @Override + public int getWidth() { + return this.width; + } + + public void setWidth(int width) { + this.width = width; + } + @Override public User getOwner() { return this.owner; diff --git a/src/main/java/app/mealsmadeeasy/api/image/S3ImageService.java b/src/main/java/app/mealsmadeeasy/api/image/S3ImageService.java index 33dd05a..0ad1aab 100644 --- a/src/main/java/app/mealsmadeeasy/api/image/S3ImageService.java +++ b/src/main/java/app/mealsmadeeasy/api/image/S3ImageService.java @@ -7,11 +7,15 @@ import app.mealsmadeeasy.api.s3.S3Manager; import app.mealsmadeeasy.api.user.User; import app.mealsmadeeasy.api.user.UserEntity; import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.time.LocalDateTime; @@ -23,6 +27,7 @@ import java.util.regex.Pattern; public class S3ImageService implements ImageService { private static final Pattern extensionPattern = Pattern.compile(".+\\.(.+)$"); + private static final Logger logger = LoggerFactory.getLogger(S3ImageService.class); private final S3Manager s3Manager; private final S3ImageRepository imageRepository; @@ -112,11 +117,23 @@ public class S3ImageService implements ImageService { this.imageBucketName, filename, mimeType, inputStream, objectSize ); + final int height, width; + try (final InputStream imageContent = this.s3Manager.load(this.imageBucketName, objectName)) { + final BufferedImage bufferedImage = ImageIO.read(imageContent); + if (bufferedImage == null) { + logger.error("ImageIO could not read image: {} ({})", userFilename, objectName); + } + height = bufferedImage.getHeight(); + width = bufferedImage.getWidth(); + } + final S3ImageEntity draft = new S3ImageEntity(); draft.setOwner((UserEntity) owner); draft.setUserFilename(userFilename); draft.setMimeType(mimeType); draft.setObjectName(objectName); + draft.setHeight(height); + draft.setWidth(width); this.transferFromSpec(draft, createSpec); return this.imageRepository.save(draft); } diff --git a/src/main/java/app/mealsmadeeasy/api/image/view/ImageView.java b/src/main/java/app/mealsmadeeasy/api/image/view/ImageView.java index 949cfe9..32a54af 100644 --- a/src/main/java/app/mealsmadeeasy/api/image/view/ImageView.java +++ b/src/main/java/app/mealsmadeeasy/api/image/view/ImageView.java @@ -21,6 +21,8 @@ public class ImageView { view.setCaption(image.getCaption()); view.setOwner(UserInfoView.from(image.getOwner())); view.setIsPublic(image.isPublic()); + view.setHeight(image.getHeight()); + view.setWidth(image.getWidth()); if (includeViewers) { view.setViewers(image.getViewers().stream() .map(UserInfoView::from) @@ -39,6 +41,8 @@ public class ImageView { private @Nullable String caption; private UserInfoView owner; private boolean isPublic; + private int height; + private int width; private @Nullable Set viewers; public String getUrl() { @@ -113,6 +117,22 @@ public class ImageView { this.isPublic = isPublic; } + public int getHeight() { + return this.height; + } + + public void setHeight(int height) { + this.height = height; + } + + public int getWidth() { + return this.width; + } + + public void setWidth(int width) { + this.width = width; + } + public @Nullable Set getViewers() { return this.viewers; }