blendpreview

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 24, 2026 License: MIT Imports: 12 Imported by: 0

README

blendpreview

Go Reference CI Release

A small Go package for extracting the embedded thumbnail from Blender .blend files without launching Blender.

blendpreview is intended for file browsers, asset managers, version-control tools, desktop applications, media pipelines, and other software that needs to display Blender thumbnails quickly.

Features

  • Pure Go API; Blender does not need to be installed.
  • Extracts Blender's embedded TEST preview block.
  • Supports legacy 32-bit and 64-bit blend block headers.
  • Supports Blender's newer 17-byte / LargeBHead8 file-header format.
  • Supports uncompressed, gzip-compressed, and zstd-compressed .blend files.
  • Compressed files are decoded as streams; the complete file is not decompressed up front.
  • Uncompressed files use seeking where possible to skip irrelevant blocks efficiently.
  • Returns a standard Go *image.RGBA.
  • Includes a convenience PNG writer and a small CLI.
  • Includes allocation and overflow checks for malformed/untrusted files.

Installation

go get github.com/aderemi-adesada/blendpreview

Requires Go 1.22 or newer.

Package usage

Extract from a file
package main

import (
    "fmt"
    "image/png"
    "os"

    "github.com/aderemi-adesada/blendpreview"
)

func main() {
    img, err := blendpreview.Extract("scene.blend")
    if err != nil {
        panic(err)
    }

    out, err := os.Create("preview.png")
    if err != nil {
        panic(err)
    }
    defer out.Close()

    if err := png.Encode(out, img); err != nil {
        panic(err)
    }

    fmt.Println(img.Bounds())
}
Save directly to PNG
err := blendpreview.SavePNG("scene.blend", "preview.png")
if err != nil {
    panic(err)
}
Decode from an io.Reader

Useful when the blend file comes from an archive, object store, network stream, or another abstraction:

f, err := os.Open("scene.blend")
if err != nil {
    panic(err)
}
defer f.Close()

img, err := blendpreview.Decode(f)
if err != nil {
    panic(err)
}

_ = img

Decode automatically detects uncompressed, gzip, and zstd input.

Error handling

The package exposes sentinel errors so callers can use errors.Is:

img, err := blendpreview.Extract("scene.blend")
if err != nil {
    switch {
    case errors.Is(err, blendpreview.ErrNoPreview):
        // The file is valid enough to read but has no embedded thumbnail.
    case errors.Is(err, blendpreview.ErrNotBlend):
        // The input is not a recognized .blend file.
    case errors.Is(err, blendpreview.ErrUnsupportedFormat):
        // Blender file header format is not supported yet.
    case errors.Is(err, blendpreview.ErrInvalidPreview):
        // The TEST block is malformed or inconsistent.
    case errors.Is(err, blendpreview.ErrPreviewTooLarge):
        // Preview exceeds the allocation safety limit.
    default:
        // I/O or another parsing error.
    }
}

_ = img

Compressed .blend files

The package does not first create a fully decompressed temporary copy of a compressed .blend file.

For gzip and zstd files, decompression is streamed:

compressed .blend
      │
      ▼
gzip / zstd reader
      │
      ▼
Blender header
      │
      ▼
file blocks
      │
      ├── REND / other blocks
      │
      └── TEST  ──► embedded RGBA preview
                     extraction stops here

Because ordinary gzip and zstd streams are sequential, bytes before the TEST block still have to be decompressed. Bytes after the preview do not need to be processed.

For uncompressed files opened through Extract, the package can seek over unrelated blocks instead of reading their contents.

CLI

The repository also includes a small command-line utility.

Install it:

go install github.com/aderemi-adesada/blendpreview/cmd/blendpreview@latest

Use it:

blendpreview -o preview.png scene.blend
Prebuilt binaries

Tagged releases include prebuilt CLI binaries for:

  • Linux: amd64 and arm64
  • macOS: amd64 and arm64
  • Windows: amd64 and arm64

Each release also includes checksums.txt containing SHA-256 checksums for the downloadable archives.

See the GitHub Releases page to download a binary.

How it works

A .blend file starts with a Blender header followed by a sequence of file blocks. Blender uses the TEST block for the file thumbnail. The preview payload contains two integers for width and height followed by raw 8-bit RGBA pixel data.

The pixel rows are stored bottom-up. blendpreview flips the rows while reading them directly into Go's image.RGBA, avoiding an extra full-size pixel buffer.

The package only parses the small amount of the .blend format needed to locate and decode the embedded preview; it does not parse Blender DNA or scene data.

Compatibility

The parser supports:

Input Support
Uncompressed .blend Yes
gzip-compressed .blend Yes
zstd-compressed .blend Yes
Legacy 32-bit block headers Yes
Legacy 64-bit block headers Yes
Big-endian legacy files Yes
New 17-byte / LargeBHead8 header Yes

