Ashampoo / kim

Image metadata manipulation library for Kotlin Multiplatform
https://ashampoo.github.io/kim/
Apache License 2.0
163 stars 8 forks source link
avif camera-raw digital-images dng exif geotiff heic image-metadata iptc jpeg-xl jpg jxl kotlin kotlin-multiplatform metadata png tiff webp xmp

Kim - Kotlin Image Metadata

Kotlin JVM Android iOS Windows Linux macOS JS WASM Coverage

Kim is a Kotlin Multiplatform library for reading and writing image metadata.

It's part of Ashampoo Photo Organizer.

Features

The future development of features on our part is driven entirely by the needs of Ashampoo Photo Organizer, which, in turn, is driven by user community feedback.

Installation

implementation("com.ashampoo:kim:0.18.4")

For the targets wasmJs & js you also need to specify this:

implementation(npm("pako", "2.1.0"))

Sample usages

Read metadata

Kim.readMetadata() takes kotlin.ByteArray on all platforms and depending on the platform also kotlinx.io.files.Path, Ktor ByteReadPacket & ByteReadChannel, java.io.File, java.io.InputStream, NSData and String paths.

val bytes: ByteArray = loadBytes()

val metadata = Kim.readMetadata(bytes)

/* ImageMetadata has a proper toString() similar to the output of ExifTool */
println(metadata)

val orientation = metadata.findShortValue(TiffTag.TIFF_TAG_ORIENTATION)

println("Orientation: $orientation")

val takenDate = metadata.findStringValue(ExifTag.EXIF_TAG_DATE_TIME_ORIGINAL)

println("Taken date: $takenDate")

Create high level summary object

This creates an instance of PhotoMetadata. It contains the following:

val bytes: ByteArray = loadBytes()

val photoMetadata = Kim.readMetadata(bytes).convertToPhotoMetadata()

Change orientation using low level API

val inputFile = File("myphoto.jpg")
val outputFile = File("myphoto_changed.jpg")

val metadata = Kim.readMetadata(inputFile)

val outputSet: TiffOutputSet = metadata.exif?.createOutputSet() ?: TiffOutputSet()

val rootDirectory = outputSet.getOrCreateRootDirectory()

rootDirectory.removeField(TiffTag.TIFF_TAG_ORIENTATION)
rootDirectory.add(TiffTag.TIFF_TAG_ORIENTATION, 8)

OutputStreamByteWriter(outputFile.outputStream()).use { outputStreamByteWriter ->

    JpegRewriter.updateExifMetadataLossless(
        byteReader = JvmInputStreamByteReader(inputFile.inputStream(), inputFile.length()),
        byteWriter = outputStreamByteWriter,
        outputSet = outputSet
    )
}

See the example project for more details.

Change orientation using Kim.update() API

val bytes: ByteArray = loadBytes()

val newBytes = Kim.update(
    bytes = bytes,
    update = MetadataUpdate.Orientation(TiffOrientation.ROTATE_RIGHT)
)

See AbstractUpdaterTest for more samples.

Update thumbnail using Kim.update() API

val bytes: ByteArray = loadBytes()
val thumbnailBytes: ByteArray = loadThumbnailBytes()

val newBytes = Kim.updateThumbnail(
    bytes = bytes,
    thumbnailBytes = thumbnailBytes
)

Using Java

See the Java example project how to use Kim in Java projects.

Limitations

Regarding HEIC & AVIF metadata

In the processing of HEIC and AVIF files, we handle them as standard ISOBMFF-based files, adhering rigorously to the EIC/ISO 14496-12 specification. To preempt potential legal issues, we intentionally omit certain boxes outlined in the HEIC specification, notably the image size ("ispe") and image rotation ("irot") boxes. This approach extends to AVIF images, as they repurpose the same boxes.

Contributions

Contributions to Ashampoo Kim are welcome! If you encounter any issues, have suggestions for improvements, or would like to contribute new features, please feel free to submit a pull request.

Acknowledgements

License

This code is under the Apache License 2.0.

See the NOTICE.txt file for required notices and attributions.