Exemplo n.º 1
0
Arquivo: io-xpm.c Projeto: chipx86/gtk
/* This function does all the work. */
static GdkPixbuf *
pixbuf_create_from_xpm (const gchar * (*get_buf) (enum buf_op op, gpointer handle), gpointer handle,
                        GError **error)
{
	gint w, h, n_col, cpp, x_hot, y_hot, items;
	gint cnt, xcnt, ycnt, wbytes, n;
	gint is_trans = FALSE;
	const gchar *buffer;
        gchar *name_buf;
	gchar pixel_str[32];
	GHashTable *color_hash;
	XPMColor *colors, *color, *fallbackcolor;
	guchar *pixtmp;
	GdkPixbuf *pixbuf;

	fallbackcolor = NULL;

	buffer = (*get_buf) (op_header, handle);
	if (!buffer) {
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("No XPM header found"));
		return NULL;
	}
	items = sscanf (buffer, "%d %d %d %d %d %d", &w, &h, &n_col, &cpp, &x_hot, &y_hot);

	if (items != 4 && items != 6) {
		g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("Invalid XPM header"));
		return NULL;
	}

	if (w <= 0) {
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("XPM file has image width <= 0"));
		return NULL;

	}
	if (h <= 0) {
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("XPM file has image height <= 0"));
		return NULL;

	}
	if (cpp <= 0 || cpp >= 32) {
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("XPM has invalid number of chars per pixel"));
		return NULL;
	}
	if (n_col <= 0 || 
	    n_col >= G_MAXINT / (cpp + 1) || 
	    n_col >= G_MAXINT / sizeof (XPMColor)) {
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("XPM file has invalid number of colors"));
		return NULL;
	}

	/* The hash is used for fast lookups of color from chars */
	color_hash = g_hash_table_new (g_str_hash, g_str_equal);

	name_buf = g_try_malloc (n_col * (cpp + 1));
	if (!name_buf) {
		g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
                                     _("Cannot allocate memory for loading XPM image"));
		g_hash_table_destroy (color_hash);
		return NULL;
	}
	colors = (XPMColor *) g_try_malloc (sizeof (XPMColor) * n_col);
	if (!colors) {
		g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
                                     _("Cannot allocate memory for loading XPM image"));
		g_hash_table_destroy (color_hash);
		g_free (name_buf);
		return NULL;
	}

	for (cnt = 0; cnt < n_col; cnt++) {
		gchar *color_name;

		buffer = (*get_buf) (op_cmap, handle);
		if (!buffer) {
                        g_set_error_literal (error,
                                             GDK_PIXBUF_ERROR,
                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                             _("Cannot read XPM colormap"));
			g_hash_table_destroy (color_hash);
			g_free (name_buf);
			g_free (colors);
			return NULL;
		}

		color = &colors[cnt];
		color->color_string = &name_buf[cnt * (cpp + 1)];
		strncpy (color->color_string, buffer, cpp);
		color->color_string[cpp] = 0;
		buffer += strlen (color->color_string);
		color->transparent = FALSE;

		color_name = xpm_extract_color (buffer);

		if ((color_name == NULL) || (g_ascii_strcasecmp (color_name, "None") == 0)
		    || (parse_color (color_name, color) == FALSE)) {
			color->transparent = TRUE;
			color->red = 0;
			color->green = 0;
			color->blue = 0;
			is_trans = TRUE;
		}

		g_free (color_name);
		g_hash_table_insert (color_hash, color->color_string, color);

		if (cnt == 0)
			fallbackcolor = color;
	}

	pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, is_trans, 8, w, h);

	if (!pixbuf) {
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
                                     _("Cannot allocate memory for loading XPM image"));
		g_hash_table_destroy (color_hash);
		g_free (colors);
		g_free (name_buf);
		return NULL;
	}

	wbytes = w * cpp;

	for (ycnt = 0; ycnt < h; ycnt++) {
		pixtmp = pixbuf->pixels + ycnt * pixbuf->rowstride;

		buffer = (*get_buf) (op_body, handle);
		if ((!buffer) || (strlen (buffer) < wbytes))
			continue;

		for (n = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++) {
			strncpy (pixel_str, &buffer[n], cpp);
			pixel_str[cpp] = 0;

			color = g_hash_table_lookup (color_hash, pixel_str);

			/* Bad XPM...punt */
			if (!color)
				color = fallbackcolor;

			*pixtmp++ = color->red >> 8;
			*pixtmp++ = color->green >> 8;
			*pixtmp++ = color->blue >> 8;

			if (is_trans && color->transparent)
				*pixtmp++ = 0;
			else if (is_trans)
				*pixtmp++ = 0xFF;
		}
	}

	g_hash_table_destroy (color_hash);
	g_free (colors);
	g_free (name_buf);

	if (items == 6) {
		gchar hot[10];
		g_snprintf (hot, 10, "%d", x_hot);
		gdk_pixbuf_set_option (pixbuf, "x_hot", hot);
		g_snprintf (hot, 10, "%d", y_hot);
		gdk_pixbuf_set_option (pixbuf, "y_hot", hot);

	}

	return pixbuf;
}
Exemplo n.º 2
0
/* This function does all the work. */
static GdkPixbuf *
pixbuf_create_from_xpm (gpointer handle, xfwmColorSymbol *color_sym)
{
    gchar pixel_str[32];
    const gchar *buffer;
    gchar *name_buf;
    gint w, h, n_col, cpp, items;
    gint cnt, xcnt, ycnt, wbytes, n;
    GHashTable *color_hash;
    XPMColor *colors, *color, *fallbackcolor;
    guchar *pixtmp;
    GdkPixbuf *pixbuf;

    fallbackcolor = NULL;

    buffer = file_buffer (op_header, handle);
    if (!buffer)
    {
        g_warning ("Cannot read Pixmap header");
        return NULL;
    }
    items = sscanf (buffer, "%d %d %d %d", &w, &h, &n_col, &cpp);

    if (items != 4)
    {
        g_warning ("Pixmap definition contains invalid number attributes (expecting at least 4, got %i)", items);
        return NULL;
    }

    if ((w <= 0) ||
            (h <= 0) ||
            (cpp <= 0) ||
            (cpp >= 32) ||
            (n_col <= 0) ||
            (n_col >= G_MAXINT / (cpp + 1)) ||
            (n_col >= G_MAXINT / (gint) sizeof (XPMColor)))
    {
        g_warning ("Pixmap definition contains invalid attributes");
        return NULL;
    }

    /* The hash is used for fast lookups of color from chars */
    color_hash = g_hash_table_new (g_str_hash, g_str_equal);

    name_buf = g_try_malloc (n_col * (cpp + 1));
    if (!name_buf) {
        g_hash_table_destroy (color_hash);
        g_warning ("Cannot allocate buffer");
        return NULL;
    }

    colors = (XPMColor *) g_try_malloc (sizeof (XPMColor) * n_col);
    if (!colors)
    {
        g_hash_table_destroy (color_hash);
        g_free (name_buf);
        g_warning ("Cannot allocate colors for Pixmap");
        return NULL;
    }

    for (cnt = 0; cnt < n_col; cnt++)
    {
        gchar *color_name;

        buffer = file_buffer (op_cmap, handle);
        if (!buffer)
        {
            g_hash_table_destroy (color_hash);
            g_free (name_buf);
            g_free (colors);
            g_warning ("Cannot load colormap attributes");
            return NULL;
        }

        color = &colors[cnt];
        color->color_string = &name_buf[cnt * (cpp + 1)];
        strncpy (color->color_string, buffer, cpp);
        color->color_string[cpp] = 0;
        buffer += strlen (color->color_string);
        color->transparent = FALSE;

        color_name = xpm_extract_color (buffer, color_sym);

        if ((color_name == NULL) ||
                (g_ascii_strcasecmp (color_name, "None") == 0) ||
                (parse_color (color_name, color) == FALSE))
        {
            color->transparent = TRUE;
            color->red = 0;
            color->green = 0;
            color->blue = 0;
        }

        g_free (color_name);
        g_hash_table_insert (color_hash, color->color_string, color);

        if (cnt == 0)
        {
            fallbackcolor = color;
        }
    }

    pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, w, h);

    if (!pixbuf)
    {
        g_hash_table_destroy (color_hash);
        g_free (colors);
        g_free (name_buf);
        g_warning ("Cannot allocate Pixbuf");
        return NULL;
    }

    wbytes = w * cpp;

    for (ycnt = 0; ycnt < h; ycnt++)
    {
        pixtmp = gdk_pixbuf_get_pixels (pixbuf) + ycnt * gdk_pixbuf_get_rowstride(pixbuf);

        buffer = file_buffer (op_body, handle);
        if ((!buffer) || (wbytes > (gint) strlen (buffer)))
        {
            continue;
        }

        for (n = 0, cnt = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++)
        {
            strncpy (pixel_str, &buffer[n], cpp);
            pixel_str[cpp] = 0;

            color = g_hash_table_lookup (color_hash, pixel_str);

            /* Bad XPM...punt */
            if (!color)
            {
                color = fallbackcolor;
            }

            *pixtmp++ = color->red   >> 8;
            *pixtmp++ = color->green >> 8;
            *pixtmp++ = color->blue  >> 8;

            if (color->transparent)
            {
                *pixtmp++ = 0;
            }
            else
            {
                *pixtmp++ = 0xFF;
            }
        }
    }

    g_hash_table_destroy (color_hash);
    g_free (colors);
    g_free (name_buf);

    return pixbuf;
}