gopixi

package module
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Jan 1, 2026 License: BSD-3-Clause Imports: 32 Imported by: 0

README

pixi

This repository contains the specification of a the Pixi file format. To start, think of Pixi like an opinionated cloud optimized GeoTIFF, but with explicit support for more than two dimensions and fewer built-in specifics for image-particular interpretation concerns.

Design Considerations

  1. More than images: Pixi is a format for tiled multidimensional raster data, which can be in dimensions higher than 2 or even 3. The interpretation of each dimension, even for dimensions 2 and 3, is defined on a per-file basis and cannot necessarily be assumed. Viewer applications may assume conventions for such files, but this is not specified by this document.

  2. Queryable: it should be possible to transmit only a portion of a file (a 'tile') without needing to transmit the rest of the data. This is especially important for cloud optimized scenarios or files that are accessed by many different machines.

  3. Robustness to transmission errors: it should be possible to detect datastream transmission errors reliably.

  4. Portability: encoding, decoding, and transmission should be software and hardware platform independent.

  5. Performance: any filtering and compression should be aimed at efficient decoding. Fast encoding is a less important goal than fast decoding. Decoding speed may be achieved at the expense of encoding speed.

  6. Compression: files should be compressed effectively, consistent with the other design goals.

  7. Interchangeability: any standard-conforming Pixi decoder shall be capable of reading all conforming Pixi datastreams.

  8. Freedom from legal restrictions: no algorithms should be used that are not freely available.

Terminology

Concepts

Layers
Channels
Separation
Dimensions and Tiling
Robustness and Errors

Layout

This section details the byte-level layout of a Pixi file.

Pixi Header

Every Pixi file should start with four bytes: "PIXI". This is followed by the version number, written as a number in UTF-8 string in four bytes. The version number should be prefixed with leading zeros if the printed number string is not long enough to fill two bytes.

Following this magic sequence and version number is the offset size indicator. This is a single byte, indicating the number of bytes that will make up offset values later in this file, used to point to different byte indices within the file. Currently, the only supported values of the offset size indicator are 4 and 8 (for 32-bit and 64-bit requirements respectively).

Then the endianness indicator follows, another single byte. This indicates the endianness of all multibyte values that follow in the data stream. The two supported options are little endian at 0x00 and big endian with 0xff.

Following this is the first layer offset, which will be an integer composed of the number of bytes specified by the offset size indicator. This will be the byte offset in the file, with index 0 equal to the start of the file, at which the first layer's first byte can be found.

Following this offset is the tagging offset. This will be the offset in the file at which the tagging section can start being read.

Layer Header
Tagging Section
Channel Header

Compression

Conformance

Viewers

Editors

Documentation

Index

Constants

View Source
const (
	FileType string = "pixi" // Every file starts with these four bytes.
	Version  int    = 1      // Every file has a version number as the second set of four bytes.
)

Variables

This section is empty.

Functions

func ChannelAt

func ChannelAt(accessor TileAccessLayer, coord SampleCoordinate, channelIndex int) (any, error)

func LayerAsImage

func LayerAsImage(r io.ReadSeeker, pixImg *Pixi, layer Layer, srcModel string) (image.Image, error)

func OpenFileOrHttp

func OpenFileOrHttp(path string) (io.ReadSeekCloser, error)

OpenFileOrHttp opens a file from a local path or an HTTP(S) URL. If the path is a URL, it opens a buffered HTTP stream to reduce the number of individual reads of the file from the network; otherwise, it opens a local file.

func PackBool

func PackBool(value bool, raw []byte, bitIndex int)

Packs a boolean value into a bit channel byte array at the specified bit index. Used for boolean channels in separated mode only.

func SetChannelAt

func SetChannelAt(modifier TileModifierLayer, coord SampleCoordinate, channelIndex int, value any) error

func SetSampleAt

func SetSampleAt(modifier TileModifierLayer, coord SampleCoordinate, values Sample) error

func UnpackBool

func UnpackBool(raw []byte, bitIndex int) bool

Unpacks a boolean value from a bit channel byte array at the specified bit index. Used for boolean channels in separated mode only.

Types

type Accessor

type Accessor interface {
	Layer() Layer
}

type BufferedHttpReadSeeker

type BufferedHttpReadSeeker struct {
	HttpReadSeeker
	// contains filtered or unexported fields
}

func OpenBufferedHttp

func OpenBufferedHttp(url *url.URL, client *http.Client) (*BufferedHttpReadSeeker, error)

func (*BufferedHttpReadSeeker) Close

func (b *BufferedHttpReadSeeker) Close() error

