bitfocus / companion

Bitfocus Companion enables the reasonably priced Elgato Stream Deck and other controllers to be a professional shotbox surface for an increasing amount of different presentation switchers, video playback software and broadcast equipment.
http://bitfocus.io/companion
Other
1.57k stars 501 forks source link

Refresh PNG icons #2097

Open xavifumi opened 2 years ago

xavifumi commented 2 years ago

Is this a feature relevant to companion itself, and not a module?

Is there an existing issue for this?

Describe the feature

An internal action to "refresh" a button PNG or all of them.

Usecases

When working in different projects, sometimes we use thumbnails to show on the button the graphics that will be triggered. Usually we have a Streamdeck base layout that uses the same structure but the graphics change between projects and we managed to create a companion button to generate a thumbnail of the desired video inputs (vMix layers in our case) replacing the old ones. Aauto updating those button PNGs with an action, not just changing them manually every time, could save a lot of time on the preparation.

Julusian commented 2 years ago

By refresh, do you want it to fetch the new png from the same path on disk, or should it be looking somewhere else?

Companion doesnt know where they originally resided on disk because the ui where you choose it runs in your browser (which could have been done from another computer entirely).

Perhaps it would work for you to write a script which pushes the new pngs to the http endpoints? Its not fully documented, but the docs do say for other style properties. A GET request to /style/bank/2/4/?png64=<PNG DATA>, where <PNG DATA> is a base64 encoded png image should work

xavifumi commented 2 years ago

For me it has more sense to fetch from the same path on disk, so any change to the images would be updated in a faster way than looking somewhere else. The script way seems more complicated as the images should be also converted to base64, which companion does when charging a PNG

jsjoen7896 commented 2 years ago

A GET request to /style/bank/2/4/?png64=<PNG DATA>, where <PNG DATA> is a base64 encoded png image should work.

I have tries this and it doesn't seem to work! :( Any ideas?

kbowling76 commented 2 years ago

So, I got this working, and it took me a couple hours longer than I care to admit because I forgot to encode the Base64 data, resulting in a PNG ERROR message.

Here are the steps:

  1. Convert your PNG to a Base64 image. This requires a Base64 image not just the Base64 string. In plainer words, it has to be a Data URL. So, you want it in this form: data:image/png;base64,<PNG DATA>

  2. Encode your Base64 image so it can be sent as a URL parameter. In JS, you want to use encodeURIComponent().

That's it. Well, almost. The other issue I ran into is that a button has to exist already for you to be able to push an image onto it. That's true for any of the properties, so, I found that issue early on when image and text were both not working. After a couple of hours of trial and error, I dug into the internals of Companion (specifically the db file where button configs are stored) and realized that my Base64 PNG was corrupted.

Here's an example (note: this example sets every button property available, but you can send whichever ones you want to send):

