gorle

package module
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Jul 2, 2026 License: MIT Imports: 3 Imported by: 0

README

gorle

Go DICOM RLE Lossless codec — pure Go, no CGO.

Aligned with pylibjpeg-rle for transfer syntax 1.2.840.10008.1.2.5.

Status

Phase 1: decode/encode frame API, PackBits 1-bit helpers, DICOM pixel data wrappers.

Installation

go get github.com/godicom-dev/gorle

Usage

Decode one encapsulated frame

DecodeFrame returns planar configuration 1 bytes (all R, then all G, then all B for RGB).
Pass rows * columns as nrPixels (not the byte length).

package main

import (
	"fmt"
	"log"

	"github.com/godicom-dev/gorle"
)

func main() {
	// `frame` is one item from DICOM encapsulated Pixel Data (OB/OW).
	var frame []byte

	rows, cols := 512, 512
	pixels, err := gorle.DecodeFrame(frame, rows*cols, 16, gorle.LittleEndian)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("decoded %d bytes (planar config 1)\n", len(pixels))
}
Encode one frame

EncodeFrame expects planar configuration 0 input (R1,G1,B1,R2,G2,B2,…).

rows, cols, spp := 64, 64, 3
// PC0: interleaved samples per pixel
src := make([]byte, rows*cols*spp*2)

encoded, err := gorle.EncodeFrame(src, rows, cols, spp, 16, gorle.LittleEndian)
if err != nil {
	log.Fatal(err)
}
DICOM pixel data helpers

DecodePixelData / EncodePixelData mirror pylibjpeg-rle decode_pixel_data / encode_pixel_data.

// Decode (v2 returns raw bytes, like pylibjpeg Version.v2)
out, err := gorle.DecodePixelData(frame, gorle.PixelDataOptions{
	Version: gorle.PixelDataV2,
	FrameOptions: gorle.FrameOptions{
		Rows:          512,
		Columns:       512,
		BitsAllocated: 16,
		ByteOrder:     gorle.LittleEndian,
	},
})

// Encode
enc, err := gorle.EncodePixelData(pc0Pixels, gorle.PixelDataOptions{
	FrameOptions: gorle.FrameOptions{
		Rows:            512,
		Columns:         512,
		SamplesPerPixel: 1,
		BitsAllocated:   16,
		ByteOrder:       gorle.LittleEndian,
	},
})

For 1-bit images, DecodePixelData with PackBits: true (v2 only) returns packed bits;
EncodePixelData accepts either packed or unpacked 1-bit input.

Low-level segment API
offsets, err := gorle.ParseHeader(frame[:64])
seg, err := gorle.DecodeSegment(frame[offsets[0]:offsets[1]])
row, err := gorle.EncodeRow([]byte{1, 2, 3, 3, 3, 4})

API

func DecodeFrame(src []byte, nrPixels, bitsAllocated int, byteOrder ByteOrder) ([]byte, error)
func EncodeFrame(src []byte, rows, cols, spp, bitsAllocated int, byteOrder ByteOrder) ([]byte, error)
func DecodePixelData(src []byte, opts PixelDataOptions) ([]byte, error)
func EncodePixelData(src []byte, opts PixelDataOptions) ([]byte, error)
func ParseHeader(src []byte) ([]uint32, error)
func DecodeSegment(src []byte) ([]byte, error)
func EncodeSegment(src []byte, cols int) ([]byte, error)
func PackBits(src []byte, byteOrder ByteOrder) ([]byte, error)
func UnpackBits(src []byte, count int, byteOrder ByteOrder) ([]byte, error)
Direction Pixel layout
EncodeFrame / EncodePixelData input Planar configuration 0
DecodeFrame / DecodePixelData output Planar configuration 1

Supported: SamplesPerPixel 1 or 3; BitsAllocated 1, 8, 16, 32, 64.

Development

git clone https://github.com/godicom-dev/gorle.git
cd gorle
go test ./...

Optional cross-check against pylibjpeg-rle (Python tests skip if not installed):

pip install pylibjpeg-rle
go test -v ./...

