MME-10 Attempt to include heic support; just moving to extracting metadata from images instead.
This commit is contained in:
parent
0d80c92850
commit
38f80aa8cd
@ -102,15 +102,14 @@ dependencies {
|
||||
|
||||
compileOnly 'org.jetbrains:annotations:26.0.2-1'
|
||||
|
||||
// https://mvnrepository.com/artifact/com.twelvemonkeys.imageio/imageio-webp
|
||||
runtimeOnly 'com.twelvemonkeys.imageio:imageio-webp:3.12.0'
|
||||
|
||||
// https://mvnrepository.com/artifact/com.twelvemonkeys.imageio/imageio-batik
|
||||
runtimeOnly 'com.twelvemonkeys.imageio:imageio-batik:3.12.0'
|
||||
|
||||
// https://mvnrepository.com/artifact/org.apache.xmlgraphics/batik-all
|
||||
runtimeOnly 'org.apache.xmlgraphics:batik-all:1.19'
|
||||
|
||||
implementation 'com.drewnoakes:metadata-extractor:2.19.0'
|
||||
|
||||
// Custom testing
|
||||
testImplementation 'org.testcontainers:testcontainers:1.21.4'
|
||||
testImplementation 'org.testcontainers:junit-jupiter:1.21.4'
|
||||
|
||||
BIN
src/integrationTest/resources/willow.HEIC
Normal file
BIN
src/integrationTest/resources/willow.HEIC
Normal file
Binary file not shown.
@ -7,6 +7,14 @@ import app.mealsmadeeasy.api.user.User;
|
||||
import app.mealsmadeeasy.api.util.MimeTypeService;
|
||||
import app.mealsmadeeasy.api.util.NoSuchEntityWithIdException;
|
||||
import app.mealsmadeeasy.api.util.NoSuchEntityWithUsernameAndFilenameException;
|
||||
import com.drew.imaging.ImageMetadataReader;
|
||||
import com.drew.imaging.ImageProcessingException;
|
||||
import com.drew.metadata.Directory;
|
||||
import com.drew.metadata.Metadata;
|
||||
import com.drew.metadata.MetadataException;
|
||||
import com.drew.metadata.jpeg.JpegDirectory;
|
||||
import com.drew.metadata.png.PngDirectory;
|
||||
import com.drew.metadata.webp.WebpDirectory;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@ -103,6 +111,33 @@ public class S3ImageService implements ImageService {
|
||||
return didTransfer;
|
||||
}
|
||||
|
||||
private record HeightWidth(int height, int width) {}
|
||||
|
||||
private <D extends Directory> HeightWidth getHeightAndWidthFromMetadata(
|
||||
InputStream inputStream,
|
||||
Class<D> directoryClass,
|
||||
int heightTag,
|
||||
int widthTag,
|
||||
String debugName
|
||||
) throws IOException {
|
||||
try {
|
||||
final Metadata metadata = ImageMetadataReader.readMetadata(inputStream);
|
||||
final D directory = metadata.getFirstDirectoryOfType(directoryClass);
|
||||
if (directory == null) {
|
||||
throw new RuntimeException("Unable to get " + directoryClass.getSimpleName() + " for " + debugName);
|
||||
}
|
||||
if (!directory.containsTag(heightTag)) {
|
||||
throw new RuntimeException("Unable to find height tag for " + debugName);
|
||||
}
|
||||
if (!directory.containsTag(widthTag)) {
|
||||
throw new RuntimeException("Unable to find width tag for " + debugName);
|
||||
}
|
||||
return new HeightWidth(directory.getInt(heightTag), directory.getInt(widthTag));
|
||||
} catch (ImageProcessingException | MetadataException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @apiNote Consumes and closes the {@link java.io.InputStream}.
|
||||
*
|
||||
@ -137,15 +172,43 @@ public class S3ImageService implements ImageService {
|
||||
this.imageBucketName, filename, mimeType, toStore, objectSize
|
||||
);
|
||||
|
||||
final BufferedImage bufferedImage = ImageIO.read(toRead);
|
||||
if (bufferedImage == null) {
|
||||
throw new ImageException(
|
||||
ImageException.Type.UNSUPPORTED_IMAGE_TYPE,
|
||||
"ImageIO could not read image: " + userFilename
|
||||
final HeightWidth hw;
|
||||
switch (mimeType) {
|
||||
case "image/jpeg" -> {
|
||||
hw = this.getHeightAndWidthFromMetadata(
|
||||
toRead,
|
||||
JpegDirectory.class,
|
||||
JpegDirectory.TAG_IMAGE_HEIGHT,
|
||||
JpegDirectory.TAG_IMAGE_WIDTH,
|
||||
userFilename
|
||||
);
|
||||
}
|
||||
final int height = bufferedImage.getHeight();
|
||||
final int width = bufferedImage.getWidth();
|
||||
case "image/png" -> {
|
||||
hw = this.getHeightAndWidthFromMetadata(
|
||||
toRead,
|
||||
PngDirectory.class,
|
||||
PngDirectory.TAG_IMAGE_HEIGHT,
|
||||
PngDirectory.TAG_IMAGE_WIDTH,
|
||||
userFilename
|
||||
);
|
||||
}
|
||||
case "image/webp" -> {
|
||||
hw = this.getHeightAndWidthFromMetadata(
|
||||
toRead,
|
||||
WebpDirectory.class,
|
||||
WebpDirectory.TAG_IMAGE_HEIGHT,
|
||||
WebpDirectory.TAG_IMAGE_WIDTH,
|
||||
userFilename
|
||||
);
|
||||
}
|
||||
case "image/svg+xml" -> {
|
||||
final BufferedImage bufferedImage = ImageIO.read(toRead);
|
||||
hw = new HeightWidth(bufferedImage.getHeight(), bufferedImage.getWidth());
|
||||
}
|
||||
default -> throw new RuntimeException("Unsupported mime type: " + mimeType);
|
||||
}
|
||||
final int height = hw.height();
|
||||
final int width = hw.width();
|
||||
|
||||
toRead.close();
|
||||
toStore.close();
|
||||
|
||||
@ -19,7 +19,7 @@ public class MimeTypeService {
|
||||
final Matcher m = extensionPattern.matcher(userFilename);
|
||||
if (m.matches()) {
|
||||
final String extension = m.group(1);
|
||||
return switch (extension) {
|
||||
return switch (extension.toLowerCase()) {
|
||||
case "jpg", "jpeg" -> IMAGE_JPEG;
|
||||
case "png" -> IMAGE_PNG;
|
||||
case "svg" -> IMAGE_SVG;
|
||||
@ -32,7 +32,7 @@ public class MimeTypeService {
|
||||
}
|
||||
|
||||
public String getExtension(String mimeType) {
|
||||
return switch (mimeType) {
|
||||
return switch (mimeType.toLowerCase()) {
|
||||
case IMAGE_JPEG -> "jpg";
|
||||
case IMAGE_PNG -> "png";
|
||||
case IMAGE_SVG -> "svg";
|
||||
|
||||
Loading…
Reference in New Issue
Block a user