Last modified 2 years ago
Thumbnail Generator
Generating thumbnails with Ecore-Evas is simple, but may not be so trivial to new comers so here we present a simple example on how to do it properly.
We provide a thumbnail library and client-server using DBus to make it much easier and faster (and non-blocking), see Ethumb.
Theory
- Evas provides evas_object_image_save() api that will save image data to given file. Notice that the saved data is not scaled to current object size (as in evas_object_resize(o, w, h) but rather the current image data size (as in evas_object_image_size_set(o, w, h)).
- If one wants to save the scaled image, he should use as image data the already scaled image.
- One can use as image data the pixels from ecore_evas_buffer, what is rendered in this child canvas will show as image data on the parent canvas. This is automated with the ecore_evas_object_image_new() call that will create an image object that pixels are already set to be read from a child canvas.
- In order to have pixels painted to image data buffer, you need the child canvas to render. To do so you should damage the whole canvas area with evas_damage_rectangle_add(), this process is also known as "expose". Without this evas_render() will be void since it would believe canvas user is not willing to see updates.
Code
- main() just setup libraries and check parameters.
- image_load() builds the to-be-thumbnailed scene, here we create a rectangle to serve as border and then an image resized with the same aspect as the original. Nothing really interesting, at least in the point of view of a thumbnailer.
- thumb_gen() is the tricky machinery, except by cache configuration that can be skipped, everything else is very important to be there and in the same order!
#include <stdlib.h> #include <stdio.h> #include <Evas.h> #include <Ecore.h> #include <Ecore_Evas.h> #define BORDER_COLOR 255, 255, 255, 255 #define BORDER 1 #define WIDTH 256 #define HEIGHT 256 #define FLAGS "quality=85" static int image_load(Evas *e, const char *input, Evas_Coord *rw, Evas_Coord *rh) { Evas_Object *img, *border; int error; Evas_Coord w, h; border = evas_object_rectangle_add(e); evas_object_color_set(border, BORDER_COLOR); img = evas_object_image_add(e); if ((!border) || (!img)) { fputs("ERROR: could not create source objects.\n", stderr); return -1; } /* request image to be loaded close to WIDTHxHEIGHT * this is a hint that some loaders like JPEG may use to speed up */ evas_object_image_load_size_set(img, WIDTH, HEIGHT); evas_object_image_file_set(img, input, NULL); error = evas_object_image_load_error_get(img); if (error != EVAS_LOAD_ERROR_NONE) { fprintf(stderr, "ERROR: could not load image '%s': %d\n", input, error); return -1; } /* get the original image size, as in the 'input' file. */ evas_object_image_size_get(img, &w, &h); if ((w <= 0) || (h <= 0)) return -1; if (w >= h) { h = h * (WIDTH / (double)w); w = WIDTH; } else { w = w * (HEIGHT / (double)h); h = HEIGHT; } evas_object_move(border, 0, 0); evas_object_resize(border, w + BORDER * 2, h + BORDER * 2); evas_object_show(border); evas_object_move(img, BORDER, BORDER); evas_object_resize(img, w, h); evas_object_image_fill_set(img, 0, 0, w, h); evas_object_show(img); *rw = w + BORDER * 2; *rh = h + BORDER * 2; return 0; } static int thumb_gen(const char *input, const char *output) { Ecore_Evas *ee, *sub_ee; Evas *e, *sub_e; Evas_Object *o; Evas_Coord w, h; int r; /* ecore_evas so we get an evas so we can create objects. * size does not matter here. */ ee = ecore_evas_buffer_new(1, 1); e = ecore_evas_get(ee); if (!e) { fputs("ERROR: could not create ecore evas buffer\n", stderr); return -1; } evas_image_cache_set(e, 0); evas_font_cache_set(e, 0); o = ecore_evas_object_image_new(ee); if (!o) { fputs("ERROR: could not create sub ecore evas buffer\n", stderr); goto error; } /* magic that comes from ecore_evas_object_image_new() */ sub_ee = evas_object_data_get(o, "Ecore_Evas"); sub_e = ecore_evas_get(sub_ee); evas_image_cache_set(sub_e, 0); evas_font_cache_set(sub_e, 0); if (image_load(sub_e, input, &w, &h) != 0) { fputs("ERROR: could not load input image.\n", stderr); goto error; } /* set buffer size to the size of returned object */ evas_object_image_size_set(o, w, h); ecore_evas_resize(sub_ee, w, h); /* force area to be painted */ evas_damage_rectangle_add(sub_e, 0, 0, w, h); evas_render(sub_e); /* pixels are painted, just need to save and free canvas (and children) */ r = evas_object_image_save(o, output, NULL, FLAGS); ecore_evas_free(ee); if (!r) { fputs("ERROR: could not save image.\n", stderr); return -1; } return 0; error: ecore_evas_free(ee); return -1; } int main(int argc, char *argv[]) { int r; if (argc < 3) { fprintf(stderr, "usage: %s <infile> <outfile>\n", argv[0]); return -1; } evas_init(); ecore_init(); ecore_evas_init(); r = thumb_gen(argv[1], argv[2]); ecore_evas_shutdown(); ecore_shutdown(); evas_shutdown(); return r; }