References

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidHeaderLength     = errors.New("the RLE header must be 64 bytes long")
	ErrInvalidSegmentOffset    = errors.New("invalid segment offset found in the RLE header")
	ErrInsufficientData        = errors.New("frame is not long enough to contain RLE encoded data")
	ErrInvalidBitsAllocated    = errors.New("the (0028,0100) 'Bits Allocated' value must be 1, 8, 16, 32 or 64")
	ErrInvalidSamplesPerPixel  = errors.New("the (0028,0002) 'Samples per Pixel' must be 1 or 3")
	ErrSamplesPerPixelBA1      = errors.New("the (0028,0002) 'Samples per Pixel' must be 1 if (0028,0100) 'Bits Allocated' is 1")
	ErrSegmentLength           = errors.New("the decoded segment length does not match the expected length")
	ErrInvalidByteOrder        = errors.New("'byteorder' must be '>' or '<'")
	ErrSegmentDecodeEOF        = errors.New("the end of the data was reached before the segment was completely decoded")
	ErrTooManySegments         = errors.New("unable to encode as the DICOM Standard only allows a maximum of 15 segments in RLE encoded data")
	ErrInvalidParameters       = errors.New("the length of the data to be encoded is not consistent with the values of the dataset's 'Rows', 'Columns', 'Samples per Pixel' and 'Bits Allocated' elements")
	ErrInvalidColumns          = errors.New("the (0028,0011) 'Columns' value is invalid")
	ErrInvalidPackBitsInput    = errors.New("only binary input (containing zeros or ones) can be packed")
	ErrMissingPixelDataArgs    = errors.New("missing expected keyword arguments: bits_allocated, columns, rows")
	ErrUnsupportedPixelVersion = errors.New("gorle: unsupported pixel data version")
)

Functions

func DecodeFrame

func DecodeFrame(src []byte, nrPixels int, bitsAllocated int, byteOrder ByteOrder) ([]byte, error)

DecodeFrame decodes a single RLE Lossless frame.

func DecodePixelData

func DecodePixelData(src []byte, opts PixelDataOptions) ([]byte, error)

DecodePixelData decodes a single RLE Lossless frame (pylibjpeg-rle decode_pixel_data).

func DecodeSegment

func DecodeSegment(src []byte) ([]byte, error)

DecodeSegment decodes a single RLE segment (PackBits).

func EncodeFrame

func EncodeFrame(src []byte, rows, cols, spp, bitsAllocated int, byteOrder ByteOrder) ([]byte, error)

EncodeFrame encodes planar-configuration-0 pixel data (R1,G1,B1,R2,…).

func EncodePixelData

func EncodePixelData(src []byte, opts PixelDataOptions) ([]byte, error)

EncodePixelData encodes a single frame using DICOM RLE (pylibjpeg-rle encode_pixel_data).

func EncodeRow

func EncodeRow(src []byte) ([]byte, error)

EncodeRow RLE-encodes a single row of sample values.

func EncodeSegment

func EncodeSegment(src []byte, cols int) ([]byte, error)

EncodeSegment encodes a segment. cols is the number of values per row.

func PackBits

func PackBits(src []byte, byteOrder ByteOrder) ([]byte, error)

PackBits packs binary data (0/1 bytes) into one bit per pixel.

func Packed1BitLength

func Packed1BitLength(rows, cols int) int

Packed1BitLength returns packed 1-bit frame size in bytes.

func ParseHeader

func ParseHeader(src []byte) ([]uint32, error)

ParseHeader returns the 15 segment offsets from a 64-byte RLE header. Bytes 0–3 hold the segment count; offsets are little-endian uint32 values starting at byte 4 (DICOM PS3.5 G.3).

func UnpackBits

func UnpackBits(src []byte, count int, byteOrder ByteOrder) ([]byte, error)

UnpackBits unpacks bit-packed data. count is the number of bits to return; zero means unpack the entire input.

func UnpackedFrameLength

func UnpackedFrameLength(rows, cols, spp, bitsAllocated int) int

UnpackedFrameLength returns the decoded frame length in bytes for validation.

Types

type ByteOrder

type ByteOrder string

ByteOrder is the sample byte order for multi-byte pixels.

const (
	LittleEndian ByteOrder = "<"
	BigEndian    ByteOrder = ">"
)

type FrameOptions

type FrameOptions struct {
	Rows            int
	Columns         int
	SamplesPerPixel int
	BitsAllocated   int
	ByteOrder       ByteOrder
}

FrameOptions configures single-frame RLE encode/decode.

type PixelDataOptions

type PixelDataOptions struct {
	Version PixelDataVersion
	FrameOptions
	PackBits bool // v2 only: return 1-bit data packed when BitsAllocated is 1
}

PixelDataOptions configures DecodePixelData / EncodePixelData.

type PixelDataVersion

type PixelDataVersion int

PixelDataVersion selects decode_pixel_data behaviour.

const (
	PixelDataV1 PixelDataVersion = 1
	PixelDataV2 PixelDataVersion = 2
)

Jump to

Keyboard shortcuts

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