/style/bank/2/4/?text=&alignment=center:center&size=14&color=%23ffffff&bgcolor=%23000000&pngalignment=center:center&png64=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAAEgAAAA6CAYAAAATBx%2BNAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAubSURBVHhe7ZsJdFTVGce%2FWZLJnkBICAGBmACRXRARpKAiaGU5SqW1pmDBBVyKxZZa6KmoR6QVazyKqKnVgpFFFIW0sikeLFgEkcIBDMQkLIkkCEkmk4WsX%2F%2FfnTdDJBPz3psJUQ%2B%2Fc%2F6Td99M7tz3ve9%2B97v3vqFLXOISbYlF%2B9veRELjoeuggVBXKAJqhCqgIugItBvaCh2DfnQEQb2hEdA1UBLUC8qAXBDrVAP0MXQT1Oa0tQdJ%2FROh2dD1UCjUDJvNRiNGjKBbbrmFhg0bRj179qSIiAhiZnK5XFRQUECHDh2i7du305YtW9Q5jdXQ3VCVKv3AEI9ZBak7b7VaOSkpiWEIHj58OHft2pVhBJ45cyZnZ2fDFvpwOp28ZMkSjoqK8njUvyAr9IMhHBoOvQhxTEwMp6enc3FxsXaJ52lsbNSOjHP48GGOj4%2F3GGkPJDfjD5DEsO8lo6D3IXF3T8N506ZN2iUFnlWrVjG6p%2Fe7NElg3wldC%2FlNIGKQuPdz0BzIIvGkf%2F%2F%2BlJKSQqNHj6Y5c%2BR02yHxKT8%2Fn%2FLy8mjnzp20bt06Onv2rLwlwfwh6BUptCcLIQ4JCeGFCxdyUVGRdn%2Fbh4qKCp4%2Ff76KeWhXPSTdvd2QeOOSxmB00Zr4%2FWDevHmeLve6NNQs%2Fkb%2F7lBEcnIyjRs3zn3me4J0bw1JOtuNKKjabrfz7t27tXunnwMHDnBhYaFW8s2uXbu4rKxMK%2BmjqqqKx4wZ4%2FGgp6Sh7Uk6pIbzZcuWcWVlpdbM72bPnj0cFBTEcXFxnJGR8a004MyZM7x%2B%2FXqeMGGCukh4A1dXV2vvtkxdXZ36vwEDBniMUwjFQaYJxCgWDC2H7pACEjgaOXIk9erVS2XDPXr0oKFDhxISQ5Uxw2MIQz8h2aPS0lL5FwXiGIWHh6vsGR5AyJG0d9wMHjyYFixYQGPHjiXcDIIxVHYNg1BJSYkayeBtnhFMkLnbbdCXqtTOiKGnQMchz91rVVOnTuXMzExG%2FOLIyEjvecmwR40axYsXL%2BZt27YxYpz3Pcl7JIuWUdNz7gLVQI9CPqc17cUwaDPkbWhirI1H9Xd4y3JR0p369u3L06dP582bN7v7hYZk1TKNKC8vb5ZhS0xZunSpMpoY0mKxeOuNjbJy7252tlrOfzcks%2F8%2FQhIj250FkOQbHBVm5fsnR%2FD29Hgu3dCNy7K68cRrQlWjZ8yYoV2uf0icOXr0qPIgC4yStSiOnfiew2904Wfui%2BGkLvamhiqBUqF2QzynDlINSuho42njwnnxPTH82u87cm5mIu%2FLSGCblRjxRXlIIJDJqnzfBBhfjLP%2F7wk8op%2BDO8Kb0NebGki0HWqXyazEnR0Qj7sugpN7Bl%2FYMO6ZYOfT73ZVjZfy2rVrtUv0D1kRkPoyF8QqA6WNDVdl8ajoKBuPvz6Clz2byAnxXm%2F6BXTR%2BSnEnePsXJp3BdcW9ePdH17Ozz%2FdhX9zbywn9XAbbPakCH78rmh1PGvWLO0SzSM5kaQHjiAL%2F3dpZ54%2BPlwZJjjYwru3Xs41p%2Fpx%2FWm3Xn0u0WMgGcls0EVFVvV4yRMJ3gY11X%2F%2BncQOhzuYpnYPUn8HDRqkXaY%2BXC4XL1q0SAV2pA6clpbGkydPVnVJUPYE5hB8z4pl3Zq1ofrrvk09W4b8i4YEvsaoSCuX5F7RrGEebXirO8tn8Fklh8PBq1ev9rk25KG2tpZ37NjBc%2BfO5djYWO%2F%2F%2BlJEuJV%2FNTWGD%2B5M8fn9ovRFCZ7Pb4IMYzZRfAJ6bGZaB8pIT3SfaYETBXX0p6eKae2Gcqqvl3a6SUxMVElkdHQ0YUQiZMpUVFREOTk5KlH0cOXAEJr%2F2ziCl1DB1%2FVUU9tIHaJt1DvFQYP6hRC8VPukb0pKG6j7wCN0roZlpL0MkhRAN2YNtA8avPHtHoQA7T7TCnnHa2nVu07a9FEF7TtQLQ3W3vk2iCd0WdcguumGCLrzZzE06powdc4fJqedoA%2B2qnXsmdAbcqAXM18tc5tT4WFWW3F2Ku6%2B8SpqYJz8E7V0srCOKisbqQGzCsxCKLaDnVIuD6Yune3aJwPDsn%2BU0Jz5p%2BQwE5omB3oxY6CboY2jR4TRtvWyc6MPTLFgCCa7zT93MFPP%2FoPnaOgNuXJ4FOojB3oxk0D1k5eB6P96WbGmjPoMz6G4Xtk06c7jdPyk5JbGkXpSvfWc0F1Pam8HIQ2QwxRIf8OBGQMpt0lOkkl860jMuXtOIeUdqyVXRSNt%2FLBCGamuScDWg6eeXG89Lpr4y%2BNU39B6PQ4Yp1ui7EKp65VFPt2YMZBaX0GCqAqt8ebbZapbNOXwkRra%2B79qraQPX%2FV8ebSGPt%2Bnr54m7TW0PmTGQLIOTchBVKE1LrwoDy2dbwl%2F62nSXtV%2BvZgxkCHuvD262TCd2stBVw02tlyT5qOePsiFhl3Ztss%2BZgyksrgKDM96mDg%2Bkl7%2BW6LKbYKCLDR2dDghw1bHRpgg9TyLehBLPPVkrexOdru%2BeiSd0DC0j2%2BslW6WQg8ihSdMSt1ndCBdQWT102fN1tPn6hwV4OUQkuFeF2aaq57NyTtmbKiW7uGvcQQz9WB6h2mKaq%2B40Qk50IuZJh%2BSl%2F2HzqlCICkta1DZtVxQIMnOqcEcTtUp2aKhhpsx0F6oYe%2F%2BludTRnkHE9lhN%2BZS59RsSrryKMX3yaYZDxWqiW4g2PmZN%2BzIE2qGMGOg09BBCXo7dlW6z5hEYsnDC07RHfecxAT2HHl2emQAkLznqrG5tOtzY%2FmSLzZvk6f4FNu0v7oxGxU2yMva9eWqYJbnXzlLL70m6%2Bq%2BkaWK26adoFPFslJhDum2H36iDCSVbJQDI5g1kHpy7J0NTip36RvuL6T4dD09%2Fldxxu%2Fmm7P19Oeni7WScVa%2B66Rz51QokBVQNaU3glkDyRrvdmd5I73%2B1vndUSP8c3UZVVbpM%2B7qdU7lTUaRBboXM7w7raaeEzJrIOFZ9bL0DFVg8miULefjQqvIYPDJp8bjncSxr%2FJV7iN5jwoLRvHHQB9Anxahqzyd%2Fo37jAGOfCU7xPrJ%2FkpdqG6c5Q302GJvF34cMhXI%2FDGQdOy5UEM6gu3nBmbnMnpVVRvzOr3d0cO8hcWe4C57d2vkwAz%2BGEiQvOKFujqmabMLqMypL05INhwdZWybqkO0%2Fqauec9Jb6xUsVHu2izI3EgC%2FDWQIHvzX%2BTk1VLarAKqhbH0MKCvoYU93Z%2Ff80U13Tf3a%2BWl4BHosDoySSAMJKn77VCxJGQzHiz81vZOS0y8SX6eoY8OMTa6dniYVmqZA5j%2BTE477umOr0F%2BP%2BEaCAMJ%2BdAEqGzN%2B06aOvNk0%2BUFn8j6TkK8vlXJ%2B2d0pLDQ727qDkwnbpxyDHmT6uYyYj0gB%2F4SKAMJMkeTH5icydrkojGT8iknt%2BWRJzzMSi8906XVmXm%2FVAc9%2BnAnrdQc6UqvLi%2Bhm28%2F5smV3oN%2BDgVkIhfoDX15JlDu3jgM%2F52WIxmMirTRkEEhMETzpSdZWUxMCKKtH1dQg4%2F4LnEna2UP6hTr29NkCePX6NLpL5%2Bl%2BgY1qr4A3QsFZpYL2uKJB0ld34QuQ8AesPGjCkvWZpfaVUhJcqgRrClDBobSlIlRajogmblsIA64IoQeeaCTWkGM7di8iSWYX%2F3l%2BTN01wOFdPBLlU%2FJkCW7ppK8mh6xfNH8tgaWWyF5CranFOTC753egabeGkVxLXhFS0hXklxrBbwyc22Z2vrReBuS0Uq8N%2BC0tYEEGZ%2Fl92K%2Fg7rJCZvNQlcPCaUxI8PQ%2FUKpd3IwdUFXCwu1kA1dUfbMnMipjp2so0PZNfTZ3ir66JNKtZimIdaRXx4%2BCX0qJ34MOCAJnlmQJHASM7xC1%2BPgIIt61sduP%2F%2BQ5gU6CckPZ%2FpDF4WL4UG%2BkKdPfwKNhOT3XclQZ0iSHQk64ipOqADKhmSElGcND0ABjTGt0V4G8oUM%2BGIcaZMYwfwq2SUuFkT%2FBzJRNKWFKJBHAAAAAElFTkSuQmCC