func (*BufferedHttpReadSeeker) Read

func (b *BufferedHttpReadSeeker) Read(p []byte) (n int, err error)

func (*BufferedHttpReadSeeker) Seek

func (b *BufferedHttpReadSeeker) Seek(offset int64, whence int) (int64, error)

type Channel

type Channel struct {
	Name string      // A friendly name for this channel, to help guide interpretation of the data.
	Type ChannelType // The type of data stored in each element of this channel.
	Min  any         // Optional minimum value for the range of data in this channel. Must match Type if present.
	Max  any         // Optional maximum value for the range of data in this channel. Must match Type if present.
}

Describes a set of values in a data set with a common shape. Similar to a column of a table in a database, but with a more restricted set of available types per channel.

func (Channel) HeaderSize

func (c Channel) HeaderSize(h Header) int

Get the size in bytes of this dimension description as it is laid out and written to disk.

func (Channel) PutValue

func (c Channel) PutValue(val any, order binary.ByteOrder, raw []byte)

This function writes a value of any type into bytes according to the specified ChannelType. The written bytes are stored in the provided byte array. This function will panic if the ChannelType is unknown or if an unsupported channel type is encountered.

func (*Channel) Read

func (c *Channel) Read(r io.Reader, h Header) error

Reads a description of the channel from the given binary stream, according to the specification in the Pixi header h.

func (Channel) Size

func (c Channel) Size() int

Returns the size of a channel in bytes.

func (Channel) Value

func (c Channel) Value(raw []byte, order binary.ByteOrder) any

Reads the value of a given ChannelType from the provided raw byte slice. The read operation is type-dependent, with each channel type having its own specific method for reading values. This ensures that the correct data is read and converted into the expected format.

func (Channel) WithMinMax

func (channel Channel) WithMinMax(value any) Channel

Updates the channel's Min and Max values based on a new value. Returns true if the channel was modified.

func (Channel) Write

func (c Channel) Write(w io.Writer, h Header) error

Writes the binary description of the channel to the given stream, according to the specification in the Pixi header h.

type ChannelSet

type ChannelSet []Channel

An ordered set of named channels present in each sample of a layer in a Pixi file.

func (ChannelSet) Index

func (set ChannelSet) Index(channelName string) int

The index of the (first) channel with the given name in the set, or -1 if not found.

func (ChannelSet) NamedOffset

func (set ChannelSet) NamedOffset(channelName string) (int, bool)

NamedOffset returns the byte offset of the channel with the given name within a sample. Returns the offset and true if found, or 0 and false if not found.

func (ChannelSet) Offset

func (set ChannelSet) Offset(channelIndex int) int

The byte offset of the channel within a given sample. This is the sum of the sizes of all preceding channels.

func (ChannelSet) Size

func (set ChannelSet) Size() int

The size in bytes of each sample in the data set. Each channel has a fixed size, and a sample is made up of one element of each channel, so the sample size is the sum of all channel sizes.

type ChannelType

type ChannelType uint32

Describes the size and interpretation of a channel.

const (
	ChannelUnknown  ChannelType = 0  // Generally indicates an error.
	ChannelInt8     ChannelType = 1  // An 8-bit signed integer.
	ChannelUint8    ChannelType = 2  // An 8-bit unsigned integer.
	ChannelInt16    ChannelType = 3  // A 16-bit signed integer.
	ChannelUint16   ChannelType = 4  // A 16-bit unsigned integer.
	ChannelInt32    ChannelType = 5  // A 32-bit signed integer.
	ChannelUint32   ChannelType = 6  // A 32-bit unsigned integer.
	ChannelInt64    ChannelType = 7  // A 64-bit signed integer.
	ChannelUint64   ChannelType = 8  // A 64-bit unsigned integer.
	ChannelFloat8   ChannelType = 9  // An 8-bit floating point number.
	ChannelFloat16  ChannelType = 10 // A 16-bit floating point number.
	ChannelFloat32  ChannelType = 11 // A 32-bit floating point number.
	ChannelFloat64  ChannelType = 12 // A 64-bit floating point number.
	ChannelBool     ChannelType = 13 // A boolean value.
	ChannelInt128   ChannelType = 14 // A 128-bit signed integer using github.com/shogo82148/int128.
	ChannelUint128  ChannelType = 15 // A 128-bit unsigned integer using github.com/shogo82148/int128.
	ChannelFloat128 ChannelType = 16 // A 128-bit floating point number using github.com/shogo82148/float128.
	ChannelBFloat16 ChannelType = 17 // A 16-bit brain floating point number.
)

