1818 */
1919package com .github .mfl28 .boundingboxeditor .model .data ;
2020
21+ import com .drew .imaging .jpeg .JpegMetadataReader ;
22+ import com .drew .imaging .jpeg .JpegProcessingException ;
23+ import com .drew .metadata .MetadataException ;
24+ import com .drew .metadata .exif .ExifDirectoryBase ;
25+ import com .drew .metadata .exif .ExifIFD0Directory ;
2126import com .google .gson .annotations .SerializedName ;
2227
2328import javax .imageio .ImageIO ;
2429import javax .imageio .ImageReader ;
2530import javax .imageio .stream .ImageInputStream ;
2631import java .io .File ;
2732import java .io .IOException ;
33+ import java .io .Serial ;
2834import java .util .Iterator ;
2935import java .util .List ;
3036import java .util .Objects ;
@@ -37,6 +43,7 @@ public final class ImageMetaData {
3743 private static final String NOT_AN_IMAGE_FILE_ERROR_MESSAGE = "Not an image file." ;
3844 private static final String UNSUPPORTED_IMAGE_FORMAT_ERROR_MESSAGE = "Unsupported image file format." ;
3945 private static final String INVALID_IMAGE_FILE_ERROR_MESSAGE = "Invalid image file." ;
46+ private static final String JPEG_READ_ERROR_MESSAGE = "Cannot read JPEG metadata." ;
4047 private final String fileName ;
4148 private ImageMetaDataDetails details ;
4249
@@ -49,9 +56,14 @@ public final class ImageMetaData {
4956 * @param imageHeight the height of the image
5057 * @param imageDepth the depth (= number of channels) of the image
5158 */
52- public ImageMetaData (String fileName , String folderName , double imageWidth , double imageHeight , int imageDepth ) {
59+ public ImageMetaData (String fileName , String folderName , String url , double imageWidth , double imageHeight , int imageDepth ) {
5360 this .fileName = fileName ;
54- this .details = new ImageMetaDataDetails (folderName , imageWidth , imageHeight , imageDepth );
61+ this .details = new ImageMetaDataDetails (folderName , url , imageWidth , imageHeight , imageDepth , 1 );
62+ }
63+
64+ public ImageMetaData (String fileName , String folderName , String url , double imageWidth , double imageHeight , int imageDepth , int orientation ) {
65+ this .fileName = fileName ;
66+ this .details = new ImageMetaDataDetails (folderName , url , imageWidth , imageHeight , imageDepth , orientation );
5567 }
5668
5769 public ImageMetaData (String fileName ) {
@@ -67,7 +79,8 @@ public ImageMetaData(String fileName) {
6779 public static ImageMetaData fromFile (File imageFile ) throws IOException {
6880 ImageDimensions imageDimensions = readImageDimensionsFromFile (imageFile );
6981 return new ImageMetaData (imageFile .getName (), imageFile .toPath ().getParent ().toFile ().getName (),
70- imageDimensions .width (), imageDimensions .height (), imageDimensions .depth ());
82+ imageFile .toURI ().toString (),
83+ imageDimensions .width (), imageDimensions .height (), imageDimensions .depth (), imageDimensions .orientation ());
7184 }
7285
7386 /**
@@ -79,6 +92,14 @@ public double getImageWidth() {
7992 return details .imageWidth ;
8093 }
8194
95+ public double getOrientedWidth () {
96+ if (details .orientation >= 5 ) {
97+ return getImageHeight ();
98+ }
99+
100+ return getImageWidth ();
101+ }
102+
82103 /**
83104 * Returns the height of the image.
84105 *
@@ -88,6 +109,14 @@ public double getImageHeight() {
88109 return details .imageHeight ;
89110 }
90111
112+ public double getOrientedHeight () {
113+ if (details .orientation >= 5 ) {
114+ return getImageWidth ();
115+ }
116+
117+ return getImageHeight ();
118+ }
119+
91120 /**
92121 * Returns the depth (= number of channels) of the image.
93122 *
@@ -97,6 +126,10 @@ public int getImageDepth() {
97126 return details .imageDepth ;
98127 }
99128
129+ public int getOrientation () {
130+ return details .orientation ;
131+ }
132+
100133 /**
101134 * Returns the filename of the image.
102135 *
@@ -115,6 +148,10 @@ public String getFolderName() {
115148 return details .folderName ;
116149 }
117150
151+ public String getFileUrl () {
152+ return details .url ;
153+ }
154+
118155 public boolean hasDetails () {
119156 return details != null ;
120157 }
@@ -137,14 +174,15 @@ public String getDimensionsString() {
137174 return "[]" ;
138175 }
139176
140- return "[" + (int ) getImageWidth () + " x " + (int ) getImageHeight () + "]" ;
177+ return "[" + (int ) getOrientedWidth () + " x " + (int ) getOrientedHeight () + "]" ;
141178 }
142179
143180 private static ImageDimensions readImageDimensionsFromFile (File imageFile ) throws IOException {
144181 double width ;
145182 double height ;
146183 int numComponents ;
147- // Source: https://stackoverflow.com/a/1560052
184+ int orientation = 1 ;
185+
148186 try (ImageInputStream imageStream = ImageIO .createImageInputStream (imageFile )) {
149187 if (imageStream == null ) {
150188 throw new NotAnImageFileException (NOT_AN_IMAGE_FILE_ERROR_MESSAGE );
@@ -166,6 +204,18 @@ private static ImageDimensions readImageDimensionsFromFile(File imageFile) throw
166204 width = reader .getWidth (0 );
167205 height = reader .getHeight (0 );
168206 numComponents = reader .getRawImageType (0 ).getNumComponents ();
207+
208+ if (imageFormatName .equals ("jpeg" )) {
209+ try {
210+ final ExifIFD0Directory exifDirectory = JpegMetadataReader .readMetadata (imageFile ).getFirstDirectoryOfType (ExifIFD0Directory .class );
211+
212+ if (exifDirectory != null && exifDirectory .containsTag (ExifDirectoryBase .TAG_ORIENTATION )) {
213+ orientation = exifDirectory .getInt (ExifDirectoryBase .TAG_ORIENTATION );
214+ }
215+ } catch (JpegProcessingException | MetadataException | IOException exception ) {
216+ throw new UnsupportedImageFileException (JPEG_READ_ERROR_MESSAGE );
217+ }
218+ }
169219 } finally {
170220 reader .dispose ();
171221 }
@@ -174,35 +224,17 @@ private static ImageDimensions readImageDimensionsFromFile(File imageFile) throw
174224 }
175225 }
176226
177- return new ImageDimensions (width , height , numComponents );
227+ return new ImageDimensions (width , height , numComponents , orientation );
178228 }
179229
180- private record ImageMetaDataDetails (String folderName , @ SerializedName ("width" ) double imageWidth ,
230+ private record ImageMetaDataDetails (String folderName , String url , @ SerializedName ("width" ) double imageWidth ,
181231 @ SerializedName ("height" ) double imageHeight ,
182- @ SerializedName ("depth" ) int imageDepth ) {
183-
184- @ Override
185- public int hashCode () {
186- return Objects .hash (imageWidth , imageHeight , imageDepth );
187- }
188-
189- @ Override
190- public boolean equals (Object o ) {
191- if (this == o ) {
192- return true ;
193- }
194-
195- if (!(o instanceof ImageMetaDataDetails that )) {
196- return false ;
197- }
198-
199- return Double .compare (that .imageWidth , imageWidth ) == 0 &&
200- Double .compare (that .imageHeight , imageHeight ) == 0 &&
201- imageDepth == that .imageDepth ;
202- }
203- }
232+ @ SerializedName ("depth" ) int imageDepth ,
233+ int orientation ) {
234+ }
204235
205236 public static class NotAnImageFileException extends RuntimeException {
237+ @ Serial
206238 private static final long serialVersionUID = 5256590447321177896L ;
207239
208240 public NotAnImageFileException (String errorMessage ) {
@@ -211,13 +243,14 @@ public NotAnImageFileException(String errorMessage) {
211243 }
212244
213245 public static class UnsupportedImageFileException extends RuntimeException {
246+ @ Serial
214247 private static final long serialVersionUID = -4143199502921469708L ;
215248
216249 public UnsupportedImageFileException (String errorMessage ) {
217250 super (errorMessage );
218251 }
219252 }
220253
221- private record ImageDimensions (double width , double height , int depth ) {
254+ private record ImageDimensions (double width , double height , int depth , int orientation ) {
222255 }
223256}
0 commit comments