Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read ExifInteropDirectory #3497

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ object MappingTest {
iptc = Map("iptc1" -> "value1"),
exif = Map("exif1" -> "value1"),
exifSub = Map("exifSub1" -> "value1"),
exifInterop = Map("exifInterop1" -> "value1"),
xmp = Map(
"xmp1" -> JsString("value1"),
"xmp2" -> JsNumber(12345),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ case class FileMetadata(
iptc: Map[String, String] = Map(),
exif: Map[String, String] = Map(),
exifSub: Map[String, String] = Map(),
xmp: Map[String, JsValue] = Map(),
exifInterop: Map[String, String] = Map(),
xmp: Map[String, JsValue] = Map(),
icc: Map[String, String] = Map(),
getty: Map[String, String] = Map(),
colourModel: Option[String] = None,
Expand All @@ -22,6 +23,7 @@ case class FileMetadata(
"iptcFieldCount" -> iptc.size,
"exifFieldCount" -> exif.size,
"exifSubFieldCount" -> exifSub.size,
"exifInteropFieldCount" -> exifInterop.size,
"xmpFieldCount" -> xmp.size,
"iccFieldCount" -> icc.size,
"gettyFieldCount" -> getty.size,
Expand Down Expand Up @@ -52,6 +54,7 @@ object FileMetadata {
(__ \ "iptc").read[Map[String,String]] ~
(__ \ "exif").read[Map[String,String]] ~
(__ \ "exifSub").read[Map[String,String]] ~
(__ \ "exifInterop").readNullable[Map[String,String]].map(_ getOrElse Map()) ~
(__ \ "xmp").read[Map[String,JsValue]] ~
(__ \ "icc").readNullable[Map[String,String]].map(_ getOrElse Map()).map(removeLongValues) ~
(__ \ "getty").readNullable[Map[String,String]].map(_ getOrElse Map()) ~
Expand All @@ -74,6 +77,7 @@ object FileMetadata {
(JsPath \ "iptc").write[Map[String,String]] and
(JsPath \ "exif").write[Map[String,String]] and
(JsPath \ "exifSub").write[Map[String,String]] and
(JsPath \ "exifInterop").write[Map[String,String]] and
(JsPath \ "xmp").write[Map[String,JsValue]] and
(JsPath \ "icc").write[Map[String,String]].contramap[Map[String, String]](removeLongValues) and
(JsPath \ "getty").write[Map[String,String]] and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,14 +378,14 @@ class ImageMetadataConverterTest extends FunSpec with Matchers {
// People in Image

it("should populate peopleInImage field of ImageMetadata from corresponding xmp iptc ext fields") {
val fileMetadata = FileMetadata(Map(), Map(), Map(), Map("Iptc4xmpExt:PersonInImage" -> JsArray(Seq(JsString("person 1")))))
val fileMetadata = FileMetadata(Map(), Map(), Map(), Map(), Map("Iptc4xmpExt:PersonInImage" -> JsArray(Seq(JsString("person 1")))))
val imageMetadata = ImageMetadataConverter.fromFileMetadata(fileMetadata)
imageMetadata.peopleInImage should be (Set("person 1"))
}

it("should populate peopleInImage field of ImageMetadata from multiple corresponding people xmp fields") {
val fileMetadata = FileMetadata(
Map(), Map(), Map(),
Map(), Map(), Map(), Map(),
Map("Iptc4xmpExt:PersonInImage" ->
JsArray(Seq(
JsString("person 1"),
Expand All @@ -400,7 +400,7 @@ class ImageMetadataConverterTest extends FunSpec with Matchers {
}

it("should distinctly populate peopleInImage field of ImageMetadata from multiple corresponding xmp iptc ext fields") {
val fileMetadata = FileMetadata(Map(), Map(), Map(),
val fileMetadata = FileMetadata(Map(), Map(), Map(), Map(),
Map("Iptc4xmpExt:PersonInImage" ->
JsArray(Seq(
JsString("person 1"),
Expand All @@ -413,7 +413,7 @@ class ImageMetadataConverterTest extends FunSpec with Matchers {
}

it("should distinctly populate peopleInImage field of ImageMetadata from multiple corresponding xmp people fields") {
val fileMetadata = FileMetadata(Map(), Map(), Map(),
val fileMetadata = FileMetadata(Map(), Map(), Map(), Map(),
Map(
"Iptc4xmpExt:PersonInImage" -> JsArray(Seq(
JsString("person 1"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,60 +8,60 @@ class FileMetadataTest extends FreeSpec with Matchers with Checkers with Propert

"Dehydrate a non-empty object" - {
"Leave all short values alone" in {
val fm = new FileMetadata(Map(), Map(), Map(), Map(), Map(("hello" -> "goodbye")), Map(), None, Map())
val fm = new FileMetadata(Map(), Map(), Map(), Map(), Map(), Map(("hello" -> "goodbye")), Map(), None, Map())
val json = Json.toJson(fm).toString()
json should be ("{\"iptc\":{},\"exif\":{},\"exifSub\":{},\"xmp\":{},\"icc\":{\"hello\":\"goodbye\"},\"getty\":{},\"colourModelInformation\":{}}")
json should be ("{\"iptc\":{},\"exif\":{},\"exifSub\":{},\"exifInterop\":{},\"xmp\":{},\"icc\":{\"hello\":\"goodbye\"},\"getty\":{},\"colourModelInformation\":{}}")
}
"Remove a single long value" in {
val A5000 = (1 to 5000).toList.mkString(",")
val fm = new FileMetadata(Map(), Map(), Map(), Map(), Map("hello" -> "goodbye", "A5000" -> A5000), Map(), None, Map())
val fm = new FileMetadata(Map(), Map(), Map(), Map(), Map(), Map("hello" -> "goodbye", "A5000" -> A5000), Map(), None, Map())
val json = Json.toJson(fm).toString()
json should be ("{\"iptc\":{},\"exif\":{},\"exifSub\":{},\"xmp\":{},\"icc\":{\"hello\":\"goodbye\",\"removedFields\":\"A5000\"},\"getty\":{},\"colourModelInformation\":{}}")
json should be ("{\"iptc\":{},\"exif\":{},\"exifSub\":{},\"exifInterop\":{},\"xmp\":{},\"icc\":{\"hello\":\"goodbye\",\"removedFields\":\"A5000\"},\"getty\":{},\"colourModelInformation\":{}}")
}
"Remove multiple long values" in {
val A5000 = (1 to 5000).toList.mkString(",")
val B5000 = (1 to 10000).toList.mkString(",")
val fm = new FileMetadata(Map(), Map(), Map(), Map(), Map("hello" -> "goodbye", "A5000" -> A5000, "B5000" -> B5000), Map(), None, Map())
val fm = new FileMetadata(Map(), Map(), Map(), Map(), Map(), Map("hello" -> "goodbye", "A5000" -> A5000, "B5000" -> B5000), Map(), None, Map())
val json = Json.toJson(fm).toString()
json should be ("{\"iptc\":{},\"exif\":{},\"exifSub\":{},\"xmp\":{},\"icc\":{\"hello\":\"goodbye\",\"removedFields\":\"A5000, B5000\"},\"getty\":{},\"colourModelInformation\":{}}")
json should be ("{\"iptc\":{},\"exif\":{},\"exifSub\":{},\"exifInterop\":{},\"xmp\":{},\"icc\":{\"hello\":\"goodbye\",\"removedFields\":\"A5000, B5000\"},\"getty\":{},\"colourModelInformation\":{}}")
}
}

"Dehydrate and rehydrate a non-empty object" - {
"Leave all short values alone" in {
val fm = new FileMetadata(Map(), Map(), Map(), Map(), Map(("hello" -> "goodbye")), Map(), None, Map())
val fm = new FileMetadata(Map(), Map(), Map(), Map(), Map(), Map(("hello" -> "goodbye")), Map(), None, Map())
val json = Json.toJson(fm).toString()
val fmRehydrated = Json.fromJson[FileMetadata](Json.parse(json)).get
fmRehydrated should be (new FileMetadata(Map(), Map(), Map(), Map(), Map("hello" -> "goodbye"), Map(), None, Map()))
fmRehydrated should be (new FileMetadata(Map(), Map(), Map(), Map(), Map(), Map("hello" -> "goodbye"), Map(), None, Map()))
}
"Remove a single long value" in {
val A5000 = (1 to 5000).toList.mkString(",")
val fm = new FileMetadata(Map(), Map(), Map(), Map(), Map("hello" -> "goodbye", "A5000" -> A5000), Map(), None, Map())
val fm = new FileMetadata(Map(), Map(), Map(), Map(), Map(), Map("hello" -> "goodbye", "A5000" -> A5000), Map(), None, Map())
val json = Json.toJson(fm).toString()
val fmRehydrated = Json.fromJson[FileMetadata](Json.parse(json)).get
fmRehydrated should be ( new FileMetadata(Map(), Map(), Map(), Map(), Map("hello" -> "goodbye", "removedFields" -> "A5000"), Map(), None, Map()))
fmRehydrated should be ( new FileMetadata(Map(), Map(), Map(), Map(), Map(), Map("hello" -> "goodbye", "removedFields" -> "A5000"), Map(), None, Map()))
}
"Remove multiple long values" in {
val A5000 = (1 to 5000).toList.mkString(",")
val B5000 = (1 to 10000).toList.mkString(",")
val fm = new FileMetadata(Map(), Map(), Map(), Map(), Map("hello" -> "goodbye", "A5000" -> A5000, "B5000" -> B5000), Map(), None, Map())
val fm = new FileMetadata(Map(), Map(), Map(), Map(), Map(), Map("hello" -> "goodbye", "A5000" -> A5000, "B5000" -> B5000), Map(), None, Map())
val json = Json.toJson(fm).toString()
val fmRehydrated = Json.fromJson[FileMetadata](Json.parse(json)).get
fmRehydrated should be ( new FileMetadata(Map(), Map(), Map(), Map(), Map("hello" -> "goodbye", "removedFields" -> "A5000, B5000"), Map(), None, Map()))
fmRehydrated should be ( new FileMetadata(Map(), Map(), Map(), Map(), Map(), Map("hello" -> "goodbye", "removedFields" -> "A5000, B5000"), Map(), None, Map()))
}
}

"Dehydrate and rehydrate an empty file metadata object" - {
"Dehydrate" in {
val fm = new FileMetadata()
val json = Json.toJson(fm).toString()
json should be ("{\"iptc\":{},\"exif\":{},\"exifSub\":{},\"xmp\":{},\"icc\":{},\"getty\":{},\"colourModelInformation\":{}}")
json should be ("{\"iptc\":{},\"exif\":{},\"exifSub\":{},\"exifInterop\":{},\"xmp\":{},\"icc\":{},\"getty\":{},\"colourModelInformation\":{}}")
}

"Rehydrate" in {
val json = "{\"iptc\":{},\"exif\":{},\"exifSub\":{},\"xmp\":{},\"icc\":{},\"getty\":{},\"colourModelInformation\":{}}"
val json = "{\"iptc\":{},\"exif\":{},\"exifSub\":{},\"exifInterop\":{},\"xmp\":{},\"icc\":{},\"getty\":{},\"colourModelInformation\":{}}"
val fm = Json.fromJson[FileMetadata](Json.parse(json)).get
fm should be (new FileMetadata(Map(), Map(), Map(), Map(), Map(), Map(), None, Map()))
fm should be (new FileMetadata(Map(), Map(), Map(), Map(), Map(), Map(), Map(), None, Map()))
}
}

Expand Down
3 changes: 2 additions & 1 deletion image-loader/app/lib/imaging/FileMetadataReader.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import java.util.concurrent.Executors

import com.adobe.internal.xmp.XMPMetaFactory
import com.drew.imaging.ImageMetadataReader
import com.drew.metadata.exif.{ExifDirectoryBase, ExifIFD0Directory, ExifSubIFDDirectory}
import com.drew.metadata.exif.{ExifDirectoryBase, ExifIFD0Directory, ExifSubIFDDirectory, ExifInteropDirectory}
import com.drew.metadata.icc.IccDirectory
import com.drew.metadata.iptc.IptcDirectory
import com.drew.metadata.jpeg.JpegDirectory
Expand Down Expand Up @@ -73,6 +73,7 @@ object FileMetadataReader {
iptc = exportDirectory(metadata, classOf[IptcDirectory]),
exif = exportDirectory(metadata, classOf[ExifIFD0Directory]),
exifSub = exportDirectory(metadata, classOf[ExifSubIFDDirectory]),
exifInterop = exportDirectory(metadata, classOf[ExifInteropDirectory]),
xmp = exportXmpPropertiesInTransformedSchema(metadata, imageId),
icc = exportDirectory(metadata, classOf[IccDirectory]),
getty = exportGettyDirectory(metadata, imageId),
Expand Down