func (ChannelType) Base

func (c ChannelType) Base() ChannelType

Returns the base channel type without the optional flags.

func (ChannelType) CompareValues

func (ctype ChannelType) CompareValues(a, b any) int

Compares two values based on the channel type. Returns -1 if a < b, 0 if a == b, 1 if a > b.

func (ChannelType) HasMax

func (c ChannelType) HasMax() bool

Returns whether the Max value flag is set.

func (ChannelType) HasMin

func (c ChannelType) HasMin() bool

Returns whether the Min value flag is set.

func (ChannelType) PutValue

func (c ChannelType) PutValue(val any, o binary.ByteOrder, bytes []byte)

Writes the given value, assumed to correspond to the ChannelType, into it's raw representation in bytes according to the byte order specified.

func (ChannelType) Size

func (c ChannelType) Size() int

This function returns the size of each element in a channel in bytes.

func (ChannelType) String

func (c ChannelType) String() string

func (ChannelType) Value

func (c ChannelType) Value(raw []byte, o binary.ByteOrder) any

This function reads the value of a given ChannelType from the provided raw byte slice. The read operation is type-dependent, with each channel type having its own specific method for reading values. This ensures that the correct data is read and converted into the expected format.

func (ChannelType) WithMax

func (c ChannelType) WithMax(hasMax bool) ChannelType

Returns a new ChannelType with the Max flag set or cleared.

func (ChannelType) WithMin

func (c ChannelType) WithMin(hasMin bool) ChannelType

Returns a new ChannelType with the Min flag set or cleared.

type Compression

type Compression uint32

Represents the compression method used to shrink the data persisted to a layer in a Pixi file.

const (
	CompressionNone   Compression = 0 // No compression
	CompressionFlate  Compression = 1 // Standard FLATE compression
	CompressionLzwLsb Compression = 2 // Least-significant-bit Lempel-Ziv-Welch compression from Go standard lib
	CompressionLzwMsb Compression = 3 // Most-significant-bit Lempel-Ziv-Welch compression from Go standard lib
	CompressionRle8   Compression = 4 // Run-length encoding capable of compressing up to 255 repeats of a sample
)

func (Compression) String

func (c Compression) String() string

type Dimension

type Dimension struct {
	Name     string // Friendly name to refer to the dimension in the layer.
	Size     int    // The total number of elements in the dimension.
	TileSize int    // The size of the tiles in the dimension. Does not need to be a factor of Size.
}

Represents an axis along which tiled, gridded data is stored in a Pixi file. Data sets can have one or more dimensions, but never zero. If a dimension is not tiled, then the TileSize should be the same as a the total Size.

func (Dimension) HeaderSize

func (d Dimension) HeaderSize(h Header) int

Get the size in bytes of this dimension description as it is laid out and written to disk.

func (*Dimension) Read

func (d *Dimension) Read(r io.Reader, h Header) error

Reads a description of the dimension from the given binary stream, according to the specification in the Pixi header h.

func (Dimension) String

func (d Dimension) String() string

func (Dimension) Tiles

func (d Dimension) Tiles() int

Returns the number of tiles in this dimension. The number of tiles is calculated by dividing the size of the dimension by the tile size, and then rounding up to the nearest whole number if there are any remaining bytes that do not fit into a full tile.

func (Dimension) Write

func (d Dimension) Write(w io.Writer, h Header) error

Writes the binary description of the dimenson to the given stream, according to the specification in the Pixi header h.

type DimensionSet

type DimensionSet []Dimension

An ordered set of named dimensions present in the layer of a Pixi file.

func (DimensionSet) ContainsCoordinate

func (set DimensionSet) ContainsCoordinate(coord SampleCoordinate) bool

Returns true if the given sample coordinate is within the bounds of the dimension set.

func (DimensionSet) SampleCoordinates

func (set DimensionSet) SampleCoordinates() iter.Seq[SampleCoordinate]

Iterate over the sample indices of the dimensions in the order the dimensions are laid out. That is, the index increments all the way through the first dimension, then increments the second (nesting the first each time), then the third (nesting the second (nesting the first)), and so on. The first dimension changes the most frequently, the last dimension changes the least frequently.

func (DimensionSet) Samples

func (d DimensionSet) Samples() int

The total number of samples in the data set. If the tile size of any dimension is not a multiple of the dimension size, the 'padding' samples are not included in the count.

func (DimensionSet) String

func (set DimensionSet) String() string

func (DimensionSet) TileCoordinates

func (set DimensionSet) TileCoordinates() iter.Seq[TileCoordinate]

