1 // comic.c
2 // weed plugin
3 // (c) G. Finch (salsaman) 2010
4 //
5 // released under the GNU GPL 3 or later
6 // see file COPYING or www.gnu.org for details
7
8 // thanks to Chris Yates for the idea
9
10 ///////////////////////////////////////////////////////////////////
11
12 static int package_version = 1; // version of this package
13
14 //////////////////////////////////////////////////////////////////
15
16 #define NEED_PALETTE_UTILS
17
18 #ifndef NEED_LOCAL_WEED_PLUGIN
19 #include <weed/weed-plugin.h>
20 #include <weed/weed-utils.h> // optional
21 #include <weed/weed-plugin-utils.h> // optional
22 #else
23 #include "../../libweed/weed-plugin.h"
24 #include "../../libweed/weed-utils.h" // optional
25 #include "../../libweed/weed-plugin-utils.h" // optional
26 #endif
27
28 #include "weed-plugin-utils.c"
29
30 /////////////////////////////////////////////////////////////
31
32 #include <inttypes.h>
33
sqrti(uint32_t n)34 static uint32_t sqrti(uint32_t n) {
35 register uint32_t root = 0, remainder = n, place = 0x40000000, tmp;
36 while (place > remainder) place >>= 2;
37 while (place) {
38 if (remainder >= (tmp = (root + place))) {
39 remainder -= tmp;
40 root += (place << 1);
41 }
42 root >>= 1;
43 place >>= 2;
44 }
45 return root;
46 }
47
48
cp_chroma(unsigned char * dst,unsigned char * src,int irowstride,int orowstride,int width,int height)49 static void cp_chroma(unsigned char *dst, unsigned char *src, int irowstride, int orowstride, int width, int height) {
50 if (irowstride == orowstride && irowstride == width) weed_memcpy(dst, src, width * height);
51 else {
52 for (int i = 0; i < height; i++) {
53 weed_memcpy(dst, src, width);
54 src += irowstride;
55 dst += orowstride;
56 }
57 }
58 }
59
60
comic_process(weed_plant_t * inst,weed_timecode_t timestamp)61 static weed_error_t comic_process(weed_plant_t *inst, weed_timecode_t timestamp) {
62 weed_plant_t *in_channel = weed_get_in_channel(inst, 0),
63 *out_channel = weed_get_out_channel(inst, 0);
64 uint8_t **srcp = (uint8_t **)weed_channel_get_pixel_data_planar(in_channel, NULL);
65 uint8_t **dstp = (uint8_t **)weed_channel_get_pixel_data_planar(out_channel, NULL);
66
67 int width = weed_channel_get_width(in_channel);
68 int height = weed_channel_get_height(in_channel);
69 int *irowstrides = weed_channel_get_rowstrides(in_channel, NULL);
70 int *orowstrides = weed_channel_get_rowstrides(out_channel, NULL);
71 int palette = weed_channel_get_palette(in_channel);
72 int clamping = weed_channel_get_yuv_clamping(in_channel);
73 int irowstride, orowstride;
74
75 uint8_t *src, *dst, *end;
76 int row0, row1, sum, scale = 384;
77 int ymin, ymax, nplanes;
78 int i;
79
80 // get the Y planes
81 src = srcp[0];
82 dst = dstp[0];
83
84 irowstride = irowstrides[0];
85 orowstride = orowstrides[0];
86
87 // skip top scanline
88 weed_memcpy(dst, src, width);
89
90 src += irowstride;
91 dst += orowstride;
92
93 // calc end
94 end = src + (height - 2) * irowstride;
95
96 // dst remainder after copying width
97 orowstride -= width;
98
99
100 if (clamping == WEED_YUV_CLAMPING_UNCLAMPED) {
101 ymin = 0;
102 ymax = 255;
103 } else {
104 ymin = 16;
105 ymax = 235;
106 }
107
108 // skip rightmost pixel
109 width--;
110
111 // process each row
112 for (; src < end; src += irowstride - width - 1) {
113 // skip leftmost pixel
114 *(dst++) = *src;
115 src++;
116
117 // process all pixels except leftmost and rightmost
118 for (i = 1; i < width; i++) {
119 // do edge detect and convolve
120 row0 = (*(src + irowstride - 1) - * (src - irowstride - 1)) + ((*(src + irowstride) - * (src - irowstride)) << 1)
121 + (*(src + irowstride + 1) - * (src + irowstride - 1));
122 row1 = (*(src - irowstride + 1) - * (src - irowstride - 1)) + ((*(src + 1) - * (src - 1)) << 1)
123 + (*(src + irowstride + 1) - * (src + irowstride - 1));
124
125 sum = ((3 * sqrti(row0 * row0 + row1 * row1) / 2) * scale) >> 8;
126
127 // clamp and invert
128 sum = 255 - (sum < 0 ? 0 : sum > 255 ? 255 : sum);
129
130 // mix 25% effected with 75% original
131 sum = (64 * sum + 192 * (*src)) >> 8;
132 if (clamping == WEED_YUV_CLAMPING_CLAMPED) sum = (double)sum / 255. * 219. + 16.;
133
134 *(dst++) = (uint8_t)(sum < ymin ? ymin : sum > ymax ? ymax : sum);
135 src++;
136 }
137
138 // skip rightmost pixel
139 *(dst++) = *src;
140 src++;
141
142 // dst to next row
143 dst += orowstride;
144 }
145
146 width++;
147
148 // copy bottom row
149 weed_memcpy(dst, src, width);
150
151 if (palette == WEED_PALETTE_YUV420P || palette == WEED_PALETTE_YVU420P) height >>= 1;
152 if (palette == WEED_PALETTE_YUV420P || palette == WEED_PALETTE_YVU420P || palette == WEED_PALETTE_YUV422P) width >>= 1;
153
154 if (palette == WEED_PALETTE_YUVA4444P) nplanes = 4;
155 else nplanes = 3;
156
157 for (i = 1; i < nplanes; i++) {
158 cp_chroma(dstp[i], srcp[i], irowstrides[i], orowstrides[i], width, height);
159 }
160
161 weed_free(srcp);
162 weed_free(dstp);
163 weed_free(irowstrides);
164 weed_free(orowstrides);
165 return WEED_SUCCESS;
166 }
167
168
169 WEED_SETUP_START(200, 200) {
170 int palette_list[] = ALL_PLANAR_PALETTES;
171 weed_plant_t *in_chantmpls[] = {weed_channel_template_init("in channel 0", 0), NULL};
172 weed_plant_t *out_chantmpls[] = {weed_channel_template_init("out channel 0", 0), NULL};
173 weed_plant_t *filter_class = weed_filter_class_init("comicbook", "salsaman", 1, 0,
174 palette_list, NULL, comic_process, NULL, in_chantmpls, out_chantmpls, NULL, NULL);
175
176 // set preference of unclamped
177 weed_set_int_value(in_chantmpls[0], WEED_LEAF_YUV_CLAMPING, WEED_YUV_CLAMPING_UNCLAMPED);
178 weed_plugin_info_add_filter_class(plugin_info, filter_class);
179 weed_plugin_set_package_version(plugin_info, package_version);
180 }
181 WEED_SETUP_END;
182