Skip to main content
The Go client library is a set of plain .go files you copy directly into your project — no module dependency, no CGo. It communicates with the dpf binary over stdin/stdout.
1

Copy the binary

Build or download the dpf binary and place it somewhere your application can reach at runtime.
# Regular build
cp devpixelforge/dpf/target/release/dpf ./bin/dpf

# Static build (no libc dependency — preferred for containers)
cp devpixelforge/dpf/target/x86_64-unknown-linux-musl/release/dpf ./bin/dpf
Verify it works:
./bin/dpf caps
2

Copy the Go client files

Create a package directory inside your project and copy the four source files:
mkdir -p internal/dpf

cp devpixelforge/go-bridge/dpf.go       ./internal/dpf/
cp devpixelforge/go-bridge/job.go       ./internal/dpf/
cp devpixelforge/go-bridge/video_job.go ./internal/dpf/
cp devpixelforge/go-bridge/audio_job.go ./internal/dpf/
After copying, change the package declaration at the top of each file to match your internal package path. For example, if you placed the files under internal/dpf/, the declaration should read package dpf. The package name does not have to match the directory path, but keeping them consistent avoids confusion.
3

Review the final directory structure

Your project should look like this:
your-project/
├── bin/
│   └── dpf                    # Rust binary
├── internal/
│   └── dpf/
│       ├── dpf.go             # Client, StreamClient, job types
│       ├── job.go             # Image job types (crop, rotate, watermark, …)
│       ├── video_job.go       # Video job types
│       └── audio_job.go       # Audio job types
└── main.go
4

Create a client and execute a job

Import your internal package and call NewClient with the path to the binary.
package main

import (
    "context"
    "log"
    "time"

    "your-project/internal/dpf"
)

func main() {
    client := dpf.NewClient("./bin/dpf")
    client.SetTimeout(60 * time.Second)

    ctx := context.Background()

    result, err := client.Resize(ctx, "photo.png", "out/", []uint32{320, 640, 1024})
    if err != nil {
        log.Fatalf("resize failed: %v", err)
    }

    log.Printf("produced %d files in %dms", len(result.Outputs), result.ElapsedMs)
}

Client API

Creating a client

client := dpf.NewClient("./bin/dpf")
NewClient sets a default timeout of 30 seconds. Adjust it with SetTimeout before executing any jobs:
// Default (image operations)
client.SetTimeout(30 * time.Second)

// Video processing (can be slow for large files)
client.SetTimeout(5 * time.Minute)

// Quick operations
client.SetTimeout(10 * time.Second)

Executing a job

Execute accepts any of the typed job structs and returns a *JobResult:
webp := "webp"
q := uint8(85)

result, err := client.Execute(ctx, &dpf.ResizeJob{
    Operation: "resize",
    Input:     "photo.png",
    OutputDir: "out/",
    Widths:    []uint32{320, 640, 1024},
    Format:    &webp,
    Quality:   &q,
})

Convenience methods

The client exposes shorthand methods for the most common operations:
// Resize to multiple widths
result, err := client.Resize(ctx, "photo.png", "out/", []uint32{320, 640, 1024})

// Optimize (lossless + WebP variant)
result, err := client.Optimize(ctx, []string{"photo.png"}, "out/")

// Convert to a different format
result, err := client.Convert(ctx, "photo.png", "out/photo.webp", "webp")

// Generate multi-size favicons + web manifest
result, err := client.Favicon(ctx, "logo.png", "out/favicons/")

// Generate a LQIP placeholder (returned as base64)
result, err := client.Placeholder(ctx, "hero.png")

// Resize by percentage
result, err := client.ResizePercent(ctx, "photo.png", "out/", 50.0)

Error handling

Check the returned error first (network/process failures), then check result.Success for operation-level failures:
result, err := client.Convert(ctx, "photo.png", "out/photo.avif", "avif")
if err != nil {
    // Binary failed to start, timed out, or returned invalid JSON
    log.Printf("execution error: %v", err)
    return
}

if !result.Success {
    // The Rust engine ran but the operation failed (e.g. missing file, bad format)
    log.Printf("operation %q failed after %dms", result.Operation, result.ElapsedMs)
    return
}

for _, f := range result.Outputs {
    log.Printf("wrote %s (%d bytes)", f.Path, f.SizeBytes)
}

JobResult structure

Every successful call returns a *JobResult:
FieldTypeDescription
SuccessboolWhether the operation succeeded
OperationstringName of the executed operation
Outputs[]OutputFileProduced files
ElapsedMsuint64Processing time in milliseconds
Metadata*json.RawMessageOperation-specific metadata (e.g. video stats)
Each OutputFile contains Path, Format, Width, Height, SizeBytes, and optionally DataBase64 when Inline: true was set on the job.

Build docs developers (and LLMs) love