Rotate a pixmap - Xwindows

This is a discussion on Rotate a pixmap - Xwindows ; With a view to rotate the whole content of a TK Canvas (which is a X11 Pixmap), i am searching for a fast algorithm to rotate a X11 Pixmap. I have the idea to rotate each pixel of the source ...

+ Reply to Thread
Results 1 to 6 of 6

Thread: Rotate a pixmap

  1. Rotate a pixmap

    With a view to rotate the whole content of a TK Canvas
    (which is a X11 Pixmap), i am searching for a fast
    algorithm to rotate a X11 Pixmap. I have the idea
    to rotate each pixel of the source pixmap and
    put it in a destination pixmap which then can be displayed
    with copyarea on the canvas. So I don`t know if
    i am on the right pass and i am searching for ideas
    and sample code.

    Thank you for help.

  2. Re: Rotate a pixmap

    jubi writes:

    > With a view to rotate the whole content of a TK Canvas
    > (which is a X11 Pixmap), i am searching for a fast
    > algorithm to rotate a X11 Pixmap. I have the idea
    > to rotate each pixel of the source pixmap and
    > put it in a destination pixmap which then can be displayed
    > with copyarea on the canvas. So I don`t know if
    > i am on the right pass and i am searching for ideas
    > and sample code.


    The RENDER extension includes the SetPictureTransform request,
    with which you could get arbitrary rotation pretty easily, I
    think. And that can apparently be combined with filtering.

    If the X server does not support that extension, then you can
    instead copy the pixmap into a client-side XImage and rotate
    there. If the pixmap is large, doing the rotation in tiles may
    help use the processor's data cache more effectively.

    Certainly you should not fetch pixels from the server one at a
    time.

  3. Re: Rotate a pixmap

    On Dec 12, 1:56 am, jubi wrote:
    > With a view to rotate the whole content of a TK Canvas
    > (which is a X11 Pixmap), i am searching for a fast
    > algorithm to rotate a X11 Pixmap.



    > I have the idea
    > to rotate each pixel of the source pixmap and
    > put it in a destination pixmap which then can be displayed
    > with copyarea on the canvas. So I don`t know if
    > i am on the right pass and i am searching for ideas
    > and sample code.



    Without using an extension of the X server, you need to get an XImage
    from a pixmap (using XGetImage), rotate it and put it back using
    XPutImage.

    To rotate the image by an angle theta, you need to be able to access
    pixels. Do this using XGetPixel and XPutPixel


    For each pixel (x,y) in the destination:
    Move the origin to the center, (x0, y0) = (x-dest_width/2, y-
    dest_height/2)
    Rotate to the source image xr = x0 * cos(theta) + y0 * sin(theta)
    yr = x0 * -sin(theta) + y0 * cos(theta)

    Translate to the source image origin
    (xs, ys) = (xr + src_height/2, y2 + src_width/2);

    Copy pixel (xs, ys) from the source to (x, y) in the destination
    XPutPixel(dest, x, y, XGetPixel(source, xs, ys));


    This uses nearest neighbout interpolation, so it looks rather bad. To
    do interpolation, you need to know how your images are coloured and
    threrefore how to extract the xolours from XGetPixel, interpolate them
    and put them back together.

    It's also slow.

    You will probably want to write some hand-coded versions not using
    XGetPixel and XPutPixel for the image types you really care about.

    -Ed

    --
    (You can't go wrong with psycho-rats.) (http://mi.eng.cam.ac.uk/
    ~er258)

    /d{def}def/f{/Times findfont s scalefont setfont}d/s{11}d/r{roll}d f 2/
    m
    {moveto}d -1 r 230 350 m 0 1 179{1 index show 88 rotate 4 mul 0
    rmoveto}
    for /s 12 d f pop 235 420 translate 0 0 moveto 1 2 scale show
    showpage






  4. Re: Rotate a pixmap

    jubi wrote:
    > With a view to rotate the whole content of a TK Canvas
    > (which is a X11 Pixmap), i am searching for a fast
    > algorithm to rotate a X11 Pixmap. I have the idea
    > to rotate each pixel of the source pixmap and
    > put it in a destination pixmap which then can be displayed
    > with copyarea on the canvas. So I don`t know if
    > i am on the right pass and i am searching for ideas
    > and sample code.
    >
    > Thank you for help.


    I'd suggest using XShm pixmaps or images if you do it. XGetImage and
    XPutImage can be slow, but they are the fallbacks when shared memory
    isn't available.

    I have some code that does rotation of an image, incidentally for Tcl,
    so perhaps the extension is something you could use. I'm also working
    on a NexTk that uses the megaimage extension to represent window
    buffers. Full RGBA support and alpha blending are also part of NexTk.

    The algorithm is fairly simple. You use a standard rotation matrix and
    multiply by the x,y. You first need to calculate the rotated size of
    the image.

    This is the algorithm I use for the final size:
    static void
    instance_cmd_rotate_new_size ( struct megaimage *img, int d, int
    *newwidth, int *newheight ) {
    double a;

    a = (3.14159265359 * d) / 180;

    *newwidth = round (abs (img->width * cos (a)) + abs (img->height * sin
    (a)) + 2.0);
    *newheight = round (abs (img->height * cos (a)) + abs (img->width * sin
    (a)) + 2.0);
    }

    2.0 is basically a fudge factor, because the operation isn't exact with
    some angles.

    Then you iterate the destination image buffer, and translate each x,y
    with the rotation matrix.

    Here's the code I use:
    http://megapkg.googlecode.com/svn/tr...rotate_fixed.c

    That algorithm can be much simpler. I have optimized it quite a bit
    during profiling, to reduce the amount of overall computation.

    I also have an alternative that's a little slower (on a Pentium 4) that
    uses double floating point:
    http://megapkg.googlecode.com/svn/tr...rotate_float.c

    By the way the svn/trunk/csrc/ntk/x tree has code for XShm.


    George

  5. Re: Rotate a pixmap

    Kalle Olavi Niemitalo writes:

    > The RENDER extension includes the SetPictureTransform request,
    > with which you could get arbitrary rotation pretty easily, I
    > think. And that can apparently be combined with filtering.


    I tried to set up some sample code, but it's not working.
    The following should tile the contents of window 0x100002f to
    the root window, but I only get black. If I change the 1.01 to
    exact 1.0, then it works all right. This is with Debian
    xserver-xorg 1:7.1.0-7 and xserver-xorg-video-mga 1:1.4.4.dfsg.1-1.
    (I'm not using later versions yet, because of Debian bug 430112.)
    Is it a bug in the X server, or did I misunderstand something?

    #! /usr/bin/tcc -run -lX11 -lXrender -lm

    #include
    #include
    #include
    #include
    #include

    static XFixed
    float_to_fixed(float f)
    {
    return f * 0x10000;
    }

    int
    main(void)
    {
    int mainret = EXIT_FAILURE;
    Display *display = NULL;
    int render_event_base;
    int render_error_base;
    int render_major_ver;
    int render_minor_ver;
    Window src_window;
    Window dst_window;
    Picture src_picture = None;
    Picture dst_picture = None;
    XRenderPictFormat *src_pictformat = NULL;
    XRenderPictFormat *dst_pictformat = NULL;
    XRenderPictureAttributes pictattr = {0};
    XWindowAttributes src_window_attributes;
    XWindowAttributes dst_window_attributes;
    XTransform transform;

    display = XOpenDisplay(NULL);
    if (display == NULL) {
    fprintf(stderr, "Cannot open display\n");
    goto error;
    }

    if (!XRenderQueryExtension(display, &render_event_base, &render_error_base)) {
    fprintf(stderr, "RENDER extension not found and alternative code not yet implemented\n");
    goto error;
    }
    if (!XRenderQueryVersion(display, &render_major_ver, &render_minor_ver)) {
    fprintf(stderr, "RENDER extension version is unclear\n");
    goto error;
    }
    if (render_major_ver != 0 || render_minor_ver < 10) {
    fprintf(stderr, "RENDER extension version is incompatible\n");
    goto error;
    }

    pictattr.repeat = RepeatNormal;
    src_window = 0x100002f; /* change this */
    dst_window = DefaultRootWindow(display);
    if (!XGetWindowAttributes(display, src_window, &src_window_attributes)) {
    fprintf(stderr, "Cannot retrieve source window attributes\n");
    goto error;
    }
    if (!XGetWindowAttributes(display, dst_window, &dst_window_attributes)) {
    fprintf(stderr, "Cannot retrieve destination window attributes\n");
    goto error;
    }
    src_pictformat = XRenderFindVisualFormat(display,
    src_window_attributes.visual);
    dst_pictformat = XRenderFindVisualFormat(display,
    dst_window_attributes.visual);
    src_picture = XRenderCreatePicture(display, src_window, src_pictformat,
    CPRepeat, &pictattr);
    dst_picture = XRenderCreatePicture(display, dst_window, dst_pictformat,
    CPRepeat, &pictattr);

    transform.matrix[0][0] = float_to_fixed(1.01);
    transform.matrix[0][1] = float_to_fixed(0.0);
    transform.matrix[0][2] = float_to_fixed(0.0);
    transform.matrix[1][0] = float_to_fixed(0.0);
    transform.matrix[1][1] = float_to_fixed(1.0);
    transform.matrix[1][2] = float_to_fixed(0.0);
    transform.matrix[2][0] = float_to_fixed(0.0);
    transform.matrix[2][1] = float_to_fixed(0.0);
    transform.matrix[2][2] = float_to_fixed(1.0);
    XRenderSetPictureTransform(display, src_picture, &transform);
    XRenderSetPictureFilter(display, src_picture, "fast", NULL, 0);

    XRenderComposite(display, PictOpSrc, src_picture, None, dst_picture,
    0, 0, 0, 0, 0, 0,
    dst_window_attributes.width, dst_window_attributes.height);
    XSync(display, False);

    mainret = EXIT_SUCCESS;
    error:
    if (src_picture != None)
    XRenderFreePicture(display, src_picture);
    if (dst_picture != None)
    XRenderFreePicture(display, dst_picture);
    if (display != NULL)
    XCloseDisplay(display);
    return mainret;
    }

  6. Re: Rotate a pixmap

    Kalle Olavi Niemitalo writes:

    > The following should tile the contents of window 0x100002f to
    > the root window, but I only get black. If I change the 1.01 to
    > exact 1.0, then it works all right. This is with Debian
    > xserver-xorg 1:7.1.0-7 and xserver-xorg-video-mga 1:1.4.4.dfsg.1-1.


    It doesn't work with xserver-xorg-core 2:1.4.1~git20071212-2 and
    xserver-xorg-video-mga 1:1.9.100.dfsg.1-1, either. There seems
    to be another bug too: when I make the destination window so
    large that the source has to wrap, it wraps to the edge of the
    root window, rather than to the edge of the source window.
    The revised demo program follows.

    #! /usr/bin/tcc -run -lX11 -lXrender -lm

    #include
    #include
    #include
    #include
    #include

    enum
    {
    WM_DELETE_WINDOW,
    ATOMCOUNT
    };

    static char *atom_names[ATOMCOUNT] = {
    "WM_DELETE_WINDOW"
    };

    static Window
    create_dst_window(Display *display, const Atom atoms[], int argc, char **argv)
    {
    Screen *screen;
    Window dst_window;
    XWMHints wm_hints;
    Atom protocols[1];
    XSetWindowAttributes attributes;

    screen = DefaultScreenOfDisplay(display);
    attributes.event_mask = ExposureMask;
    attributes.bit_gravity = ForgetGravity;
    dst_window = XCreateWindow(display, RootWindowOfScreen(screen),
    0, 0, 302, 202, 1,
    DefaultDepthOfScreen(screen), InputOutput,
    DefaultVisualOfScreen(screen),
    CWEventMask | CWBitGravity,
    &attributes);

    wm_hints.flags = InputHint;
    wm_hints.input = False;
    XmbSetWMProperties(display, dst_window,
    "xrender-rotate", NULL, argv, argc,
    NULL, &wm_hints, NULL);
    protocols[0] = atoms[WM_DELETE_WINDOW];
    XSetWMProtocols(display, dst_window, protocols, 1);
    return dst_window;
    }

    static XFixed
    float_to_fixed(float f)
    {
    return f * 0x10000;
    }

    static int
    demonstrate_render(Display *display, Window src_window, Window dst_window)
    {
    int ok = 0;
    Picture src_picture = None;
    Picture dst_picture = None;
    XRenderPictFormat *src_pictformat = NULL;
    XRenderPictFormat *dst_pictformat = NULL;
    XRenderPictureAttributes pictattr = {0};
    XWindowAttributes src_window_attributes;
    XWindowAttributes dst_window_attributes;
    XTransform transform;

    pictattr.repeat = RepeatNormal;
    if (!XGetWindowAttributes(display, src_window, &src_window_attributes)) {
    fprintf(stderr, "Cannot retrieve source window attributes\n");
    goto error;
    }
    if (!XGetWindowAttributes(display, dst_window, &dst_window_attributes)) {
    fprintf(stderr, "Cannot retrieve destination window attributes\n");
    goto error;
    }
    src_pictformat = XRenderFindVisualFormat(display,
    src_window_attributes.visual);
    dst_pictformat = XRenderFindVisualFormat(display,
    dst_window_attributes.visual);
    src_picture = XRenderCreatePicture(display, src_window, src_pictformat,
    CPRepeat, &pictattr);
    dst_picture = XRenderCreatePicture(display, dst_window, dst_pictformat,
    CPRepeat, &pictattr);

    transform.matrix[0][0] = float_to_fixed(1.0);
    transform.matrix[0][1] = float_to_fixed(0.0);
    transform.matrix[0][2] = float_to_fixed(0.0);
    transform.matrix[1][0] = float_to_fixed(0.0);
    transform.matrix[1][1] = float_to_fixed(1.0);
    transform.matrix[1][2] = float_to_fixed(0.0);
    transform.matrix[2][0] = float_to_fixed(0.0);
    transform.matrix[2][1] = float_to_fixed(0.0);
    transform.matrix[2][2] = float_to_fixed(1.0);
    XRenderSetPictureTransform(display, src_picture, &transform);
    XRenderSetPictureFilter(display, src_picture, "fast", NULL, 0);

    XRenderComposite(display, PictOpSrc, src_picture, None, dst_picture,
    0, 0, 0, 0, 0, 0,
    dst_window_attributes.width, dst_window_attributes.height);

    ok = 1;
    error:
    if (src_picture != None)
    XRenderFreePicture(display, src_picture);
    if (dst_picture != None)
    XRenderFreePicture(display, dst_picture);
    return ok;
    }

    int
    main(int argc, char **argv)
    {
    int mainret = EXIT_FAILURE;
    Display *display = NULL;
    Atom atoms[ATOMCOUNT];

    int render_event_base;
    int render_error_base;
    int render_major_ver;
    int render_minor_ver;
    Window src_window;
    Window dst_window = None;
    XEvent event;

    if (argc != 2) {
    fprintf(stderr, "Usage: xrender-rotate WINDOWID\n");
    goto error;
    }
    src_window = strtol(argv[1], NULL, 0);

    display = XOpenDisplay(NULL);
    if (display == NULL) {
    fprintf(stderr, "Cannot open display\n");
    goto error;
    }

    XInternAtoms(display, atom_names, ATOMCOUNT, False, atoms);

    if (!XRenderQueryExtension(display, &render_event_base, &render_error_base)) {
    fprintf(stderr, "RENDER extension not found and alternative code not yet implemented\n");
    goto error;
    }
    if (!XRenderQueryVersion(display, &render_major_ver, &render_minor_ver)) {
    fprintf(stderr, "RENDER extension version is unclear\n");
    goto error;
    }
    if (render_major_ver != 0 || render_minor_ver < 10) {
    fprintf(stderr, "RENDER extension version is incompatible\n");
    goto error;
    }

    dst_window = create_dst_window(display, atoms, argc, argv);
    XMapWindow(display, dst_window);

    for (; {
    XNextEvent(display, &event);
    switch (event.type) {
    case Expose:
    if (event.xexpose.count == 0) {
    if (!demonstrate_render(display, src_window, dst_window))
    goto error;
    }
    break;
    case ClientMessage:
    if (event.xclient.data.l[0] == atoms[WM_DELETE_WINDOW])
    goto finish;
    }
    }

    finish:
    mainret = EXIT_SUCCESS;
    error:
    if (dst_window != None)
    XDestroyWindow(display, dst_window);
    if (display != NULL)
    XCloseDisplay(display);
    return mainret;
    }

+ Reply to Thread