Edit

IABSD.fr/xenocara/lib/pixman/demos/dither.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2025-08-12 16:39:28
    Hash : 81405b23
    Message : Update to pixman 0.46.4. tested in a bulk ports build and ok jca@ runs of the tests on differents by gkoeler@, jca@ and others.

  • lib/pixman/demos/dither.c
  • /*
     * Copyright 2012, Red Hat, Inc.
     * Copyright 2012, Soren Sandmann
     * Copyright 2018, Basile Clement
     *
     * Permission is hereby granted, free of charge, to any person obtaining a
     * copy of this software and associated documentation files (the "Software"),
     * to deal in the Software without restriction, including without limitation
     * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     * and/or sell copies of the Software, and to permit persons to whom the
     * Software is furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice (including the next
     * paragraph) shall be included in all copies or substantial portions of the
     * Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     * DEALINGS IN THE SOFTWARE.
     */
    #ifdef HAVE_CONFIG_H
    #include "pixman-config.h"
    #endif
    #include <math.h>
    #include <gtk/gtk.h>
    #include <stdlib.h>
    #include "utils.h"
    #include "gtk-utils.h"
    
    #define WIDTH 1024
    #define HEIGHT 640
    
    typedef struct
    {
        GtkBuilder *         builder;
        pixman_image_t *	 original;
        pixman_format_code_t format;
        pixman_dither_t      dither;
        int                  width;
        int                  height;
    } app_t;
    
    static GtkWidget *
    get_widget (app_t *app, const char *name)
    {
        GtkWidget *widget = GTK_WIDGET (gtk_builder_get_object (app->builder, name));
    
        if (!widget)
    	g_error ("Widget %s not found\n", name);
    
        return widget;
    }
    
    typedef struct
    {
        char	name [20];
        int		value;
    } named_int_t;
    
    static const named_int_t formats[] =
    {
        { "a8r8g8b8",  PIXMAN_a8r8g8b8      },
        { "rgb",       PIXMAN_rgb_float     },
        { "sRGB",      PIXMAN_a8r8g8b8_sRGB },
        { "r5g6b5",    PIXMAN_r5g6b5        },
        { "a4r4g4b4",  PIXMAN_a4r4g4b4      },
        { "a2r2g2b2",  PIXMAN_a2r2g2b2      },
        { "r3g3b2",    PIXMAN_r3g3b2        },
        { "r1g2b1",    PIXMAN_r1g2b1        },
        { "a1r1g1b1",  PIXMAN_a1r1g1b1      },
    };
    
    static const named_int_t dithers[] =
    {
        { "None",                   PIXMAN_REPEAT_NONE },
        { "Bayer 8x8",              PIXMAN_DITHER_ORDERED_BAYER_8 },
        { "Blue noise 64x64",       PIXMAN_DITHER_ORDERED_BLUE_NOISE_64 },
    };
    
    static int
    get_value (app_t *app, const named_int_t table[], const char *box_name)
    {
        GtkComboBox *box = GTK_COMBO_BOX (get_widget (app, box_name));
    
        return table[gtk_combo_box_get_active (box)].value;
    }
    
    static void
    rescale (GtkWidget *may_be_null, app_t *app)
    {
        app->dither = get_value (app, dithers, "dithering_combo_box");
        app->format = get_value (app, formats, "target_format_combo_box");
    
        gtk_widget_set_size_request (
    	get_widget (app, "drawing_area"), app->width + 0.5, app->height + 0.5);
    
        gtk_widget_queue_draw (
    	get_widget (app, "drawing_area"));
    }
    
    static gboolean
    on_draw (GtkWidget *widget, cairo_t *cr, gpointer user_data)
    {
        app_t *app = user_data;
        GdkRectangle area;
        cairo_surface_t *surface;
        pixman_image_t *tmp, *final;
        uint32_t *pixels;
    
        gdk_cairo_get_clip_rectangle(cr, &area);
    
        tmp = pixman_image_create_bits (
    	app->format, area.width, area.height, NULL, 0);
        pixman_image_set_dither (tmp, app->dither);
    
        pixman_image_composite (
    	PIXMAN_OP_SRC,
    	app->original, NULL, tmp,
    	area.x, area.y, 0, 0, 0, 0,
    	app->width - area.x,
    	app->height - area.y);
    
        pixels = calloc (1, area.width * area.height * 4);
        final = pixman_image_create_bits (
    	PIXMAN_a8r8g8b8, area.width, area.height, pixels, area.width * 4);
    
        pixman_image_composite (
    	PIXMAN_OP_SRC,
    	tmp, NULL, final,
    	area.x, area.y, 0, 0, 0, 0,
    	app->width - area.x,
    	app->height - area.y);
    
        surface = cairo_image_surface_create_for_data (
    	(uint8_t *)pixels, CAIRO_FORMAT_ARGB32,
    	area.width, area.height, area.width * 4);
    
        cairo_set_source_surface (cr, surface, area.x, area.y);
    
        cairo_paint (cr);
    
        cairo_surface_destroy (surface);
        free (pixels);
        pixman_image_unref (final);
        pixman_image_unref (tmp);
    
        return TRUE;
    }
    
    static void
    set_up_combo_box (app_t *app, const char *box_name,
    		  int n_entries, const named_int_t table[])
    {
        GtkWidget *widget = get_widget (app, box_name);
        GtkListStore *model;
        GtkCellRenderer *cell;
        int i;
    
        model = gtk_list_store_new (1, G_TYPE_STRING);
    
        cell = gtk_cell_renderer_text_new ();
        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), cell, TRUE);
        gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (widget), cell,
    				    "text", 0,
    				    NULL);
    
        gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (model));
    
        for (i = 0; i < n_entries; ++i)
        {
    	const named_int_t *info = &(table[i]);
    	GtkTreeIter iter;
    
    	gtk_list_store_append (model, &iter);
    	gtk_list_store_set (model, &iter, 0, info->name, -1);
        }
    
        gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
    
        g_signal_connect (widget, "changed", G_CALLBACK (rescale), app);
    }
    
    static app_t *
    app_new (pixman_image_t *original)
    {
        GtkWidget *widget;
        app_t *app = g_malloc (sizeof *app);
        GError *err = NULL;
    
        app->builder = gtk_builder_new ();
        app->original = original;
    
        if (original->type == BITS)
        {
    	app->width = pixman_image_get_width (original);
    	app->height = pixman_image_get_height (original);
        }
        else
        {
    	app->width = WIDTH;
    	app->height = HEIGHT;
        }
    
        if (!gtk_builder_add_from_file (app->builder, "dither.ui", &err))
    	g_error ("Could not read file dither.ui: %s", err->message);
    
        widget = get_widget (app, "drawing_area");
        g_signal_connect (widget, "draw", G_CALLBACK (on_draw), app);
    
        set_up_combo_box (app, "target_format_combo_box",
    		      G_N_ELEMENTS (formats), formats);
        set_up_combo_box (app, "dithering_combo_box",
    		      G_N_ELEMENTS (dithers), dithers);
    
        app->dither = get_value (app, dithers, "dithering_combo_box");
        app->format = get_value (app, formats, "target_format_combo_box");
    
        rescale (NULL, app);
    
        return app;
    }
    
    int
    main (int argc, char **argv)
    {
        GtkWidget *window;
        pixman_image_t *image;
        app_t *app;
    
        gtk_init (&argc, &argv);
    
        if (argc < 2)
        {
    	pixman_gradient_stop_t stops[] = {
    	    /* These colors make it very obvious that dithering
    	     * is useful even for 8-bit gradients
    	     */
    	    { 0x00000, { 0x1b1b, 0x5d5d, 0x7c7c, 0xffff } },
    	    { 0x10000, { 0x3838, 0x3232, 0x1010, 0xffff } },
    	};
    	pixman_point_fixed_t p1, p2;
    
    	p1.x = p1.y = 0x0000;
    	p2.x = WIDTH << 16;
    	p2.y = HEIGHT << 16;
    
    	if (!(image = pixman_image_create_linear_gradient (
    		  &p1, &p2, stops, ARRAY_LENGTH (stops))))
    	{
    	    printf ("Could not create gradient\n");
    	    return -1;
    	}
        }
        else if (!(image = pixman_image_from_file (argv[1], PIXMAN_a8r8g8b8)))
        {
    	printf ("Could not load image \"%s\"\n", argv[1]);
    	return -1;
        }
    
        app = app_new (image);
    
        window = get_widget (app, "main");
    
        g_signal_connect (window, "delete_event", G_CALLBACK (gtk_main_quit), NULL);
    
        gtk_window_set_default_size (GTK_WINDOW (window), 1024, 768);
    
        gtk_widget_show_all (window);
    
        gtk_main ();
    
        return 0;
    }