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 }