buffos commented 1 year ago

I have tried to automate that, with a small powershell script (+ imagemagick) but I always get the following error

  1. I am using 3.0.0 beta (windows)
  2. I use the following code
magick.exe convert thessaloniki.jpg -resize 72x58! test.png  # run imagemagic to create a 72x58 png image
$header = "data:image/png;base64,"  # create the header
$t = openssl base64 -in test.png  # create the base64 string
$base = [System.Web.HttpUtility]::UrlEncode($header+$t)  #url encode the result
$companionURL = "http://127.0.0.1:9000"
$request = "${companionURL}/style/bank/8/2/?text=&bgcolor=%00000000&size=14&png64=" + $base
Invoke-WebRequest  $request  #invoke the request to companion.

I do not understand why it does not work

buffos commented 1 year ago

Actually I think its a bug. I went through the code and generated the same dataURL that the code does, but going through the GET request it returns an error due to length of the url. (the image is of the correct size)

Probably there should be an option to set the image through a post request.

Julusian commented 1 year ago

Following on from some recent core changes, I realised that doing this as part of a module is much simpler than it used to be.

In the 3.0 betas, there is now a feedback for the generic-http module called 'Image from URL'. This will fetch an png/jpeg from the provided url (supporting variables in the url field), scale and display it. When the variable changes, it will update with the new url. It can also be set to reload the image on an interval. Screenshot from 2023-01-29 20-38-38

