pabloko / Wacom-STU-WebHID

JavaScript library to use the Wacom STU series (540) Signature pad tablets with WebHID API on the browser, without external apps or drivers.
MIT License
9 stars 2 forks source link

Question #2

Open JoaoBRBR opened 9 months ago

JoaoBRBR commented 9 months ago

Hi, this is not an issue with the code, its more of a question, I want to use web-Hid with stu-540 and 430, and your code helped a lot to use it with 540, so the question is: how do you find information about how the devices expect the report-ids and the information's regarding device communication, I want it to work for stu-340 as well, the signing is working, but not the part of sending image to the device screen.

pabloko commented 9 months ago

i just had access to the stu-540 model and reverse engineered it using wireshark with usbpcap and also reversing the OCX that wacom ships as browser extension or something like that... i dont fully recall now, but to work with other models it just should be matter of adapting the size settings and output image to what the tablet accepts.

As far as i know, all the firmwares use the same protocol not only for HID but also for serial tablets. and i implemented just enough protocol to make it workable. try adjusting the screen size, multiplier and other parameters to mach the device. Also bw devices may use 8bit bw images instead 24bgr color pixels

I looked around for SDK code and found this file wich have many clues about the protocol https://github.com/luguiant/wacomgss/blob/main/index.js

pabloko commented 8 months ago

Cool, feel free to submit PR if you have it working and tested

sirbig commented 4 months ago

Thanks! the resources you shared helped a lot! I took a while to realize I had to send 1bit array, now its working fine.

Hello @JoaoBRBR,

Could you please share your code or part of it so I can support STU-430 comms in my project? Great work!

Thank you! 👍

Andrew-av commented 4 months ago

Hello. Could you tell me how I can save it in PNG format?

pabloko commented 4 months ago

you can use a hidden canvas to export the svg paths into png, theres js libraries for that

devgar commented 3 months ago

Hello @JoaoBRBR, I´m also looking for a method to paint images on STU-430. I tried to convert Images to 1bit array from so many methods but never worked.

pabloko commented 3 months ago

@devgar apart from sending the correct bitmap you have to update the packet header to inform the tablet of the format of the image:

        EncodingMode_1bit       : 0x00, // uncompressed monochrome
        EncodingMode_1bit_Zlib  : 0x01, // Zlib-compressed monochrome
        EncodingMode_16bit      : 0x02, // uncompressed color
        EncodingMode_24bit      : 0x04, // uncompressed color (530 only)
        EncodingMode_1bit_Bulk  : 0x10, // data will be sent using Interface::write() instead of Interface::set().
        EncodingMode_16bit_Bulk : 0x12, // data will be sent using Interface::write() instead of Interface::set().
        EncodingMode_24bit_Bulk : 0x14  // data will be sent using Interface::write() instead of Interface::set() (530 only).

my code is full color 24bpp so i use 0x14 in the library. you have to use 0x10

i did not add it since i cannot test, but if you make it work send a PR if you want

btw soy de almería xd

sirbig commented 3 months ago

@devgar apart from sending the correct bitmap you have to update the packet header to inform the tablet of the format of the image:

...

my code is full color 24bpp so i use 0x14 in the library. you have to use 0x00 or 0x01 if you compress it with zlib

i did not add it since i cannot test, but if you make it work send a PR if you want

btw soy de almería xd

Hello @pabloko,

Changing the encoding value is not enough for monochrome tablets. Here is the initializer for the STU-430 that I tried so far but the Wacom tablet only shows random tiny characters across the screen:

...

Maybe there is a need to change the way to chunks are sent to the tablet? Your help is much appreciated, thank you!

pabloko commented 3 months ago

please show me how you compose and send the image, the default code extract bgr color from canvas intead monochrome and the packing is different

pabloko commented 3 months ago

looking at

https://github.com/pabloko/Wacom-STU-WebHID/blob/main/demo.html#L197C8-L198C32

you could use something like this

        const rgb1 = new Uint8Array(imageData.data.length / 4 / 8)
        var i = 0, j = 0;
        var buffer = imageData.data;
        var setBit = function (n, bitIndex, value) {
            const bitMask = 1 << bitIndex;
            return value? n | bitMask : n;
        }
        while (i < imageData.data.length) {
            //Remap pixels
            var pixel = 0;
            // take 8 pixels per byte
            // if the device is big endian maybe this loop has to be inverted from 7 to 0
            for (var z = 0; z < 8; z++) { 
                  // calculate yuv luminance for a good b/w balance
                  var luma = buffer[i] * 0.3 + buffer[i + 1] * 0.59 + buffer[i + 2] * 0.11;  i += 4;
                  // set independent bits as binary black or white color on half scale threeshold
                  setBit(pixel, z, luma > 127)
            }
            // keep appending pixel groups until finished
            rgb1[j++] = pixel
        }
        image = rgb1

this would convert colors to a single byte of luminance and then bitset 8 pixels into a each byte as the buffer for monochrome image

sirbig commented 3 months ago

looking at

https://github.com/pabloko/Wacom-STU-WebHID/blob/main/demo.html#L197C8-L198C32

you could use something like this

...

this would convert colors to a single byte of luminance and then bitset 8 pixels into a each byte as the buffer for monochrome image