Iterate over the indices of the dimensions in the 'tile order', such that all indices for the first tile are yielded before the second tile, and so on. While iterating within the tile, the first dimension changes the most frequently, all the way to the last which changes the least frequently. See the documentation for SampleCoordinates for more details on iteration within tile coordinates.

func (DimensionSet) TileSamples

func (d DimensionSet) TileSamples() int

The number of samples per tile in the data set. Each tile has the same number of samples, regardless of if the data is stored separated or continguous.

func (DimensionSet) Tiles

func (d DimensionSet) Tiles() int

Computes the number of non-separated tiles in the data set. This number is the same regardless of how the tiles are laid out on disk; use the DiskTiles() method to determine the number of tiles actually stored on disk. Note that DiskTiles() >= Tiles() by definition.

type ErrChannelNotFound

type ErrChannelNotFound struct {
	ChannelName string
}

func (ErrChannelNotFound) Error

func (e ErrChannelNotFound) Error() string

type ErrDataIntegrity

type ErrDataIntegrity struct {
	TileIndex int
	LayerName string
}

func (ErrDataIntegrity) Error

func (e ErrDataIntegrity) Error() string

type ErrFormat

type ErrFormat string

func (ErrFormat) Error

func (e ErrFormat) Error() string

type ErrSampleCoordinateOutOfBounds

type ErrSampleCoordinateOutOfBounds struct {
	Coordinate SampleCoordinate
	Dimensions DimensionSet
}

func (ErrSampleCoordinateOutOfBounds) Error

type ErrTileNotFound

type ErrTileNotFound struct {
	TileIndex int
}

func (ErrTileNotFound) Error

func (e ErrTileNotFound) Error() string

type ErrUnsupported

type ErrUnsupported string

func (ErrUnsupported) Error

func (e ErrUnsupported) Error() string

type FifoCacheLayer

type FifoCacheLayer struct {
	FifoCacheReadLayer
	// contains filtered or unexported fields
}

func NewFifoCacheLayer

func NewFifoCacheLayer(backing io.ReadWriteSeeker, header Header, layer Layer, maxSize int) *FifoCacheLayer

func (*FifoCacheLayer) Commit

func (c *FifoCacheLayer) Commit() error

func (*FifoCacheLayer) SetDirty

func (c *FifoCacheLayer) SetDirty(tile int)

type FifoCacheLayerTile

type FifoCacheLayerTile struct {
	// contains filtered or unexported fields
}

type FifoCacheReadLayer

type FifoCacheReadLayer struct {
	// contains filtered or unexported fields
}

func NewFifoCacheReadLayer

func NewFifoCacheReadLayer(backing io.ReadSeeker, header Header, layer Layer, maxSize int) *FifoCacheReadLayer

func (*FifoCacheReadLayer) Header

func (c *FifoCacheReadLayer) Header() Header

func (*FifoCacheReadLayer) Layer

func (c *FifoCacheReadLayer) Layer() Layer

func (*FifoCacheReadLayer) Tile

func (c *FifoCacheReadLayer) Tile(tile int) ([]byte, error)

type FromImageOption

type FromImageOption interface {
	// contains filtered or unexported methods
}

type FromImageOptions

type FromImageOptions struct {
	Compression Compression
	OffsetSize  OffsetSize
	ByteOrder   binary.ByteOrder
	XTileSize   int
	YTileSize   int
	Tags        map[string]string
}
type Header struct {
	Version          int
	OffsetSize       OffsetSize
	ByteOrder        binary.ByteOrder
	FirstLayerOffset int64
	FirstTagsOffset  int64
}

Contains information used to read or write the rest of a Pixi data file. This information is always found at the start of a stream of Pixi data. Because so much of how the rest of the file is serialized is dependent on this information, it is threaded throughout the reading and writing methods of the other structures that make up a Pixi stream.

func NewHeader

func NewHeader(byteOrder binary.ByteOrder, offsetSize OffsetSize) Header

Creates a new Pixi header struct with the given byte order and offset size, setting the version to the current supported version.

func (Header) DiskSize

func (s Header) DiskSize() int

Get the size in bytes of the full Pixi header (including first tag section and first layer offsets) as it is laid out and written to disk.

func (*Header) OverwriteOffsets

func (h *Header) OverwriteOffsets(w io.WriteSeeker, firstLayer int64, firstTags int64) error

Temporarily returns to the beginning of the Pixi stream to overwrite the offsets of the first layer and the first tags sections. Useful during initial file creation or editing, especially for large data that is difficult to know the size of in advance. After completing the offsets overwrite, or upon encountering an error in attempting to do so, this function will return the cursor to the position at which it was when the call to this function was made.

