in vncclient/encoding.go [234:440]
func (*ZRLEEncoding) parseTile(rect *Rectangle, colors []Color, r *QuickBuf, tileX, tileY, tileWidth, tileHeight uint16, scratch []Color) error {
// Each tile begins with a subencoding type byte. The top bit of this
// byte is set if the tile has been run-length encoded, clear otherwise.
// The bottom 7 bits indicate the size of the palette used: zero means
// no palette, 1 means that the tile is of a single color, and 2 to 127
// indicate a palette of that size. The special subencoding values 129
// and 127 indicate that the palette is to be reused from the last tile
// that had a palette, with and without RLE, respectively.
subencoding, err := r.ReadByte()
if err != nil {
return errors.Annotate(err, "failed to read subencoding")
}
runLengthEncoded := subencoding&128 != 0
paletteSize := subencoding & 127
paletteData, err := r.ReadColors(int(paletteSize))
if err != nil {
return errors.Annotatef(err, "failed to read palette: runLengthEncoded:%v paletteSize:%v", runLengthEncoded, paletteSize)
}
if paletteSize == 0 && !runLengthEncoded {
// 0: Raw pixel data. width*height pixel values follow (where width and
// height are the width and height of the tile):
//
// +-----------------------------+--------------+-------------+
// | No. of bytes | Type [Value] | Description |
// +-----------------------------+--------------+-------------+
// | width*height*BytesPerCPixel | CPIXEL array | pixels |
// +-----------------------------+--------------+-------------+
colors, err := r.ReadColors(len(scratch))
if err != nil {
return errors.Annotate(err, "failed to read raw colors")
}
// Don't bother with the scratch buffer
scratch = colors
} else if paletteSize == 1 && !runLengthEncoded {
// 1: A solid tile consisting of a single color. The pixel value
// follows:
//
// +----------------+--------------+-------------+
// | No. of bytes | Type [Value] | Description |
// +----------------+--------------+-------------+
// | bytesPerCPixel | CPIXEL | pixelValue |
// +----------------+--------------+-------------+
pixelValue := paletteData[0]
fillColor(scratch, pixelValue)
} else if !runLengthEncoded {
// 2 to 16: Packed palette types. The paletteSize is the value of the
// subencoding, which is followed by the palette, consisting of
// paletteSize pixel values. The packed pixels follow, with each
// pixel represented as a bit field yielding a zero-based index into
// the palette. For paletteSize 2, a 1-bit field is used; for
// paletteSize 3 or 4, a 2-bit field is used; and for paletteSize
// from 5 to 16, a 4-bit field is used. The bit fields are packed
// into bytes, with the most significant bits representing the
// leftmost pixel (i.e., big endian). For tiles not a multiple of 8,
// 4, or 2 pixels wide (as appropriate), padding bits are used to
// align each row to an exact number of bytes.
// +----------------------------+--------------+--------------+
// | No. of bytes | Type [Value] | Description |
// +----------------------------+--------------+--------------+
// | paletteSize*bytesPerCPixel | CPIXEL array | palette |
// | m | U8 array | packedPixels |
// +----------------------------+--------------+--------------+
// where m is the number of bytes representing the packed pixels.
// For paletteSize of 2, this is div(width+7,8)*height; for
// paletteSize of 3 or 4, this is div(width+3,4)*height; or for
// paletteSize of 5 to 16, this is div(width+1,2)*height.
var bitsPerPackedPixel uint8
if paletteSize > 16 {
// No palette reuse in zrle
bitsPerPackedPixel = 8
} else if paletteSize > 4 {
bitsPerPackedPixel = 4
} else if paletteSize > 2 {
bitsPerPackedPixel = 2
} else {
bitsPerPackedPixel = 1
}
for j := uint16(0); j < tileHeight; j++ {
// We discard any leftover bits for each new line
var b uint8
var nbits uint8
for i := uint16(0); i < tileWidth; i++ {
if nbits == 0 {
b, err = r.ReadByte()
if err != nil {
return errors.Annotate(err, "failed to read nbits byte")
}
nbits = 8
}
nbits -= bitsPerPackedPixel
paletteIdx := (b >> nbits) & ((1 << bitsPerPackedPixel) - 1) & 127
pixelValue := paletteData[paletteIdx]
scratch[j*tileWidth+i] = pixelValue
}
}
} else if runLengthEncoded && paletteSize == 0 {
// 128: Plain RLE. The data consists of a number of runs, repeated
// until the tile is done. Runs may continue from the end of one row
// to the beginning of the next. Each run is represented by a single
// pixel value followed by the length of the run. The length is
// represented as one or more bytes. The length is calculated as one
// more than the sum of all the bytes representing the length. Any
// byte value other than 255 indicates the final byte. So for
// example, length 1 is represented as [0], 255 as [254], 256 as
// [255,0], 257 as [255,1], 510 as [255,254], 511 as [255,255,0], and
// so on.
//
// +-------------------------+--------------+-----------------------+
// | No. of bytes | Type [Value] | Description |
// +-------------------------+--------------+-----------------------+
// | bytesPerCPixel | CPIXEL | pixelValue |
// | div(runLength - 1, 255) | U8 array | 255 |
// | 1 | U8 | (runLength-1) mod 255 |
// +-------------------------+--------------+-----------------------+
for pos := 0; pos < len(scratch); {
pixelValue, err := r.ReadColor()
if err != nil {
return err
}
count := 1
for b := uint8(255); b == 255; {
b, err = r.ReadByte()
if err != nil {
return errors.Annotate(err, "failed to read rle byte")
}
count += int(b)
}
fillColor2(scratch[pos:pos+count], pixelValue)
pos += count
}
} else if runLengthEncoded && paletteSize > 1 {
// 130 to 255: Palette RLE. Followed by the palette, consisting of
// paletteSize = (subencoding - 128) pixel values:
//
// +----------------------------+--------------+-------------+
// | No. of bytes | Type [Value] | Description |
// +----------------------------+--------------+-------------+
// | paletteSize*bytesPerCPixel | CPIXEL array | palette |
// +----------------------------+--------------+-------------+
//
// Following the palette is, as with plain RLE, a number of runs,
// repeated until the tile is done. A run of length one is
// represented simply by a palette index:
//
// +--------------+--------------+--------------+
// | No. of bytes | Type [Value] | Description |
// +--------------+--------------+--------------+
// | 1 | U8 | paletteIndex |
// +--------------+--------------+--------------+
//
// A run of length more than one is represented by a palette index
// with the top bit set, followed by the length of the run as for
// plain RLE.
//
// +-------------------------+--------------+-----------------------+
// | No. of bytes | Type [Value] | Description |
// +-------------------------+--------------+-----------------------+
// | 1 | U8 | paletteIndex + 128 |
// | div(runLength - 1, 255) | U8 array | 255 |
// | 1 | U8 | (runLength-1) mod 255 |
// +-------------------------+--------------+-----------------------+
for pos := 0; pos < len(scratch); {
paletteIdx, err := r.ReadByte()
if err != nil {
return errors.Annotate(err, "failed to read palette index")
}
count := 1
if paletteIdx&128 != 0 {
for b := uint8(255); b == 255; {
b, err = r.ReadByte()
if err != nil {
return errors.Annotate(err, "failed to read byte")
}
count += int(b)
}
}
paletteIdx &= 127
pixelValue := paletteData[paletteIdx]
fillColor(scratch[pos:pos+count], pixelValue)
pos += count
}
} else {
return errors.Errorf("Unhandled case: runLengthEncoded=%v paletteSize=%v", runLengthEncoded, paletteSize)
}
for j := 0; j < int(tileHeight); j++ {
off := int(tileY)*int(rect.Width) + int(tileX)
start := j*int(rect.Width) + off
copy(colors[start:start+int(tileWidth)], scratch[j*int(tileWidth):])
}
return nil
}