pre-scale a bunch of resolutions for generated wallpaper files that intersect with common resolution sizes so e will automatically load the nearest resolution to be more efficient on load to only decode what is needed. a bi-product is that e now has a wallapper gen tool that is simpler than writing your own edc files... :) @featureenlightenment-0.24
parent
1c237e4c3e
commit
3f22a0c26d
5 changed files with 568 additions and 256 deletions
@ -0,0 +1,499 @@ |
||||
#include <Elementary.h> |
||||
#include "config.h" |
||||
|
||||
// a set of commonly found resolution buckets to try size the image down
|
||||
// to to match width OR height so we can avoid decoding a larger image from
|
||||
// disk making startup time faster by picking the right res that's encoded
|
||||
// already in the file... the more resolutions we encode the bigger
|
||||
// the file so it's a tradeoff, thus commenting out a lot of the resolutions
|
||||
// because they are so close or can just miildly crop another res...
|
||||
// only encode resolutiosn less than the original image a well as throw in
|
||||
// the original as the highest res option
|
||||
// pick onne of each y resolution and scale accordingly so e.g. Nx480, Nx600,
|
||||
// Nx720, Nx788, Nx800, Nx900, ...
|
||||
static const int resolutions[] = |
||||
{ |
||||
// not bothering below 640x480
|
||||
// 640, 480,
|
||||
// 800, 480,
|
||||
854, 480, |
||||
// 768, 576,
|
||||
// 1024, 576,
|
||||
// 800, 600,
|
||||
1024, 600, |
||||
1280, 720, |
||||
// 1024, 768,
|
||||
// 1152, 768
|
||||
// 1280, 768
|
||||
1366, 768, |
||||
1280, 800, |
||||
// 1280, 854,
|
||||
// 1152, 864,
|
||||
// 1152, 900,
|
||||
// 1440, 900,
|
||||
1600, 900, |
||||
// 1280, 960,
|
||||
1440, 960, |
||||
// 1280, 1024,
|
||||
// 1400, 1050,
|
||||
// 1680, 1050,
|
||||
// 1440, 1080,
|
||||
// 1920, 1080,
|
||||
// 2048, 1080,
|
||||
// 2880, 1080,
|
||||
3840, 1080, |
||||
// 1600, 1200,
|
||||
1920, 1200, |
||||
// 1920, 1280,
|
||||
2560, 1440, |
||||
// 3840, 1440,
|
||||
// 5120, 1440,
|
||||
// 2048, 1536,
|
||||
2560, 1600, |
||||
// 2880, 1620,
|
||||
// 2880, 1800,
|
||||
3200, 1800, |
||||
// 2560, 2048,
|
||||
// 3840, 2160,
|
||||
4096, 2160, |
||||
// 5120, 2160,
|
||||
5120, 2880, |
||||
6016, 3384, |
||||
// 7680, 4320,
|
||||
8192, 4320, |
||||
|
||||
// one day... we may have to add more resolutions here. when that day comes...
|
||||
// we'll do that. until then... I think 8k is "good enough"
|
||||
0, 0 // sentinel
|
||||
}; |
||||
// when we have more res's above bump this to be that + 1 at a minimum
|
||||
#define MAX_RES_NUM 20 |
||||
|
||||
#define ETC1 -1 |
||||
#define ETC2 -2 |
||||
|
||||
static Evas_Object *win = NULL, *subwin = NULL, *image = NULL, *rend = NULL; |
||||
|
||||
typedef struct |
||||
{ |
||||
int from_w, from_h, to_w, to_h; |
||||
Eina_Bool last : 1; |
||||
} Mip; |
||||
|
||||
static Mip * |
||||
_resolutions_calc(int w, int h) |
||||
{ |
||||
int i, j = 0; |
||||
int nw, nh, pw = 0, ph = 0; |
||||
Mip *mips = calloc(1, sizeof(Mip) * MAX_RES_NUM); |
||||
|
||||
if (!mips) return NULL; |
||||
for (i = 0; resolutions[i]; i += 2) |
||||
{ |
||||
nh = resolutions[i + 1]; |
||||
nw = (w * nh) / h; |
||||
if ((nh >= h) || (nw >= w)) |
||||
{ |
||||
mips[j].from_w = pw; |
||||
mips[j].from_h = ph; |
||||
mips[j].to_w = 1000000000; |
||||
mips[j].to_h = 1000000000; |
||||
mips[j].last = EINA_TRUE; |
||||
break; |
||||
} |
||||
|
||||
mips[j].from_w = pw; |
||||
mips[j].from_h = ph; |
||||
mips[j].to_w = nw; |
||||
mips[j].to_h = nh; |
||||
|
||||
j++; |
||||
pw = nw + 1; |
||||
ph = nh + 1; |
||||
} |
||||
return mips; |
||||
} |
||||
|
||||
EAPI int |
||||
elm_main(int argc, char **argv) |
||||
{ |
||||
const char *edje_cc, *mode, *file, *outfile; |
||||
int bg_r = 64; |
||||
int bg_g = 64; |
||||
int bg_b = 64; |
||||
char dir_buf[128], img_buf[256], edc_buf[256], cmd_buf[1024], qual_buf[64]; |
||||
const char *dir, *quality_string = NULL, *img_name = NULL; |
||||
Mip *mips = NULL; |
||||
int i, imw, imh, w, h, quality; |
||||
int ret = 0, mips_num = 0; |
||||
Eina_Bool alpha; |
||||
FILE *f; |
||||
|
||||
if (argc <= 1) |
||||
{ |
||||
printf("USAGE: enlightenment_wallpaper_gen EDJE FILL INPUT OUT QUALITY [R G B]\n" |
||||
"\n" |
||||
" EDJE is edje_cc command to use (full path or in $PATH)\n" |
||||
" FILL is one of:\n" |
||||
" stretch\n" |
||||
" tile\n" |
||||
" center (requires R G B)\n" |
||||
" scale_in (requires R G B)\n" |
||||
" scale_out\n" |
||||
" pan\n" |
||||
" INPUT is some image file to put into the wallpaper edj\n" |
||||
" OUT is the paht/location of the wallpaper edj output\n" |
||||
" QUALITY is:\n" |
||||
" 0-100 (0-99 is lossy, 100 is lossless compression)\n" |
||||
" etc1\n" |
||||
" etc2\n" |
||||
" R, G, B are Red, Green and Blue values 0 to 255\n" |
||||
"\n" |
||||
" e.g.\n" |
||||
" enlightenment_wallpaper_gen edje_cc scale_out cat.jpg wallpaper.edj 80\n" |
||||
" enlightenment_wallpaper_gen edje_cc center mylogo.png wallpaper.edj 100 48 64 64\n" |
||||
" enlightenment_wallpaper_gen /usr/local/bin/edje_cc tile pattern.jpg wallpaper.edj 98\n" |
||||
" enlightenment_wallpaper_gen /opt/e/bin/edje_cc scale_out hugeimg.jpg wallpaper.edj etc1\n" |
||||
); |
||||
return 1; |
||||
} |
||||
|
||||
elm_config_preferred_engine_set("buffer"); |
||||
win = elm_win_add(NULL, "Wallpaper-Gen", ELM_WIN_BASIC); |
||||
elm_win_norender_push(win); |
||||
evas_object_show(win); |
||||
|
||||
subwin = elm_win_add(win, "inlined", ELM_WIN_INLINED_IMAGE); |
||||
rend = elm_win_inlined_image_object_get(subwin); |
||||
elm_win_norender_push(subwin); |
||||
evas_object_show(subwin); |
||||
|
||||
if (argc < 6) return 2; |
||||
edje_cc = argv[1]; |
||||
mode = argv[2]; |
||||
file = argv[3]; |
||||
outfile = argv[4]; |
||||
if (!strcmp(argv[5], "etc1")) quality = ETC1; |
||||
else if (!strcmp(argv[5], "etc2")) quality = ETC2; |
||||
else |
||||
{ |
||||
quality = atoi(argv[5]); |
||||
if (quality < 0) quality = 0; |
||||
else if (quality > 100) quality = 100; |
||||
} |
||||
|
||||
image = evas_object_image_filled_add(evas_object_evas_get(subwin)); |
||||
evas_object_image_file_set(image, file, NULL); |
||||
evas_object_image_size_get(image, &w, &h); |
||||
if ((w <= 0) || (h <= 0)) return 3; |
||||
alpha = evas_object_image_alpha_get(image); |
||||
elm_win_alpha_set(subwin, alpha); |
||||
evas_object_show(image); |
||||
|
||||
snprintf(dir_buf, sizeof(dir_buf), "/tmp/e_bg-XXXXXX"); |
||||
dir = mkdtemp(dir_buf); |
||||
if (!dir) return 4; |
||||
|
||||
if ((!strcmp(mode, "center")) || |
||||
(!strcmp(mode, "scale_in"))) |
||||
{ // need backing rgb color here
|
||||
if (argc < 9) return 5; |
||||
bg_r = atoi(argv[6]); |
||||
bg_g = atoi(argv[7]); |
||||
bg_b = atoi(argv[8]); |
||||
} |
||||
if ((!strcmp(mode, "stretch")) || |
||||
(!strcmp(mode, "scale_in")) || |
||||
(!strcmp(mode, "scale_out")) || |
||||
(!strcmp(mode, "pan"))) |
||||
{ // need to produce multiple scaled versions
|
||||
mips = _resolutions_calc(w, h); |
||||
if (!mips) return 6; |
||||
for (i = 0; mips[i].to_w; i++) |
||||
{ |
||||
mips_num++; |
||||
if (mips[i].last) |
||||
{ |
||||
imw = w; |
||||
imh = h; |
||||
} |
||||
else |
||||
{ |
||||
imw = mips[i].to_w; |
||||
imh = mips[i].to_h; |
||||
} |
||||
evas_object_resize(subwin, imw, imh); |
||||
evas_object_resize(image, imw, imh); |
||||
elm_win_render(subwin); |
||||
if (mips[i].last) |
||||
snprintf(img_buf, sizeof(img_buf), "%s/img.png", |
||||
dir); |
||||
else |
||||
snprintf(img_buf, sizeof(img_buf), "%s/img-%ix%i.png", |
||||
dir, imw, imh); |
||||
if (!evas_object_image_save(rend, img_buf, NULL, "compress=0")) |
||||
{ |
||||
ret = 7; |
||||
goto cleanup; |
||||
} |
||||
} |
||||
} |
||||
// no multiple resolutions -0 save out original
|
||||
if (!mips) |
||||
{ |
||||
evas_object_resize(subwin, w, h); |
||||
evas_object_resize(image, w, h); |
||||
elm_win_render(subwin); |
||||
snprintf(img_buf, sizeof(img_buf), "%s/img.png", dir); |
||||
if (!evas_object_image_save(rend, img_buf, NULL, "compress=0")) |
||||
{ |
||||
ret = 8; |
||||
goto cleanup; |
||||
} |
||||
} |
||||
if ((quality == ETC1) && (alpha)) quality = ETC2; // etc1 -> etc2 if alpha
|
||||
if (quality == 100) quality_string = "COMP"; |
||||
else |
||||
{ |
||||
if (quality == ETC1) quality_string = "LOSSY_ETC1"; |
||||
else if (quality == ETC2) quality_string = "LOSSY_ETC2"; |
||||
else |
||||
{ |
||||
snprintf(qual_buf, sizeof(qual_buf), "LOSSY %i", quality); |
||||
quality_string = qual_buf; |
||||
} |
||||
} |
||||
// generate edc
|
||||
snprintf(edc_buf, sizeof(edc_buf), "%s/bg.edc", dir); |
||||
f = fopen(edc_buf, "w"); |
||||
if (!f) goto cleanup; |
||||
if ((mips) && (mips_num > 1)) |
||||
{ |
||||
fprintf(f, |
||||
"images {\n" |
||||
" set { name: \"img\";\n"); |
||||
for (i = mips_num - 1; i >= 0; i--) |
||||
{ |
||||
fprintf(f, |
||||
" image {\n"); |
||||
if (mips[i].last) |
||||
{ |
||||
imw = w; |
||||
imh = h; |
||||
fprintf(f, |
||||
" image: \"img.png\" %s;\n", |
||||
quality_string); |
||||
} |
||||
else |
||||
{ |
||||
imw = mips[i].to_w; |
||||
imh = mips[i].to_h; |
||||
fprintf(f, |
||||
" image: \"img-%ix%i.png\" %s;\n", |
||||
imw, imh, quality_string); |
||||
} |
||||
fprintf(f, |
||||
" size: %i %i %i %i;\n" |
||||
" }\n", |
||||
mips[i].from_w, mips[i].from_h, |
||||
mips[i].to_w, mips[i].to_h); |
||||
} |
||||
fprintf(f, |
||||
" }\n" |
||||
"}\n"); |
||||
img_name = "img"; |
||||
} |
||||
else |
||||
{ |
||||
fprintf(f, "images.image: \"img.png\" %s;\n", quality_string); |
||||
img_name = "img.png"; |
||||
} |
||||
fprintf(f, |
||||
"collections {\n" |
||||
" group { name: \"e/desktop/background\";\n" |
||||
" data.item: \"noanimation\" \"1\";\n"); |
||||
if (!strcmp(mode, "stretch")) |
||||
{ |
||||
fprintf(f, " data { item: \"style\" \"0\"; }\n"); |
||||
fprintf(f, |
||||
" parts {\n" |
||||
" part { name: \"bg\"; mouse_events: 0;\n" |
||||
" description { state: \"default\" 0;\n" |
||||
" image {\n" |
||||
" normal: \"%s\";\n" |
||||
" scale_hint: STATIC;\n" |
||||
" }\n" |
||||
" }\n" |
||||
" }\n" |
||||
" }\n" |
||||
, img_name); |
||||
} |
||||
else if (!strcmp(mode, "tile")) |
||||
{ |
||||
fprintf(f, " data { item: \"style\" \"1\"; }\n"); |
||||
fprintf(f, |
||||
" parts {\n" |
||||
" part { name: \"bg\"; mouse_events: 0;\n" |
||||
" description { state: \"default\" 0;\n" |
||||
" image {\n" |
||||
" normal: \"%s\";\n" |
||||
" }\n" |
||||
" fill.size.relative: 0 0;\n" |
||||
" fill.size.offset: %i %i;\n" |
||||
" }\n" |
||||
" }\n" |
||||
" }\n" |
||||
, img_name, w, h); |
||||
} |
||||
else if (!strcmp(mode, "center")) |
||||
{ |
||||
fprintf(f, " data { item: \"style\" \"2\"; }\n"); |
||||
fprintf(f, |
||||
" parts {\n" |
||||
" part { name: \"col\"; type: RECT; mouse_events: 0;\n" |
||||
" description { state: \"default\" 0;\n" |
||||
" color: %i %i %i 255;\n" |
||||
" }\n" |
||||
" }\n" |
||||
" part { name: \"bg\"; mouse_events: 0;\n" |
||||
" description { state: \"default\" 0;\n" |
||||
" image {\n" |
||||
" normal: \"%s\";\n" |
||||
" }\n" |
||||
" min: %i %i; max: %i %i;\n" |
||||
" }\n" |
||||
" }\n" |
||||
" }\n" |
||||
, bg_r, bg_g, bg_b, img_name, w, h, w, h); |
||||
} |
||||
else if (!strcmp(mode, "scale_in")) |
||||
{ |
||||
fprintf(f, " data { item: \"style\" \"3\"; }\n"); |
||||
fprintf(f, |
||||
" parts {\n" |
||||
" part { name: \"col\"; type: RECT; mouse_events: 0;\n" |
||||
" description { state: \"default\" 0;\n" |
||||
" color: %i %i %i 255;\n" |
||||
" }\n" |
||||
" }\n" |
||||
" part { name: \"bg\"; mouse_events: 0;\n" |
||||
" description { state: \"default\" 0;\n" |
||||
" image {\n" |
||||
" normal: \"%s\";\n" |
||||
" scale_hint: STATIC;\n" |
||||
" }\n" |
||||
" aspect: (%i/%i) (%i/%i); aspect_preference: BOTH;\n" |
||||
" }\n" |
||||
" }\n" |
||||
" }\n" |
||||
, bg_r, bg_g, bg_b, img_name, w, h, w, h); |
||||
} |
||||
else if (!strcmp(mode, "scale_out")) |
||||
{ |
||||
fprintf(f, " data { item: \"style\" \"4\"; }\n"); |
||||
fprintf(f, |
||||
" parts {\n" |
||||
" part { name: \"bg\"; mouse_events: 0;\n" |
||||
" description { state: \"default\" 0;\n" |
||||
" image {\n" |
||||
" normal: \"%s\";\n" |
||||
" scale_hint: STATIC;\n" |
||||
" }\n" |
||||
" aspect: (%i/%i) (%i/%i); aspect_preference: NONE;\n" |
||||
" }\n" |
||||
" }\n" |
||||
" }\n" |
||||
, img_name, w, h, w, h); |
||||
} |
||||
else if (!strcmp(mode, "pan")) |
||||
{ |
||||
fprintf(f, " data { item: \"style\" \"5\"; }\n"); |
||||
fprintf(f, |
||||
" script {\n" |
||||
" public cur_anim; public cur_x; public cur_y;\n" |
||||
" public prev_x; public prev_y;\n" |
||||
" public total_x; public total_y;\n" |
||||
" public pan_bg(val, Float:v) {\n" |
||||
" new Float:x, Float:y, Float:px, Float: py;\n" |
||||
" px = get_float(prev_x);\n" |
||||
" py = get_float(prev_y);\n" |
||||
" if (get_int(total_x) > 1) {\n" |
||||
" x = float(get_int(cur_x)) / (get_int(total_x) - 1);\n" |
||||
" x = px - (px - x) * v;\n" |
||||
" } else {\n" |
||||
" x = 0.0;\n" |
||||
" v = 1.0;\n" |
||||
" }\n" |
||||
" if (get_int(total_y) > 1) {\n" |
||||
" y = float(get_int(cur_y)) / (get_int(total_y) - 1);\n" |
||||
" y = py - (py - y) * v;\n" |
||||
" } else {\n" |
||||
" y = 0.0;\n" |
||||
" v = 1.0; }\n" |
||||
" set_state_val(PART:\"bg\", STATE_ALIGNMENT, x, y);\n" |
||||
" if (v >= 1.0) {\n" |
||||
" set_int(cur_anim, 0);\n" |
||||
" set_float(prev_x, x);\n" |
||||
" set_float(prev_y, y);\n" |
||||
" return 0;\n" |
||||
" }\n" |
||||
" return 1;\n" |
||||
" }\n" |
||||
" public message(Msg_Type:type, id, ...) {\n" |
||||
" if ((type == MSG_FLOAT_SET) && (id == 0)) {\n" |
||||
" new ani;\n" |
||||
" get_state_val(PART:\"bg\", STATE_ALIGNMENT, prev_x, prev_y);\n" |
||||
" set_int(cur_x, round(getfarg(3)));\n" |
||||
" set_int(total_x, round(getfarg(4)));\n" |
||||
" set_int(cur_y, round(getfarg(5)));\n" |
||||
" set_int(total_y, round(getfarg(6)));\n" |
||||
" ani = get_int(cur_anim);\n" |
||||
" if (ani > 0) cancel_anim(ani);\n" |
||||
" ani = anim(getfarg(2), \"pan_bg\", 0);\n" |
||||
" set_int(cur_anim, ani);\n" |
||||
" }\n" |
||||
" }\n" |
||||
" }\n" |
||||
" parts {\n" |
||||
" part { name: \"bg\"; mouse_events: 0;\n" |
||||
" description { state: \"default\" 0.0;\n" |
||||
" image {\n" |
||||
" normal: \"%s\";\n" |
||||
" scale_hint: STATIC;\n" |
||||
" }\n" |
||||
" aspect: (%i/%i) (%i/%i); aspect_preference: NONE;\n" |
||||
" }\n" |
||||
" }\n" |
||||
" program {\n" |
||||
" signal: \"load\"; source: \"\";\n" |
||||
" script {\n" |
||||
" custom_state(PART:\"bg\", \"default\", 0.0);\n" |
||||
" set_state(PART:\"bg\", \"custom\", 0.0);\n" |
||||
" set_float(prev_x, 0.0);\n" |
||||
" set_float(prev_y, 0.0);\n" |
||||
" }\n" |
||||
" }\n" |
||||
" }\n" |
||||
, img_name, w, h, w, h); |
||||
} |
||||
fprintf(f, |
||||
" }\n" |
||||
"}\n"); |
||||
fclose(f); |
||||
free(mips); |
||||
if (snprintf(cmd_buf, sizeof(cmd_buf), |
||||
"%s -fastdecomp -id %s -fd %s -sd %s -vd %s -dd %s -md %s " |
||||
"%s/bg.edc %s", |
||||
edje_cc, dir, dir, dir, dir, dir, dir, |
||||
dir, outfile) >= (int)sizeof(cmd_buf)) |
||||
{ |
||||
ret = 9; |
||||
goto cleanup; |
||||
} |
||||
ret = system(cmd_buf); |
||||
cleanup: |
||||
ecore_file_recursive_rm(dir); |
||||
evas_object_del(win); |
||||
return ret; |
||||
} |
||||
ELM_MAIN() |
Loading…
Reference in new issue