node-rfb2 icon indicating copy to clipboard operation
node-rfb2 copied to clipboard

Add TightPNG encoding

Open sidorares opened this issue 11 years ago • 37 comments

http://wiki.qemu.org/VNC_Tight_PNG

sidorares avatar Jul 02 '14 01:07 sidorares

i think this is more proper place. Now i need only working compact length calculation for tight png working. I found simple code from wireshark dissector for tight encoding http://code.metager.de/source/xref/wireshark/epan/dissectors/packet-vnc.c#3031

i'm already check my own code and it looks the same. So i'm stuck now. sorry for reindent issues =( . i'm cleanup pr when it will be ready https://github.com/sidorares/node-rfb2/compare/master...vtolstov:master?expand=1

vtolstov avatar Jan 22 '17 12:01 vtolstov

As i debug, png data in rectangle in my case started after 0,0,0,0,0,0,19,0,231,0,13,255,255,254,252,160,224,2

first rect has rect.x 0 rect.y 0 rect.width 1024 rect.height 19

vtolstov avatar Jan 22 '17 12:01 vtolstov

I'll be able to help early tomorrow ( +9 hours in my time)

sidorares avatar Jan 22 '17 12:01 sidorares

No problem, now i have free time and may be found some own mistakes

vtolstov avatar Jan 22 '17 12:01 vtolstov

@sidorares so i think that we have error in decoding stream. In case of raw encoding, do you have proper image received from frame buffer update message?

vtolstov avatar Jan 22 '17 23:01 vtolstov

what I see is that first byte is 0 and reading stops because it's not tight.png

        var tight = rfb.subEncodings.tight;
        console.log('TIGHT: byte 0', ctl[0]);
        ctl = ctl[0] >> 4;
        if (ctl & tight.png) {
            console.log('Reading tight png...');
            cli.readTightPng(rect, cb);
        }

sidorares avatar Jan 22 '17 23:01 sidorares

Does it possible this issue with endianes? or all rectangles and encoding always send via little endian?

vtolstov avatar Jan 22 '17 23:01 vtolstov

no, I think the issue is that we can't just add png part only. We need to decode BasicCompression bytes ( or at leas skip them ) - see BasicCompression part here - https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#id78

sidorares avatar Jan 22 '17 23:01 sidorares

But basic compression part goes after control part...

vtolstov avatar Jan 22 '17 23:01 vtolstov

And we have control = 0...

vtolstov avatar Jan 22 '17 23:01 vtolstov

When I connect first update seems to be in tight / BasicCompression - same color rectangle, I think control byte is followed by single TPIXEL value ( I guess it 3 bytes )

The Tight encoding makes use of a new type TPIXEL (Tight pixel). This is the same as a PIXEL for the agreed pixel format, except where true-colour-flag is non-zero, bits-per-pixel is 32, depth is 24 and all of the bits making up the red, green and blue intensities are exactly 8 bits wide. In this case a TPIXEL is only 3 bytes long, where the first byte is the red component, the second byte is the green component, and the third byte is the blue component of the pixel color value.

sidorares avatar Jan 22 '17 23:01 sidorares

But basic compression part goes after control part...

isn't control = 0 indication of basic compression?

sidorares avatar Jan 22 '17 23:01 sidorares

@sidorares yes, but why we have tpixel?

vtolstov avatar Jan 22 '17 23:01 vtolstov

as far as I understand, basic compression + fill = one single pixel follows, same color for whole rectangle

sidorares avatar Jan 22 '17 23:01 sidorares

so i need to add to tight some compression types like fill, jpeg, basic compression types and recheck control for it ?

vtolstov avatar Jan 22 '17 23:01 vtolstov

like

exports.tightCompressions = {
    fill: 8,
    jpeg: 9,
    png: 10,
};

vtolstov avatar Jan 22 '17 23:01 vtolstov

yes:

If bit 6 of the compression-control byte is set to 0 (no filter-id byte), then the CopyFilter is used.

CopyFilter When the CopyFilter is active, raw pixel values in TPIXEL format will be compressed. See below for details on the compression.

...

After the pixel data has been filtered with one of the above three filters, it is compressed using the zlib library. But if the data size after applying the filter but before the compression is less then 12, then the data is sent as is, uncompressed. Four separate zlib streams (0..3) can be used and the decoder should read the actual stream id from the compression-control byte (see [NOTE1]).

sidorares avatar Jan 22 '17 23:01 sidorares

plus basic

exports.tightCompressions = {
    basic: 0
    fill: 8,
    jpeg: 9,
    png: 10,
};

and basic is CopyFilter, PaletteFilter, GradientFilter

sidorares avatar Jan 22 '17 23:01 sidorares

@sidorares how we can represent tpixel inside rfb2 package ? create new type ?

vtolstov avatar Jan 22 '17 23:01 vtolstov

I'd rather just store as node Buffer

sidorares avatar Jan 23 '17 00:01 sidorares

RfbClient.prototype.readTight = function(rect, cb)
{
    var stream = this.pack_stream;
    var cli = this;

    stream.unpack('C', function(ctl) {
        var comp = rfb.tightCompressions;

        cmp = ctl[0] >> 4;
      console.log('cmp ' + cmp);
        switch (cmp) {
          case comp.fill:
            cli.readTightFill(rect, cb);
            break;
          case comp.png:
            cli.readTightPng(rect, cb);
            break;
          default:
            console.log('unknown tight comp!!! ' + ctl);
        }
    });
}

RfbClient.prototype.readTightFill = function(rect, cb)
{
  var stream = this.pack_stream;
  var cli = this;

  stream.get(3, function(rawbuff) {
    rect.buffer = rect.data = rawbuff;
    cli.emit('rect', rect);
    cb(rect);
  });
}

vtolstov avatar Jan 23 '17 00:01 vtolstov

Does you mean something like this?

vtolstov avatar Jan 23 '17 00:01 vtolstov

my example data:

TIGHT RECT { x: 0, y: 0, width: 1280, height: 51, encoding: 7 }
Buffer 00 9f 57 78 9c 00 00 00 ff ff ec 5d 07 58 16 c7 d6 4e 8c 49 4c d5 68 4c 4c e2 35 f5 c6 24 6a 6e 62 2c b1 37 14 05 15 89 15 10 13 3b d6 d8 8d bd 8b 80 ... >

looks like control = 0 ( BasicCompression + no zlib ) followed by 3 bytes length = 9f 57 78 followed by len data ( which is TPIXEL fb update )

sidorares avatar Jan 23 '17 00:01 sidorares

This is tight encoding, but in my case encoding -260 (tight png)

vtolstov avatar Jan 23 '17 00:01 vtolstov

so i think that read compressed len must be exclded from png because it may be used in all tight cases...

vtolstov avatar Jan 23 '17 00:01 vtolstov

@sidorares can you help me and extract it to dedicated function that can be used from all tight cases?

vtolstov avatar Jan 23 '17 00:01 vtolstov

looks like logic is a bit more complicated, need to implement full spec https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#tight-encoding describing all 0-7 bits of control byte to get values of stream, filter id and compression

sidorares avatar Jan 23 '17 00:01 sidorares

@sidorares in case of all tight - yes, but in case of png - no. stream don't needed and filter id = 10.... but thanks for info i have more knowledge why i have issues.

vtolstov avatar Jan 23 '17 00:01 vtolstov

oh. I'm confused :)

Id Tight separate encoding to TightPng? From spec it look png is just a compression type for tight:

Bits Binary value Description 7-4 1000 FillCompression 1001 JpegCompression any other Invalid

sidorares avatar Jan 23 '17 00:01 sidorares

http://wiki.qemu.org/Features/VNC_Tight_PNG

If you want I can run qemu on external IP and share it for you for easy testing

vtolstov avatar Jan 23 '17 06:01 vtolstov