1 // mask_overlay.c
2 // weed plugin - resize using gdk
3 // (c) G. Finch (salsaman) 2011
4 //
5 // released under the GNU GPL 3 or later
6 // see file COPYING or www.gnu.org for details
7
8 ///////////////////////////////////////////////////////////////////
9
10 static int package_version = 1; // version of this package
11
12 //////////////////////////////////////////////////////////////////
13
14 #define NEED_PALETTE_UTILS
15
16 #ifndef NEED_LOCAL_WEED_PLUGIN
17 #include <weed/weed-plugin.h>
18 #include <weed/weed-utils.h> // optional
19 #include <weed/weed-plugin-utils.h> // optional
20 #else
21 #include "../../../libweed/weed-plugin.h"
22 #include "../../../libweed/weed-utils.h"
23 #include "../../../libweed/weed-plugin-utils.h" // optional
24 #endif
25
26 #include "../weed-plugin-utils.c" // optional
27
28 /////////////////////////////////////////////////////////////
29
30 typedef struct _sdata {
31 int *xmap; // x offset in src0 to map to point (or -1 to map src1)
32 int *ymap; // x offset in src0 to map to point (or -1 to map src1)
33 } sdata;
34
35 #include <gdk/gdk.h>
36
37
make_mask(GdkPixbuf * pbuf,int mode,int owidth,int oheight,int * xmap,int * ymap)38 static void make_mask(GdkPixbuf *pbuf, int mode, int owidth, int oheight, int *xmap, int *ymap) {
39 int iwidth = gdk_pixbuf_get_width(pbuf);
40 int iheight = gdk_pixbuf_get_height(pbuf);
41 int stride = gdk_pixbuf_get_rowstride(pbuf);
42 guchar *pdata = gdk_pixbuf_get_pixels(pbuf);
43 gboolean has_alpha = gdk_pixbuf_get_has_alpha(pbuf);
44
45 double xscale = (double)iwidth / (double)owidth;
46 double yscale = (double)iheight / (double)oheight;
47
48 double xscale2 = xscale, yscale2 = yscale;
49
50 int psize = 3;
51
52 int top = -1, bot = -1, left = -1, right = -1, tline = 0, xwidth = 0;
53 double xpos = 0., ypos = 0.;
54
55 register int i, j;
56
57 if (has_alpha) psize = 4;
58
59 if (mode == 1) {
60 // get bounds
61
62 for (i = 0; i < oheight; i++) {
63 for (j = 0; j < owidth; j++) {
64 if (*(pdata + (int)(i * yscale) * stride + (int)(j * xscale) * psize + 1) == 0) {
65 if (top == -1) top = i;
66 if (j < left || left == -1) left = j;
67 if (j > right) right = j;
68 if (i > bot) bot = i;
69 }
70 }
71 }
72
73 // get width (ignoring non-black)
74
75 tline = (top + bot) >> 1;
76
77 for (j = 0; j < owidth; j++) {
78 if (*(pdata + (int)(tline * yscale) * stride + (int)(j * xscale) * psize + 1) == 0) xwidth++;
79 }
80
81 yscale2 = (double)oheight / (double)(bot - top);
82 xscale2 = (double)owidth / (double)xwidth;
83
84 // map center row as template for other rows
85 for (j = 0; j < owidth; j++) {
86 if (*(pdata + (int)(tline * yscale) * stride + (int)(j * xscale) * psize + 1) == 0) {
87 // map front frame
88 xmap[tline * owidth + j] = (int)xpos;
89 xpos += xscale2;
90 } else {
91 xmap[tline * owidth + j] = -1;
92 }
93 }
94 }
95
96 for (i = 0; i < oheight; i++) {
97 for (j = 0; j < owidth; j++) {
98 if (*(pdata + (int)(i * yscale) * stride + (int)(j * xscale) * psize + 1) == 0) {
99 // map front frame
100
101 if (mode == 0) {
102 // no re-mapping of front frame
103 xmap[i * owidth + j] = j;
104 ymap[i * owidth + j] = i;
105 } else {
106 xmap[i * owidth + j] = xmap[tline * owidth + j];
107 ymap[i * owidth + j] = (int)ypos;
108 }
109
110 } else {
111 // map back frame
112 xmap[i * owidth + j] = ymap[i * owidth + j] = -1;
113 }
114 }
115 if (i >= top) ypos += yscale2;
116 }
117 }
118
119
masko_init(weed_plant_t * inst)120 static weed_error_t masko_init(weed_plant_t *inst) {
121 struct _sdata *sdata;
122 int video_height, video_width, video_area;
123 int mode;
124 weed_plant_t *in_channel, **in_params;
125 GdkPixbuf *pbuf;
126 GError *gerr = NULL;
127 char *mfile;
128
129 in_channel = weed_get_plantptr_value(inst, WEED_LEAF_IN_CHANNELS, NULL);
130
131 sdata = weed_malloc(sizeof(struct _sdata));
132
133 if (sdata == NULL) return WEED_ERROR_MEMORY_ALLOCATION;
134
135 video_height = weed_get_int_value(in_channel, WEED_LEAF_HEIGHT, NULL);
136 video_width = weed_get_int_value(in_channel, WEED_LEAF_WIDTH, NULL);
137 video_area = video_width * video_height;
138
139 sdata->xmap = (int *)weed_malloc(video_area * sizeof(int));
140
141 if (sdata->xmap == NULL) {
142 weed_free(sdata);
143 return WEED_ERROR_MEMORY_ALLOCATION;
144 }
145
146 sdata->ymap = (int *)weed_malloc(video_area * sizeof(int));
147
148 if (sdata->ymap == NULL) {
149 weed_free(sdata->xmap);
150 weed_free(sdata);
151 return WEED_ERROR_MEMORY_ALLOCATION;
152 }
153
154 // load image, then get luma values and scale
155 in_params = weed_get_plantptr_array(inst, WEED_LEAF_IN_PARAMETERS, NULL);
156 mfile = weed_get_string_value(in_params[0], WEED_LEAF_VALUE, NULL);
157 mode = weed_get_int_value(in_params[1], WEED_LEAF_VALUE, NULL);
158
159 pbuf = gdk_pixbuf_new_from_file(mfile, &gerr);
160
161 if (gerr != NULL) {
162 weed_free(sdata->xmap);
163 weed_free(sdata->ymap);
164 //g_object_unref(gerr);
165 sdata->xmap = sdata->ymap = NULL;
166 } else {
167 make_mask(pbuf, mode, video_width, video_height, sdata->xmap, sdata->ymap);
168 g_object_unref(pbuf);
169 }
170
171 weed_free(mfile);
172 weed_free(in_params);
173
174 weed_set_voidptr_value(inst, "plugin_internal", sdata);
175
176 return WEED_SUCCESS;
177 }
178
179
masko_deinit(weed_plant_t * inst)180 static weed_error_t masko_deinit(weed_plant_t *inst) {
181 struct _sdata *sdata = weed_get_voidptr_value(inst, "plugin_internal", NULL);
182 if (sdata) {
183 if (sdata->xmap != NULL) weed_free(sdata->xmap);
184 if (sdata->ymap != NULL) weed_free(sdata->ymap);
185 weed_free(sdata);
186 }
187 weed_set_voidptr_value(inst, "plugin_internal", NULL);
188 return WEED_SUCCESS;
189 }
190
191
masko_process(weed_plant_t * inst,weed_timecode_t timestamp)192 static weed_error_t masko_process(weed_plant_t *inst, weed_timecode_t timestamp) {
193 weed_plant_t **in_channels = weed_get_plantptr_array(inst, WEED_LEAF_IN_CHANNELS, NULL),
194 *out_channel = weed_get_plantptr_value(inst, WEED_LEAF_OUT_CHANNELS, NULL);
195
196 int palette = weed_get_int_value(out_channel, WEED_LEAF_CURRENT_PALETTE, NULL);
197 int width = weed_get_int_value(out_channel, WEED_LEAF_WIDTH, NULL);
198 int height = weed_get_int_value(out_channel, WEED_LEAF_HEIGHT, NULL);
199 int offset = 0;
200
201 register int i, j, pos;
202 struct _sdata *sdata;
203
204 int psize = 3;
205
206 unsigned char *dst, *src0, *src1;
207 int orow, irow0, irow1;
208
209 if (palette == WEED_PALETTE_RGBA32 || palette == WEED_PALETTE_BGRA32 || palette == WEED_PALETTE_ARGB32 ||
210 palette == WEED_PALETTE_YUVA8888) psize = 4;
211
212 sdata = weed_get_voidptr_value(inst, "plugin_internal", NULL);
213
214 if (sdata->xmap == NULL || sdata->ymap == NULL) return WEED_SUCCESS;
215
216 dst = weed_get_voidptr_value(out_channel, WEED_LEAF_PIXEL_DATA, NULL);
217 src0 = weed_get_voidptr_value(in_channels[0], WEED_LEAF_PIXEL_DATA, NULL);
218 src1 = weed_get_voidptr_value(in_channels[1], WEED_LEAF_PIXEL_DATA, NULL);
219
220 orow = weed_get_int_value(out_channel, WEED_LEAF_ROWSTRIDES, NULL);
221 irow0 = weed_get_int_value(in_channels[0], WEED_LEAF_ROWSTRIDES, NULL);
222 irow1 = weed_get_int_value(in_channels[1], WEED_LEAF_ROWSTRIDES, NULL);
223
224 // new threading arch
225 if (weed_plant_has_leaf(out_channel, WEED_LEAF_OFFSET)) {
226 offset = weed_get_int_value(out_channel, WEED_LEAF_OFFSET, NULL);
227 int dheight = weed_get_int_value(out_channel, WEED_LEAF_HEIGHT, NULL);
228 height = offset + dheight;
229 dst += offset * orow;
230 src1 += offset * irow1;
231 }
232
233 pos = offset * width;
234 orow -= width * psize;
235 irow1 -= width * psize;
236
237 for (i = offset; i < height; i++) {
238 for (j = 0; j < width; j++) {
239 if (sdata->xmap[pos] == -1 || sdata->ymap[pos] == -1) {
240 // map bg pixel to dst
241 weed_memcpy(dst, src1, psize);
242 } else {
243 // remap fg pixel
244 weed_memcpy(dst, src0 + sdata->ymap[pos]*irow0 + sdata->xmap[pos]*psize, psize);
245 }
246 dst += psize;
247 src1 += psize;
248 pos++;
249 }
250 dst += orow;
251 src1 += irow1;
252 }
253
254 weed_free(in_channels);
255
256 return WEED_SUCCESS;
257 }
258
259
260 WEED_SETUP_START(200, 200) {
261 int palette_list[] = ALL_PACKED_PALETTES;
262
263 weed_plant_t *in_chantmpls[] = {weed_channel_template_init("in channel 0", 0),
264 weed_channel_template_init("in channel 1", 0), NULL
265 };
266
267 weed_plant_t *out_chantmpls[] = {weed_channel_template_init("out channel 0", WEED_CHANNEL_REINIT_ON_SIZE_CHANGE), NULL};
268 weed_plant_t *filter_class;
269 weed_plant_t *in_params[3], *gui;
270 char *rfx_strings[] = {"special|fileread|0|"};
271 const char *modes[] = {"normal", "stretch", NULL};
272
273 char *defmaskfile = g_build_filename(g_get_home_dir(), "mask.png", NULL);
274 int flags;
275
276 in_params[0] = weed_text_init("maskfile", "_Mask file (.png or .jpg)", defmaskfile);
277 gui = weed_paramtmpl_get_gui(in_params[0]);
278 weed_set_int_value(gui, WEED_LEAF_MAXCHARS, 80); // for display only - fileread will override this
279 flags = 0;
280 if (weed_plant_has_leaf(in_params[0], WEED_LEAF_FLAGS))
281 flags = weed_get_int_value(in_params[0], WEED_LEAF_FLAGS, NULL);
282 flags |= WEED_PARAMETER_REINIT_ON_VALUE_CHANGE;
283 weed_set_int_value(in_params[0], WEED_LEAF_FLAGS, flags);
284
285 in_params[1] = weed_string_list_init("mode", "Effect _mode", 0, modes);
286 flags = 0;
287 if (weed_plant_has_leaf(in_params[1], WEED_LEAF_FLAGS))
288 flags = weed_get_int_value(in_params[1], WEED_LEAF_FLAGS, NULL);
289 flags |= WEED_PARAMETER_REINIT_ON_VALUE_CHANGE;
290 weed_set_int_value(in_params[1], WEED_LEAF_FLAGS, flags);
291 in_params[2] = NULL;
292
293 weed_free(defmaskfile);
294
295 filter_class = weed_filter_class_init("mask_overlay", "salsaman", 1, WEED_FILTER_HINT_MAY_THREAD, palette_list,
296 masko_init, masko_process, masko_deinit, in_chantmpls, out_chantmpls, in_params, NULL);
297
298 gui = weed_filter_get_gui(filter_class);
299 weed_set_string_value(gui, WEED_LEAF_LAYOUT_SCHEME, "RFX");
300 weed_set_string_value(gui, "layout_rfx_delim", "|");
301 weed_set_string_array(gui, "layout_rfx_strings", 1, rfx_strings);
302
303 weed_plugin_info_add_filter_class(plugin_info, filter_class);
304 weed_set_int_value(plugin_info, WEED_LEAF_VERSION, package_version);
305 }
306 WEED_SETUP_END;
307
308
309