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

Expertimental WASM support #44

Merged
merged 22 commits into from
Dec 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
feb5850
Refactored TagInfoGpsText.kt
StefanOltmann Dec 14, 2023
bb0176c
Renamings & constants
StefanOltmann Dec 14, 2023
d197ba4
Renamings & constants
StefanOltmann Dec 14, 2023
9b5d886
Refactoring: Moved latin1 decoding into its own class.
StefanOltmann Dec 14, 2023
afaccbb
Corrected package
StefanOltmann Dec 14, 2023
8b3d484
Removed Ktor imports from TagInfoGpsText.kt
StefanOltmann Dec 14, 2023
2908113
Fix: Interpret nullified GPS strings as empty strings
StefanOltmann Dec 14, 2023
0e337af
Optimize imports
StefanOltmann Dec 14, 2023
634e695
Save changed test data
StefanOltmann Dec 14, 2023
2226187
Latin1EncodingTest extended
StefanOltmann Dec 14, 2023
ce4e3b3
Latin1EncodingTest extended
StefanOltmann Dec 14, 2023
c9aa31d
Replacement implementation of decodeLatin1BytesToString()
StefanOltmann Dec 14, 2023
745a402
Replacement implementation of encodeToLatin1Bytes()
StefanOltmann Dec 14, 2023
d7c6dd3
Improved Latin1EncodingTest
StefanOltmann Dec 14, 2023
2652011
Latin1EncodingExtensions.kt: Ktor replaced
StefanOltmann Dec 14, 2023
3f7532a
decodeLatin1BytesToString(): More elegant implementation
StefanOltmann Dec 14, 2023
a4a60d5
Implemented own Closeable.kt to reduce Ktor dependency
StefanOltmann Dec 14, 2023
3ce4c82
Update to XMP Core 0.3
StefanOltmann Dec 15, 2023
0833d32
Added wasmJs() target and moved Ktor related stuff into its own sourc…
StefanOltmann Dec 15, 2023
0572140
Renamed different ZLib.kt implementations
StefanOltmann Dec 15, 2023
92200b4
Use only custom latin1 encoder for WASM
StefanOltmann Dec 15, 2023
143f2c0
Bump version
StefanOltmann Dec 15, 2023
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
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
![Android](https://img.shields.io/badge/-Android-gray.svg?style=flat)
![macOS](https://img.shields.io/badge/-macOS-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)
![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)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.ashampoo/kim/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.ashampoo/kim)

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

```
implementation("com.ashampoo:kim:0.7.5")
implementation("com.ashampoo:kim:0.8")
```

## Sample usages
Expand Down Expand Up @@ -137,7 +139,7 @@ val newBytes = Kim.updateThumbnail(
## Limitations

* Inability to update EXIF, IPTC and XMP in JPG files simultaneously.
* Insufficient error handling for broken or non-standard conforming files.
* There is no implementation of WebAssembly (WASM) for ZLib compression, which means that PNG files utilizing this compression cannot be processed.

## Contributions

Expand Down
59 changes: 49 additions & 10 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl

plugins {
kotlin("multiplatform") version "1.9.21"
Expand All @@ -23,7 +24,7 @@ repositories {
val productName = "Ashampoo Kim"

val ktorVersion: String = "2.3.7"
val xmpCoreVersion: String = "0.2.4"
val xmpCoreVersion: String = "0.3"
val dateTimeVersion: String = "0.5.0"
val testRessourcesVersion: String = "0.4.0"
val ioCoreVersion: String = "0.3.0"
Expand Down Expand Up @@ -144,6 +145,13 @@ kotlin {
}
}

@OptIn(ExperimentalWasmDsl::class)
wasmJs()

// Note: Missing support in kotlinx-datetime
// @OptIn(ExperimentalWasmDsl::class)
// wasmWasi()

@Suppress("UnusedPrivateMember") // False positive
val commonMain by sourceSets.getting {

Expand All @@ -152,10 +160,6 @@ kotlin {
/* Date handling */
implementation("org.jetbrains.kotlinx:kotlinx-datetime:$dateTimeVersion")

/* Needed for Charset class. */
/* Defined as api() to prevent problems when used from a pure-java project. */
api("io.ktor:ktor-io:$ktorVersion")

/* XMP handling */
api("com.ashampoo:xmpcore:$xmpCoreVersion")

Expand Down Expand Up @@ -202,15 +206,31 @@ kotlin {
}
}

val jvmMain by sourceSets.getting
val ktorMain by sourceSets.creating {

@Suppress("UnusedPrivateMember", "UNUSED_VARIABLE") // False positive
val androidMain by sourceSets.getting {
dependsOn(jvmMain)
dependsOn(commonMain)

dependencies {

api("io.ktor:ktor-io:$ktorVersion")
}
}

val posixMain by sourceSets.creating {

dependsOn(commonMain)
dependsOn(ktorMain)
}

val jvmMain by sourceSets.getting {

dependsOn(commonMain)
dependsOn(ktorMain)
}

@Suppress("UnusedPrivateMember", "UNUSED_VARIABLE") // False positive
val androidMain by sourceSets.getting {
dependsOn(jvmMain)
}

@Suppress("UnusedPrivateMember", "UNUSED_VARIABLE") // False positive
Expand All @@ -227,13 +247,25 @@ kotlin {
val appleMain by sourceSets.creating {

dependsOn(commonMain)
dependsOn(ktorMain)
dependsOn(posixMain)

iosArm64Main.dependsOn(this)
iosSimulatorArm64Main.dependsOn(this)
macosX64Main.dependsOn(this)
macosArm64Main.dependsOn(this)
}

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

val wasmMain by sourceSets.creating {

dependsOn(commonMain)

wasmJsMain.dependsOn(this)
// wasmWasiMain.dependsOn(this)
}
}

// region Writing version.txt for GitHub Actions
Expand Down Expand Up @@ -303,6 +335,8 @@ afterEvaluate {
val signMacosArm64Publication by tasks.getting
val signMacosX64Publication by tasks.getting
val signWinPublication by tasks.getting
val signWasmJsPublication by tasks.getting
val signWasmWasiPublication by tasks.getting
val signKotlinMultiplatformPublication by tasks.getting

val publishJvmPublicationToSonatypeRepository by tasks.getting
Expand All @@ -312,14 +346,17 @@ afterEvaluate {
val publishMacosArm64PublicationToSonatypeRepository by tasks.getting
val publishMacosX64PublicationToSonatypeRepository by tasks.getting
val publishWinPublicationToSonatypeRepository by tasks.getting
val publishWasmJsPublicationToSonatypeRepository by tasks.getting
val publishWasmWasiPublicationToSonatypeRepository by tasks.getting
val publishKotlinMultiplatformPublicationToSonatypeRepository by tasks.getting
val publishAllPublicationsToSonatypeRepository by tasks.getting

val signTasks = listOf(
signJvmPublication, signAndroidReleasePublication,
signIosArm64Publication, signIosSimulatorArm64Publication,
signMacosArm64Publication, signMacosX64Publication,
signWinPublication, signKotlinMultiplatformPublication
signWinPublication, signWasmJsPublication, signWasmWasiPublication,
signKotlinMultiplatformPublication
)

val publishTasks = listOf(
Expand All @@ -330,6 +367,8 @@ afterEvaluate {
publishMacosArm64PublicationToSonatypeRepository,
publishMacosX64PublicationToSonatypeRepository,
publishWinPublicationToSonatypeRepository,
publishWasmJsPublicationToSonatypeRepository,
publishWasmWasiPublicationToSonatypeRepository,
publishKotlinMultiplatformPublicationToSonatypeRepository,
publishAllPublicationsToSonatypeRepository
)
Expand Down
16 changes: 1 addition & 15 deletions src/commonMain/kotlin/com/ashampoo/kim/Kim.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,12 @@ import com.ashampoo.kim.input.ByteArrayByteReader
import com.ashampoo.kim.input.ByteReader
import com.ashampoo.kim.input.DefaultRandomAccessByteReader
import com.ashampoo.kim.input.KotlinIoSourceByteReader
import com.ashampoo.kim.input.KtorByteReadChannelByteReader
import com.ashampoo.kim.input.KtorInputByteReader
import com.ashampoo.kim.input.PrePendingByteReader
import com.ashampoo.kim.input.use
import com.ashampoo.kim.model.ImageFormat
import com.ashampoo.kim.model.MetadataUpdate
import com.ashampoo.kim.output.ByteArrayByteWriter
import com.ashampoo.kim.output.ByteWriter
import io.ktor.utils.io.ByteReadChannel
import io.ktor.utils.io.core.ByteReadPacket
import io.ktor.utils.io.core.use
import kotlinx.io.files.Path

object Kim {
Expand All @@ -71,16 +67,6 @@ object Kim {
}
}

@kotlin.jvm.JvmStatic
@Throws(ImageReadException::class)
fun readMetadata(byteReadPacket: ByteReadPacket): ImageMetadata? =
readMetadata(KtorInputByteReader(byteReadPacket))

@kotlin.jvm.JvmStatic
@Throws(ImageReadException::class)
fun readMetadata(byteReadChannel: ByteReadChannel, contentLength: Long): ImageMetadata? =
readMetadata(KtorByteReadChannelByteReader(byteReadChannel, contentLength))

@kotlin.jvm.JvmStatic
@Throws(ImageReadException::class)
fun readMetadata(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@

package com.ashampoo.kim.common

import io.ktor.utils.io.charsets.Charsets

private const val FF = 0xFF

const val HEX_RADIX = 16
Expand All @@ -40,13 +38,6 @@ fun ByteArray.toHex(): String =
fun ByteArray.toSingleNumberHexes(): String =
joinToString(", ") { "0x" + it.toHex() }

@Suppress("MagicNumber")
fun ByteArray.decodeToIso8859String(): String =
io.ktor.utils.io.core.String(
bytes = this,
charset = Charsets.ISO_8859_1
)

fun ByteArray.indexOfNullTerminator(): Int =
indexOfNullTerminator(0)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright 2023 Ashampoo GmbH & Co. KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.ashampoo.kim.common

expect fun ByteArray.decodeLatin1BytesToString(): String

expect fun String.encodeToLatin1Bytes(): ByteArray
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package com.ashampoo.kim.format.jpeg.iptc

import com.ashampoo.kim.common.ByteOrder
import com.ashampoo.kim.common.ImageReadException
import com.ashampoo.kim.common.decodeToIso8859String
import com.ashampoo.kim.common.decodeLatin1BytesToString
import com.ashampoo.kim.common.slice
import com.ashampoo.kim.common.startsWith
import com.ashampoo.kim.common.toInt
Expand Down Expand Up @@ -143,7 +143,7 @@ object IptcParser {
value = if (isUtf8)
recordData.decodeToString()
else
recordData.decodeToIso8859String()
recordData.decodeLatin1BytesToString()
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
package com.ashampoo.kim.format.png.chunks

import com.ashampoo.kim.common.ImageReadException
import com.ashampoo.kim.common.decodeToIso8859String
import com.ashampoo.kim.common.decodeLatin1BytesToString
import com.ashampoo.kim.common.decompress
import com.ashampoo.kim.common.indexOfNullTerminator
import com.ashampoo.kim.common.slice
Expand Down Expand Up @@ -51,7 +51,7 @@ class PngChunkItxt(
keyword = bytes.slice(
startIndex = 0,
count = terminatorIndex
).decodeToIso8859String()
).decodeLatin1BytesToString()

var index = terminatorIndex + 1

Expand All @@ -75,7 +75,7 @@ class PngChunkItxt(
languageTag = bytes.copyOfRange(
fromIndex = index,
toIndex = terminatorIndex
).decodeToIso8859String()
).decodeLatin1BytesToString()

index = terminatorIndex + 1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
package com.ashampoo.kim.format.png.chunks

import com.ashampoo.kim.common.ImageReadException
import com.ashampoo.kim.common.decodeToIso8859String
import com.ashampoo.kim.common.decodeLatin1BytesToString
import com.ashampoo.kim.common.indexOfNullTerminator
import com.ashampoo.kim.format.png.ChunkType

Expand All @@ -44,14 +44,14 @@ class PngChunkText(
keyword = bytes.copyOfRange(
fromIndex = 0,
toIndex = index
).decodeToIso8859String()
).decodeLatin1BytesToString()

val textLength = bytes.size - (index + 1)

text = bytes.copyOfRange(
fromIndex = index + 1,
toIndex = textLength
).decodeToIso8859String()
).decodeLatin1BytesToString()
}

override fun getKeyword(): String =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
package com.ashampoo.kim.format.png.chunks

import com.ashampoo.kim.common.ImageReadException
import com.ashampoo.kim.common.decodeToIso8859String
import com.ashampoo.kim.common.decodeLatin1BytesToString
import com.ashampoo.kim.common.decompress
import com.ashampoo.kim.common.indexOfNullTerminator
import com.ashampoo.kim.format.png.ChunkType
Expand Down Expand Up @@ -46,7 +46,7 @@ class PngChunkZtxt(
keyword = bytes.copyOfRange(
fromIndex = 0,
toIndex = index
).decodeToIso8859String()
).decodeLatin1BytesToString()

index++

Expand Down
Loading