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

JS support & XMP picked flag #78

Merged
merged 17 commits into from
Mar 15, 2024
Merged
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
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# Kim - Kotlin Image Metadata

[![Kotlin](https://img.shields.io/badge/kotlin-1.9.22-blue.svg?logo=kotlin)](httpw://kotlinlang.org)
[![Kotlin](https://img.shields.io/badge/kotlin-1.9.23-blue.svg?logo=kotlin)](httpw://kotlinlang.org)
![JVM](https://img.shields.io/badge/-JVM-gray.svg?style=flat)
![Android](https://img.shields.io/badge/-Android-gray.svg?style=flat)
![iOS](https://img.shields.io/badge/-iOS-gray.svg?style=flat)
![Windows](https://img.shields.io/badge/-Windows-gray.svg?style=flat)
![Linux](https://img.shields.io/badge/-Linux-gray.svg?style=flat)
![macOS](https://img.shields.io/badge/-macOS-gray.svg?style=flat)
![JS](https://img.shields.io/badge/-JS-gray.svg?style=flat)
![WASM](https://img.shields.io/badge/-WASM-gray.svg?style=flat)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=kim&metric=coverage)](https://sonarcloud.io/summary/new_code?id=kim)

Expand Down Expand Up @@ -38,7 +39,7 @@ of Ashampoo Photos, which, in turn, is driven by user community feedback.
## Installation

```
implementation("com.ashampoo:kim:0.15.1")
implementation("com.ashampoo:kim:0.16")
```

## Sample usages
Expand Down Expand Up @@ -125,7 +126,7 @@ val newBytes = Kim.update(
)
```

See [JpegUpdaterTest](src/commonTest/kotlin/com/ashampoo/kim/format/jpeg/JpegUpdaterTest.kt)
See [AbstractUpdaterTest](src/commonTest/kotlin/com/ashampoo/kim/format/AbstractUpdaterTest.kt)
for more samples.

### Update thumbnail using Kim.update() API
Expand Down
24 changes: 20 additions & 4 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl

plugins {
kotlin("multiplatform") version "1.9.22"
kotlin("multiplatform") version "1.9.23"
id("com.android.library") version "8.2.2"
id("maven-publish")
id("signing")
Expand All @@ -14,7 +14,7 @@ plugins {
id("me.qoomon.git-versioning") version "6.4.3"
id("com.goncalossilva.resources") version "0.4.0"
id("com.github.ben-manes.versions") version "0.51.0"
id("org.jetbrains.dokka") version "1.9.10"
id("org.jetbrains.dokka") version "1.9.20"
}

repositories {
Expand All @@ -25,7 +25,7 @@ repositories {
val productName = "Ashampoo Kim"

val ktorVersion: String = "2.3.8"
val xmpCoreVersion: String = "1.1.0"
val xmpCoreVersion: String = "1.2.0"
val dateTimeVersion: String = "0.5.0"
val testRessourcesVersion: String = "0.4.0"
val ioCoreVersion: String = "0.3.1"
Expand Down Expand Up @@ -168,6 +168,10 @@ kotlin {
}
}

js() {
// nodejs()
}

@OptIn(ExperimentalWasmDsl::class)
wasmJs {
// All tests reading from files fail, because kotlinx-io
Expand Down Expand Up @@ -315,6 +319,15 @@ kotlin {
macosArm64Test.dependsOn(this)
}

val jsMain by sourceSets.getting {

dependsOn(commonMain)

dependencies {
implementation(npm("pako", "2.1.0"))
}
}

val wasmJsMain by sourceSets.getting
// val wasmWasiMain by sourceSets.getting

Expand Down Expand Up @@ -402,6 +415,7 @@ afterEvaluate {
val signWinPublication by tasks.getting
val signLinuxX64Publication by tasks.getting
val signLinuxArm64Publication by tasks.getting
val signJsPublication by tasks.getting
val signWasmJsPublication by tasks.getting
// val signWasmWasiPublication by tasks.getting
val signKotlinMultiplatformPublication by tasks.getting
Expand All @@ -416,6 +430,7 @@ afterEvaluate {
val publishWinPublicationToSonatypeRepository by tasks.getting
val publishLinuxX64PublicationToSonatypeRepository by tasks.getting
val publishLinuxArm64PublicationToSonatypeRepository by tasks.getting
val publishJsPublicationToSonatypeRepository by tasks.getting
val publishWasmJsPublicationToSonatypeRepository by tasks.getting
// val publishWasmWasiPublicationToSonatypeRepository by tasks.getting
val publishKotlinMultiplatformPublicationToSonatypeRepository by tasks.getting
Expand All @@ -427,7 +442,7 @@ afterEvaluate {
signIosSimulatorArm64Publication,
signMacosArm64Publication, signMacosX64Publication,
signWinPublication, signLinuxX64Publication, signLinuxArm64Publication,
signWasmJsPublication, // signWasmWasiPublication,
signJsPublication, signWasmJsPublication, // signWasmWasiPublication,
signKotlinMultiplatformPublication
)

Expand All @@ -442,6 +457,7 @@ afterEvaluate {
publishWinPublicationToSonatypeRepository,
publishLinuxX64PublicationToSonatypeRepository,
publishLinuxArm64PublicationToSonatypeRepository,
publishJsPublicationToSonatypeRepository,
publishWasmJsPublicationToSonatypeRepository,
// publishWasmWasiPublicationToSonatypeRepository,
publishKotlinMultiplatformPublicationToSonatypeRepository,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,12 @@ fun ImageMetadata.convertToPhotoMetadata(
exposureTime = exposureTime,
fNumber = fNumber,
focalLength = focalLength,
flagged = xmpMetadata?.flagged ?: false,
rating = xmpMetadata?.rating,
keywords = keywords.ifEmpty { xmpMetadata?.keywords ?: emptySet() },
faces = xmpMetadata?.faces ?: emptyMap(),
personsInImage = xmpMetadata?.personsInImage ?: emptySet(),
albums = xmpMetadata?.albums ?: emptySet(),
thumbnailImageSize = thumbnailImageSize,
thumbnailBytes = thumbnailBytes
)
Expand Down
13 changes: 6 additions & 7 deletions src/commonMain/kotlin/com/ashampoo/kim/format/xmp/XmpReader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,16 @@ object XmpReader {
?.substringBefore('+')
?.substringBefore('Z')

val takenDate = if (takenDateIsoStringWithoutTimezone != null)
val takenDate = takenDateIsoStringWithoutTimezone?.let {
try {
LocalDateTime.parse(takenDateIsoStringWithoutTimezone)
LocalDateTime.parse(it)
.toInstant(timeZone)
.toEpochMilliseconds()
} catch (ignore: Exception) {
/* We ignore invalid XMP DateTimeOriginal values. */
null
}
else
null
}

/*
* Read location
Expand All @@ -87,18 +86,18 @@ object XmpReader {
*/

return PhotoMetadata(
widthPx = null,
heightPx = null,
orientation = TiffOrientation.of(xmpMeta.getOrientation()),
takenDate = takenDate,
gpsCoordinates = gpsCoordinates,
location = null, // TODO Read location information to avoid GPS resolving!
flagged = xmpMeta.isFlagged(),
rating = xmpMeta.getRating()?.let { PhotoRating.of(it) },
keywords = xmpMeta.getKeywords().ifEmpty {
xmpMeta.getAcdSeeKeywords()
},
faces = xmpMeta.getFaces(),
personsInImage = xmpMeta.getPersonsInImage()
personsInImage = xmpMeta.getPersonsInImage(),
albums = xmpMeta.getAlbums()
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ object XmpWriter {
deleteGpsCoordinates()
}

is MetadataUpdate.Flagged ->
setFlagged(update.flagged)

is MetadataUpdate.Rating ->
setRating(update.photoRating.value)

Expand All @@ -86,6 +89,9 @@ object XmpWriter {

is MetadataUpdate.Persons ->
setPersonsInImage(update.personsInImage)

is MetadataUpdate.Albums ->
setAlbums(update.albums)
}
}

Expand Down
16 changes: 15 additions & 1 deletion src/commonMain/kotlin/com/ashampoo/kim/model/MetadataUpdate.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ sealed interface MetadataUpdate {
val gpsCoordinates: com.ashampoo.kim.model.GpsCoordinates?
) : MetadataUpdate

/**
* Set a photo as flagged/tagged/picked.
*/
data class Flagged(
val flagged: Boolean
) : MetadataUpdate

/**
* Set a new Rating.
* Can't be NULL and should be UNRATED instead.
Expand All @@ -68,10 +75,17 @@ sealed interface MetadataUpdate {
) : MetadataUpdate

/**
* List of new faces to set. An empty list removes all faces.
* List of new persons to set. An empty list removes all persons.
*/
data class Persons(
val personsInImage: Set<String>
) : MetadataUpdate

/**
* List of new albums to set. An empty list removes all albums.
*/
data class Albums(
val albums: Set<String>
) : MetadataUpdate

}
8 changes: 8 additions & 0 deletions src/commonMain/kotlin/com/ashampoo/kim/model/PhotoMetadata.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,17 @@ data class PhotoMetadata(
val focalLength: Double? = null,

/* Ratings & Tags */
val flagged: Boolean = false,
val rating: PhotoRating? = null,
val keywords: Set<String> = emptySet(),

/* Persons */
val faces: Map<String, XMPRegionArea> = emptyMap(),
val personsInImage: Set<String> = emptySet(),

/* Albums */
val albums: Set<String> = emptySet(),

/* EXIF Thumbnail (IFD1) */
val thumbnailImageSize: ImageSize? = null,
val thumbnailBytes: ByteArray? = null
Expand Down Expand Up @@ -132,13 +136,17 @@ data class PhotoMetadata(
focalLength = focalLength ?: other.focalLength,

/* Ratings & Tags */
flagged = flagged || other.flagged,
rating = rating ?: other.rating,
keywords = keywords.ifEmpty { other.keywords },

/* Persons */
faces = faces.ifEmpty { other.faces },
personsInImage = personsInImage.ifEmpty { other.personsInImage },

/* Albums */
albums = albums.ifEmpty { other.albums },

/* EXIF Thumbnail (IFD1) */
thumbnailImageSize = thumbnailImageSize ?: other.thumbnailImageSize,
thumbnailBytes = thumbnailBytes ?: other.thumbnailBytes
Expand Down
3 changes: 2 additions & 1 deletion src/commonTest/kotlin/com/ashampoo/kim/ImageMetadataTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import com.ashampoo.kim.common.writeBytes
import com.ashampoo.kim.testdata.KimTestData
import kotlinx.io.files.Path
import kotlin.test.Test
import kotlin.test.fail

class ImageMetadataTest {

Expand Down Expand Up @@ -46,7 +47,7 @@ class ImageMetadataTest {
Path("build/photo_$index.txt")
.writeBytes(actualToString)

// fail("photo_$index.txt is different.")
fail("photo_$index.txt is different.")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ class PhotoMetadataConverterTest {
stringBuilder.appendLine(
"name;widthPx;heightPx;orientation;takenDate;latitude;longitude;" +
"cameraMake;cameraModel;lensMake;lensModel;iso;exposureTime;fNumber;" +
"focalLength;rating;keywords;thumbnailImageSize;thumbnailBytes.size"
"focalLength;flagged;rating;keywords;personsInAlbums;albums;" +
"thumbnailImageSize;thumbnailBytes.size"
)

for (entry in metadataMap.entries) {
Expand All @@ -92,9 +93,10 @@ class PhotoMetadataConverterTest {
"${metadata.gpsCoordinates?.latitude};${metadata.gpsCoordinates?.longitude};" +
"${metadata.cameraMake};${metadata.cameraModel};${metadata.lensMake};" +
"${metadata.lensModel};${metadata.iso};${metadata.exposureTime};" +
"${metadata.fNumber};${metadata.focalLength};${metadata.rating?.value};" +
"${metadata.keywords};${metadata.thumbnailImageSize};" +
"${metadata.thumbnailBytes?.size}"
"${metadata.fNumber};${metadata.focalLength};" +
"${metadata.flagged};${metadata.rating?.value};" +
"${metadata.keywords};${metadata.personsInImage};${metadata.albums};" +
"${metadata.thumbnailImageSize};${metadata.thumbnailBytes?.size}"
)
}

Expand Down
Loading
Loading