A .blend file is not guaranteed to contain a preview. Blender can save files without one, in which case ErrNoPreview is returned.

Performance

The package is designed for thumbnail-heavy applications:

  • no Blender process startup;
  • no scene loading;
  • no DNA parsing;
  • no temporary decompressed file;
  • streaming decompression for compressed files;
  • seek-based block skipping for normal files;
  • one image-sized allocation for preview pixels.

For file browsers and asset managers, it is still a good idea to cache the generated PNG/WebP thumbnail and invalidate it when the .blend file's size or modification time changes.

Format references

The implementation follows Blender's public file-format structures, particularly:

Blender itself is a separate project and is not bundled with this package. This project is not affiliated with or endorsed by the Blender Foundation.

Releasing

Releases are created automatically by GitHub Actions when a semantic-version tag is pushed.

For example:

git tag -a v0.1.0 -m "v0.1.0"
git push origin v0.1.0

The release workflow verifies the module, runs tests and go vet, builds the CLI for Linux, macOS, and Windows on amd64/arm64, generates SHA-256 checksums, and creates the GitHub Release with generated release notes.

Pre-release tags such as v1.0.0-rc.1 are automatically marked as pre-releases on GitHub.

Contributing

Issues and pull requests are welcome. Please include a small reproducible fixture or enough information about the Blender version and compression mode when reporting format compatibility problems.

Run the test suite with:

go test ./...

Run formatting before submitting changes:

gofmt -w $(find . -name '*.go' -type f)

License

MIT. See LICENSE.

Documentation

Overview

Package blendpreview extracts the embedded thumbnail from Blender .blend files without launching Blender.

The package supports uncompressed, gzip-compressed, and zstd-compressed blend files. Compressed files are decoded as streams, so extraction stops as soon as the embedded TEST preview block is found; the entire file does not need to be decompressed first.

Index

Examples

Constants

View Source
const MaxPreviewBytes int64 = 256 << 20 // 256 MiB

MaxPreviewBytes is the maximum amount of pixel data accepted from an embedded preview. Blender previews are normally tiny; this limit primarily protects callers that process untrusted files from excessive allocations.

Variables

View Source
var (
	// ErrNotBlend indicates that the input is not a recognized Blender .blend file.
	ErrNotBlend = errors.New("blendpreview: not a Blender file")

	// ErrNoPreview indicates that the .blend file does not contain an embedded preview.
	ErrNoPreview = errors.New("blendpreview: no embedded preview")

	// ErrUnsupportedFormat indicates that the file starts like a .blend file but uses
	// a low-level header format this version of the package does not understand.
	ErrUnsupportedFormat = errors.New("blendpreview: unsupported Blender file format")

	// ErrInvalidPreview indicates that a TEST block exists but its dimensions or payload
	// are invalid or inconsistent.
	ErrInvalidPreview = errors.New("blendpreview: invalid embedded preview")

	// ErrPreviewTooLarge indicates that a malformed or unusually large preview exceeds
	// the package's allocation safety limit.
	ErrPreviewTooLarge = errors.New("blendpreview: embedded preview is too large")
)

Functions

func Decode

func Decode(r io.Reader) (*image.RGBA, error)

Decode reads a .blend file from r and returns its embedded preview.

Decode auto-detects uncompressed, gzip, and zstd input. It does not close r. Any decompressor created internally is closed before Decode returns.

Example
package main

import (
	"bytes"

	"github.com/aderemi-adesada/blendpreview"
)

func main() {
	var blendData []byte // e.g. bytes downloaded from object storage
	img, err := blendpreview.Decode(bytes.NewReader(blendData))
	if err != nil {
		return
	}

	_ = img
}

func Extract

func Extract(path string) (*image.RGBA, error)

Extract opens path and returns the embedded .blend preview as an *image.RGBA.

Uncompressed files are skipped with Seek where possible. gzip and zstd files are decompressed as streams and extraction stops as soon as the TEST block is found. The entire compressed file is therefore not decompressed up front.

Example
package main

import (
	"image/png"
	"os"

	"github.com/aderemi-adesada/blendpreview"
)

func main() {
	img, err := blendpreview.Extract("scene.blend")
	if err != nil {
		return
	}

	out, err := os.Create("preview.png")
	if err != nil {
		return
	}
	defer out.Close()

	_ = png.Encode(out, img)
}

func SavePNG

func SavePNG(blendPath, pngPath string) error

SavePNG extracts the embedded preview from blendPath and writes it as a PNG file to pngPath.

Types

This section is empty.

Directories

Path Synopsis
cmd
blendpreview command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL