| | 984 | void blur(float blur_amount) |
|---|
| | 985 | { |
|---|
| | 986 | fast_blur(this, this, blur_amount, blur_amount ); |
|---|
| | 987 | } |
|---|
| | 988 | |
|---|
| | 989 | /* |
|---|
| | 990 | void blur(float blur_amount_todo) |
|---|
| | 991 | { |
|---|
| | 992 | float blur_amount = 30.0f; |
|---|
| | 993 | |
|---|
| | 994 | //We don't want it to be negative: |
|---|
| | 995 | if( blur_amount < 0.0f ) |
|---|
| | 996 | blur_amount = blur_amount * -1.0f; |
|---|
| | 997 | |
|---|
| | 998 | if( blur_amount == 0.0f ) |
|---|
| | 999 | return; |
|---|
| | 1000 | |
|---|
| | 1001 | if( imageData !is null ) |
|---|
| | 1002 | { |
|---|
| | 1003 | float[] grad_result; |
|---|
| | 1004 | int red_val = 0; |
|---|
| | 1005 | int green_val = 0; |
|---|
| | 1006 | int blue_val = 0; |
|---|
| | 1007 | int alpha_val = 0; |
|---|
| | 1008 | |
|---|
| | 1009 | float[] gm = new float[(cast(uint)blur_amount)+1];//[0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.4f, 0.3f, 0.2f, 0.1f]; |
|---|
| | 1010 | float half_len = (cast(float)gm.length)/2.0f; |
|---|
| | 1011 | for( uint i = 0; i < gm.length; i++ ) |
|---|
| | 1012 | { |
|---|
| | 1013 | gm[i] = ((cast(float)i) - half_len) / (half_len);//translate from 0...10 range to -5...5 and then to -1...1 range. |
|---|
| | 1014 | //(and actually smaller because of half_len*3.0f) |
|---|
| | 1015 | if( gm[i] < 0.0f )//swap negative to be positive. Now we got 1...0...1 range. kind of. |
|---|
| | 1016 | gm[i] = gm[i] * -1.0f; |
|---|
| | 1017 | gm[i] = (1.0f - gm[i]) * 0.4;//to 0...1...0 range. And then to 0...0.4...0 range. |
|---|
| | 1018 | //This propably could be done earlier, but I'm no mathematician! |
|---|
| | 1019 | |
|---|
| | 1020 | Trace.formatln("gm: i:{} val: {}", i, cast(double)gm[i] ); |
|---|
| | 1021 | } |
|---|
| | 1022 | int ind = 0; |
|---|
| | 1023 | |
|---|
| | 1024 | //assert(0); |
|---|
| | 1025 | |
|---|
| | 1026 | float val1 = 0; |
|---|
| | 1027 | float val2 = 0; |
|---|
| | 1028 | float val3 = 0; |
|---|
| | 1029 | |
|---|
| | 1030 | scope GLubyte[] imageDataCopy = imageData.dup; |
|---|
| | 1031 | |
|---|
| | 1032 | |
|---|
| | 1033 | //Horizontal blur: |
|---|
| | 1034 | for( uint i = 0; i < height; i++ ) |
|---|
| | 1035 | { |
|---|
| | 1036 | for( uint j = 0; j < width; j++ ) |
|---|
| | 1037 | { |
|---|
| | 1038 | for( uint c = 0; c < gm.length; c++ ) |
|---|
| | 1039 | { |
|---|
| | 1040 | //ind = (cast(int)j - (cast(int)half_len)) + cast(int)c; |
|---|
| | 1041 | ind = (cast(int)j - (cast(int)(half_len/2))) + cast(int)c; |
|---|
| | 1042 | |
|---|
| | 1043 | for( uint chan = 0; chan < channels; chan++ ) |
|---|
| | 1044 | { |
|---|
| | 1045 | if( ind >= 0 && ind < width ) |
|---|
| | 1046 | { |
|---|
| | 1047 | val1 = gm[c] * imageData[(i*width*channels) + (j*channels) + chan] ;//our source pixel with weight gm[c]. |
|---|
| | 1048 | val2 = (1.0f-gm[c]) * imageDataCopy[(i*width*channels) + (ind*channels) + chan];//our target pixels current value |
|---|
| | 1049 | //weighed so that the sum of the weights becomes 1.0. |
|---|
| | 1050 | val3 = val1 + val2;//The result. |
|---|
| | 1051 | |
|---|
| | 1052 | imageDataCopy[(i*width*channels) + (ind*channels) + chan] = cast(uint) val3; |
|---|
| | 1053 | } |
|---|
| | 1054 | } |
|---|
| | 1055 | } |
|---|
| | 1056 | } |
|---|
| | 1057 | } |
|---|
| | 1058 | |
|---|
| | 1059 | |
|---|
| | 1060 | //Vertical blur: |
|---|
| | 1061 | |
|---|
| | 1062 | scope GLubyte[] imageDataCopy2 = imageData.dup; |
|---|
| | 1063 | |
|---|
| | 1064 | for( uint j = 0; j < width; j++ ) |
|---|
| | 1065 | { |
|---|
| | 1066 | for( uint i = 0; i < height; i++ ) |
|---|
| | 1067 | { |
|---|
| | 1068 | for( uint c = 0; c < gm.length; c++ ) |
|---|
| | 1069 | { |
|---|
| | 1070 | ind = (cast(int)i - (cast(int)(half_len/2))) + cast(int)c; |
|---|
| | 1071 | |
|---|
| | 1072 | for( uint chan = 0; chan < channels; chan++ ) |
|---|
| | 1073 | { |
|---|
| | 1074 | if( ind >= 0 && ind < height ) |
|---|
| | 1075 | { |
|---|
| | 1076 | val1 = gm[c] * imageData[(i*width*channels) + (j*channels) + chan] ;//our source pixel with weight gm[c]. |
|---|
| | 1077 | val2 = (1.0f-gm[c]) * imageDataCopy2[(ind*width*channels) + (j*channels) + chan];//our target pixels current value |
|---|
| | 1078 | //weighed so that the sum of the weights becomes 1.0. |
|---|
| | 1079 | val3 = val1 + val2;//The result. |
|---|
| | 1080 | |
|---|
| | 1081 | imageDataCopy2[(ind*width*channels) + (j*channels) + chan] = cast(uint) val3; |
|---|
| | 1082 | } |
|---|
| | 1083 | } |
|---|
| | 1084 | } |
|---|
| | 1085 | } |
|---|
| | 1086 | } |
|---|
| | 1087 | |
|---|
| | 1088 | |
|---|
| | 1089 | //And now an additional pass to combine the two buffers. |
|---|
| | 1090 | |
|---|
| | 1091 | for( uint i = 0; i < height; i++ ) |
|---|
| | 1092 | { |
|---|
| | 1093 | for( uint j = 0; j < width; j++ ) |
|---|
| | 1094 | { |
|---|
| | 1095 | for( uint chan = 0; chan < channels; chan++ ) |
|---|
| | 1096 | { |
|---|
| | 1097 | val1 = imageDataCopy[(i*width*channels) + (j*channels) + chan]; |
|---|
| | 1098 | val2 = imageDataCopy2[(i*width*channels) + (j*channels) + chan]; |
|---|
| | 1099 | val3 = (val1 + val2) * 0.5f;//average. |
|---|
| | 1100 | //val3 = val1; |
|---|
| | 1101 | imageData[(i*width*channels) + (j*channels) + chan] = cast(uint) val3; |
|---|
| | 1102 | } |
|---|
| | 1103 | } |
|---|
| | 1104 | } |
|---|
| | 1105 | |
|---|
| | 1106 | } |
|---|
| | 1107 | } |
|---|
| | 1108 | */ |
|---|
| | 1109 | |
|---|
| | 1110 | //The following two functions were taken from librsvg-2.15.90. |
|---|
| | 1111 | //And modified to fit this class. |
|---|
| | 1112 | //Here's the licence: |
|---|
| | 1113 | |
|---|
| | 1114 | /* |
|---|
| | 1115 | rsvg-filter.c: Provides filters |
|---|
| | 1116 | |
|---|
| | 1117 | Copyright (C) 2004 Caleb Moore |
|---|
| | 1118 | |
|---|
| | 1119 | This program is free software; you can redistribute it and/or |
|---|
| | 1120 | modify it under the terms of the GNU Library General Public License as |
|---|
| | 1121 | published by the Free Software Foundation; either version 2 of the |
|---|
| | 1122 | License, or (at your option) any later version. |
|---|
| | 1123 | |
|---|
| | 1124 | This program is distributed in the hope that it will be useful, |
|---|
| | 1125 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| | 1126 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| | 1127 | Library General Public License for more details. |
|---|
| | 1128 | |
|---|
| | 1129 | You should have received a copy of the GNU Library General Public |
|---|
| | 1130 | License along with this program; if not, write to the |
|---|
| | 1131 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|---|
| | 1132 | Boston, MA 02111-1307, USA. |
|---|
| | 1133 | |
|---|
| | 1134 | Author: Caleb Moore <c.moore@student.unsw.edu.au> |
|---|
| | 1135 | */ |
|---|
| | 1136 | |
|---|
| | 1137 | |
|---|
| | 1138 | static void |
|---|
| | 1139 | box_blur (Image input, Image output, GLubyte[] intermediate, int kw, |
|---|
| | 1140 | int kh )//, RsvgIRect boundarys, RsvgFilterPrimitiveOutput op) |
|---|
| | 1141 | { |
|---|
| | 1142 | int ch; |
|---|
| | 1143 | int x, y; |
|---|
| | 1144 | //int rowstride;//, |
|---|
| | 1145 | int height = input.height; |
|---|
| | 1146 | int width = input.width; |
|---|
| | 1147 | int channels = input.channels; |
|---|
| | 1148 | |
|---|
| | 1149 | //GLubyte* in_pixels; |
|---|
| | 1150 | //GLubyte* output_pixels; |
|---|
| | 1151 | |
|---|
| | 1152 | int sum; |
|---|
| | 1153 | |
|---|
| | 1154 | //height = gdk_pixbuf_get_height (in); |
|---|
| | 1155 | //width = gdk_pixbuf_get_width (in); |
|---|
| | 1156 | |
|---|
| | 1157 | GLubyte[] in_pixels = input.imageData;//gdk_pixbuf_get_pixels (in); |
|---|
| | 1158 | GLubyte[] output_pixels = output.imageData;//gdk_pixbuf_get_pixels (output); |
|---|
| | 1159 | |
|---|
| | 1160 | int rowstride = input.width * input.channels;//gdk_pixbuf_get_rowstride (in); |
|---|
| | 1161 | |
|---|
| | 1162 | //if (kw > boundarys.x1 - boundarys.x0) |
|---|
| | 1163 | // kw = boundarys.x1 - boundarys.x0; |
|---|
| | 1164 | |
|---|
| | 1165 | //if (kh > boundarys.y1 - boundarys.y0) |
|---|
| | 1166 | // kh = boundarys.y1 - boundarys.y0; |
|---|
| | 1167 | |
|---|
| | 1168 | if (kw > width) |
|---|
| | 1169 | kw = width; |
|---|
| | 1170 | |
|---|
| | 1171 | if (kh > height) |
|---|
| | 1172 | kh = height; |
|---|
| | 1173 | |
|---|
| | 1174 | |
|---|
| | 1175 | if (kw >= 1) |
|---|
| | 1176 | { |
|---|
| | 1177 | for (ch = 0; ch < channels; ch++) |
|---|
| | 1178 | { |
|---|
| | 1179 | /* |
|---|
| | 1180 | switch (ch) |
|---|
| | 1181 | { |
|---|
| | 1182 | case 0: |
|---|
| | 1183 | if (!op.Rused) |
|---|
| | 1184 | continue; |
|---|
| | 1185 | case 1: |
|---|
| | 1186 | if (!op.Gused) |
|---|
| | 1187 | continue; |
|---|
| | 1188 | case 2: |
|---|
| | 1189 | if (!op.Bused) |
|---|
| | 1190 | continue; |
|---|
| | 1191 | case 3: |
|---|
| | 1192 | if (!op.Aused) |
|---|
| | 1193 | continue; |
|---|
| | 1194 | } |
|---|
| | 1195 | */ |
|---|
| | 1196 | //for (y = boundarys.y0; y < boundarys.y1; y++) |
|---|
| | 1197 | for (y = 0; y < height; y++) |
|---|
| | 1198 | { |
|---|
| | 1199 | sum = 0; |
|---|
| | 1200 | //for (x = boundarys.x0; x < boundarys.x0 + kw; x++) |
|---|
| | 1201 | for (x = 0; x < 0 + kw; x++) |
|---|
| | 1202 | { |
|---|
| | 1203 | sum += (intermediate[x % kw] = in_pixels[channels * x + y * rowstride + ch]); |
|---|
| | 1204 | |
|---|
| | 1205 | //if (x - kw / 2 >= 0 && x - kw / 2 < boundarys.x1) |
|---|
| | 1206 | if (x - kw / 2 >= 0 && x - kw / 2 < width) |
|---|
| | 1207 | output_pixels[channels * (x - kw / 2) + y * rowstride + ch] = sum / kw; |
|---|
| | 1208 | } |
|---|
| | 1209 | //for (x = boundarys.x0 + kw; x < boundarys.x1; x++) |
|---|
| | 1210 | for (x = 0 + kw; x < width; x++) |
|---|
| | 1211 | { |
|---|
| | 1212 | sum -= intermediate[x % kw]; |
|---|
| | 1213 | sum += (intermediate[x % kw] = in_pixels[channels * x + y * rowstride + ch]); |
|---|
| | 1214 | output_pixels[channels * (x - kw / 2) + y * rowstride + ch] = sum / kw; |
|---|
| | 1215 | } |
|---|
| | 1216 | //for (x = boundarys.x1; x < boundarys.x1 + kw; x++) |
|---|
| | 1217 | for (x = width; x < width + kw; x++) |
|---|
| | 1218 | { |
|---|
| | 1219 | sum -= intermediate[x % kw]; |
|---|
| | 1220 | |
|---|
| | 1221 | //if (x - kw / 2 >= 0 && x - kw / 2 < boundarys.x1) |
|---|
| | 1222 | if (x - kw / 2 >= 0 && x - kw / 2 < width) |
|---|
| | 1223 | output_pixels[channels * (x - kw / 2) + y * rowstride + ch] = sum / kw; |
|---|
| | 1224 | } |
|---|
| | 1225 | } |
|---|
| | 1226 | } |
|---|
| | 1227 | in_pixels = output_pixels; |
|---|
| | 1228 | } |
|---|
| | 1229 | |
|---|
| | 1230 | if (kh >= 1) |
|---|
| | 1231 | { |
|---|
| | 1232 | for (ch = 0; ch < channels; ch++) |
|---|
| | 1233 | { |
|---|
| | 1234 | /* |
|---|
| | 1235 | switch (ch) |
|---|
| | 1236 | { |
|---|
| | 1237 | case 0: |
|---|
| | 1238 | if (!op.Rused) |
|---|
| | 1239 | continue; |
|---|
| | 1240 | case 1: |
|---|
| | 1241 | if (!op.Gused) |
|---|
| | 1242 | continue; |
|---|
| | 1243 | case 2: |
|---|
| | 1244 | if (!op.Bused) |
|---|
| | 1245 | continue; |
|---|
| | 1246 | case 3: |
|---|
| | 1247 | if (!op.Aused) |
|---|
| | 1248 | continue; |
|---|
| | 1249 | } |
|---|
| | 1250 | */ |
|---|
| | 1251 | |
|---|
| | 1252 | //for (x = boundarys.x0; x < boundarys.x1; x++) |
|---|
| | 1253 | for (x = 0; x < width; x++) |
|---|
| | 1254 | { |
|---|
| | 1255 | sum = 0; |
|---|
| | 1256 | |
|---|
| | 1257 | //for (y = boundarys.y0; y < boundarys.y0 + kh; y++) |
|---|
| | 1258 | for (y = 0; y < 0 + kh; y++) |
|---|
| | 1259 | { |
|---|
| | 1260 | sum += (intermediate[y % kh] = in_pixels[channels * x + y * rowstride + ch]); |
|---|
| | 1261 | |
|---|
| | 1262 | //if (y - kh / 2 >= 0 && y - kh / 2 < boundarys.y1) |
|---|
| | 1263 | if (y - kh / 2 >= 0 && y - kh / 2 < height) |
|---|
| | 1264 | output_pixels[channels * x + (y - kh / 2) * rowstride + ch] = sum / kh; |
|---|
| | 1265 | } |
|---|
| | 1266 | //for (; y < boundarys.y1; y++) |
|---|
| | 1267 | for (; y < height; y++) |
|---|
| | 1268 | { |
|---|
| | 1269 | sum -= intermediate[y % kh]; |
|---|
| | 1270 | sum += (intermediate[y % kh] = in_pixels[channels * x + y * rowstride + ch]); |
|---|
| | 1271 | output_pixels[channels * x + (y - kh / 2) * rowstride + ch] = sum / kh; |
|---|
| | 1272 | } |
|---|
| | 1273 | //for (; y < boundarys.y1 + kh; y++) |
|---|
| | 1274 | for (; y < height + kh; y++) |
|---|
| | 1275 | { |
|---|
| | 1276 | sum -= intermediate[y % kh]; |
|---|
| | 1277 | |
|---|
| | 1278 | //if (y - kh / 2 >= 0 && y - kh / 2 < boundarys.y1) |
|---|
| | 1279 | if (y - kh / 2 >= 0 && y - kh / 2 < height) |
|---|
| | 1280 | output_pixels[channels * x + (y - kh / 2) * rowstride + ch] = sum / kh; |
|---|
| | 1281 | } |
|---|
| | 1282 | } |
|---|
| | 1283 | } |
|---|
| | 1284 | } |
|---|
| | 1285 | } |
|---|
| | 1286 | |
|---|
| | 1287 | static void fast_blur(Image input, Image output, float blur_amount_x, |
|---|
| | 1288 | float blur_amount_y )//, RsvgIRect boundarys, RsvgFilterPrimitiveOutput op) |
|---|
| | 1289 | { |
|---|
| | 1290 | int kx, ky; |
|---|
| | 1291 | |
|---|
| | 1292 | kx = cast(int) floor(blur_amount_x * 3.0f * sqrt(2.0f*PI) / 4.0f + 0.5f); |
|---|
| | 1293 | ky = cast(int) floor(blur_amount_y * 3.0f * sqrt(2.0f*PI) / 4.0f + 0.5f); |
|---|
| | 1294 | |
|---|
| | 1295 | if (kx < 1 && ky < 1) |
|---|
| | 1296 | return; |
|---|
| | 1297 | |
|---|
| | 1298 | scope GLubyte[] intermediate = new GLubyte[max(kx, ky)]; |
|---|
| | 1299 | |
|---|
| | 1300 | box_blur (input, output, intermediate, kx, |
|---|
| | 1301 | ky );//, boundarys, op); |
|---|
| | 1302 | box_blur (output, output, intermediate, kx, |
|---|
| | 1303 | ky );//, boundarys, op); |
|---|
| | 1304 | box_blur (output, output, intermediate, kx, |
|---|
| | 1305 | ky );//, boundarys, op); |
|---|
| | 1306 | |
|---|
| | 1307 | } |
|---|
| | 1308 | |
|---|
| | 1309 | |
|---|
| | 1310 | |
|---|
| | 1311 | |
|---|