func (Header) Read

func (s Header) Read(r io.Reader, val any) error

Reads a fixed-size value, or a slice of such values, using the byte order given in the header.

func (Header) ReadFriendly

func (s Header) ReadFriendly(r io.Reader) (string, error)

Read a 'friendly' name from the reader stream at the current position. 'Friendly' strings are always the same format, specified by a 16-bit length followed by that number of bytes interpreted as a UTF8 string.

func (*Header) ReadHeader

func (h *Header) ReadHeader(r io.Reader) error

Read Pixi header information into this struct from the current position in the reader stream. Will return an error if the reading fails, or if there are format errors in the Pixi header.

func (Header) ReadOffset

func (s Header) ReadOffset(r io.Reader) (int64, error)

Reads a file offset from the current position in the reader, based on the offset size read earlier in the file. Panics if the file offset size has not yet been set, and returns an error if reading fails.

func (Header) ReadOffsets

func (s Header) ReadOffsets(r io.Reader, offsets []int64) error

Reads a slice of offsets from the current position in the reader, based on the offset size read earlier in the file. Panics if the file offset size has not yet been set, and returns an error if reading fails.

func (Header) Write

func (s Header) Write(w io.Writer, val any) error

Writes a fixed size value, or a slice of such values, using the byte order given in the header.

func (Header) WriteFriendly

func (s Header) WriteFriendly(w io.Writer, friendly string) error

Writes a 'friendly' name from to the writer stream at the current position. A 'friendly' string is always the same format, specified by a 16-bit length followed by that number of bytes of UTF8 string.

func (Header) WriteHeader

func (h Header) WriteHeader(w io.Writer) error

Write the information in this header to the current position in the writer stream.

func (Header) WriteOffset

func (s Header) WriteOffset(w io.Writer, offset int64) error

Writes a file offset to the current position in the writer stream, based on the offset size specified in the header. Panics if the file offset size has not yet been set, and returns an error if writing fails.

func (Header) WriteOffsets

func (s Header) WriteOffsets(w io.Writer, offsets []int64) error

Writes a slice of offsets to the current position in the writer stream, based on the offset size specified in the header. Panics if the file offset size has not yet been set, and returns an error if writing fails.

type HttpReadSeeker

type HttpReadSeeker struct {
	// contains filtered or unexported fields
}

func OpenHttp

func OpenHttp(url *url.URL, client *http.Client) (*HttpReadSeeker, error)

func (*HttpReadSeeker) Read

func (h *HttpReadSeeker) Read(p []byte) (n int, err error)

func (*HttpReadSeeker) Seek

func (h *HttpReadSeeker) Seek(offset int64, whence int) (int64, error)

func (*HttpReadSeeker) WithContext

func (h *HttpReadSeeker) WithContext(ctx context.Context) *HttpReadSeeker

func (*HttpReadSeeker) WithHeader

func (h *HttpReadSeeker) WithHeader(header http.Header) *HttpReadSeeker

type IterativeLayer

type IterativeLayer interface {
	Accessor
	Done()
	Next() bool
	Error() error
	Coordinate() SampleCoordinate
}

type IterativeLayerReadWriter

type IterativeLayerReadWriter interface {
	IterativeLayerReader
	IterativeLayerWriter
}

type IterativeLayerReader

type IterativeLayerReader interface {
	IterativeLayer
	Channel(channelIndex int) any
	Sample() Sample
}

type IterativeLayerWriter

type IterativeLayerWriter interface {
	IterativeLayer
	SetChannel(channelIndex int, value any)
	SetSample(values Sample)
}

type Layer

type Layer struct {
	Name string // Friendly name of the layer
	// Indicates whether the channels of the dataset are stored separated or contiguously. If true,
	// values for each channel are stored next to each other. If false, the default, values for each
	// index are stored next to each other, with values for different channels stored next to each
	// other at the same index.
	Separated   bool
	Compression Compression // The type of compression used on this dataset (e.g., Flate, lz4).
	// A slice of Dimension structs representing the dimensions and tiling of this dataset.
	// No dimensions equals an empty dataset. Dimensions are stored and iterated such that the
	// samples for the first dimension are the closest together in memory, with progressively
	// higher dimensions samples becoming further apart.
	Dimensions     DimensionSet
	Channels       ChannelSet // An array of Channel structs representing the channels in this dataset.
	TileBytes      []int64    // An array of byte counts representing (compressed) size of each tile in bytes for this dataset.
	TileOffsets    []int64    // An array of byte offsets representing the position in the file of each tile in the dataset.
	NextLayerStart int64      // The byte-index offset of the next layer in the file, from the start of the file. 0 if this is the last layer in the file.
}

