aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHermet Park <hermetpark@gmail.com>2019-05-02 16:42:25 +0900
committerHermet Park <hermetpark@gmail.com>2019-05-02 17:02:00 +0900
commit53cdf850ba0f10a4a4db3e3c7f7cf1742ca88db1 (patch)
treed77c5d31fa0038da1e88cf5314ff5319225e5d78
parentEina: add eina_strndup() API as inlined function (diff)
downloadefl-53cdf850ba0f10a4a4db3e3c7f7cf1742ca88db1.tar.gz
evas png: apply interpolation when scale down image loading.
Summary: This patch improves png quality when image uses scale-down at image loading. Since current scale-down logic just works like point sampling, image result could be wholely different, Simply, if source data is consist of continous white and black pixels, and scale down factor is 2, the sampled data would be only white, and lose all black pixels, or vice versa. The result can be unexpected by users. Even current jpeg scale-down works with interpolation. Before: {F3711651} After: {F3711652} Original: {F3711653} Reviewers: cedric, raster, #committers, kimcinoo, jsuya Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D8788
-rw-r--r--src/examples/evas/Makefile.examples1
-rw-r--r--src/examples/evas/evas-images6.c98
-rw-r--r--src/examples/evas/meson.build1
-rw-r--r--src/examples/evas/resources/images/scale_down.pngbin0 -> 1650468 bytes
-rw-r--r--src/modules/evas/image_loaders/png/evas_image_load_png.c99
5 files changed, 168 insertions, 31 deletions
diff --git a/src/examples/evas/Makefile.examples b/src/examples/evas/Makefile.examples
index 48173f91b6..7e3f7c2dd3 100644
--- a/src/examples/evas/Makefile.examples
+++ b/src/examples/evas/Makefile.examples
@@ -16,6 +16,7 @@ EXAMPLES= evas-aspect-hints \
evas-images3 \
evas-images4 \
evas-images5 \
+ evas-images6 \
evas-init-shutdown \
evas-map-utils \
evas-object-manipulation \
diff --git a/src/examples/evas/evas-images6.c b/src/examples/evas/evas-images6.c
new file mode 100644
index 0000000000..ac09b4486e
--- /dev/null
+++ b/src/examples/evas/evas-images6.c
@@ -0,0 +1,98 @@
+/**
+ * Example of handling events for image objects in Evas.
+ *
+ * You'll need at least one engine built for it (excluding the buffer
+ * one) and the png image loader/saver also built. See stdout/stderr
+ * for output.
+ *
+ * @verbatim
+ * gcc -o evas-images6 evas-images6.c `pkg-config --libs --cflags evas ecore ecore-evas`
+ * @endverbatim
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#else
+#define PACKAGE_EXAMPLES_DIR "."
+#endif
+
+#include <Ecore.h>
+#include <Ecore_Evas.h>
+#include <stdio.h>
+#include <errno.h>
+#include "evas-common.h"
+
+#define WIDTH (960)
+#define HEIGHT (540)
+
+static const char *img_path = PACKAGE_EXAMPLES_DIR EVAS_IMAGE_FOLDER "/scale_down.png";
+
+struct test_data
+{
+ Ecore_Evas *ee;
+ Evas *evas;
+ Evas_Object *bg, *img;
+};
+
+static struct test_data d = {0};
+
+
+static void
+_on_destroy(Ecore_Evas *ee EINA_UNUSED)
+{
+ ecore_main_loop_quit();
+}
+
+/* Keep the example's window size in sync with the background image's size */
+static void
+_canvas_resize_cb(Ecore_Evas *ee)
+{
+ int w, h;
+
+ ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
+ evas_object_resize(d.bg, w, h);
+}
+
+int
+main(void)
+{
+ if (!ecore_evas_init())
+ return EXIT_FAILURE;
+
+ /* this will give you a window with an Evas canvas under the first
+ * engine available */
+ d.ee = ecore_evas_new(NULL, 10, 10, WIDTH, HEIGHT, NULL);
+ if (!d.ee)
+ goto error;
+
+ ecore_evas_callback_destroy_set(d.ee, _on_destroy);
+ ecore_evas_callback_resize_set(d.ee, _canvas_resize_cb);
+ ecore_evas_show(d.ee);
+
+ /* the canvas pointer, de facto */
+ d.evas = ecore_evas_get(d.ee);
+
+ d.bg = evas_object_rectangle_add(d.evas);
+ evas_object_color_set(d.bg, 255, 255, 255, 255); /* white bg */
+ evas_object_move(d.bg, 0, 0); /* at canvas' origin */
+ evas_object_resize(d.bg, WIDTH, HEIGHT); /* covers full canvas */
+ evas_object_show(d.bg);
+
+ d.img = evas_object_image_filled_add(d.evas);
+ evas_object_image_file_set(d.img, img_path, NULL);
+ evas_object_image_load_scale_down_set(d.img, 2);
+ evas_object_resize(d.img, WIDTH, HEIGHT);
+ evas_object_show(d.img);
+
+ ecore_main_loop_begin();
+
+ ecore_evas_free(d.ee);
+ ecore_evas_shutdown();
+ return 0;
+
+error:
+ fprintf(stderr, "error: Requires at least one Evas engine built and linked"
+ " to ecore-evas for this example to run properly.\n");
+ ecore_evas_shutdown();
+ return -1;
+}
diff --git a/src/examples/evas/meson.build b/src/examples/evas/meson.build
index 34c8bd3463..9a9bd1fe2f 100644
--- a/src/examples/evas/meson.build
+++ b/src/examples/evas/meson.build
@@ -29,6 +29,7 @@ examples = [
'evas-images3',
'evas-images4',
'evas-images5',
+ 'evas-images6',
'evas-images',
'evas-init-shutdown',
'evas-map-aa',
diff --git a/src/examples/evas/resources/images/scale_down.png b/src/examples/evas/resources/images/scale_down.png
new file mode 100644
index 0000000000..ff4bdc4b81
--- /dev/null
+++ b/src/examples/evas/resources/images/scale_down.png
Binary files differ
diff --git a/src/modules/evas/image_loaders/png/evas_image_load_png.c b/src/modules/evas/image_loaders/png/evas_image_load_png.c
index 9e47d0dc98..2cc0f52242 100644
--- a/src/modules/evas/image_loaders/png/evas_image_load_png.c
+++ b/src/modules/evas/image_loaders/png/evas_image_load_png.c
@@ -230,7 +230,6 @@ evas_image_load_file_data_png(void *loader_data,
Eina_File *f;
unsigned char *surface;
- unsigned char *tmp_line;
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
Evas_PNG_Info epi;
@@ -382,7 +381,7 @@ evas_image_load_file_data_png(void *loader_data,
}
passes = png_set_interlace_handling(png_ptr);
-
+
/* we read image line by line if scale down was set */
if (scale_ratio == 1 && region_set == 0)
{
@@ -396,6 +395,7 @@ evas_image_load_file_data_png(void *loader_data,
else
{
unsigned char *src_ptr;
+ unsigned char *dst_ptr = surface;
int skip_row = 0, region_x = 0, region_y = 0;
if (region_set)
@@ -406,51 +406,86 @@ evas_image_load_file_data_png(void *loader_data,
if (passes == 1)
{
- tmp_line = (unsigned char *) alloca(image_w * pack_offset);
+ int line_size = (image_w * pack_offset) - (region_x * pack_offset);
+ unsigned char *tmp_line = (unsigned char *) alloca(image_w * pack_offset);
+ //accumulate pixel color here.
+ unsigned short *interp_buf = (unsigned short *) alloca(line_size * sizeof(unsigned short));
+ unsigned short *pbuf;
for (skip_row = 0; skip_row < region_y; skip_row++)
png_read_row(png_ptr, tmp_line, NULL);
- //general case: 4 bytes pixel.
- if (pack_offset == sizeof(DATA32))
- {
- DATA32 *dst_ptr = (DATA32 *) surface;
- DATA32 *src_ptr2;
+ png_read_row(png_ptr, tmp_line, NULL);
+ src_ptr = tmp_line + (region_x * pack_offset);
- for (i = 0; i < h; i++)
- {
- png_read_row(png_ptr, tmp_line, NULL);
- src_ptr2 = (DATA32 *) (tmp_line + region_x * pack_offset);
+ //The first pixel, of the first line
+ for (k = 0; k < (int) pack_offset; k++)
+ dst_ptr[k] = src_ptr[k];
- for (j = 0; j < w; j++)
- {
- *dst_ptr = *src_ptr2;
- ++dst_ptr;
- src_ptr2 += scale_ratio;
- }
- for (j = 0; j < (scale_ratio - 1); j++)
- png_read_row(png_ptr, tmp_line, NULL);
+ dst_ptr += pack_offset;
+ src_ptr += (scale_ratio * pack_offset);
+
+ for (j = 1; j < w; j++)
+ {
+ //rgba
+ interp_buf[0] = 0;
+ interp_buf[1] = 0;
+ interp_buf[2] = 0;
+ interp_buf[3] = 0;
+
+ //horizontal interpolation.
+ for (p = 0; p < scale_ratio; p++)
+ {
+ for (k = 0; k < (int) pack_offset; k++)
+ interp_buf[k] += src_ptr[k - (int)(p * pack_offset)];
}
+ for (k = 0; k < (int) pack_offset; k++)
+ dst_ptr[k] = (interp_buf[k] / scale_ratio);
+
+ dst_ptr += pack_offset;
+ src_ptr += (scale_ratio * pack_offset);
}
- else
+
+ //next lines
+ for (i = 1; i < h; i++)
{
- unsigned char *dst_ptr = surface;
+ memset(interp_buf, 0x00, line_size * sizeof(unsigned short));
- for (i = 0; i < h; i++)
+ //vertical interpolation.
+ for (j = 0; j < scale_ratio; j++)
{
png_read_row(png_ptr, tmp_line, NULL);
- src_ptr = tmp_line + region_x * pack_offset;
+ src_ptr = tmp_line + (region_x * pack_offset);
- for (j = 0; j < w; j++)
+ for (p = 0; p < line_size; ++p)
+ interp_buf[p] += src_ptr[p];
+ }
+
+ for (p = 0; p < line_size; ++p)
+ interp_buf[p] /= scale_ratio;
+
+ pbuf = interp_buf;
+
+ //The first pixel of the current line
+ for (k = 0; k < (int) pack_offset; k++)
+ dst_ptr[k] = pbuf[k];
+
+ dst_ptr += pack_offset;
+ pbuf += scale_ratio * pack_offset;
+
+ for (j = 1; j < w; j++)
+ {
+ //horizontal interpolation.
+ for (p = 1; p < scale_ratio; ++p)
{
for (k = 0; k < (int) pack_offset; k++)
- dst_ptr[k] = src_ptr[k];
-
- dst_ptr += pack_offset;
- src_ptr += scale_ratio * pack_offset;
+ pbuf[k] += pbuf[k - (int)(p * pack_offset)];
}
- for (j = 0; j < (scale_ratio - 1); j++)
- png_read_row(png_ptr, tmp_line, NULL);
+ for (k = 0; k < (int) pack_offset; k++)
+ dst_ptr[k] = (pbuf[k] / scale_ratio);
+
+ dst_ptr += pack_offset;
+ pbuf += (scale_ratio * pack_offset);
}
}
@@ -459,6 +494,8 @@ evas_image_load_file_data_png(void *loader_data,
}
else
{
+ //TODO: Scale-down interpolation for multi-pass?
+
unsigned char *pixels2 = malloc(image_w * image_h * pack_offset);
if (pixels2)