Groups | Search | Server Info | Login | Register
Groups > comp.graphics.misc > #546
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Newsgroups | comp.graphics.misc |
| Subject | Re: Running into problems while trying to scale Cairo surface to take up maximum space at specific aspect ratio |
| Date | 2023-06-12 01:07 +0100 |
| Organization | A noiseless patient Spider |
| Message-ID | <87352xy24e.fsf@bsb.me.uk> (permalink) |
| References | <u65kfe$2r139$2@bluemanedhawk.eternal-september.org> |
Blue-Maned_Hawk <bluemanedhawk@gmail.com> writes:
> Hello!
>
> I'm looking for help with a problem i'm running into with the Cairo
> graphics library. I want to paint a surface onto another surface (in this
> case an XLib window) in such a way that it will take up as much space as
> possible while staying at a 4:3 aspect ratio and be centered within the
> window. However, i seemingly can't figure out the right parameters for
> cairo_scale(), and am running into issues with a stretched image and an
> image that doesn't take up the right amount of space.
There are quite a few issues. This is what jumped out at me:
> Minimum example program demonstrating this behavior below; compile with
> `$CC tmp.c -lX11 -lm -lcairo`. Rescale the window and you'll see the
> problem i'm facing. (I am fully aware this will lead to a pixelated output
> [not visible in the example program where it's just pure white]; this is
> intentional and exactly what i want to happen.)
>
> #include <X11/Xlib.h>
> #include <cairo/cairo.h>
> #include <cairo/cairo-xlib.h>
> #include <stddef.h>
> #include <math.h>
>
> const int width = 640, height = 480;
> const long double aspect_ratio = 4.0l/3.0l, inverse_aspect_ratio =
> 3.0l/4.0l;
>
> int main(void)
> {
> Display * display = XOpenDisplay(NULL);
> int screen = DefaultScreen(display);
> Window window = XCreateSimpleWindow(display, RootWindow(display,
> screen), 10, 10, width, height, 1, BlackPixel(display, screen),
> WhitePixel(display, screen));
> XSelectInput(display, window, StructureNotifyMask);
> XMapWindow(display, window);
>
> cairo_surface_t * surface = cairo_xlib_surface_create(display, window,
> DefaultVisual(display, screen), width, height);
> cairo_xlib_surface_set_size(surface, width, height);
> cairo_t * root_instance = cairo_create(surface);
> cairo_surface_destroy(surface);
> surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width,
> height);
> cairo_t * instance = cairo_create(surface);
>
> cairo_set_source_rgb(instance, 1, 1, 1);
> cairo_paint(instance);
>
> for (;;) {
> for (XEvent e; XPending(display) != 0; XNextEvent(display, &e))
This is busy waiting which will ramp up the CPU use. Presumably this is
just for testing, but even so...
> if (e.type == ConfigureNotify) {
> cairo_identity_matrix(root_instance);
> if (e.xconfigure.width < width || e.xconfigure.height <
> height) {
> XResizeWindow(display, window, fmax(width,
> e.xconfigure.width), fmax(width, e.xconfigure.height));
Surely you wanted fmax(height, e.xconfigure.height) here?
> cairo_xlib_surface_set_size(cairo_get_target(root_instance), fmax(width,
> e.xconfigure.width), fmax(height, e.xconfigure.height));
This case looks odd. What's the intent? Do you want stop the user
making the window narrower than width or shorted than height? If that's
what you want you should probably limit e.xconfigure.{width,height}, set
the X window size and then carry on as before because you still need to
set the offset and scale and offset the source in this case as well.
> } else {
>
> cairo_xlib_surface_set_size(cairo_get_target(root_instance),
> e.xconfigure.width, e.xconfigure.height);
> if (e.xconfigure.width >= aspect_ratio *
> e.xconfigure.height) {
> cairo_translate(root_instance, (e.xconfigure.width
> - e.xconfigure.height * aspect_ratio) / 2, 0);
> cairo_scale(root_instance, (e.xconfigure.height *
> aspect_ratio) / width, e.xconfigure.height /
> height);
I'm pretty sure you did not intend to divide two integers here. Both
e.xconfigure.height and height have integer type.
But there's is a bigger issue. To maintain the aspect ration, the x and y
scaling should be the same. Once you have decided whether it's the
window width or the height that will determine the scaling, you should
calculate the scale factor and use that in both arguments.
> } else {
> cairo_translate(root_instance, 0,
> (e.xconfigure.height - e.xconfigure.width *
> inverse_aspect_ratio) / 2);
> cairo_scale(root_instance, e.xconfigure.width /
> width, (e.xconfigure.height * inverse_aspect_ratio)
> / height);
> }
> }
> }
>
> cairo_push_group(root_instance);
> cairo_set_source_rgb(root_instance, 0, 0, 0);
> cairo_paint(root_instance);
> cairo_set_source_surface(root_instance, surface, 0, 0);
> cairo_paint(root_instance);
> cairo_pop_group_to_source(root_instance);
> cairo_paint(root_instance);
> cairo_surface_flush(cairo_get_target(root_instance));
Do you realise that this is in the outer for (;;) loop? That's a lot of
busy work!
> }
> }
--
Ben.
Back to comp.graphics.misc | Previous | Next — Previous in thread | Next in thread | Find similar
Running into problems while trying to scale Cairo surface to take up maximum space at specific aspect ratio Blue-Maned_Hawk <bluemanedhawk@gmail.com> - 2023-06-11 19:13 -0400
Re: Running into problems while trying to scale Cairo surface to take up maximum space at specific aspect ratio Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-06-12 01:07 +0100
Re: Running into problems while trying to scale Cairo surface to take up maximum space at specific aspect ratio Blue-Maned_Hawk <bluemanedhawk@gmail.com> - 2023-06-11 20:54 -0400
Re: Running into problems while trying to scale Cairo surface to take up maximum space at specific aspect ratio Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-06-12 12:24 +0100
Re: Running into problems while trying to scale Cairo surface to take up maximum space at specific aspect ratio Ben Bacarisse <ben.usenet@bsb.me.uk> - 2023-06-12 14:48 +0100
Re: Running into problems while trying to scale Cairo surface to take up maximum space at specific aspect ratio Blue-Maned_Hawk <bluemanedhawk@gmail.com> - 2023-06-12 14:23 -0400
csiph-web