func()

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
}