Pixi files are composed of one or more layers. Generally, layers are used to represent the same data set at different 'zoom levels'. For example, a large digital elevation model data set might have a layer that shows a zoomed-out view of the terrain at a much smaller footprint, useful for thumbnails and previews. Layers are also useful if data sets of different resolutions should be stored together in the same file.

func ImageToLayer

func ImageToLayer(img image.Image, layerName string, separated bool, compression Compression, xTileSize int, yTileSize int) (Layer, error)

func NewLayer

func NewLayer(name string, dimensions DimensionSet, channels ChannelSet, opts ...LayerOption) Layer

Helper constructor to ensure that certain invariants in a layer are maintained when it is created.

func (Layer) DataSize

func (d Layer) DataSize() int64

The on-disk size in bytes of the (potentially compressed) data set. Does not include the dataset header size.

func (Layer) DiskTileSize

func (d Layer) DiskTileSize(tileIndex int) int

The size of the requested disk tile in bytes. For contiguous files, the size of each tile is always the same. However, for separated data sets, each channel is tiled (so the number of on-disk tiles is actually channelCount * Tiles()). Hence, the tile size changes depending on which channel is being accessed.

func (Layer) DiskTiles

func (d Layer) DiskTiles() int

The number of discrete data tiles actually stored in the backing file. This number differs based on whether channels are stored 'contiguous' or 'separated'; in the former case, DiskTiles() == Tiles(), in the latter case, DiskTiles() == Tiles() * number of channels.

func (Layer) HeaderSize

func (d Layer) HeaderSize(h Header) int

Get the total number of bytes that will be occupied in the file by this layer's header.

func (Layer) OverwriteHeader

func (l Layer) OverwriteHeader(w io.WriteSeeker, h Header, headerStartOffset int64) error

For a layer header which has already been written to the given position, writes the layer header again to the same location before returning the stream cursor to the position it was at previously. Generally this is used to update tile byte counts and tile offsets after they've been written to a stream.

func (Layer) OverwriteTile

func (l Layer) OverwriteTile(w io.WriteSeeker, h Header, tileIndex int, data []byte) error

Overwrite the already-written tile at the given tile index with new data. Seeks to the correct position in the stream before writing. Panics if the tile at the given index has not already been written. Does not seek back to the original position after writing.

func (*Layer) ReadLayer

func (d *Layer) ReadLayer(r io.Reader, h Header) error

Reads a description of the layer from the given binary stream, according to the specification in the Pixi header h.

func (Layer) ReadTile

func (l Layer) ReadTile(r io.ReadSeeker, h Header, tileIndex int, data []byte) error

Read a raw tile (not yet decoded into sample channels) at the given tile index. The tile must have been previously written (either in this session or a previous one) for this operation to succeed. The data is verified for integrity using a four-byte checksum placed directly after the saved tile data, and an error is returned (along with the data read into the chunk) if the checksum check fails.

func (Layer) WriteHeader

func (d Layer) WriteHeader(w io.Writer, h Header) error

Writes the binary description of the layer to the given stream, according to the specification in the Pixi header h.

func (Layer) WriteTile

func (l Layer) WriteTile(w io.WriteSeeker, h Header, tileIndex int, data []byte) error

Write the encoded tile data to the current stream position, updating the offset and byte count for this tile in the layer header (but not writing those offsets to the stream just yet). The data is written with a 4-byte checksum directly after it, which is used to verify data integrity when reading the tile later. The compression attribute of the layer is used to apply compression to the tile data before writing it to the stream.

type LayerOption

type LayerOption interface {
	// contains filtered or unexported methods
}

func WithCompression

func WithCompression(c Compression) LayerOption

func WithPlanar

func WithPlanar() LayerOption

type MemoryLayer

type MemoryLayer struct {
	// contains filtered or unexported fields
}

func NewMemoryLayer

func NewMemoryLayer(backing io.ReadWriteSeeker, header Header, layer Layer) *MemoryLayer

func (*MemoryLayer) Commit

func (s *MemoryLayer) Commit() error

func (*MemoryLayer) Header

func (s *MemoryLayer) Header() Header

func (*MemoryLayer) Layer

func (s *MemoryLayer) Layer() Layer

func (*MemoryLayer) SetDirty

func (s *MemoryLayer) SetDirty(tile int)

func (*MemoryLayer) Tile

func (s *MemoryLayer) Tile(tile int) ([]byte, error)

