Skip to content

Commit

Permalink
Expertimental WASM support (#44)
Browse files Browse the repository at this point in the history
Introducing WASM support
  • Loading branch information
StefanOltmann authored Dec 15, 2023
1 parent f97c352 commit f95aa63
Show file tree
Hide file tree
Showing 36 changed files with 1,446 additions and 842 deletions.
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

0 comments on commit f95aa63

Please sign in to comment.