@pabloko Thank you very much for your help so far.

I tried something like that in the past after some research and were getting nowhere. After I tried your code it only displays a black screen on the Wacom STU-430, even after setting the screen size according to this tablet which is 320x200. Maybe it has something to do with the background that is being set when converting from white color to monochrome it just overrides and it shows a black screen on the tablet.

... removed code for uncluttering the conv.

pabloko commented 3 months ago

@sirbig well without access to the device its very difficul to troubleshoot what is going wrong...

lets do one thing, download "wireshark", it has an option to sniff usb-hid traffic using usbpcap, start sniffing the the device (is useful if you select option to start on plug, so it captures all comms) and then using the official app from wacom set the image a few times capturing the comms, then pass the pen over the screen to test other stuff, try to annotate the timestamps and upload the .pcap file. I will be able then to examine the protocol and tell you whats going on.

devgar commented 3 months ago

I have access to a STU430 again and this is going really better.

I have set the loop to meet bigEndian needs, and also fix an Issue with setBit(..) return not being captured.

The image is so close to the desired result. I think it only needs to adjust luma treeshold to improve resolution.

Thank you @pabloko for this repo and all this support.

This is my current version

        var byteArray = new Uint8Array(imageData.data.length / 4 / 8)
        var i = 0, j = 0;
        var buffer = imageData.data;
        var setBit = function (n, bitIndex, value) {
            const bitMask = 1 << bitIndex;
            return value? n | bitMask : n;
        }
        while (i < imageData.data.length) {
            //Remap pixels
            var byte = 0;
            // take 8 pixels per byte
            // // if the device is big endian maybe this loop has to be inverted from 7 to 0
            // This needs to be big endian
            for (var z = 7; z >= 0; z--) { 
                  // calculate yuv luminance for a good b/w balance
                  var luma = buffer[i] * 0.3 + buffer[i + 1] * 0.59 + buffer[i + 2] * 0.11;  i += 4;
                  // set independent bits as binary black or white color on half scale threeshold
                  byte = setBit(byte, z, luma > 127)
            }
            // keep appending pixel groups until finished
            byteArray[j++] = byte
        }
        console.log(byteArray.length, j);
        image = byteArray
devgar commented 3 months ago

My screen is currently as this

IMG_20240606_163907821 (1).jpg

sirbig commented 3 months ago

I have access to a STU430 again and this is going really better.

I have set the loop to meet bigEndian needs, and also fix an Issue with setBit(..) return not being captured.

The image is so close to the desired result. I think it only needs to adjust luma treeshold to improve resolution.

Thank you @pabloko for this repo and all this support.

This is my current version

        var byteArray = new Uint8Array(imageData.data.length / 4 / 8)
        var i = 0, j = 0;
        var buffer = imageData.data;
        var setBit = function (n, bitIndex, value) {
            const bitMask = 1 << bitIndex;
            return value? n | bitMask : n;
        }
        while (i < imageData.data.length) {
            //Remap pixels
            var byte = 0;
            // take 8 pixels per byte
            // // if the device is big endian maybe this loop has to be inverted from 7 to 0
            // This needs to be big endian
            for (var z = 7; z >= 0; z--) { 
                  // calculate yuv luminance for a good b/w balance
                  var luma = buffer[i] * 0.3 + buffer[i + 1] * 0.59 + buffer[i + 2] * 0.11;  i += 4;
                  // set independent bits as binary black or white color on half scale threeshold
                  byte = setBit(byte, z, luma > 127)
            }
            // keep appending pixel groups until finished
            byteArray[j++] = byte
        }
        console.log(byteArray.length, j);
        image = byteArray

@devgar Great job! I can confirm the same behaviour with my STU-430 as well, it is getting pretty close to the desired result, just needs a little more tweaking to get the best possible results. Maybe changing the values of the luma calculations will do the trick.

pabloko commented 3 months ago

hola @devgar por la foto parece que mas o menos el empaquetado de pixels funciona, el problema del monocromo es que necesitas ajustar el valor del threeshold (tanto si usas aproximación por luma, o como si usas la capa alpha) dependiendo de si quieres mostrar imágenes con objetos o líneas finas como texto, o ambos... Una cosa que deberías hacer es desactivar el antialiasing del canvas, puesto con el activado se van a generar montones de pixels grises adyacentes al texto y formas que computan en el luma. comprueba que la imagen no se esté escalando y tratar siempre que la fuente y tamaño seleccionado formen líneas de al menos 1px de ancho te ayudará a obtener mejores resultados.

devgar commented 3 months ago

Muchas gracias, @pabloko. Seguiré con las modificaciones que comentas.

Si alguna vez vienes a Castellón tienes una cerveza (u otra consumición) pagada.

pabloko commented 3 months ago

de nada @devgar, estoy pensando que esta lib se está usando mucho más de lo que pensaba inicialmente, así que lo mismo saco un rato y la rehago incluyendo todo el tema del ui y las imágenes para hacerlo menos tedioso, este es otro caso de un proof-of-concept que fue a producción... y ya de paso me gustaría meter soporte para los 430, si puedes pasarme la impl cuando esté lista, o hacer un PR y lo rediseño bien

devgar commented 3 months ago

Por supuesto tendrás nuestra implementación cuando esté lista