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