Support for type byte

The type byte is new in ScriptFu in GIMP v3.

It lets you read single 8-bit bytes from ports i.e. files and streams. For example, you could read sequences of RGBA bytes from an image file.

About

This is about the type byte in the ScriptFu language of GIMP. As implemented in the TinyScheme interpreter embedded in ScriptFu tools.

Other Scheme implementations may differ. In particular, the RSR5 and RSR6 Scheme standards do not mention a byte type. The proposal SRFI-56 discusses a similar thing.

This is about a type in Scheme. This is not about any “byte” type in other languages.

The type byte is a divergence from the upstream TinyScheme. ScriptFu also implements Unicode strings, diverging from upsteam TinyScheme. The two are related: the type char in the upstream TinyScheme could be used for 8-bit byte operations on ports. Whereas the type char in ScriptFu is a so-called “wide byte” represented by one to three 8-bit bytes.

Built-in functions on the byte type.

The type byte is used for port operations, i.e. input and output. It is an unsigned, 8-bit integer.

It has no numeric operations.

It has conversions to and from type integer.

Type conversion operations

The usual conversions are to/from integer.

Convert from byte type to integer type.

(byte->integer <byte>) => <integer>

Converts a byte to an integer in range [0,255].

Convert from integer type to byte type

(integer->byte <integer>) => <byte>

Converts an integer to a byte. Returns the lower eight bits of the binary representation of the integer. Returns an error for negative integers. This is NOT the modulo 256 operation, which should succeed for negative integers.

Predicate on byte type

(byte? <any>) => [#f, #t]

Returns #t if the value has type byte.

Type byte is not a numeric type:

(number? (integer->byte 1)) => #f
(integer? (integer->byte 1)) => #f

eof-object is not of type byte.

(byte? (read-byte)) => #f

This reads from the standard input port and when you have not typed anything it returns the eof-object, which is not of type byte. The EOF character in ASCII (26) is also not the same thing as the eof-object. The EOF character in ASCII can be read as a byte.

Convert from byte type to character type

There are no direct conversion operations between byte and character. For bytes which hold single-byte chars you can use:

(integer->char (byte->integer b))

and for multi-byte chars you can write bytes into a string port to build a string.

Port operations by byte: read, write, and peek

(read-byte [<port>]) => <byte> | eof-object

Reads a byte from the port and advances the port’s position. Returns a byte or the eof-object when the port is in the EOF condition. You can use “eof-object?” predicate. May yield an IO error from the OS. The port is optional, in which case it reads from the standard input port.

(peek-byte [<port>]) => <byte> | eof-object

Same as read-byte but does not advance the port’s position.

(write-byte <byte> [<port>]) => [#f, #t]

Writes a byte to the port. Returns #t if successful. May yield IO errors. Illegal to pass an integer type.

Suitable ports

You can use byte operations on any port. We do not distinguish ports by whether you can use byte operations on them. Other Scheme implementations have “binary-ports”. ScriptFu has no “binary-port?” predicate.

In ScriptFu TinyScheme, character operations on ports are implemented by byte operations. Character operations may read/write many bytes for one character, say for UTF-8 encoding. Generally, you would not mix byte and character operations on a port.

The standard input port is non-blocking. File ports are blocking and string ports are non-blocking. For other low-level uses and some ports to devices, a read may also block.

(byte-ready? <port>) => [#f, #t]

Returns #t if a subsequent read-byte would not block. This is only a test of the kind and state of the port. Returned #t does not guarantee that a subsequent read-byte would return other than eof-object. Returned #f means the port is a kind that could block, and is in a state that will block were read-byte to be called (unless the state changes in the meantime.)

The Gimp PDB and byte type

ScriptFu does not support calls to the Gimp PDB passing or returning arguments of type byte in Scheme. You must explicitly convert byte type to integer type.

In other words, ScriptFu does not marshal the byte type into appropriate C types. For example, a PDB procedure taking the C type “GIMP_UINT8ARRAY” takes a vector of integers, not bytes, in Scheme.

Vectors of bytes

You can put bytes in Scheme vectors.

A vector of bytes is compact in that it is contiguous in the interpreter’s allocated memory.

A vector of bytes is not as small as you might think, since each element of a vector takes 32 bits, even if the element is of type byte.

A vector of bytes is not the same thing as the “byte-vector” type of some Scheme implementations.