Skip to content

Commit

Permalink
Split cairo_draw_image into two functions
Browse files Browse the repository at this point in the history
In some cases you are already working with a cairo_t and know
your destination image size, this adds an API that allows you
to handle these cases more easily. Along with now being able to
draw images with an alpha level. It also leaves the original API
unchanged.
  • Loading branch information
simotek authored and brndnmtthws committed Mar 11, 2024
1 parent 2ade1e2 commit 96337be
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 33 deletions.
8 changes: 7 additions & 1 deletion lua/cairo_imlib2_helper.pkg
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
$#include <cairo.h>
$#include <libcairo_imlib2_helper.h>

void cairo_draw_image(const char *, cairo_surface_t *, int, int, double, double,
/* Paints the image onto the cairo_surface_t */
void cairo_draw_image(const char *, cairo_surface_t *, int, int,
double scale_x=1.0, double scale_y=1.0,
double * return_scale_w, double * return_scale_h);

/* Places an image onto a cairo_t but doesn't call cairo_paint */
void cairo_place_image(const char *file, cairo_t *cr, int x, int y,
int width, int height, double alpha=1.0);
98 changes: 66 additions & 32 deletions lua/libcairo_imlib2_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,36 +30,28 @@

#include "logging.h"

void cairo_draw_image(const char *file, cairo_surface_t *cs, int x, int y,
double scale_x, double scale_y, double *return_scale_w,
double *return_scale_h) {
void cairo_place_image(const char *file, cairo_t *cr, int x, int y,
int width, int height, double alpha) {
int w, h, stride;
double scaled_w, scaled_h;
Imlib_Image alpha, premul;
Imlib_Image alpha_image, image, premul;
cairo_surface_t *result;
cairo_t *cr;

if (!file) {
NORM_ERR("cairoimagehelper: File is NULL\n");
return;
}

if (!cs) {
NORM_ERR("cairoimagehelper: Surface is NULL\n");
if (!cr) {
NORM_ERR("cairoimagehelper: cairo_t is NULL\n");
return;
}

Imlib_Image *image = imlib_load_image(file);
image = imlib_load_image(file);
if (!image) {
NORM_ERR("cairoimagehelper: Couldn't load %s\n", file);
return;
}

if ((scale_x <= 0.0) && (scale_y <= 0.0)) {
NORM_ERR("cairoimagehelper: Image Scale is 0, %s\n", file);
return;
}

imlib_context_set_image(image);
w = imlib_image_get_width();
h = imlib_image_get_height();
Expand All @@ -69,19 +61,11 @@ void cairo_draw_image(const char *file, cairo_surface_t *cs, int x, int y,
return;
}

scaled_w = *return_scale_w = scale_x * (double)w;
scaled_h = *return_scale_h = scale_y * (double)h;

if ((scaled_w <= 0.0) && (scaled_h <= 0.0)) {
NORM_ERR("cairoimagehelper: %s scaled image has 0 size\n", file);
return;
}

/* create scaled version of image to later extract the alpha channel */
alpha = imlib_create_cropped_scaled_image (0, 0, w, h, scaled_w, scaled_h);
alpha_image = imlib_create_cropped_scaled_image (0, 0, w, h, width, height);

/* create temporary image */
premul = imlib_create_image(scaled_w, scaled_h);
premul = imlib_create_image(width, height);
if (!premul) {
NORM_ERR("cairoimagehelper: Couldn't create premul image for %s\n", file);
return;
Expand All @@ -90,33 +74,83 @@ void cairo_draw_image(const char *file, cairo_surface_t *cs, int x, int y,
/* fill with opaque black */
imlib_context_set_image(premul);
imlib_context_set_color(0, 0, 0, 255);
imlib_image_fill_rectangle(0, 0, scaled_w, scaled_h);
imlib_image_fill_rectangle(0, 0, width, height);

/* blend source image on top -
* in effect this multiplies the rgb values by alpha */
imlib_blend_image_onto_image(image, 0, 0, 0, w, h, 0, 0, scaled_w, scaled_h);
imlib_blend_image_onto_image(image, 0, 0, 0, w, h, 0, 0, width, height);

/* and use the alpha channel of the source image */
imlib_image_copy_alpha_to_image(alpha, 0, 0);
imlib_image_copy_alpha_to_image(alpha_image, 0, 0);

stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, scaled_w);
stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, width);

/* now pass the result to cairo */
result = cairo_image_surface_create_for_data(
(void *)imlib_image_get_data_for_reading_only(), CAIRO_FORMAT_ARGB32,
scaled_w, scaled_h, stride);
width, height, stride);

cr = cairo_create(cs);
cairo_set_source_surface(cr, result, x, y);
cairo_paint(cr);
cairo_paint_with_alpha(cr, alpha);

imlib_context_set_image(image);
imlib_free_image();
imlib_context_set_image(premul);
imlib_free_image();

cairo_destroy(cr);
cairo_surface_destroy(result);

}

void cairo_draw_image(const char *file, cairo_surface_t *cs, int x, int y,
double scale_x, double scale_y, double *return_scale_w,
double *return_scale_h) {
cairo_t *cr;
int w, h;
double scaled_w, scaled_h;

if (!file) {
NORM_ERR("cairoimagehelper: File is NULL\n");
return;
}

if (!cs) {
NORM_ERR("cairoimagehelper: Surface is NULL\n");
return;
}

if ((scale_x <= 0.0) && (scale_y <= 0.0)) {
NORM_ERR("cairoimagehelper: Image Scale is 0, %s\n", file);
return;
}

Imlib_Image *image = imlib_load_image(file);
if (!image) {
NORM_ERR("cairoimagehelper: Couldn't load %s\n", file);
return;
}

imlib_context_set_image(image);
w = imlib_image_get_width();
h = imlib_image_get_height();

if ((w <= 0) && (h <= 0)) {
NORM_ERR("cairoimagehelper: %s has 0 size\n", file);
return;
}

scaled_w = *return_scale_w = scale_x * (double)w;
scaled_h = *return_scale_h = scale_y * (double)h;

if ((scaled_w <= 0.0) && (scaled_h <= 0.0)) {
NORM_ERR("cairoimagehelper: %s scaled image has 0 size\n", file);
return;
}

cr = cairo_create(cs);
cairo_place_image(file, cr, x, y, scaled_w, scaled_h, 1.0);

cairo_destroy(cr);
}

#endif /* _LIBCAIRO_IMAGE_HELPER_H_ */

0 comments on commit 96337be

Please sign in to comment.