func()

in vncclient/encoding.go [523:676]


func (t *TightEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding, error) {
	t.size = 0
	if t.buf == nil {
		t.buf = bytes.NewBuffer(nil)
		for i := range t.streamBufs {
			t.streamBufs[i] = bytes.NewBuffer(nil)
		}
	}
	// To reduce implementation complexity, the width of any Tight-encoded
	// rectangle cannot exceed 2048 pixels. If a wider rectangle is
	// desired, it must be split into several rectangles and each one
	// should be encoded separately.
	if rect.Width > 2048 {
		return nil, errors.Errorf("rectangle too wide: %vpx. tight-encoded rectangles cannot be wider than 2048 pixels.", rect.Width)
	}

	// To simplify implementation at the cost of full spec compliance,
	// we only accept the simplest case of pixel format.
	if f := c.PixelFormat; f.BPP != 32 || f.Depth != 24 || !f.TrueColor || f.RedMax != 255 || f.GreenMax != 255 || f.BlueMax != 255 {
		return nil, errors.Errorf("this implementation of Tight encoding does not support this pixel format: %#v", f)
	}

	// The first byte of each Tight-encoded rectangle is a compression-
	// control byte:
	//
	//  +---------------------+--------------+---------------------+
	//  | No. of bytes        | Type [Value] | Description         |
	//  +---------------------+--------------+---------------------+
	//  | 1                   | U8           | compression-control |
	//  +---------------------+--------------+---------------------+
	var compressionControl uint8
	if err := binary.Read(r, binary.BigEndian, &compressionControl); err != nil {
		return nil, err
	}
	t.size++

	// The least significant four bits of the compression-control byte
	// inform the client which zlib compression streams should be reset
	// before decoding the rectangle. Each bit is independent and
	// corresponds to a separate zlib stream that should be reset:
	//
	//  +-----+----------------+
	//  | Bit | Description    |
	//  +-----+----------------+
	//  | 0   | Reset stream 0 |
	//  +-----+----------------+
	//  | 1   | Reset stream 1 |
	//  +-----+----------------+
	//  | 2   | Reset stream 2 |
	//  +-----+----------------+
	//  | 3   | Reset stream 3 |
	//  +-----+----------------+
	t.reset |= compressionControl & 0x0F

	// One of three possible compression methods are supported in the Tight
	// encoding. These are BasicCompression, FillCompression and
	// JpegCompression. If the bit 7 (the most significant bit) of the
	// compression-control byte is 0, then the compression type is
	// BasicCompression.
	if compressionControl>>7 == 0 {
		// In that case, bits 7-4 (the most significant four bits) of
		// compression-control should be interpreted as follows:
		//
		//  +------+--------------+------------------+
		//  | Bits | Binary value | Description      |
		//  +------+--------------+------------------+
		//  | 5-4  | 00           | Use stream 0     |
		//  +------+--------------+------------------+
		//  |      | 01           | Use stream 1     |
		//  +------+--------------+------------------+
		//  |      | 10           | Use stream 2     |
		//  +------+--------------+------------------+
		//  |      | 11           | Use stream 3     |
		//  +------+--------------+------------------+
		//  | 6    | 0            | ---              |
		//  +------+--------------+------------------+
		//  |      | 1            | read-filter-id   |
		//  +------+--------------+------------------+
		//  | 7    | 0            | BasicCompression |
		//  +------+--------------+------------------+
		readFilterID := compressionControl>>6 == 1
		stream := compressionControl >> 4 & 0x03
		log.Debugf("BasicCompression")
		return t.readBasicCompression(c, rect, r, readFilterID, stream)
	}

	// Otherwise, if the bit 7 of compression-control is set to 1, then the
	// compression method is either FillCompression or JpegCompression,
	// depending on other bits of the same byte:
	//
	//  +------+--------------+------------------+
	//  | Bits | Binary value | Description      |
	//  +------+--------------+------------------+
	//  | 7-4  | 1000         | FillCompression  |
	//  +------+--------------+------------------+
	//  |      | 1001         | JpegCompression  |
	//  +------+--------------+------------------+
	//  |      | any other    | invalid          |
	//  +------+--------------+------------------+
	switch compressionControl >> 4 {
	// FillCompression
	case 8:
		log.Debugf("FillCompression")
		// If the compression type is FillCompression, then the only
		// pixel value follows, in TPIXEL format. This value applies to
		// all pixels of the rectangle.
		t.buf.Reset()
		fill, err := t.readTPixels(r, 1)
		if err != nil {
			return nil, err
		}
		colors := make([]Color, rect.Area())
		for i := range colors {
			colors[i] = fill[0]
		}
		return &TightEncoding{Colors: colors, size: t.size}, nil
	// JpegCompression
	case 9:
		log.Debugf("JpegCompression")
		// If the compression type is JpegCompression, the following data
		// stream looks like this:
		//
		//  +--------------+----------+----------------------------------+
		//  | No. of bytes | Type     | Description                      |
		//  +--------------+----------+----------------------------------+
		//  | 1-3          |          | length in compact representation |
		//  +--------------+----------+----------------------------------+
		//  | length       | U8 array | jpeg-data                        |
		//  +--------------+----------+----------------------------------+
		//
		// The jpeg-data is a JFIF stream.
		length, err := t.readCompactLength(byteIOReader{Reader: r})
		if err != nil {
			return nil, err
		}
		buf := io.LimitReader(r, int64(length))
		img, err := jpeg.DecodeIntoRGB(buf, &jpeg.DecoderOptions{})
		if err != nil {
			return nil, errors.Annotate(err, "could not decode jpeg")
		} else if img == nil {
			return nil, errors.New("jpeg decoding returned nil (usually a result of the network being closed)")
		}
		t.size += length

		qbuf := NewQuickBuf(img.Pix)
		colors, err := qbuf.ReadColors(rect.Area())
		if err != nil {
			return nil, err
		}
		return &TightEncoding{Colors: colors, size: t.size}, nil
	default:
		return nil, errors.Errorf("invalid compression control byte: %b", compressionControl)
	}
}