blendpreview

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
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.
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.
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.