Skip to content

Instantly share code, notes, and snippets.

@prmichaelsen
Created October 27, 2024 00:42
Show Gist options
  • Save prmichaelsen/d82304f07427ec6cce87ea16ee9b4917 to your computer and use it in GitHub Desktop.
Save prmichaelsen/d82304f07427ec6cce87ea16ee9b4917 to your computer and use it in GitHub Desktop.
@Log4j2
public class ImageUtility {
public MultipartFile removeExifAndApplyOrientation(MultipartFile file, String mimeType) throws Exception {
final BufferedImage image = ImageIO.read(file.getInputStream());
final Path tempDir = Paths.get(System.getProperty("java.io.tmpdir"));
final Path originalFile = Files.createTempFile(tempDir, "original-image-", "");
final String originalPath = originalFile.toAbsolutePath().toString();
final ByteArrayOutputStream originalBytes = new ByteArrayOutputStream();
// jpg is lossy, and in this case when we try to write the file out,
// the ICCProfile is lost. Therefore, if it's a jpg, we use the lossless
// tiff format to write to file so we can then copy the color profile later.
// https://stackoverflow.com/a/1271751/5013193
// https://stackoverflow.com/a/21219913/5013193
ImageIO.write(image, this.getType(mimeType) == "jpg" ? "tiff" : "png", originalBytes);
Files.write(originalFile, originalBytes.toByteArray());
final Path tempFile = Files.createTempFile(tempDir, "image-", "");
final String tempPath = tempFile.toAbsolutePath().toString();
final ByteArrayOutputStream tempBytes = new ByteArrayOutputStream();
ImageIO.write(image, this.getType(mimeType), tempBytes);
Files.write(tempFile, tempBytes.toByteArray());
final int orientation = this.getOrientation(file, mimeType);
if (orientation != 1) {
String degrees;
boolean mirror = false;
switch (orientation) {
case 2:
mirror = true;
degrees = "0";
break;
case 3:
degrees = "180";
break;
case 4:
mirror = true;
degrees = "180";
break;
case 5:
mirror = true;
degrees = "90";
break;
case 6:
degrees = "90";
break;
case 7:
mirror = true;
degrees = "270";
break;
case 8:
degrees = "270";
break;
default:
degrees = "0";
break;
}
String[] magickCommand;
if (mirror) {
magickCommand = new String[] {
"/apollo/env/GestaltBuyerExperience/bin/magick-script",
"convert", tempPath,
"-rotate", degrees,
"-flop",
tempPath,
};
} else {
magickCommand = new String[] {
"/apollo/env/GestaltBuyerExperience/bin/magick-script",
"convert", tempPath,
"-rotate", degrees,
tempPath,
};
}
final Process magickProcess = Runtime.getRuntime().exec(magickCommand);
magickProcess.waitFor();
}
final String[] exifCommand = {
"/apollo/env/GestaltBuyerExperience/bin/exiftool/exiftool",
"-gps:all=",
"-orientation=",
"-overwrite_original",
tempPath,
};
final Process exifProcess = Runtime.getRuntime().exec(exifCommand);
exifProcess.waitFor();
// https://exiftool.org/exiftool_pod.html#exiftool--TagsFromFile-src.jpg--icc_profile-dst.jpg
String[] copyProfileCommand = {
"/apollo/env/GestaltBuyerExperience/bin/exiftool/exiftool",
"-TagsFromFile",
originalPath,
"-icc_profile",
tempPath,
};
final Process copyProfileProcess = Runtime.getRuntime().exec(copyProfileCommand);
copyProfileProcess.waitFor();
final byte[] bytes = Files.readAllBytes(tempFile);
final MultipartFile resultImageFile = new MockMultipartFile(file.getName(),
file.getOriginalFilename(), file.getContentType(), bytes);
Files.delete(originalFile);
Files.delete(tempFile);
return resultImageFile;
}
private int getOrientation(MultipartFile file, String mimeType) throws Exception {
switch (mimeType) {
case "image/jpeg":
return this.getJpgOrientation(file);
case "image/png":
return this.getPngOrientation(file);
default:
throw new Exception("File type not valid");
}
}
private int getJpgOrientation(MultipartFile file) throws Exception {
final Metadata metadata = ImageMetadataReader.readMetadata(file.getInputStream());
final Directory directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
final JpegDirectory jpegDirectory = metadata.getFirstDirectoryOfType(JpegDirectory.class);
int orientation = 1;
try {
if (directory != null) {
orientation = directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
}
} catch (MetadataException me) {
log.warn("Could not get orientation");
}
return orientation;
}
private int getPngOrientation(MultipartFile file) throws Exception {
final Metadata metadata = ImageMetadataReader.readMetadata(file.getInputStream());
final Directory directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
int orientation = 1;
try {
if (directory != null) {
orientation = directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
}
} catch (MetadataException me) {
log.warn("Could not get orientation");
}
return orientation;
}
private String getType(String mimeType) throws Exception {
switch (mimeType) {
case "image/jpeg":
return "jpg";
case "image/png":
return "png";
default:
throw new Exception("File type not valid");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment