The problem is that, as far as I know, there is no way to control the alpha channel with this methods
For a custom painting use case, I doubt the alpha changes while you paint, is it? Because then you can just precalculate that alpha in your brush image before painting, for example when the user changes transparency option.
I know that there is set_pixel, but I do not know if it would be overkill
It is surely slower, but I've been using that just fine in my terrain plugin to paint over large images. It starts to lag only with brushes larger than 50 pixels (while also using a system to only upload what changed).
On the other hand, if speed is a concern and your image isn't too big, you could use a GPU-driven approach and use a non-clearing viewport instead.