/** * eel_gdk_pixbuf_draw_to_pixbuf: * @pixbuf: The source pixbuf to draw. * @destination_pixbuf: The destination pixbuf. * @source_x: The source pixbuf x coordiate to composite from. * @source_y: The source pixbuf y coordiate to composite from. * @destination_area: The destination area within the destination pixbuf. * This area will be clipped if invalid in any way. * * Copy one pixbuf onto another another.. This function has some advantages * over plain gdk_pixbuf_copy_area(): * * Composition paramters (source coordinate, destination area) are * given in a way that is consistent with the rest of the extensions * in this file. That is, it matches the declaration of * eel_gdk_pixbuf_draw_to_pixbuf_alpha() and * eel_gdk_pixbuf_draw_to_drawable() very closely. * * All values are clipped to make sure they are valid. * */ void eel_gdk_pixbuf_draw_to_pixbuf (const GdkPixbuf *pixbuf, GdkPixbuf *destination_pixbuf, int source_x, int source_y, EelIRect destination_area) { EelDimensions dimensions; EelIRect target; EelIRect source; int target_width; int target_height; int source_width; int source_height; g_return_if_fail (eel_gdk_pixbuf_is_valid (pixbuf)); g_return_if_fail (eel_gdk_pixbuf_is_valid (destination_pixbuf)); g_return_if_fail (!eel_irect_is_empty (&destination_area)); dimensions = eel_gdk_pixbuf_get_dimensions (pixbuf); g_return_if_fail (source_x >= 0); g_return_if_fail (source_y >= 0); g_return_if_fail (source_x < dimensions.width); g_return_if_fail (source_y < dimensions.height); /* Clip the destination area to the pixbuf dimensions; bail if no work */ target = eel_gdk_pixbuf_intersect (destination_pixbuf, 0, 0, destination_area); if (eel_irect_is_empty (&target)) { return; } /* Assign the source area */ source = eel_irect_assign (source_x, source_y, dimensions.width - source_x, dimensions.height - source_y); /* Adjust the target width if the source area is smaller than the * source pixbuf dimensions */ target_width = target.x1 - target.x0; target_height = target.y1 - target.y0; source_width = source.x1 - source.x0; source_height = source.y1 - source.y0; target.x1 = target.x0 + MIN (target_width, source_width); target.y1 = target.y0 + MIN (target_height, source_height); gdk_pixbuf_copy_area (pixbuf, source.x0, source.y0, target.x1 - target.x0, target.y1 - target.y0, destination_pixbuf, target.x0, target.y0); }
/** * eel_gdk_pixbuf_intersect: * @pixbuf: A GdkPixbuf. * @pixbuf_x: X coordinate of pixbuf. * @pixbuf_y: Y coordinate of pixbuf. * @rectangle: An EelIRect. * * Return value: The intersection of the pixbuf and the given rectangle. * */ EelIRect eel_gdk_pixbuf_intersect (const GdkPixbuf *pixbuf, int pixbuf_x, int pixbuf_y, EelIRect rectangle) { EelIRect intersection; EelIRect bounds; EelDimensions dimensions; g_return_val_if_fail (eel_gdk_pixbuf_is_valid (pixbuf), eel_irect_empty); dimensions = eel_gdk_pixbuf_get_dimensions (pixbuf); bounds = eel_irect_assign_dimensions (pixbuf_x, pixbuf_y, dimensions); eel_irect_intersect (&intersection, &rectangle, &bounds); /* In theory, this is not needed because a rectangle is empty * regardless of how MUCH negative the dimensions are. * However, to make debugging and self checks simpler, we * consistenly return a standard empty rectangle. */ if (eel_irect_is_empty (&intersection)) { return eel_irect_empty; } return intersection; }
/** * eel_gdk_pixbuf_fill_rectangle_with_color: * @pixbuf: Target pixbuf to fill into. * @area: Rectangle to fill. * @color: The color to use. * * Fill the rectangle with the the given color. */ void eel_gdk_pixbuf_fill_rectangle_with_color (GdkPixbuf *pixbuf, EelIRect area, guint32 color) { EelIRect target; guchar red; guchar green; guchar blue; guchar alpha; guchar *pixels; gboolean has_alpha; guint pixel_offset; guint rowstride; guchar *row_offset; int x; int y; g_return_if_fail (eel_gdk_pixbuf_is_valid (pixbuf)); target = eel_gdk_pixbuf_intersect (pixbuf, 0, 0, area); if (eel_irect_is_empty (&target)) { return; } pixels = gdk_pixbuf_get_pixels (pixbuf); rowstride = gdk_pixbuf_get_rowstride (pixbuf); has_alpha = gdk_pixbuf_get_has_alpha (pixbuf); pixel_offset = has_alpha ? 4 : 3; red = EEL_RGBA_COLOR_GET_R (color); green = EEL_RGBA_COLOR_GET_G (color); blue = EEL_RGBA_COLOR_GET_B (color); alpha = EEL_RGBA_COLOR_GET_A (color); row_offset = pixels + target.y0 * rowstride; for (y = target.y0; y < target.y1; y++) { guchar *offset = row_offset + (target.x0 * pixel_offset); for (x = target.x0; x < target.x1; x++) { *(offset++) = red; *(offset++) = green; *(offset++) = blue; if (has_alpha) { *(offset++) = alpha; } } row_offset += rowstride; } }
/** * eel_gdk_pixbuf_get_dimensions: * @pixbuf: A GdkPixbuf * * Return value: The dimensions of the pixbuf as a EelDimensions. * * This function is useful in code that uses libart rect * intersection routines. */ EelDimensions eel_gdk_pixbuf_get_dimensions (const GdkPixbuf *pixbuf) { EelDimensions dimensions; g_return_val_if_fail (eel_gdk_pixbuf_is_valid (pixbuf), eel_dimensions_empty); dimensions.width = gdk_pixbuf_get_width (pixbuf); dimensions.height = gdk_pixbuf_get_height (pixbuf); return dimensions; }
/** * eel_gdk_pixbuf_new_from_pixbuf_sub_area: * @pixbuf: The source pixbuf. * @area: The area within the source pixbuf to use for the sub pixbuf. * This area needs to be contained within the bounds of the * source pixbuf, otherwise it will be clipped to that. * * Return value: A newly allocated pixbuf that shares the pixel data * of the source pixbuf in order to represent a sub area. * * Create a pixbuf from a sub area of another pixbuf. The resulting pixbuf * will share the pixel data of the source pixbuf. Memory bookeeping is * all taken care for the caller. All you need to do is g_object_unref() * the resulting pixbuf to properly free resources. */ GdkPixbuf * eel_gdk_pixbuf_new_from_pixbuf_sub_area (GdkPixbuf *pixbuf, EelIRect area) { GdkPixbuf *sub_pixbuf; EelIRect target; guchar *pixels; g_return_val_if_fail (eel_gdk_pixbuf_is_valid (pixbuf), NULL); g_return_val_if_fail (!eel_irect_is_empty (&area), NULL); /* Clip the pixbuf by the given area; bail if no work */ target = eel_gdk_pixbuf_intersect (pixbuf, 0, 0, area); if (eel_irect_is_empty (&target)) { return NULL; } /* Since we are going to be sharing the given pixbuf's data, we need * to ref it. It will be unreffed in the destroy function above */ g_object_ref (pixbuf); /* Compute the offset into the pixel data */ pixels = gdk_pixbuf_get_pixels (pixbuf) + (target.y0 * gdk_pixbuf_get_rowstride (pixbuf)) + (target.x0 * (gdk_pixbuf_get_has_alpha (pixbuf) ? 4 : 3)); /* Make a pixbuf pretending its real estate is the sub area */ sub_pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, gdk_pixbuf_get_has_alpha (pixbuf), 8, eel_irect_get_width (target), eel_irect_get_height (target), gdk_pixbuf_get_rowstride (pixbuf), pixbuf_destroy_callback, pixbuf); return sub_pixbuf; }
/** * eel_gdk_pixbuf_draw_to_pixbuf_alpha: * @pixbuf: The source pixbuf to draw. * @destination_pixbuf: The destination pixbuf. * @source_x: The source pixbuf x coordiate to composite from. * @source_y: The source pixbuf y coordiate to composite from. * @destination_area: The destination area within the destination pixbuf. * This area will be clipped if invalid in any way. * @opacity: The opacity of the drawn tiles where 0 <= opacity <= 255. * @interpolation_mode: The interpolation mode. See <gdk-pixbuf.h> * * Composite one pixbuf over another. This function has some advantages * over plain gdk_pixbuf_composite(): * * Composition paramters (source coordinate, destination area) are * given in a way that is consistent with the rest of the extensions * in this file. That is, it matches the declaration of * eel_gdk_pixbuf_draw_to_pixbuf() and * eel_gdk_pixbuf_draw_to_drawable() very closely. * * All values are clipped to make sure they are valid. * * Workaround a limitation in gdk_pixbuf_composite() that does not allow * the source (x,y) to be greater than (0,0) * */ void eel_gdk_pixbuf_draw_to_pixbuf_alpha (const GdkPixbuf *pixbuf, GdkPixbuf *destination_pixbuf, int source_x, int source_y, EelIRect destination_area, int opacity, GdkInterpType interpolation_mode) { EelDimensions dimensions; EelIRect target; EelIRect source; int target_width; int target_height; int source_width; int source_height; g_return_if_fail (eel_gdk_pixbuf_is_valid (pixbuf)); g_return_if_fail (eel_gdk_pixbuf_is_valid (destination_pixbuf)); g_return_if_fail (!eel_irect_is_empty (&destination_area)); g_return_if_fail (opacity >= EEL_OPACITY_FULLY_TRANSPARENT); g_return_if_fail (opacity <= EEL_OPACITY_FULLY_OPAQUE); g_return_if_fail (interpolation_mode >= GDK_INTERP_NEAREST); g_return_if_fail (interpolation_mode <= GDK_INTERP_HYPER); dimensions = eel_gdk_pixbuf_get_dimensions (pixbuf); g_return_if_fail (source_x >= 0); g_return_if_fail (source_y >= 0); g_return_if_fail (source_x < dimensions.width); g_return_if_fail (source_y < dimensions.height); /* Clip the destination area to the pixbuf dimensions; bail if no work */ target = eel_gdk_pixbuf_intersect (destination_pixbuf, 0, 0, destination_area); if (eel_irect_is_empty (&target)) { return; } /* Assign the source area */ source = eel_irect_assign (source_x, source_y, dimensions.width - source_x, dimensions.height - source_y); /* Adjust the target width if the source area is smaller than the * source pixbuf dimensions */ target_width = target.x1 - target.x0; target_height = target.y1 - target.y0; source_width = source.x1 - source.x0; source_height = source.y1 - source.y0; target.x1 = target.x0 + MIN (target_width, source_width); target.y1 = target.y0 + MIN (target_height, source_height); /* If the source point is not (0,0), then we need to create a sub pixbuf * with only the source area. This is needed to work around a limitation * in gdk_pixbuf_composite() that requires the source area to be (0,0). */ if (source.x0 != 0 || source.y0 != 0) { EelIRect area; int width; int height; width = dimensions.width - source.x0; height = dimensions.height - source.y0; area.x0 = source.x0; area.y0 = source.y0; area.x1 = area.x0 + width; area.y1 = area.y0 + height; pixbuf = eel_gdk_pixbuf_new_from_pixbuf_sub_area ((GdkPixbuf *) pixbuf, area); } else { g_object_ref (G_OBJECT (pixbuf)); } gdk_pixbuf_composite (pixbuf, destination_pixbuf, target.x0, target.y0, target.x1 - target.x0, target.y1 - target.y0, target.x0, target.y0, 1.0, 1.0, interpolation_mode, opacity); g_object_unref (G_OBJECT (pixbuf)); }
void eel_gdk_pixbuf_draw_to_drawable (const GdkPixbuf *pixbuf, GdkDrawable *drawable, GdkGC *gc, int source_x, int source_y, EelIRect destination_area, GdkRgbDither dither, GdkPixbufAlphaMode alpha_compositing_mode, int alpha_threshold) { EelDimensions dimensions; EelIRect target; EelIRect source; int target_width; int target_height; int source_width; int source_height; g_return_if_fail (eel_gdk_pixbuf_is_valid (pixbuf)); g_return_if_fail (drawable != NULL); g_return_if_fail (gc != NULL); g_return_if_fail (!eel_irect_is_empty (&destination_area)); g_return_if_fail (alpha_threshold > EEL_OPACITY_FULLY_TRANSPARENT); g_return_if_fail (alpha_threshold <= EEL_OPACITY_FULLY_OPAQUE); g_return_if_fail (alpha_compositing_mode >= GDK_PIXBUF_ALPHA_BILEVEL); g_return_if_fail (alpha_compositing_mode <= GDK_PIXBUF_ALPHA_FULL); dimensions = eel_gdk_pixbuf_get_dimensions (pixbuf); g_return_if_fail (source_x >= 0); g_return_if_fail (source_y >= 0); g_return_if_fail (source_x < dimensions.width); g_return_if_fail (source_y < dimensions.height); /* Clip the destination area to the pixbuf dimensions; bail if no work */ target = eel_gdk_pixbuf_intersect (pixbuf, destination_area.x0, destination_area.y0, destination_area); if (eel_irect_is_empty (&target)) { return; } /* Assign the source area */ source = eel_irect_assign (source_x, source_y, dimensions.width - source_x, dimensions.height - source_y); /* Adjust the target width if the source area is smaller than the * source pixbuf dimensions */ target_width = target.x1 - target.x0; target_height = target.y1 - target.y0; source_width = source.x1 - source.x0; source_height = source.y1 - source.y0; target.x1 = target.x0 + MIN (target_width, source_width); target.y1 = target.y0 + MIN (target_height, source_height); gdk_draw_pixbuf (drawable, gc, (GdkPixbuf *) pixbuf, source.x0, source.y0, target.x0, target.y0, target.x1 - target.x0, target.y1 - target.y0, dither, 0, 0); }
void eel_self_check_gdk_pixbuf_extensions (void) { GdkPixbuf *pixbuf; EelIRect clip_area; pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, 100, 100); EEL_CHECK_BOOLEAN_RESULT (eel_gdk_pixbuf_is_valid (pixbuf), TRUE); EEL_CHECK_BOOLEAN_RESULT (eel_gdk_pixbuf_is_valid (NULL), FALSE); EEL_CHECK_DIMENSIONS_RESULT (eel_gdk_pixbuf_get_dimensions (pixbuf), 100, 100); EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, eel_gdk_pixbuf_whole_pixbuf), 0, 0, 100, 100); clip_area = eel_irect_assign (0, 0, 0, 0); EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 0, 0); clip_area = eel_irect_assign (0, 0, 0, 0); EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 0, 0); clip_area = eel_irect_assign (0, 0, 100, 100); EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 100, 100); clip_area = eel_irect_assign (-10, -10, 100, 100); EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 90, 90); clip_area = eel_irect_assign (-10, -10, 110, 110); EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 100, 100); clip_area = eel_irect_assign (0, 0, 99, 99); EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 99, 99); clip_area = eel_irect_assign (0, 0, 1, 1); EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 1, 1); clip_area = eel_irect_assign (-1, -1, 1, 1); EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 0, 0); clip_area = eel_irect_assign (-1, -1, 2, 2); EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 1, 1); clip_area = eel_irect_assign (100, 100, 1, 1); EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 0, 0); clip_area = eel_irect_assign (101, 101, 1, 1); EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 0, 0, 0, 0); clip_area = eel_irect_assign (80, 0, 100, 100); EEL_CHECK_RECTANGLE_RESULT (eel_gdk_pixbuf_intersect (pixbuf, 0, 0, clip_area), 80, 0, 100, 100); g_object_unref (pixbuf); /* No checks for empty pixbufs because GdkPixbuf doesn't seem to allow them. */ EEL_CHECK_STRING_RESULT (check_average_value (1, 1, "00,00,00"), "00,00,00,FF"); EEL_CHECK_STRING_RESULT (check_average_value (1, 1, "00,00,00,00"), "00,00,00,00"); EEL_CHECK_STRING_RESULT (check_average_value (1, 1, "00,00,00,FF"), "00,00,00,FF"); EEL_CHECK_STRING_RESULT (check_average_value (1, 1, "01,01,01"), "01,01,01,FF"); EEL_CHECK_STRING_RESULT (check_average_value (1, 1, "FE,FE,FE"), "FE,FE,FE,FF"); EEL_CHECK_STRING_RESULT (check_average_value (1, 1, "FF,FF,FF"), "FF,FF,FF,FF"); EEL_CHECK_STRING_RESULT (check_average_value (1, 1, "FF,FF,FF,00"), "00,00,00,00"); EEL_CHECK_STRING_RESULT (check_average_value (1, 1, "11,22,33"), "11,22,33,FF"); EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "00,00,00"), "00,00,00,FF"); EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "00,00,00,00"), "00,00,00,00"); EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "00,00,00,FF"), "00,00,00,FF"); EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "01,01,01"), "01,01,01,FF"); EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "FE,FE,FE"), "FE,FE,FE,FF"); EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "FF,FF,FF"), "FF,FF,FF,FF"); EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "FF,FF,FF,00"), "00,00,00,00"); EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "11,22,33"), "11,22,33,FF"); EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "gray -1"), "7F,7F,7F,FF"); EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "gray 0"), "80,80,80,FF"); EEL_CHECK_STRING_RESULT (check_average_value (1000, 1000, "gray 1"), "80,80,80,FF"); }