github.com/amitbet/vnc2video@v0.0.0-20190616012314-9d50b9dab1d9/encoding_zrle.go (about)

     1  package vnc2video
     2  
     3  import (
     4  	"bytes"
     5  	"compress/zlib"
     6  	"errors"
     7  	"image/color"
     8  	"image/draw"
     9  	"io"
    10  	"github.com/amitbet/vnc2video/logger"
    11  )
    12  
    13  type ZRLEEncoding struct {
    14  	bytes      []byte
    15  	Image      draw.Image
    16  	unzipper   io.Reader
    17  	zippedBuff *bytes.Buffer
    18  }
    19  
    20  func (*ZRLEEncoding) Supported(Conn) bool {
    21  	return true
    22  }
    23  
    24  func (enc *ZRLEEncoding) SetTargetImage(img draw.Image) {
    25  	enc.Image = img
    26  }
    27  
    28  func (enc *ZRLEEncoding) Reset() error {
    29  	enc.unzipper = nil
    30  	return nil
    31  }
    32  
    33  func (*ZRLEEncoding) Type() EncodingType { return EncZRLE }
    34  
    35  func (z *ZRLEEncoding) WriteTo(w io.Writer) (n int, err error) {
    36  	return w.Write(z.bytes)
    37  }
    38  
    39  func (enc *ZRLEEncoding) Write(c Conn, rect *Rectangle) error {
    40  	return nil
    41  }
    42  
    43  func IsCPixelSpecific(pf *PixelFormat) bool {
    44  	significant := int(pf.RedMax<<pf.RedShift | pf.GreenMax<<pf.GreenShift | pf.BlueMax<<pf.BlueShift)
    45  
    46  	if pf.Depth <= 24 && 32 == pf.BPP && ((significant&0x00ff000000) == 0 || (significant&0x000000ff) == 0) {
    47  		return true
    48  	}
    49  	return false
    50  }
    51  
    52  func CalcBytesPerCPixel(pf *PixelFormat) int {
    53  	if IsCPixelSpecific(pf) {
    54  		return 3
    55  	}
    56  	return int(pf.BPP / 8)
    57  }
    58  
    59  func (enc *ZRLEEncoding) Read(r Conn, rect *Rectangle) error {
    60  	logger.Tracef("reading ZRLE:%v\n", rect)
    61  	len, err := ReadUint32(r)
    62  	if err != nil {
    63  		return err
    64  	}
    65  
    66  	b, err := ReadBytes(int(len), r)
    67  	if err != nil {
    68  		return err
    69  	}
    70  
    71  	bytesBuff := bytes.NewBuffer(b)
    72  
    73  	if enc.unzipper == nil {
    74  		enc.unzipper, err = zlib.NewReader(bytesBuff)
    75  		enc.zippedBuff = bytesBuff
    76  		if err != nil {
    77  			return err
    78  		}
    79  	} else {
    80  		enc.zippedBuff.Write(b)
    81  	}
    82  	pf := r.PixelFormat()
    83  	enc.renderZRLE(rect, &pf)
    84  
    85  	return nil
    86  }
    87  
    88  func (enc *ZRLEEncoding) readZRLERaw(reader io.Reader, pf *PixelFormat, tx, ty, tw, th int) error {
    89  	for y := 0; y < int(th); y++ {
    90  		for x := 0; x < int(tw); x++ {
    91  			col, err := readCPixel(reader, pf)
    92  			if err != nil {
    93  				return err
    94  			}
    95  
    96  			enc.Image.Set(tx+x, ty+y, col)
    97  		}
    98  	}
    99  
   100  	return nil
   101  }
   102  
   103  func (enc *ZRLEEncoding) renderZRLE(rect *Rectangle, pf *PixelFormat) error {
   104  	logger.Trace("-----renderZRLE: rendering rect:", rect)
   105  	for tileOffsetY := 0; tileOffsetY < int(rect.Height); tileOffsetY += 64 {
   106  
   107  		tileHeight := Min(64, int(rect.Height)-tileOffsetY)
   108  
   109  		for tileOffsetX := 0; tileOffsetX < int(rect.Width); tileOffsetX += 64 {
   110  
   111  			tileWidth := Min(64, int(rect.Width)-tileOffsetX)
   112  			// read subencoding
   113  			subEnc, err := ReadUint8(enc.unzipper)
   114  			logger.Tracef("-----renderZRLE: rendering got tile:(%d,%d) w:%d, h:%d subEnc:%d", tileOffsetX, tileOffsetY, tileWidth, tileHeight, subEnc)
   115  			if err != nil {
   116  				logger.Errorf("renderZRLE: error while reading subencoding: %v", err)
   117  				return err
   118  			}
   119  
   120  			switch {
   121  
   122  			case subEnc == 0:
   123  				// Raw subencoding: read cpixels and paint
   124  				err = enc.readZRLERaw(enc.unzipper, pf, int(rect.X)+tileOffsetX, int(rect.Y)+tileOffsetY, tileWidth, tileHeight)
   125  				if err != nil {
   126  					logger.Errorf("renderZRLE: error while reading Raw tile: %v", err)
   127  					return err
   128  				}
   129  			case subEnc == 1:
   130  				// background color tile - just fill
   131  				color, err := readCPixel(enc.unzipper, pf)
   132  				if err != nil {
   133  					logger.Errorf("renderZRLE: error while reading CPixel for bgColor tile: %v", err)
   134  					return err
   135  				}
   136  				myRect := MakeRect(int(rect.X)+tileOffsetX, int(rect.Y)+tileOffsetY, tileWidth, tileHeight)
   137  				FillRect(enc.Image, &myRect, color)
   138  			case subEnc >= 2 && subEnc <= 16:
   139  				err = enc.handlePaletteTile(tileOffsetX, tileOffsetY, tileWidth, tileHeight, subEnc, pf, rect)
   140  				if err != nil {
   141  					return err
   142  				}
   143  			case subEnc == 128:
   144  				err = enc.handlePlainRLETile(tileOffsetX, tileOffsetY, tileWidth, tileHeight, pf, rect)
   145  				if err != nil {
   146  					return err
   147  				}
   148  			case subEnc >= 130 && subEnc <= 255:
   149  				err = enc.handlePaletteRLETile(tileOffsetX, tileOffsetY, tileWidth, tileHeight, subEnc, pf, rect)
   150  				if err != nil {
   151  					return err
   152  				}
   153  			default:
   154  				logger.Errorf("Unknown ZRLE subencoding: %v", subEnc)
   155  			}
   156  		}
   157  	}
   158  	return nil
   159  }
   160  
   161  func (enc *ZRLEEncoding) handlePaletteRLETile(tileOffsetX, tileOffsetY, tileWidth, tileHeight int, subEnc uint8, pf *PixelFormat, rect *Rectangle) error {
   162  	// Palette RLE
   163  	paletteSize := subEnc - 128
   164  	palette := make([]*color.RGBA, paletteSize)
   165  	var err error
   166  
   167  	// Read RLE palette
   168  	for j := 0; j < int(paletteSize); j++ {
   169  		palette[j], err = readCPixel(enc.unzipper, pf)
   170  		if err != nil {
   171  			logger.Errorf("renderZRLE: error while reading color in palette RLE subencoding: %v", err)
   172  			return err
   173  		}
   174  	}
   175  	var index uint8
   176  	runLen := 0
   177  	for y := 0; y < tileHeight; y++ {
   178  		for x := 0; x < tileWidth; x++ {
   179  
   180  			if runLen == 0 {
   181  
   182  				// Read length and index
   183  				index, err = ReadUint8(enc.unzipper)
   184  				if err != nil {
   185  					logger.Errorf("renderZRLE: error while reading length and index in palette RLE subencoding: %v", err)
   186  					//return err
   187  				}
   188  				runLen = 1
   189  
   190  				// Run is represented by index | 0x80
   191  				// Otherwise, single pixel
   192  				if (index & 0x80) != 0 {
   193  
   194  					index -= 128
   195  
   196  					runLen, err = readRunLength(enc.unzipper)
   197  					if err != nil {
   198  						logger.Errorf("handlePlainRLETile: error while reading runlength in plain RLE subencoding: %v", err)
   199  						return err
   200  					}
   201  
   202  				}
   203  				//logger.Tracef("renderZRLE: writing pixel: col=%v times=%d", palette[index], runLen)
   204  			}
   205  
   206  			// Write pixel to image
   207  			enc.Image.Set(tileOffsetX+int(rect.X)+x, tileOffsetY+int(rect.Y)+y, palette[index])
   208  			runLen--
   209  		}
   210  	}
   211  	return nil
   212  }
   213  
   214  func (enc *ZRLEEncoding) handlePaletteTile(tileOffsetX, tileOffsetY, tileWidth, tileHeight int, subEnc uint8, pf *PixelFormat, rect *Rectangle) error {
   215  	//subenc here is also palette size
   216  	paletteSize := subEnc
   217  	palette := make([]*color.RGBA, paletteSize)
   218  	var err error
   219  	// Read palette
   220  	for j := 0; j < int(paletteSize); j++ {
   221  		palette[j], err = readCPixel(enc.unzipper, pf)
   222  		if err != nil {
   223  			logger.Errorf("renderZRLE: error while reading CPixel for palette tile: %v", err)
   224  			return err
   225  		}
   226  	}
   227  	// Calculate index size
   228  	var indexBits, mask uint32
   229  	if paletteSize == 2 {
   230  		indexBits = 1
   231  		mask = 0x80
   232  	} else if paletteSize <= 4 {
   233  		indexBits = 2
   234  		mask = 0xC0
   235  	} else {
   236  		indexBits = 4
   237  		mask = 0xF0
   238  	}
   239  	for y := 0; y < tileHeight; y++ {
   240  
   241  		// Packing only occurs per-row
   242  		bitsAvailable := uint32(0)
   243  		buffer := uint32(0)
   244  
   245  		for x := 0; x < tileWidth; x++ {
   246  
   247  			// Buffer more bits if necessary
   248  			if bitsAvailable == 0 {
   249  				bits, err := ReadUint8(enc.unzipper)
   250  				if err != nil {
   251  					logger.Errorf("renderZRLE: error while reading first uint8 into buffer: %v", err)
   252  					return err
   253  				}
   254  				buffer = uint32(bits)
   255  				bitsAvailable = 8
   256  			}
   257  
   258  			// Read next pixel
   259  			index := (buffer & mask) >> (8 - indexBits)
   260  			buffer <<= indexBits
   261  			bitsAvailable -= indexBits
   262  
   263  			// Write pixel to image
   264  			enc.Image.Set(tileOffsetX+int(rect.X)+x, tileOffsetY+int(rect.Y)+y, palette[index])
   265  		}
   266  	}
   267  	return err
   268  }
   269  
   270  func (enc *ZRLEEncoding) handlePlainRLETile(tileOffsetX int, tileOffsetY int, tileWidth int, tileHeight int, pf *PixelFormat, rect *Rectangle) error {
   271  	var col *color.RGBA
   272  	var err error
   273  	runLen := 0
   274  	for y := 0; y < tileHeight; y++ {
   275  		for x := 0; x < tileWidth; x++ {
   276  
   277  			if runLen == 0 {
   278  
   279  				// Read length and color
   280  				col, err = readCPixel(enc.unzipper, pf)
   281  				if err != nil {
   282  					logger.Errorf("handlePlainRLETile: error while reading CPixel in plain RLE subencoding: %v", err)
   283  					return err
   284  				}
   285  				runLen, err = readRunLength(enc.unzipper)
   286  				if err != nil {
   287  					logger.Errorf("handlePlainRLETile: error while reading runlength in plain RLE subencoding: %v", err)
   288  					return err
   289  				}
   290  
   291  			}
   292  
   293  			// Write pixel to image
   294  			enc.Image.Set(tileOffsetX+int(rect.X)+x, tileOffsetY+int(rect.Y)+y, col)
   295  			runLen--
   296  		}
   297  	}
   298  	return err
   299  }
   300  
   301  func readRunLength(r io.Reader) (int, error) {
   302  	runLen := 1
   303  
   304  	addition, err := ReadUint8(r)
   305  	if err != nil {
   306  		logger.Errorf("renderZRLE: error while reading addition to runLen in plain RLE subencoding: %v", err)
   307  		return 0, err
   308  	}
   309  	runLen += int(addition)
   310  
   311  	for addition == 255 {
   312  		addition, err = ReadUint8(r)
   313  		if err != nil {
   314  			logger.Errorf("renderZRLE: error while reading addition to runLen in-loop plain RLE subencoding: %v", err)
   315  			return 0, err
   316  		}
   317  		runLen += int(addition)
   318  	}
   319  	return runLen, nil
   320  }
   321  
   322  // Reads cpixel color from reader
   323  func readCPixel(c io.Reader, pf *PixelFormat) (*color.RGBA, error) {
   324  	if pf.TrueColor == 0 {
   325  		return nil, errors.New("support for non true color formats was not implemented")
   326  	}
   327  
   328  	isZRLEFormat := IsCPixelSpecific(pf)
   329  	var col *color.RGBA
   330  	if isZRLEFormat {
   331  		tbytes, err := ReadBytes(3, c)
   332  		if err != nil {
   333  			return nil, err
   334  		}
   335  
   336  		if pf.BigEndian != 1 {
   337  			col = &color.RGBA{
   338  				B: uint8(tbytes[0]),
   339  				G: uint8(tbytes[1]),
   340  				R: uint8(tbytes[2]),
   341  				A: uint8(1),
   342  			}
   343  		} else {
   344  			col = &color.RGBA{
   345  				R: uint8(tbytes[0]),
   346  				G: uint8(tbytes[1]),
   347  				B: uint8(tbytes[2]),
   348  				A: uint8(1),
   349  			}
   350  		}
   351  		return col, nil
   352  	}
   353  
   354  	col, err := ReadColor(c, pf)
   355  	if err != nil {
   356  		logger.Errorf("readCPixel: Error while reading zrle: %v", err)
   357  	}
   358  
   359  	return col, nil
   360  }