I would provide a demo, but my laptop appears unable to record videos today...

It should be possible to do something similar for the generic-filereader module, to support the flow of reading from disk

This doesn't really solve the original description of this task, as that wants it to be done on-demand rather than automatically. And using this automated polling would be very inefficient as it will be reloading and scaling the image every few seconds

premultiply commented 1 year ago

May this also be used for automatically fetching thumbnail button backgrounds for ptz camera presets when saving or updating?

Julusian commented 1 year ago

@premultiply

May this also be used for automatically fetching thumbnail button backgrounds for ptz camera presets when saving or updating?

If the images are served over http in some way then yeah it could probably be used. I'm going to use this with the spotify module which provides a variable with the url for album art, but no builtin way to display that

premultiply commented 1 year ago

Yes, see https://github.com/bitfocus/companion-module-generic-http/issues/40

buffos commented 1 year ago

@Julusian

That is really a great feature, and could be used as a workaround to populate images to buttons, the drawback would be one custom url per button.

buffos commented 1 year ago

I think there is a very easy fix for the problem.

First of all the problem is caused by the fact that Nodejs limits the http header size to 8Kb (or 16Kb depending on the version). This is why we get messages that the message is too big. The size can be checked by logging http.maxHeaderSize;

There is a very easy fix for that When launching nodejs add the --max-http-header=size to change the allowed size. For example --max-http-header-size=131072 will allow 128KB of header size.

In fact you can make that user defined if you want, but for an easy , zero-line fix, please increase that to 128KB or more to allow larger headers.

buffos commented 1 year ago

I am not sure what changed in the latest beta, but now even the url posted from kbowling76 above does not work. (for the png part)

DhSufi commented 1 year ago

Hello, any update on this topic? I have been trying the "/style/bank//

EricAndrechek commented 1 year ago

@DhSufi Did you ever find a solution to get this working?

buffos commented 1 year ago

@EricAndrechek . No. Waiting for it to be resolved.

DhSufi commented 1 year ago

@DhSufi Did you ever find a solution to get this working?

No. The Log shows a request received but nothing changes in the WEB GUI. I did not tested it with a streamdeck yet to check if the button changes image in the hardware. But as long as I tested, The WEB GUI changes everything I send the button (text, background color, font size, etc) so I suppose it should change the image when the request is received. Also I tested to send several changes at the same time, and all of them happen in WEB GUI except for the image change. I hope this will be possible in the future because it is extremly powerfull feature for plugins and work flow (in my case change Pokémon each battle and changing League of Legends and TFT champions)

EricAndrechek commented 1 year ago

Well I found the web UI's socket connection and can see how it changes the image there, so I guess it would be possible to use that as a janky API to change the image, but I don't feel like that is worth the trouble... hopefully we can just get the normal api working...

DhSufi commented 1 year ago

Well I found the web UI's socket connection and can see how it changes the image there, so I guess it would be possible to use that as a janky API to change the image, but I don't feel like that is worth the trouble... hopefully we can just get the normal api working...

Can you please show us how to it with a exmaple? Thanks @EricAndrechek

EricAndrechek commented 1 year ago

I've got midterms this week that should probably take priority... But sure next week I'll try to make a janky little example script.

DhSufi commented 1 year ago

OK I got it. Companion UI websocket url is: ws://127.0.0.1:8000 You need to use socket IO and send event and data. The event is: controls:set-style-field' The data is: ('bank:1-14', {"png64": "data:image/png;base64,iVBORw0KGgoAAAAN...}")

Here is a python example:

import socketio

sio = socketio.Client()

data = {"png64": "data:image/png;base64,iVBORw0KGgoAAAANSU..."}
sio.connect('ws://127.0.0.1:8000')
sio.call('controls:set-style-fields', ('bank:1-14', data))

Thanks Eric Andrechek for the hint. I hope it helps Video example for my particular use:

https://github.com/bitfocus/companion/assets/75437459/1a216d22-3634-4e9b-8192-da8ee341581a

Julusian commented 11 months ago

It turns out there was a bug which broke setting the png over this api. This is fixed in the betas now. I am currently working on a redesign of the api, which will allow for fixing the url length issue. Hopefully landing soon