type OffsetSize

type OffsetSize int
const (
	OffsetSize4 OffsetSize = 4
	OffsetSize8 OffsetSize = 8
)

type Pixi

type Pixi struct {
	Header Header       // The metadata about the file version and how to read information from the file.
	Layers []Layer      // The metadata information about each layer in the file.
	Tags   []TagSection // The string tags of the file, broken up into sections for easy appending.
}

Represents a single pixi file composed of one or more layers. Functions as a handle to access the description of the each layer as well as the data stored in each layer.

func ReadPixi

func ReadPixi(r io.ReadSeeker) (*Pixi, error)

Convenience function to read all the metadata information from a Pixi file into a single containing struct.

func (*Pixi) AllTags

func (d *Pixi) AllTags() map[string]string

func (*Pixi) AppendImage

func (p *Pixi) AppendImage(w io.WriteSeeker, img image.Image, options FromImageOptions) error

func (*Pixi) AppendIterativeLayer

func (p *Pixi) AppendIterativeLayer(w io.WriteSeeker, layer Layer, writer IterativeLayerWriter, generator func(writer IterativeLayerWriter) error) error

Appends a new layer to the end of the file, using the provided generator function for writing samples to the layer.

func (*Pixi) AppendTags

func (p *Pixi) AppendTags(w io.WriteSeeker, tags map[string]string) error

Appends a new tag section to the end of the file with the given tags.

func (*Pixi) DiskDataBytes

func (d *Pixi) DiskDataBytes() int64

The total size of the data portions of the file in bytes. Does not count header information as part of the size.

type Sample

type Sample []any

A sample is a list of channel values, in channel-index order, for at a single index / coordinate in a layer.

func FromNamedSample

func FromNamedSample(channelset ChannelSet, named map[string]any) Sample

Creates a Sample from a map of named channel values, according to the order of channels in the given layer.

func SampleAt

func SampleAt(accessor TileAccessLayer, coord SampleCoordinate) (Sample, error)

func (Sample) Named

func (s Sample) Named(channelSet ChannelSet) map[string]any

Creates a map of named channel values from the Sample, according to the order of channels in the given layer.

type SampleCoordinate

type SampleCoordinate []int

Represents a multidimensional coordinate into the samples of a DimensionSet. Each element of the coordinate indexes into the corresponding dimension of the DimensionSet, and must be in the range [0, Size).

func (SampleCoordinate) ToSampleIndex

func (coord SampleCoordinate) ToSampleIndex(set DimensionSet) SampleIndex

Convert this multidimensional SampleCoordinate into an equivalent linear SampleIndex for the given DimensionSet.

func (SampleCoordinate) ToTileCoordinate

func (coord SampleCoordinate) ToTileCoordinate(set DimensionSet) TileCoordinate

Convert this multidimensional SampleCoordinate into an equivalent TileCoordinate for the given DimensionSet.

func (SampleCoordinate) ToTileSelector

func (coord SampleCoordinate) ToTileSelector(set DimensionSet) TileSelector

Convert this multidimensional SampleCoordinate into an equivalent TileSelector for the given DimensionSet.

type SampleIndex

type SampleIndex int

Represents a linear index into the samples of a DimensionSet. This is the result of converting the multidimensional SampleCoordinate into a single integer in the range [0, Samples()).

func (SampleIndex) ToSampleCoordinate

func (index SampleIndex) ToSampleCoordinate(set DimensionSet) SampleCoordinate

Convert this linear SampleIndex into a multidimensional SampleCoordinate for the given DimensionSet.

type TagSection

type TagSection struct {
	Tags          map[string]string // The tags for this section.
	NextTagsStart int64             // A byte-index offset from the start of the file pointing to the next tag section. 0 if this is the last tag section.
}

Pixi files can contain zero or more tag sections, used for extraneous non-data related metadata to help describe the file or indicate context of the file's ownership and lifespan. While the tags are conceptually just a flat list of string pairs, the layout in the file is done in sections with offsets pointing to further sections, allowing easier 'appending' of additional tags regardless of where in the file previous tags are stored.

func (*TagSection) Read

func (t *TagSection) Read(r io.Reader, h Header) error

Reads a tag section from the given binary stream, according to the specification in the Pixi header.

func (TagSection) Write

func (t TagSection) Write(w io.Writer, h Header) error

Writes the tag section in binary to the given stream, according to the specification in the Pixi header.

func (TagSection) WriteHeader

func (t TagSection) WriteHeader(w io.Writer, h Header) error

