filipehd
filipehd

Reputation: 930

XRender Display pictures from disk / application generated images

I am making an application on Linux with GCC in which I've been loading my pictures from disk with PngLIB for some time now. I jumped from the standard xlib to the Xrender extension in order to make use of the anti-aliasing and alpha channel properties offered by this extension.

However, this extension offers a reduced set of primitives. In order to, for example, display a picture loaded from disk, I've been loading it with pnglib, and then make a call to XRenderFillRectangle, with the width and height of 1 pixel and the desired color for that pixel. However, as I increase the number of icons and pictures loaded from disk, it is easy to understand that I easily run into MILLIONS of calls to the primitive XRenderFillRectangle. Conclusion: The application takes, for now, around 20 seconds just to render all the stuff, and it is not even half of what I desire to render.

I am pretty sure that this approach I use is completely Wrong, and there must be another way! And I am also pretty sure that that's not the way Cairo or Java2D do it to generate the stuff.

So my question is: How can I prepare and put into a Picture of Xrender images that were generated by the application? Like for example, images loaded from disk?

Can the standard XPutImage function be applied on a Picture of Xrender? Shall I put the data into a Pixmap before generating the Picture? My approaches haven't worked so far.

PS: Please do not recommend me to use a Richer Library such as Cairo or Qt. I am making this question here now because, unfortunately, everytime I find a post regarding this situation, most people's answer is: Use Cairo. I really need to stay as low level as possible with this X11 system. Thank you very much.

Upvotes: 2

Views: 2488

Answers (1)

Andrey Sidorov
Andrey Sidorov

Reputation: 25466

XRenderCreatePicture takes pixmap (or any drawable) as a parameter. In order to draw pixels using xrender, you need:

  • create pixmap
  • transfer image data to server using XPutImage
  • create Picture object associated with your pixmap
  • create Picture object associated with your window
  • compose them using XRenderComposite

See libXRender documentation here

Example using node-x11:

var x11 = require('x11');

var Exposure = x11.eventMask.Exposure;

var width = 300;
var height = 300;

var rgb = {
  data:new Buffer(width*height*4),
  width: width,
  height: height
};

var index;
for (var x = 0; x < rgb.width; ++x)
{
  for (var y = 0; y < rgb.height; ++y)
  {
    index = (x + y*rgb.width)*4;
    rgb.data[index] = parseInt(Math.sin(13*x/rgb.width)*255);
    rgb.data[index+1] = parseInt(Math.cos(15*y/rgb.height)*255);
    rgb.data[index+2] = parseInt(Math.cos(16*y/rgb.height)*255);
  }
}

x11.createClient(function(err, display)
{
  var X = display.client;
  X.require('render', function(Render) {
    var root = display.screen[0].root; 
    var win, picWin, pic, gc;

    win = X.AllocID();
    X.CreateWindow(
       win, root,
       0, 0, rgb.width, rgb.height,
       0, 0, 0, 0,
       { eventMask: Exposure }
    );
    X.MapWindow(win);

    gc = X.AllocID();
    X.CreateGC(gc, win);

    var rgbPixmap = X.AllocID();
    X.CreatePixmap(rgbPixmap, win, 24, rgb.width, rgb.height);
    X.PutImage(2, rgbPixmap, gc, rgb.width, rgb.height, 0, 0, 0, 24, rgb.data);

    var rgbPicture = X.AllocID();
    Render.CreatePicture(rgbPicture, rgbPixmap, Render.rgb24);
    var winPicture = X.AllocID();
    Render.CreatePicture(winPicture, win, Render.rgb24);

    X.on('event', function(ev) {
      if (ev.name == 'Expose')
        Render.Composite(3, rgbPicture, 0, winPicture, 0, 0, 0, 0, 0, 0, rgb.width, rgb.height);
    });
  });
});

Upvotes: 3

Related Questions