From 97642c5d7b2f345498d28ea7ce843bb7a3b9e838 Mon Sep 17 00:00:00 2001 From: Cyril Hrubis Date: Tue, 22 Nov 2011 19:56:56 +0100 Subject: [PATCH] filters: Add per channel parameter passing support. --- demos/grinder/grinder.c | 10 ++- include/filters/GP_Filter.h | 2 + include/filters/GP_FilterParam.h | 107 +++++++++++++++++++++++++++++++ include/filters/GP_Filters.h | 3 + include/filters/GP_Point.h | 25 +++++--- libs/filters/GP_Brightness.gen.c.t | 55 +++++++++------- libs/filters/GP_Contrast.gen.c.t | 55 +++++++++------- libs/filters/GP_FilterParam.c | 125 +++++++++++++++++++++++++++++++++++++ libs/filters/GP_Invert.gen.c.t | 10 +-- libs/filters/Makefile | 2 +- pylib/templates/filter.point.c.t | 101 +++++++++++++++++++----------- 11 files changed, 396 insertions(+), 99 deletions(-) create mode 100644 include/filters/GP_FilterParam.h rewrite libs/filters/GP_Brightness.gen.c.t (73%) rewrite libs/filters/GP_Contrast.gen.c.t (74%) create mode 100644 libs/filters/GP_FilterParam.c diff --git a/demos/grinder/grinder.c b/demos/grinder/grinder.c index 6f86e693..97f8cd8a 100644 --- a/demos/grinder/grinder.c +++ b/demos/grinder/grinder.c @@ -281,7 +281,10 @@ static GP_RetCode bright(GP_Context **c, const char *params) return GP_EINVAL; } - GP_FilterBrightness(*c, *c, bright, progress_callback); + GP_FILTER_PARAMS((*c)->pixel_type, filter_params); + GP_FilterParamSetIntAll(filter_params, bright); + + GP_FilterBrightness(*c, *c, filter_params, progress_callback); return GP_ESUCCESS; } @@ -304,8 +307,11 @@ static GP_RetCode contrast(GP_Context **c, const char *params) print_error("contrast: mul parameter must be >= 0"); return GP_EINVAL; } + + GP_FILTER_PARAMS((*c)->pixel_type, filter_params); + GP_FilterParamSetFloatAll(filter_params, mul); - GP_FilterContrast(*c, *c, mul, progress_callback); + GP_FilterContrast(*c, *c, filter_params, progress_callback); return GP_ESUCCESS; } diff --git a/include/filters/GP_Filter.h b/include/filters/GP_Filter.h index e986ae60..af02bd01 100644 --- a/include/filters/GP_Filter.h +++ b/include/filters/GP_Filter.h @@ -32,4 +32,6 @@ #include "core/GP_Context.h" #include "core/GP_ProgressCallback.h" +#include "GP_FilterParam.h" + #endif /* FILTERS_GP_FILTER_H */ diff --git a/include/filters/GP_FilterParam.h b/include/filters/GP_FilterParam.h new file mode 100644 index 00000000..dbf9749d --- /dev/null +++ b/include/filters/GP_FilterParam.h @@ -0,0 +1,107 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2009-2011 Cyril Hrubis * + * * + *****************************************************************************/ + +/* + + Filter per channel parameter passing code. + + */ + +#ifndef FILTERS_GP_FILTER_PARAM_H +#define FILTERS_GP_FILTER_PARAM_H + +#include "core/GP_Pixel.h" + +#include + +typedef union GP_FilterParamVal { + float f; + uint32_t ui; + int32_t i; + void *ptr; +} GP_FilterParamVal; + +/* + * Filter parameter structure for one channel. + * + * Filter takes, empty channel name terminated, arrray of these as parameter. + */ +typedef struct GP_FilterParam { + //TODO: this must be >= for maximal channel name (now it's 2) + char channel_name[2]; + union GP_FilterParamVal val; +} GP_FilterParam; + +/* + * Takes array of filter parameters and returns channel. + * + * Returns NULL if channel wasn't found. + */ +GP_FilterParam *GP_FilterParamChannel(GP_FilterParam params[], + const char *channel_name); + +/* + * Returns number of filter channels. + */ +uint32_t GP_FilterParamChannels(GP_FilterParam params[]); + +/* + * Compares param channels and pixel type channels. Returns zero if channels + * match. + */ +int GP_FilterParamCheckPixelType(GP_FilterParam params[], + GP_PixelType type); + +/* + * Returns zero only if params have exactly same channels as array of + * channel_names. + */ +int GP_FilterParamCheckChannels(GP_FilterParam params[], + const char *channel_names[]); + +/* + * Create and initalize the structure on the stack + */ +#define GP_FILTER_PARAMS(pixel_type, name) \ + GP_FilterParam name[GP_PixelTypes[pixel_type].numchannels + 1]; \ + GP_FilterParamInitChannels(name, pixel_type); +/* + * Initalize param names and terminator. + * + * Sets all values to 0. + */ +void GP_FilterParamInitChannels(GP_FilterParam params[], + GP_PixelType type); + +/* + * Sets all values to integer value. + */ +void GP_FilterParamSetIntAll(GP_FilterParam params[], + int32_t val); + +/* + * Sets all values to float value. + */ +void GP_FilterParamSetFloatAll(GP_FilterParam params[], + float val); + +#endif /* FILTERS_GP_FILTER_PARAM_H */ diff --git a/include/filters/GP_Filters.h b/include/filters/GP_Filters.h index 4a38cb68..f5cb8484 100644 --- a/include/filters/GP_Filters.h +++ b/include/filters/GP_Filters.h @@ -32,6 +32,9 @@ #ifndef GP_FILTERS_H #define GP_FILTERS_H +/* Filter per channel parameter passing interface */ +#include "filters/GP_FilterParam.h" + /* Image rotations (90 180 270 grads) and mirroring */ #include "filters/GP_Rotate.h" diff --git a/include/filters/GP_Point.h b/include/filters/GP_Point.h index c5b53a85..e6aaeda0 100644 --- a/include/filters/GP_Point.h +++ b/include/filters/GP_Point.h @@ -36,30 +36,37 @@ * * Increments each pixel channel by a given value. */ -void GP_FilterBrightness_Raw(const GP_Context *src, GP_Context *dst, - int32_t inc, GP_ProgressCallback *callback); +int GP_FilterBrightness_Raw(const GP_Context *src, GP_Context *dst, + GP_FilterParam params[], + GP_ProgressCallback *callback); GP_Context *GP_FilterBrightness(const GP_Context *src, GP_Context *dst, - int32_t inc, GP_ProgressCallback *callback); + GP_FilterParam params[], + GP_ProgressCallback *callback); /* * Contrast filter. * - * Multiplies each pixel channel by a given value. + * Multiplies each pixel channel by a given float value. + * + * The parameters should have the same pixel channels as + * source pixel type and are expected to be float numbers. */ -GP_Context *GP_FilterContrast_Raw(const GP_Context *src, GP_Context *dst, - float mul, GP_ProgressCallback *callback); +int GP_FilterContrast_Raw(const GP_Context *src, GP_Context *dst, + GP_FilterParam params[], + GP_ProgressCallback *callback); GP_Context *GP_FilterContrast(const GP_Context *src, GP_Context *dst, - float mul, GP_ProgressCallback *callback); + GP_FilterParam params[], + GP_ProgressCallback *callback); /* * Invert filter. * * Inverts each pixel channel (eg. val = max - val) */ -GP_Context *GP_FilterInvert_Raw(const GP_Context *src, GP_Context *dst, - GP_ProgressCallback *callback); +int GP_FilterInvert_Raw(const GP_Context *src, GP_Context *dst, + GP_ProgressCallback *callback); GP_Context *GP_FilterInvert(const GP_Context *src, GP_Context *dst, GP_ProgressCallback *callback); diff --git a/libs/filters/GP_Brightness.gen.c.t b/libs/filters/GP_Brightness.gen.c.t dissimilarity index 73% index 1ba6fb9a..adf06427 100644 --- a/libs/filters/GP_Brightness.gen.c.t +++ b/libs/filters/GP_Brightness.gen.c.t @@ -1,23 +1,32 @@ -%% extends "filter.point.c.t" - -%% block descr -Brightness filters -- Increments all color channels by a fixed value. -%% endblock - -%% block body - -{{ filter_include() }} - -%% call(ps) filter_per_pixel_size('Brightness', 'int32_t inc') -pix = pix + inc; -{{ filter_clamp_val('pix', ps.size) }} -%% endcall - -%% call(chan) filter_per_pixel_type('Brightness', 'int32_t inc') -{{ chan[0] }} = {{ chan[0] }} + inc; -{{ filter_clamp_val(chan[0], chan[2]) }} -%% endcall - -{{ filter_functions('Brightness', 'int32_t inc', 'inc', "inc=%i") }} - -%% endblock body +%% extends "filter.point.c.t" + +%% block descr +Brightness filters -- Increments color channel(s) by a fixed value. +%% endblock + +%% block body + +{{ filter_include() }} + +%% macro filter_op(chann_name, chann_size) +{{ chann_name }} = {{ chann_name }} + {{ chann_name }}_i; +{{ filter_clamp_val(chann_name, chann_size) }} +%% endmacro + +/* + * Generated brightness filters. + */ +%% call(pt) filter_point_per_channel('Brightness', 'GP_FilterParam params[]', filter_op) +{{ filter_params(pt, 'params', 'int32_t', 'i') }} +%% endcall + +/* + * Generated constrast filters for pixels with one channel. + */ +%% call(ps) filter_point_per_bpp('Brightness', 'GP_FilterParam params[]', filter_op) +{{ filter_param(ps, 'params', 'int32_t', 'i') }} +%% endcall + +{{ filter_functions('Brightness', 'GP_FilterParam params[]', 'params') }} + +%% endblock body diff --git a/libs/filters/GP_Contrast.gen.c.t b/libs/filters/GP_Contrast.gen.c.t dissimilarity index 74% index 3398d1a7..abbb0c31 100644 --- a/libs/filters/GP_Contrast.gen.c.t +++ b/libs/filters/GP_Contrast.gen.c.t @@ -1,23 +1,32 @@ -%% extends "filter.point.c.t" - -%% block descr -Contrast filters -- Multiply all color channels by a fixed value. -%% endblock - -%% block body - -{{ filter_include() }} - -%% call(ps) filter_per_pixel_size('Contrast', 'float mul') -pix = 1.00 * pix * mul; -{{ filter_clamp_val('pix', ps.size) }} -%% endcall - -%% call(chan) filter_per_pixel_type('Contrast', 'float mul') -{{ chan[0] }} = mul * {{ chan[0] }} + 0.5; -{{ filter_clamp_val(chan[0], chan[2]) }} -%% endcall - -{{ filter_functions('Contrast', 'float mul', 'mul', "mul=%2.3f") }} - -%% endblock body +%% extends "filter.point.c.t" + +%% block descr +Contrast filters -- Multiply color channel(s) by a fixed float value. +%% endblock + +%% block body + +{{ filter_include() }} + +%% macro filter_op(chan_name, chan_size) +{{ chan_name }} = {{ chan_name }} * {{ chan_name }}_f + 0.5; +{{ filter_clamp_val(chan_name, chan_size) }} +%% endmacro + +/* + * Generated contrast filters for pixels with several channels. + */ +%% call(pt) filter_point_per_channel('Contrast', 'GP_FilterParam params[]', filter_op) +{{ filter_params(pt, 'params', 'float', 'f') }} +%% endcall + +/* + * Generated constrast filters for pixels with one channel. + */ +%% call(ps) filter_point_per_bpp('Contrast', 'GP_FilterParam params[]', filter_op) +{{ filter_param(ps, 'params', 'float', 'f') }} +%% endcall + +{{ filter_functions('Contrast', 'GP_FilterParam params[]', 'params') }} + +%% endblock body diff --git a/libs/filters/GP_FilterParam.c b/libs/filters/GP_FilterParam.c new file mode 100644 index 00000000..4277df71 --- /dev/null +++ b/libs/filters/GP_FilterParam.c @@ -0,0 +1,125 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2009-2011 Cyril Hrubis * + * * + *****************************************************************************/ + +#include + +#include + +#include "GP_FilterParam.h" + +static unsigned int count_channels(GP_FilterParam params[]) +{ + unsigned int i = 0; + + while (params[i].channel_name[0] != '\0') + i++; + + return i; +} + +GP_FilterParam *GP_FilterParamChannel(GP_FilterParam params[], + const char *channel_name) +{ + unsigned int i; + + for (i = 0; params[i].channel_name[0] != '\0'; i++) + if (!strcmp(params[i].channel_name, channel_name)) + return ¶ms[i]; + + return NULL; +} + +uint32_t GP_FilterParamChannels(GP_FilterParam params[]) +{ + return count_channels(params); +} + +int GP_FilterParamCheckPixelType(GP_FilterParam params[], + GP_PixelType pixel_type) +{ + unsigned int i, num_channels; + const GP_PixelTypeChannel *channels; + + num_channels = GP_PixelTypes[pixel_type].numchannels; + channels = GP_PixelTypes[pixel_type].channels; + + i = count_channels(params); + + if (i != num_channels) + return 1; + + for (i = 0; i < num_channels; i++) + if (GP_FilterParamChannel(params, channels[i].name) == NULL) + return 1; + + return 0; +} + +int GP_FilterParamCheckChannels(GP_FilterParam params[], + const char *channel_names[]) +{ + unsigned int i; + + for (i = 0; channel_names[i] != NULL; i++) + if (GP_FilterParamChannel(params, channel_names[i]) == NULL) + return 1; + + if (i != count_channels(params)) + return 1; + + return 0; +} + +void GP_FilterParamInitChannels(GP_FilterParam params[], + GP_PixelType pixel_type) +{ + unsigned int i, num_channels; + const GP_PixelTypeChannel *channels; + + num_channels = GP_PixelTypes[pixel_type].numchannels; + channels = GP_PixelTypes[pixel_type].channels; + + for (i = 0; i < num_channels; i++) { + strcpy(params[i].channel_name, channels[i].name); + memset(¶ms[i].val, 0, sizeof(GP_FilterParamVal)); + } + + params[i].channel_name[0] = '\0'; +} + +void GP_FilterParamSetIntAll(GP_FilterParam params[], + int32_t val) +{ + unsigned int i; + + for (i = 0; params[i].channel_name[0] != '\0'; i++) + params[i].val.i = val; +} + +void GP_FilterParamSetFloatAll(GP_FilterParam params[], + float val) +{ + unsigned int i; + + for (i = 0; params[i].channel_name[0] != '\0'; i++) + params[i].val.f = val; +} diff --git a/libs/filters/GP_Invert.gen.c.t b/libs/filters/GP_Invert.gen.c.t index 1c11b301..e6d4b242 100644 --- a/libs/filters/GP_Invert.gen.c.t +++ b/libs/filters/GP_Invert.gen.c.t @@ -8,12 +8,14 @@ Invert filters -- Invert image {{ filter_include() }} -%% call(ps) filter_per_pixel_size('Invert') -pix = {{ 2 ** ps.size - 1 }} - pix; +%% macro filter_op(chann_name, chann_size) +{{ chann_name }} = {{ 2 ** chann_size - 1 }} - {{ chann_name }}; +%% endmacro + +%% call(pt) filter_point_per_channel('Invert', '', filter_op) %% endcall -%% call(chan) filter_per_pixel_type('Invert') -{{ chan[0] }} = {{ 2 ** chan[2] - 1 }} - {{ chan[0] }}; +%% call(ps) filter_point_per_bpp('Invert', '', filter_op) %% endcall {{ filter_functions('Invert') }} diff --git a/libs/filters/Makefile b/libs/filters/Makefile index 16086479..2b4cdb6a 100644 --- a/libs/filters/Makefile +++ b/libs/filters/Makefile @@ -1,5 +1,5 @@ TOPDIR=../.. -GENSOURCES=GP_Brightness.gen.c GP_Contrast.gen.c GP_Invert.gen.c\ +GENSOURCES=GP_Contrast.gen.c GP_Brightness.gen.c GP_Invert.gen.c \ GP_MirrorV.gen.c GP_Rotate.gen.c GP_Dither.gen.c GENHEADERS= CSOURCES=$(filter-out $(wildcard *.gen.c),$(wildcard *.c)) diff --git a/pylib/templates/filter.point.c.t b/pylib/templates/filter.point.c.t index 9a925cf6..02240ee7 100644 --- a/pylib/templates/filter.point.c.t +++ b/pylib/templates/filter.point.c.t @@ -2,52 +2,50 @@ {% macro maybe_opts(opts) %}{% if opts %}, {{ opts }}{% endif %}{% endmacro %} +{% macro maybe_opts2(opts) %}{% if opts %}{{ opts }}, {% endif %}{% endmacro %} + %% macro filter_include() #include "core/GP_Context.h" #include "core/GP_Pixel.h" #include "core/GP_GetPutPixel.h" #include "core/GP_Debug.h" +#include "GP_Point.h" #include "GP_Filter.h" %% endmacro /* - * Filter per pixel size, used for one channel images. + * Value clamping macro */ -%% macro filter_per_pixel_size(name, opts="") -%% for ps in pixelsizes -%% if ps.size <= 8 and ps.size > 1 -int GP_Filter{{ name }}_{{ ps.suffix }}(const GP_Context *src, GP_Context *dst{{ maybe_opts(opts) }}, - GP_ProgressCallback *callback) -{ - uint32_t x, y; +%% macro filter_clamp_val(var, size) + if ({{ var }} < 0) + {{ var }} = 0; - for (y = 0; y < src->h; y++) { - for (x = 0; x < src->w; x++) { - int32_t pix = GP_GetPixel_Raw_{{ ps.suffix }}(src, x, y); - {{ caller(ps) }} - GP_PutPixel_Raw_{{ ps.suffix }}(dst, x, y, pix); - } - - if (GP_ProgressCallbackReport(callback, y, src->h, src->w)) - return 1; - } + if ({{ var }} > {{ 2 ** size - 1}}) + {{ var }} = {{ 2 ** size - 1}}; +%% endmacro - GP_ProgressCallbackDone(callback); - return 0; -} -%% endif -%% endfor +/* + * Load parameters from params structure into variables + */ +%% macro filter_params(pt, params, c_type, id) + GP_ASSERT(GP_FilterParamCheckPixelType({{ params }}, GP_PIXEL_{{ pt.name }}) == 0, + "Invalid params channels for context pixel type"); + + %% for chann in pt.chanslist + {{ c_type }} {{ chann[0] }}_{{ id }} = (GP_FilterParamChannel({{ params }}, "{{ chann[0] }}"))->val.{{ id }}; + %% endfor %% endmacro /* * Filter per pixel type, used for images with more than one channel per pixel */ -%% macro filter_per_pixel_type(name, opts="") +%% macro filter_point_per_channel(name, opts="", filter_op) %% for pt in pixeltypes %% if not pt.is_unknown() and len(pt.chanslist) > 1 -int GP_Filter{{ name }}_{{ pt.name }}(const GP_Context *src, GP_Context *dst{{ maybe_opts(opts) }}, - GP_ProgressCallback *callback) +int GP_Filter{{ name }}_{{ pt.name }}(const GP_Context *src, GP_Context *dst, + {{ maybe_opts2(opts) }}GP_ProgressCallback *callback) { +{{ caller(pt) }} uint32_t x, y; for (y = 0; y < src->h; y++) { @@ -58,11 +56,11 @@ int GP_Filter{{ name }}_{{ pt.name }}(const GP_Context *src, GP_Context *dst{{ m %% endfor %% for c in pt.chanslist - {{ caller(c) }} + {{ filter_op(c[0], c[2]) }} %% endfor pix = GP_Pixel_CREATE_{{ pt.name }}({{ pt.chanslist[0][0] }}{% for c in pt.chanslist[1:] %}, {{ c[0] }}{% endfor %}); - + GP_PutPixel_Raw_{{ pt.pixelsize.suffix }}(dst, x, y, pix); } @@ -79,15 +77,45 @@ int GP_Filter{{ name }}_{{ pt.name }}(const GP_Context *src, GP_Context *dst{{ m %% endmacro /* - * Value clamping macro + * Load parameters from params structure into variable */ -%% macro filter_clamp_val(var, size) - if ({{ var }} < 0) - {{ var }} = 0; +%% macro filter_param(ps, params, c_type, val) + GP_ASSERT(GP_FilterParamChannels({{ params }}) != 1, + "Expected only one channel"); - if ({{ var }} > {{ 2 ** size - 1}}) - {{ var }} = {{ 2 ** size - 1}}; -%% endmacro + {{ c_type }} pix_{{ val }} = params[0].val.{{ val }}; +%% endmacro + +/* + * Point filter per bpp (used for 1 channel pixels to save space). + */ +%% macro filter_point_per_bpp(name, opts="", filter_op) +%% for ps in pixelsizes +%% if ps.size <= 8 and ps.size > 1 +int GP_Filter{{ name }}_{{ ps.suffix }}(const GP_Context *src, GP_Context *dst, + {{ maybe_opts2(opts) }}GP_ProgressCallback *callback) +{ +{{ caller(ps) }} + uint32_t x, y; + + for (y = 0; y < src->h; y++) { + for (x = 0; x < src->w; x++) { + int32_t pix = GP_GetPixel_Raw_{{ ps.suffix }}(src, x, y); + {{ filter_op('pix', ps.size) }} + GP_PutPixel_Raw_{{ ps.suffix }}(dst, x, y, pix); + } + + if (GP_ProgressCallbackReport(callback, y, src->h, src->w)) + return 1; + } + + GP_ProgressCallbackDone(callback); + return 0; +} + +%% endif +%% endfor +%% endmacro /* * Switch per pixel sizes or pixel types. @@ -96,7 +124,7 @@ int GP_Filter{{ name }}_{{ pt.name }}(const GP_Context *src, GP_Context *dst{{ m int GP_Filter{{ name }}_Raw(const GP_Context *src, GP_Context *dst{{ maybe_opts(opts) }}, GP_ProgressCallback *callback) { - GP_DEBUG(1, "Running filter {{ name }} {{ fmt }}"{{ maybe_opts(params) }}); + GP_DEBUG(1, "Running filter {{ name }}"); switch (src->pixel_type) { %% for pt in pixeltypes @@ -145,4 +173,3 @@ GP_Context *GP_Filter{{ name }}(const GP_Context *src, GP_Context *dst{{ maybe_o return res; } %% endmacro - -- 2.11.4.GIT