Writes the tag section header in binary to the given stream, according to the specification in the Pixi header. This only writes the header (number of tags and offset to next section), not the actual tags themselves.

type TileAccessLayer

type TileAccessLayer interface {
	Accessor
	Header() Header
	Tile(tile int) ([]byte, error)
}

type TileCoordinate

type TileCoordinate struct {
	Tile   []int
	InTile []int
}

Represents a multidimensional coordinate into the tiles of a DimensionSet, and a multidimensional coordinate into the samples of that tile. Each element of the Tile coordinate indexes into the corresponding dimension of the DimensionSet, and must be in the range [0, Tiles()). Each element of the InTile coordinate indexes into the corresponding dimension of the tile, and must be in the range [0, TileSize).

func (TileCoordinate) ToSampleCoordinate

func (coord TileCoordinate) ToSampleCoordinate(set DimensionSet) SampleCoordinate

Convert this TileCoordinate into an equivalent SampleCoordinate for the given DimensionSet.

func (TileCoordinate) ToTileSelector

func (coord TileCoordinate) ToTileSelector(set DimensionSet) TileSelector

Convert this TileCoordinate into an equivalent TileSelector for the given DimensionSet.

type TileModifierLayer

type TileModifierLayer interface {
	TileAccessLayer
	SetDirty(tile int)
	Commit() error
}

type TileOrderIndex

type TileOrderIndex int

type TileOrderReadIterator

type TileOrderReadIterator struct {
	// contains filtered or unexported fields
}

func NewTileOrderReadIterator

func NewTileOrderReadIterator(backing io.ReadSeeker, header Header, layer Layer) *TileOrderReadIterator

func (*TileOrderReadIterator) Channel

func (t *TileOrderReadIterator) Channel(channelIndex int) any

func (*TileOrderReadIterator) Coordinate

func (t *TileOrderReadIterator) Coordinate() SampleCoordinate

func (*TileOrderReadIterator) Done

func (t *TileOrderReadIterator) Done()

func (*TileOrderReadIterator) Error

func (t *TileOrderReadIterator) Error() error

func (*TileOrderReadIterator) Layer

func (t *TileOrderReadIterator) Layer() Layer

func (*TileOrderReadIterator) Next

func (t *TileOrderReadIterator) Next() bool

func (*TileOrderReadIterator) Sample

func (t *TileOrderReadIterator) Sample() Sample

type TileOrderWriteIterator

type TileOrderWriteIterator struct {
	// contains filtered or unexported fields
}

func NewTileOrderWriteIterator

func NewTileOrderWriteIterator(backing io.WriteSeeker, header Header, layer Layer) *TileOrderWriteIterator

func (*TileOrderWriteIterator) Coordinate

func (t *TileOrderWriteIterator) Coordinate() SampleCoordinate

func (*TileOrderWriteIterator) Done

func (t *TileOrderWriteIterator) Done()

func (*TileOrderWriteIterator) Error

func (t *TileOrderWriteIterator) Error() error

func (*TileOrderWriteIterator) Layer

func (t *TileOrderWriteIterator) Layer() Layer

func (*TileOrderWriteIterator) Next

func (t *TileOrderWriteIterator) Next() bool

func (*TileOrderWriteIterator) SetChannel

func (t *TileOrderWriteIterator) SetChannel(channelIndex int, value any)

func (*TileOrderWriteIterator) SetSample

func (t *TileOrderWriteIterator) SetSample(value Sample)

type TileSelector

type TileSelector struct {
	Tile   int
	InTile int
}

Indexes into a sample of a particular tile in the DimensionSet. The Tile channel is a linear index into the tiles of the DimensionSet, and the InTile channel is a linear index into the samples of that tile. The Tile channel is converted from a multidimensional TileCoordinate in a similar way to SampleIndex being converted from SampleCoordinate, and the same for the InTile linear index. Note that Tile here is NOT guaranteed to be usable as a TileIndex for a Layer, since that requires knowledge of whether the Layer is separated or not.

func (TileSelector) ToTileCoordinate

func (s TileSelector) ToTileCoordinate(set DimensionSet) TileCoordinate

Convert this TileSelector into a multidimensional TileCoordinate for the given DimensionSet.

func (TileSelector) ToTileIndex

func (s TileSelector) ToTileIndex(set DimensionSet) TileOrderIndex

Convert this TileSelector into a linear TileIndex for the given DimensionSet.

Directories

Path Synopsis
cmd
pixi-compress command
pixi-convert command
pixi-decimate command
pixi-inspect command
pixi-merge command
pixi-retile command
pixi-serv command
pixi-stitch command
pixi-tag command
internal