Skip to content

shaksternano/gif.kt

Repository files navigation

gif.kt

GitHub license Download Kotlin Java KDoc link

A Kotlin Multiplatform GIF decoding and encoding library.

Features

  • Supports static and animated GIFs.
  • Easy to use API.
  • Memory-efficient decoding.
  • Fast parallel encoding.
  • Automatic lossless compression when encoding, as well as optional lossy compression.
  • Automatic handling of GIF minimum frame duration when encoding.
  • Supports several GIF options, such as looping and comments.

Installation

Requires JDK 8 or higher when targeting the JVM.

Gradle

repositories {
    mavenCentral()
    google()
}

dependencies {
    implementation("com.shakster:gifkt:0.3.0")
}

Maven

<repositories>
    <repository>
        <id>google</id>
        <url>https://maven.google.com</url>
    </repository>
</repositories>

<dependencies>
    <dependency>
        <groupId>com.shakster</groupId>
        <artifactId>gifkt-jvm</artifactId>
        <version>0.3.0</version>
    </dependency>
</dependencies>

Usage

API documentation is available here.

Decoding

Kotlin

// Obtain a Path to read the GIF data from
val path: Path = ...
val data = path.asRandomAccess()
val decoder = GifDecoder(data)

// Read a single frame by index
val frame1 = decoder[0]

// Read a single frame by timestamp
val frame2 = decoder[2.seconds]

// Read all frames
decoder.asSequence().forEach { frame ->
    // Process each frame
}

decoder.close()

Java

// Obtain a Path to read the GIF data from
Path path = ...;
RandomAccessData data = RandomAccessData.of(path);
GifDecoder decoder = new GifDecoder(data);

// Read a single frame by index
ImageFrame frame1 = decoder.get(0);

// Read a single frame by timestamp
ImageFrame frame2 = decoder.get(Duration.ofSeconds(2));

// Read all frames
for (ImageFrame frame : decoder.asList()) {
    // Process each frame
}

decoder.close();

Encoding

Kotlin

// Obtain a Path to write the GIF data to
val path: Path = ...
val sink = SystemFileSystem.sink(path).buffered()
val encoder = GifEncoder(sink)

val argb: IntArray = ...
val width: Int = ...
val height: Int = ...
val duration: Duration = ...
encoder.writeFrame(argb, width, height, duration)

encoder.close()

Java

// Obtain a Path to write the GIF data to
Path path = ...;
OutputStream outputStream = Files.newOutputStream(path);
GifEncoderBuilder builder = GifEncoder.builder(outputStream);
GifEncoder encoder = builder.build();

int[] argb = ...;
int width = ...;
int height = ...;
Duration duration = ...;
encoder.writeFrame(argb, width, height, duration);

encoder.close();

Parallel Encoding

Not supported on JavaScript or Wasm.

Kotlin

// Obtain a Path to write the GIF data to
val path: Path = ...
val sink = SystemFileSystem.sink(path).buffered()
// Use all available CPU cores for maximum encoding speed
val cpuCount: Int = ...
val encoder = ParallelGifEncoder(
    sink,
    maxConcurrency = cpuCount,
    ioContext = Dispatchers.IO,
)

val argb1: IntArray = ...
val width1: Int = ...
val height1: Int = ...
val duration1: Duration = ...

val argb2: IntArray = ...
val width2: Int = ...
val height2: Int = ...
val duration2: Duration = ...

// Frames are encoded in parallel
// Suspending
encoder.writeFrame(argb1, width1, height1, duration1)
encoder.writeFrame(argb2, width2, height2, duration2)

// Suspending
encoder.close()

Java

// Obtain a Path to write the GIF data to
Path path = ...;
OutputStream outputStream = Files.newOutputStream(path);
// Use all available CPU cores for maximum encoding speed
int cpuCount = ...;
GifEncoderBuilder builder = GifEncoder.builder(outputStream);
builder.setMaxConcurrency(cpuCount);
builder.setIoContext(Dispatchers.getIO());
ParallelGifEncoder encoder = builder.buildParallel();

int[] argb1 = ...;
int width1 = ...;
int height1 = ...;
Duration duration1 = ...;

int[] argb2 = ...;
int width2 = ...;
int height2 = ...;
Duration duration2 = ...;

// Frames are encoded in parallel
encoder.writeFrameFuture(argb1, width1, height1, duration1)
    .thenCompose(unused -> encoder.writeFrameFuture(argb2, width2, height2, duration2))
    .thenCompose(unused -> encoder.closeFuture())
    .join();

Modules

Core

The core module contains the main library code.

Compose

The compose module contains Compose Multiplatform integration.

Requires JDK 11 or higher when targeting the JVM.

Gradle

dependencies {
    implementation("com.shakster:gifkt-compose:0.3.0")
}

CLI

The cli module contains a command-line interface GIF encoder tool that uses the library to create GIFs from images, videos, and other GIFs.

Requires JDK 21 or higher to run.

Developing

JDK 21 or higher is required to build the project.

Run ./gradlew build to build the project.

Run ./gradlew cleanAllTests allTests to run all tests.

Run ./gradlew dokkaGenerate to generate API documentation. The output will be in core/build/dokka/html.

Snapshot Releases

A snapshot release is published with every push to the main branch. To use a snapshot release, add the Maven snapshot repository and append -SNAPSHOT to the version.

Gradle

repositories {
    mavenCentral()
    google()
    maven("https://central.sonatype.com/repository/maven-snapshots")
}

dependencies {
    implementation("com.shakster:gifkt:0.3.0-SNAPSHOT")
}

Maven

<repositories>
    <repository>
        <id>google</id>
        <url>https://maven.google.com</url>
    </repository>
    <repository>
        <id>maven-snapshots</id>
        <url>https://central.sonatype.com/repository/maven-snapshots</url>
    </repository>
</repositories>

<dependencies>
    <dependency>
        <groupId>com.shakster</groupId>
        <artifactId>gifkt-jvm</artifactId>
        <version>0.3.0-SNAPSHOT</version>
    </dependency>
</dependencies>

About

A Kotlin Multiplatform GIF decoding and encoding library.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages