| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | #define IMAGER_NO_CONTEXT | 
| 2 |  |  |  |  |  |  | #include "imager.h" | 
| 3 |  |  |  |  |  |  | #include "imageri.h" | 
| 4 |  |  |  |  |  |  | #include | 
| 5 |  |  |  |  |  |  | #include | 
| 6 |  |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  |  | 
| 8 |  |  |  |  |  |  | /* | 
| 9 |  |  |  |  |  |  | =head1 NAME | 
| 10 |  |  |  |  |  |  |  | 
| 11 |  |  |  |  |  |  | filters.im - implements filters that operate on images | 
| 12 |  |  |  |  |  |  |  | 
| 13 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | i_contrast(im, 0.8); | 
| 17 |  |  |  |  |  |  | i_hardinvert(im); | 
| 18 |  |  |  |  |  |  | i_hardinvertall(im); | 
| 19 |  |  |  |  |  |  | i_unsharp_mask(im, 2.0, 1.0); | 
| 20 |  |  |  |  |  |  | ... and more | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | filters.c implements basic filters for Imager.  These filters | 
| 25 |  |  |  |  |  |  | should be accessible from the filter interface as defined in | 
| 26 |  |  |  |  |  |  | the pod for Imager. | 
| 27 |  |  |  |  |  |  |  | 
| 28 |  |  |  |  |  |  | =head1 FUNCTION REFERENCE | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | Some of these functions are internal. | 
| 31 |  |  |  |  |  |  |  | 
| 32 |  |  |  |  |  |  | =over | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | =cut | 
| 35 |  |  |  |  |  |  | */ | 
| 36 |  |  |  |  |  |  |  | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  |  | 
| 39 |  |  |  |  |  |  |  | 
| 40 |  |  |  |  |  |  | /* | 
| 41 |  |  |  |  |  |  | =item saturate(in) | 
| 42 |  |  |  |  |  |  |  | 
| 43 |  |  |  |  |  |  | Clamps the input value between 0 and 255. (internal) | 
| 44 |  |  |  |  |  |  |  | 
| 45 |  |  |  |  |  |  | in - input integer | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  | =cut | 
| 48 |  |  |  |  |  |  | */ | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  | static | 
| 51 |  |  |  |  |  |  | unsigned char | 
| 52 | 315000 |  |  |  |  |  | saturate(int in) { | 
| 53 | 315000 | 100 |  |  |  |  | if (in>255) { return 255; } | 
| 54 | 301409 | 100 |  |  |  |  | else if (in>0) return in; | 
| 55 | 109185 |  |  |  |  |  | return 0; | 
| 56 |  |  |  |  |  |  | } | 
| 57 |  |  |  |  |  |  |  | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  |  | 
| 60 |  |  |  |  |  |  | /* | 
| 61 |  |  |  |  |  |  | =item i_contrast(im, intensity) | 
| 62 |  |  |  |  |  |  |  | 
| 63 |  |  |  |  |  |  | Scales the pixel values by the amount specified. | 
| 64 |  |  |  |  |  |  |  | 
| 65 |  |  |  |  |  |  | im        - image object | 
| 66 |  |  |  |  |  |  | intensity - scalefactor | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | =cut | 
| 69 |  |  |  |  |  |  | */ | 
| 70 |  |  |  |  |  |  |  | 
| 71 |  |  |  |  |  |  | void | 
| 72 | 1 |  |  |  |  |  | i_contrast(i_img *im, float intensity) { | 
| 73 |  |  |  |  |  |  | i_img_dim x, y; | 
| 74 |  |  |  |  |  |  | int ch; | 
| 75 |  |  |  |  |  |  | unsigned int new_color; | 
| 76 |  |  |  |  |  |  | i_color rcolor; | 
| 77 | 1 |  |  |  |  |  | dIMCTXim(im); | 
| 78 |  |  |  |  |  |  |  | 
| 79 | 1 |  |  |  |  |  | im_log((aIMCTX, 1,"i_contrast(im %p, intensity %f)\n", im, intensity)); | 
| 80 |  |  |  |  |  |  |  | 
| 81 | 1 | 50 |  |  |  |  | if(intensity < 0) return; | 
| 82 |  |  |  |  |  |  |  | 
| 83 | 22651 | 100 |  |  |  |  | for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) { | 
|  |  | 100 |  |  |  |  |  | 
| 84 | 22500 |  |  |  |  |  | i_gpix(im, x, y, &rcolor); | 
| 85 |  |  |  |  |  |  |  | 
| 86 | 90000 | 100 |  |  |  |  | for(ch = 0; ch < im->channels; ch++) { | 
| 87 | 67500 |  |  |  |  |  | new_color = (unsigned int) rcolor.channel[ch]; | 
| 88 | 67500 |  |  |  |  |  | new_color *= intensity; | 
| 89 |  |  |  |  |  |  |  | 
| 90 | 67500 | 50 |  |  |  |  | if(new_color > 255) { | 
| 91 | 0 |  |  |  |  |  | new_color = 255; | 
| 92 |  |  |  |  |  |  | } | 
| 93 | 67500 |  |  |  |  |  | rcolor.channel[ch] = (unsigned char) new_color; | 
| 94 |  |  |  |  |  |  | } | 
| 95 | 22500 |  |  |  |  |  | i_ppix(im, x, y, &rcolor); | 
| 96 |  |  |  |  |  |  | } | 
| 97 |  |  |  |  |  |  | } | 
| 98 |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | static int | 
| 101 | 5 |  |  |  |  |  | s_hardinvert_low(i_img *im, int all) { | 
| 102 |  |  |  |  |  |  | i_img_dim x, y; | 
| 103 |  |  |  |  |  |  | int ch; | 
| 104 | 5 | 100 |  |  |  |  | int invert_channels = all ? im->channels : i_img_color_channels(im); | 
| 105 | 5 |  |  |  |  |  | dIMCTXim(im); | 
| 106 |  |  |  |  |  |  |  | 
| 107 | 5 |  |  |  |  |  | im_log((aIMCTX,1,"i_hardinvert)low(im %p, all %d)\n", im, all)); | 
| 108 |  |  |  |  |  |  |  | 
| 109 | 5 | 100 |  |  |  |  | #code im->bits <= 8 | 
| 110 |  |  |  |  |  |  | IM_COLOR *row, *entry; | 
| 111 |  |  |  |  |  |  |  | 
| 112 |  |  |  |  |  |  | /* always rooms to allocate a single line of i_color */ | 
| 113 | 5 |  |  |  |  |  | row = mymalloc(sizeof(IM_COLOR) * im->xsize); /* checked 17feb2005 tonyc */ | 
| 114 |  |  |  |  |  |  |  | 
| 115 | 159 | 100 |  |  |  |  | for(y = 0; y < im->ysize; y++) { | 
|  |  | 100 |  |  |  |  |  | 
| 116 | 154 |  |  |  |  |  | IM_GLIN(im, 0, im->xsize, y, row); | 
| 117 | 154 |  |  |  |  |  | entry = row; | 
| 118 | 22658 | 100 |  |  |  |  | for(x = 0; x < im->xsize; x++) { | 
|  |  | 100 |  |  |  |  |  | 
| 119 | 90018 | 100 |  |  |  |  | for(ch = 0; ch < invert_channels; ch++) { | 
|  |  | 100 |  |  |  |  |  | 
| 120 | 67514 |  |  |  |  |  | entry->channel[ch] = IM_SAMPLE_MAX - entry->channel[ch]; | 
| 121 |  |  |  |  |  |  | } | 
| 122 | 22504 |  |  |  |  |  | ++entry; | 
| 123 |  |  |  |  |  |  | } | 
| 124 | 154 |  |  |  |  |  | IM_PLIN(im, 0, im->xsize, y, row); | 
| 125 |  |  |  |  |  |  | } | 
| 126 | 5 |  |  |  |  |  | myfree(row); | 
| 127 |  |  |  |  |  |  | #/code | 
| 128 |  |  |  |  |  |  |  | 
| 129 | 5 |  |  |  |  |  | return 1; | 
| 130 |  |  |  |  |  |  | } | 
| 131 |  |  |  |  |  |  |  | 
| 132 |  |  |  |  |  |  | /* | 
| 133 |  |  |  |  |  |  | =item i_hardinvert(im) | 
| 134 |  |  |  |  |  |  |  | 
| 135 |  |  |  |  |  |  | Inverts the color channels of the input image. | 
| 136 |  |  |  |  |  |  |  | 
| 137 |  |  |  |  |  |  | im        - image object | 
| 138 |  |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  | =cut | 
| 140 |  |  |  |  |  |  | */ | 
| 141 |  |  |  |  |  |  |  | 
| 142 |  |  |  |  |  |  | void | 
| 143 | 3 |  |  |  |  |  | i_hardinvert(i_img *im) { | 
| 144 | 3 |  |  |  |  |  | s_hardinvert_low(im, 0); | 
| 145 | 3 |  |  |  |  |  | } | 
| 146 |  |  |  |  |  |  |  | 
| 147 |  |  |  |  |  |  | /* | 
| 148 |  |  |  |  |  |  | =item i_hardinvertall(im) | 
| 149 |  |  |  |  |  |  |  | 
| 150 |  |  |  |  |  |  | Inverts all channels of the input image. | 
| 151 |  |  |  |  |  |  |  | 
| 152 |  |  |  |  |  |  | im        - image object | 
| 153 |  |  |  |  |  |  |  | 
| 154 |  |  |  |  |  |  | =cut | 
| 155 |  |  |  |  |  |  | */ | 
| 156 |  |  |  |  |  |  |  | 
| 157 |  |  |  |  |  |  | void | 
| 158 | 2 |  |  |  |  |  | i_hardinvertall(i_img *im) { | 
| 159 | 2 |  |  |  |  |  | s_hardinvert_low(im, 1); | 
| 160 | 2 |  |  |  |  |  | } | 
| 161 |  |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  | /* | 
| 163 |  |  |  |  |  |  | =item i_noise(im, amount, type) | 
| 164 |  |  |  |  |  |  |  | 
| 165 |  |  |  |  |  |  | Adjusts the sample values randomly by the amount specified. | 
| 166 |  |  |  |  |  |  |  | 
| 167 |  |  |  |  |  |  | If type is 0, adjust all channels in a pixel by the same (random) | 
| 168 |  |  |  |  |  |  | amount amount, if non-zero adjust each sample independently. | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | im     - image object | 
| 171 |  |  |  |  |  |  | amount - deviation in pixel values | 
| 172 |  |  |  |  |  |  | type   - noise individual for each channel if true | 
| 173 |  |  |  |  |  |  |  | 
| 174 |  |  |  |  |  |  | =cut | 
| 175 |  |  |  |  |  |  | */ | 
| 176 |  |  |  |  |  |  |  | 
| 177 |  |  |  |  |  |  | #ifdef WIN32 | 
| 178 |  |  |  |  |  |  | /* random() is non-ASCII, even if it is better than rand() */ | 
| 179 |  |  |  |  |  |  | #define random() rand() | 
| 180 |  |  |  |  |  |  | #endif | 
| 181 |  |  |  |  |  |  |  | 
| 182 |  |  |  |  |  |  | void | 
| 183 | 1 |  |  |  |  |  | i_noise(i_img *im, float amount, unsigned char type) { | 
| 184 |  |  |  |  |  |  | i_img_dim x, y; | 
| 185 |  |  |  |  |  |  | int ch; | 
| 186 |  |  |  |  |  |  | int new_color; | 
| 187 | 1 |  |  |  |  |  | float damount = amount * 2; | 
| 188 |  |  |  |  |  |  | i_color rcolor; | 
| 189 | 1 |  |  |  |  |  | int color_inc = 0; | 
| 190 | 1 |  |  |  |  |  | dIMCTXim(im); | 
| 191 |  |  |  |  |  |  |  | 
| 192 | 1 |  |  |  |  |  | im_log((aIMCTX, 1,"i_noise(im %p, intensity %.2f\n", im, amount)); | 
| 193 |  |  |  |  |  |  |  | 
| 194 | 1 | 50 |  |  |  |  | if(amount < 0) return; | 
| 195 |  |  |  |  |  |  |  | 
| 196 | 22651 | 100 |  |  |  |  | for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) { | 
|  |  | 100 |  |  |  |  |  | 
| 197 | 22500 |  |  |  |  |  | i_gpix(im, x, y, &rcolor); | 
| 198 |  |  |  |  |  |  |  | 
| 199 | 22500 | 50 |  |  |  |  | if(type == 0) { | 
| 200 | 22500 |  |  |  |  |  | color_inc = (amount - (damount * ((double)random() / RAND_MAX))); | 
| 201 |  |  |  |  |  |  | } | 
| 202 |  |  |  |  |  |  |  | 
| 203 | 90000 | 100 |  |  |  |  | for(ch = 0; ch < im->channels; ch++) { | 
| 204 | 67500 |  |  |  |  |  | new_color = (int) rcolor.channel[ch]; | 
| 205 |  |  |  |  |  |  |  | 
| 206 | 67500 | 50 |  |  |  |  | if(type != 0) { | 
| 207 | 0 |  |  |  |  |  | new_color += (amount - (damount * ((double)random() / RAND_MAX))); | 
| 208 |  |  |  |  |  |  | } else { | 
| 209 | 67500 |  |  |  |  |  | new_color += color_inc; | 
| 210 |  |  |  |  |  |  | } | 
| 211 |  |  |  |  |  |  |  | 
| 212 | 67500 | 100 |  |  |  |  | if(new_color < 0) { | 
| 213 | 17838 |  |  |  |  |  | new_color = 0; | 
| 214 |  |  |  |  |  |  | } | 
| 215 | 67500 | 50 |  |  |  |  | if(new_color > 255) { | 
| 216 | 0 |  |  |  |  |  | new_color = 255; | 
| 217 |  |  |  |  |  |  | } | 
| 218 |  |  |  |  |  |  |  | 
| 219 | 67500 |  |  |  |  |  | rcolor.channel[ch] = (unsigned char) new_color; | 
| 220 |  |  |  |  |  |  | } | 
| 221 |  |  |  |  |  |  |  | 
| 222 | 22500 |  |  |  |  |  | i_ppix(im, x, y, &rcolor); | 
| 223 |  |  |  |  |  |  | } | 
| 224 |  |  |  |  |  |  | } | 
| 225 |  |  |  |  |  |  |  | 
| 226 |  |  |  |  |  |  | /* | 
| 227 |  |  |  |  |  |  | =item i_bumpmap(im, bump, channel, light_x, light_y, st) | 
| 228 |  |  |  |  |  |  |  | 
| 229 |  |  |  |  |  |  | Makes a bumpmap on image im using the bump image as the elevation map. | 
| 230 |  |  |  |  |  |  |  | 
| 231 |  |  |  |  |  |  | im      - target image | 
| 232 |  |  |  |  |  |  | bump    - image that contains the elevation info | 
| 233 |  |  |  |  |  |  | channel - to take the elevation information from | 
| 234 |  |  |  |  |  |  | light_x - x coordinate of light source | 
| 235 |  |  |  |  |  |  | light_y - y coordinate of light source | 
| 236 |  |  |  |  |  |  | st      - length of shadow | 
| 237 |  |  |  |  |  |  |  | 
| 238 |  |  |  |  |  |  | =cut | 
| 239 |  |  |  |  |  |  | */ | 
| 240 |  |  |  |  |  |  |  | 
| 241 |  |  |  |  |  |  | void | 
| 242 | 1 |  |  |  |  |  | i_bumpmap(i_img *im, i_img *bump, int channel, i_img_dim light_x, i_img_dim light_y, i_img_dim st) { | 
| 243 |  |  |  |  |  |  | i_img_dim x, y; | 
| 244 |  |  |  |  |  |  | int ch; | 
| 245 |  |  |  |  |  |  | i_img_dim mx, my; | 
| 246 |  |  |  |  |  |  | i_color x1_color, y1_color, x2_color, y2_color, dst_color; | 
| 247 |  |  |  |  |  |  | double nX, nY; | 
| 248 |  |  |  |  |  |  | double tX, tY, tZ; | 
| 249 |  |  |  |  |  |  | double aX, aY, aL; | 
| 250 |  |  |  |  |  |  | double fZ; | 
| 251 |  |  |  |  |  |  | unsigned char px1, px2, py1, py2; | 
| 252 | 1 |  |  |  |  |  | dIMCTXim(im); | 
| 253 |  |  |  |  |  |  | i_img new_im; | 
| 254 |  |  |  |  |  |  |  | 
| 255 | 1 |  |  |  |  |  | im_log((aIMCTX, 1, "i_bumpmap(im %p, add_im %p, channel %d, light(" i_DFp "), st %" i_DF ")\n", | 
| 256 |  |  |  |  |  |  | im, bump, channel, i_DFcp(light_x, light_y), i_DFc(st))); | 
| 257 |  |  |  |  |  |  |  | 
| 258 |  |  |  |  |  |  |  | 
| 259 | 1 | 50 |  |  |  |  | if(channel >= bump->channels) { | 
| 260 | 0 |  |  |  |  |  | im_log((aIMCTX, 1, "i_bumpmap: channel = %d while bump image only has %d channels\n", channel, bump->channels)); | 
| 261 | 0 |  |  |  |  |  | return; | 
| 262 |  |  |  |  |  |  | } | 
| 263 |  |  |  |  |  |  |  | 
| 264 | 1 |  |  |  |  |  | mx = (bump->xsize <= im->xsize) ? bump->xsize : im->xsize; | 
| 265 | 1 |  |  |  |  |  | my = (bump->ysize <= im->ysize) ? bump->ysize : im->ysize; | 
| 266 |  |  |  |  |  |  |  | 
| 267 | 1 |  |  |  |  |  | i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels); | 
| 268 |  |  |  |  |  |  |  | 
| 269 | 1 | 50 |  |  |  |  | aX = (light_x > (mx >> 1)) ? light_x : mx - light_x; | 
| 270 | 1 | 50 |  |  |  |  | aY = (light_y > (my >> 1)) ? light_y : my - light_y; | 
| 271 |  |  |  |  |  |  |  | 
| 272 | 1 |  |  |  |  |  | aL = sqrt((aX * aX) + (aY * aY)); | 
| 273 |  |  |  |  |  |  |  | 
| 274 | 149 | 100 |  |  |  |  | for(y = 1; y < my - 1; y++) { | 
| 275 | 22052 | 100 |  |  |  |  | for(x = 1; x < mx - 1; x++) { | 
| 276 | 21904 |  |  |  |  |  | i_gpix(bump, x + st, y, &x1_color); | 
| 277 | 21904 |  |  |  |  |  | i_gpix(bump, x, y + st, &y1_color); | 
| 278 | 21904 |  |  |  |  |  | i_gpix(bump, x - st, y, &x2_color); | 
| 279 | 21904 |  |  |  |  |  | i_gpix(bump, x, y - st, &y2_color); | 
| 280 |  |  |  |  |  |  |  | 
| 281 | 21904 |  |  |  |  |  | i_gpix(im, x, y, &dst_color); | 
| 282 |  |  |  |  |  |  |  | 
| 283 | 21904 |  |  |  |  |  | px1 = x1_color.channel[channel]; | 
| 284 | 21904 |  |  |  |  |  | py1 = y1_color.channel[channel]; | 
| 285 | 21904 |  |  |  |  |  | px2 = x2_color.channel[channel]; | 
| 286 | 21904 |  |  |  |  |  | py2 = y2_color.channel[channel]; | 
| 287 |  |  |  |  |  |  |  | 
| 288 | 21904 |  |  |  |  |  | nX = px1 - px2; | 
| 289 | 21904 |  |  |  |  |  | nY = py1 - py2; | 
| 290 |  |  |  |  |  |  |  | 
| 291 | 21904 |  |  |  |  |  | nX += 128; | 
| 292 | 21904 |  |  |  |  |  | nY += 128; | 
| 293 |  |  |  |  |  |  |  | 
| 294 | 21904 |  |  |  |  |  | fZ = (sqrt((nX * nX) + (nY * nY)) / aL); | 
| 295 |  |  |  |  |  |  |  | 
| 296 | 21904 |  |  |  |  |  | tX = i_abs(x - light_x) / aL; | 
| 297 | 21904 |  |  |  |  |  | tY = i_abs(y - light_y) / aL; | 
| 298 |  |  |  |  |  |  |  | 
| 299 | 21904 |  |  |  |  |  | tZ = 1 - (sqrt((tX * tX) + (tY * tY)) * fZ); | 
| 300 |  |  |  |  |  |  |  | 
| 301 | 21904 | 100 |  |  |  |  | if(tZ < 0) tZ = 0; | 
| 302 | 21904 | 50 |  |  |  |  | if(tZ > 2) tZ = 2; | 
| 303 |  |  |  |  |  |  |  | 
| 304 | 87616 | 100 |  |  |  |  | for(ch = 0; ch < im->channels; ch++) | 
| 305 | 65712 |  |  |  |  |  | dst_color.channel[ch] = (unsigned char) (float)(dst_color.channel[ch] * tZ); | 
| 306 |  |  |  |  |  |  |  | 
| 307 | 21904 |  |  |  |  |  | i_ppix(&new_im, x, y, &dst_color); | 
| 308 |  |  |  |  |  |  | } | 
| 309 |  |  |  |  |  |  | } | 
| 310 |  |  |  |  |  |  |  | 
| 311 | 1 |  |  |  |  |  | i_copyto(im, &new_im, 0, 0, im->xsize, im->ysize, 0, 0); | 
| 312 |  |  |  |  |  |  |  | 
| 313 | 1 |  |  |  |  |  | i_img_exorcise(&new_im); | 
| 314 |  |  |  |  |  |  | } | 
| 315 |  |  |  |  |  |  |  | 
| 316 |  |  |  |  |  |  |  | 
| 317 |  |  |  |  |  |  |  | 
| 318 |  |  |  |  |  |  |  | 
| 319 |  |  |  |  |  |  | typedef struct { | 
| 320 |  |  |  |  |  |  | double x,y,z; | 
| 321 |  |  |  |  |  |  | } fvec; | 
| 322 |  |  |  |  |  |  |  | 
| 323 |  |  |  |  |  |  |  | 
| 324 |  |  |  |  |  |  | static | 
| 325 |  |  |  |  |  |  | float | 
| 326 | 67501 |  |  |  |  |  | dotp(fvec *a, fvec *b) { | 
| 327 | 67501 |  |  |  |  |  | return a->x*b->x+a->y*b->y+a->z*b->z; | 
| 328 |  |  |  |  |  |  | } | 
| 329 |  |  |  |  |  |  |  | 
| 330 |  |  |  |  |  |  | static | 
| 331 |  |  |  |  |  |  | void | 
| 332 | 22501 |  |  |  |  |  | normalize(fvec *a) { | 
| 333 | 22501 |  |  |  |  |  | double d = sqrt(dotp(a,a)); | 
| 334 | 22501 |  |  |  |  |  | a->x /= d; | 
| 335 | 22501 |  |  |  |  |  | a->y /= d; | 
| 336 | 22501 |  |  |  |  |  | a->z /= d; | 
| 337 | 22501 |  |  |  |  |  | } | 
| 338 |  |  |  |  |  |  |  | 
| 339 |  |  |  |  |  |  |  | 
| 340 |  |  |  |  |  |  | /* | 
| 341 |  |  |  |  |  |  | positive directions: | 
| 342 |  |  |  |  |  |  |  | 
| 343 |  |  |  |  |  |  | x - right, | 
| 344 |  |  |  |  |  |  | y - down | 
| 345 |  |  |  |  |  |  | z - out of the plane | 
| 346 |  |  |  |  |  |  |  | 
| 347 |  |  |  |  |  |  | I = Ia + Ip*( cd*Scol(N.L) + cs*(R.V)^n ) | 
| 348 |  |  |  |  |  |  |  | 
| 349 |  |  |  |  |  |  | Here, the variables are: | 
| 350 |  |  |  |  |  |  |  | 
| 351 |  |  |  |  |  |  | * Ia   - ambient colour | 
| 352 |  |  |  |  |  |  | * Ip   - intensity of the point light source | 
| 353 |  |  |  |  |  |  | * cd   - diffuse coefficient | 
| 354 |  |  |  |  |  |  | * Scol - surface colour | 
| 355 |  |  |  |  |  |  | * cs   - specular coefficient | 
| 356 |  |  |  |  |  |  | * n    - objects shinyness | 
| 357 |  |  |  |  |  |  | * N    - normal vector | 
| 358 |  |  |  |  |  |  | * L    - lighting vector | 
| 359 |  |  |  |  |  |  | * R    - reflection vector | 
| 360 |  |  |  |  |  |  | * V    - vision vector | 
| 361 |  |  |  |  |  |  |  | 
| 362 |  |  |  |  |  |  | static void fvec_dump(fvec *x) { | 
| 363 |  |  |  |  |  |  | printf("(%.2f %.2f %.2f)", x->x, x->y, x->z); | 
| 364 |  |  |  |  |  |  | } | 
| 365 |  |  |  |  |  |  | */ | 
| 366 |  |  |  |  |  |  |  | 
| 367 |  |  |  |  |  |  | /* XXX: Should these return a code for success? */ | 
| 368 |  |  |  |  |  |  |  | 
| 369 |  |  |  |  |  |  |  | 
| 370 |  |  |  |  |  |  |  | 
| 371 |  |  |  |  |  |  |  | 
| 372 |  |  |  |  |  |  | /* | 
| 373 |  |  |  |  |  |  | =item i_bumpmap_complex(im, bump, channel, tx, ty, Lx, Ly, Lz, Ip, cd, cs, n, Ia, Il, Is) | 
| 374 |  |  |  |  |  |  |  | 
| 375 |  |  |  |  |  |  | Makes a bumpmap on image im using the bump image as the elevation map. | 
| 376 |  |  |  |  |  |  |  | 
| 377 |  |  |  |  |  |  | im      - target image | 
| 378 |  |  |  |  |  |  | bump    - image that contains the elevation info | 
| 379 |  |  |  |  |  |  | channel - to take the elevation information from | 
| 380 |  |  |  |  |  |  | tx      - shift in x direction of where to start applying bumpmap | 
| 381 |  |  |  |  |  |  | ty      - shift in y direction of where to start applying bumpmap | 
| 382 |  |  |  |  |  |  | Lx      - x position/direction of light | 
| 383 |  |  |  |  |  |  | Ly      - y position/direction of light | 
| 384 |  |  |  |  |  |  | Lz      - z position/direction of light | 
| 385 |  |  |  |  |  |  | Ip      - light intensity | 
| 386 |  |  |  |  |  |  | cd      - diffuse coefficient | 
| 387 |  |  |  |  |  |  | cs      - specular coefficient | 
| 388 |  |  |  |  |  |  | n       - surface shinyness | 
| 389 |  |  |  |  |  |  | Ia      - ambient colour | 
| 390 |  |  |  |  |  |  | Il      - light colour | 
| 391 |  |  |  |  |  |  | Is      - specular colour | 
| 392 |  |  |  |  |  |  |  | 
| 393 |  |  |  |  |  |  | if z<0 then the L is taken to be the direction the light is shining in.  Otherwise | 
| 394 |  |  |  |  |  |  | the L is taken to be the position of the Light, Relative to the image. | 
| 395 |  |  |  |  |  |  |  | 
| 396 |  |  |  |  |  |  | =cut | 
| 397 |  |  |  |  |  |  | */ | 
| 398 |  |  |  |  |  |  |  | 
| 399 |  |  |  |  |  |  |  | 
| 400 |  |  |  |  |  |  | void | 
| 401 | 1 |  |  |  |  |  | i_bumpmap_complex(i_img *im, | 
| 402 |  |  |  |  |  |  | i_img *bump, | 
| 403 |  |  |  |  |  |  | int channel, | 
| 404 |  |  |  |  |  |  | i_img_dim tx, | 
| 405 |  |  |  |  |  |  | i_img_dim ty, | 
| 406 |  |  |  |  |  |  | double Lx, | 
| 407 |  |  |  |  |  |  | double Ly, | 
| 408 |  |  |  |  |  |  | double Lz, | 
| 409 |  |  |  |  |  |  | float cd, | 
| 410 |  |  |  |  |  |  | float cs, | 
| 411 |  |  |  |  |  |  | float n, | 
| 412 |  |  |  |  |  |  | i_color *Ia, | 
| 413 |  |  |  |  |  |  | i_color *Il, | 
| 414 |  |  |  |  |  |  | i_color *Is) { | 
| 415 |  |  |  |  |  |  | i_img new_im; | 
| 416 |  |  |  |  |  |  |  | 
| 417 |  |  |  |  |  |  | i_img_dim x, y; | 
| 418 |  |  |  |  |  |  | int ch; | 
| 419 |  |  |  |  |  |  | i_img_dim mx, Mx, my, My; | 
| 420 |  |  |  |  |  |  |  | 
| 421 |  |  |  |  |  |  | float cdc[MAXCHANNELS]; | 
| 422 |  |  |  |  |  |  | float csc[MAXCHANNELS]; | 
| 423 |  |  |  |  |  |  |  | 
| 424 |  |  |  |  |  |  | i_color x1_color, y1_color, x2_color, y2_color; | 
| 425 |  |  |  |  |  |  |  | 
| 426 |  |  |  |  |  |  | i_color Scol;   /* Surface colour       */ | 
| 427 |  |  |  |  |  |  |  | 
| 428 |  |  |  |  |  |  | fvec L;         /* Light vector */ | 
| 429 |  |  |  |  |  |  | fvec N;         /* surface normal       */ | 
| 430 |  |  |  |  |  |  | fvec R;         /* Reflection vector    */ | 
| 431 |  |  |  |  |  |  | fvec V;         /* Vision vector        */ | 
| 432 |  |  |  |  |  |  |  | 
| 433 | 1 |  |  |  |  |  | dIMCTXim(im); | 
| 434 |  |  |  |  |  |  |  | 
| 435 | 1 |  |  |  |  |  | im_log((aIMCTX, 1, "i_bumpmap_complex(im %p, bump %p, channel %d, t(" i_DFp | 
| 436 |  |  |  |  |  |  | "), Lx %.2f, Ly %.2f, Lz %.2f, cd %.2f, cs %.2f, n %.2f, Ia %p, Il %p, Is %p)\n", | 
| 437 |  |  |  |  |  |  | im, bump, channel, i_DFcp(tx, ty), Lx, Ly, Lz, cd, cs, n, Ia, Il, Is)); | 
| 438 |  |  |  |  |  |  |  | 
| 439 | 1 | 50 |  |  |  |  | if (channel >= bump->channels) { | 
| 440 | 0 |  |  |  |  |  | im_log((aIMCTX, 1, "i_bumpmap_complex: channel = %d while bump image only has %d channels\n", channel, bump->channels)); | 
| 441 | 0 |  |  |  |  |  | return; | 
| 442 |  |  |  |  |  |  | } | 
| 443 |  |  |  |  |  |  |  | 
| 444 | 4 | 100 |  |  |  |  | for(ch=0; chchannels; ch++) { | 
| 445 | 3 |  |  |  |  |  | cdc[ch] = (float)Il->channel[ch]*cd/255.f; | 
| 446 | 3 |  |  |  |  |  | csc[ch] = (float)Is->channel[ch]*cs/255.f; | 
| 447 |  |  |  |  |  |  | } | 
| 448 |  |  |  |  |  |  |  | 
| 449 | 1 |  |  |  |  |  | mx = 1; | 
| 450 | 1 |  |  |  |  |  | my = 1; | 
| 451 | 1 |  |  |  |  |  | Mx = bump->xsize-1; | 
| 452 | 1 |  |  |  |  |  | My = bump->ysize-1; | 
| 453 |  |  |  |  |  |  |  | 
| 454 | 1 |  |  |  |  |  | V.x = 0; | 
| 455 | 1 |  |  |  |  |  | V.y = 0; | 
| 456 | 1 |  |  |  |  |  | V.z = 1; | 
| 457 |  |  |  |  |  |  |  | 
| 458 | 1 | 50 |  |  |  |  | if (Lz < 0) { /* Light specifies a direction vector, reverse it to get the vector from surface to light */ | 
| 459 | 1 |  |  |  |  |  | L.x = -Lx; | 
| 460 | 1 |  |  |  |  |  | L.y = -Ly; | 
| 461 | 1 |  |  |  |  |  | L.z = -Lz; | 
| 462 | 1 |  |  |  |  |  | normalize(&L); | 
| 463 |  |  |  |  |  |  | } else {      /* Light is the position of the light source */ | 
| 464 | 0 |  |  |  |  |  | L.x = -0.2; | 
| 465 | 0 |  |  |  |  |  | L.y = -0.4; | 
| 466 | 0 |  |  |  |  |  | L.z =  1; | 
| 467 | 0 |  |  |  |  |  | normalize(&L); | 
| 468 |  |  |  |  |  |  | } | 
| 469 |  |  |  |  |  |  |  | 
| 470 | 1 |  |  |  |  |  | i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels); | 
| 471 |  |  |  |  |  |  |  | 
| 472 | 151 | 100 |  |  |  |  | for(y = 0; y < im->ysize; y++) { | 
| 473 | 22650 | 100 |  |  |  |  | for(x = 0; x < im->xsize; x++) { | 
| 474 |  |  |  |  |  |  | double dp1, dp2; | 
| 475 | 22500 |  |  |  |  |  | double dx = 0, dy = 0; | 
| 476 |  |  |  |  |  |  |  | 
| 477 |  |  |  |  |  |  | /* Calculate surface normal */ | 
| 478 | 22500 | 100 |  |  |  |  | if (mx | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 479 | 21609 |  |  |  |  |  | i_gpix(bump, x + 1, y,     &x1_color); | 
| 480 | 21609 |  |  |  |  |  | i_gpix(bump, x - 1, y,     &x2_color); | 
| 481 | 21609 |  |  |  |  |  | i_gpix(bump, x,     y + 1, &y1_color); | 
| 482 | 21609 |  |  |  |  |  | i_gpix(bump, x,     y - 1, &y2_color); | 
| 483 | 21609 |  |  |  |  |  | dx = x2_color.channel[channel] - x1_color.channel[channel]; | 
| 484 | 21609 |  |  |  |  |  | dy = y2_color.channel[channel] - y1_color.channel[channel]; | 
| 485 |  |  |  |  |  |  | } else { | 
| 486 | 891 |  |  |  |  |  | dx = 0; | 
| 487 | 891 |  |  |  |  |  | dy = 0; | 
| 488 |  |  |  |  |  |  | } | 
| 489 | 22500 |  |  |  |  |  | N.x = -dx * 0.015; | 
| 490 | 22500 |  |  |  |  |  | N.y = -dy * 0.015; | 
| 491 | 22500 |  |  |  |  |  | N.z = 1; | 
| 492 | 22500 |  |  |  |  |  | normalize(&N); | 
| 493 |  |  |  |  |  |  |  | 
| 494 |  |  |  |  |  |  | /* Calculate Light vector if needed */ | 
| 495 | 22500 | 50 |  |  |  |  | if (Lz>=0) { | 
| 496 | 0 |  |  |  |  |  | L.x = Lx - x; | 
| 497 | 0 |  |  |  |  |  | L.y = Ly - y; | 
| 498 | 0 |  |  |  |  |  | L.z = Lz; | 
| 499 | 0 |  |  |  |  |  | normalize(&L); | 
| 500 |  |  |  |  |  |  | } | 
| 501 |  |  |  |  |  |  |  | 
| 502 | 22500 |  |  |  |  |  | dp1 = dotp(&L,&N); | 
| 503 | 22500 |  |  |  |  |  | R.x = -L.x + 2*dp1*N.x; | 
| 504 | 22500 |  |  |  |  |  | R.y = -L.y + 2*dp1*N.y; | 
| 505 | 22500 |  |  |  |  |  | R.z = -L.z + 2*dp1*N.z; | 
| 506 |  |  |  |  |  |  |  | 
| 507 | 22500 |  |  |  |  |  | dp2 = dotp(&R,&V); | 
| 508 |  |  |  |  |  |  |  | 
| 509 | 22500 | 100 |  |  |  |  | dp1 = dp1<0 ?0 : dp1; | 
| 510 | 22500 | 100 |  |  |  |  | dp2 = pow(dp2<0 ?0 : dp2,n); | 
| 511 |  |  |  |  |  |  |  | 
| 512 | 22500 |  |  |  |  |  | i_gpix(im, x, y, &Scol); | 
| 513 |  |  |  |  |  |  |  | 
| 514 | 90000 | 100 |  |  |  |  | for(ch = 0; ch < im->channels; ch++) | 
| 515 | 67500 |  |  |  |  |  | Scol.channel[ch] = | 
| 516 | 67500 |  |  |  |  |  | saturate( Ia->channel[ch] + cdc[ch]*Scol.channel[ch]*dp1 + csc[ch]*dp2 ); | 
| 517 |  |  |  |  |  |  |  | 
| 518 | 22500 |  |  |  |  |  | i_ppix(&new_im, x, y, &Scol); | 
| 519 |  |  |  |  |  |  | } | 
| 520 |  |  |  |  |  |  | } | 
| 521 |  |  |  |  |  |  |  | 
| 522 | 1 |  |  |  |  |  | i_copyto(im, &new_im, 0, 0, im->xsize, im->ysize, 0, 0); | 
| 523 | 1 |  |  |  |  |  | i_img_exorcise(&new_im); | 
| 524 |  |  |  |  |  |  | } | 
| 525 |  |  |  |  |  |  |  | 
| 526 |  |  |  |  |  |  |  | 
| 527 |  |  |  |  |  |  | /* | 
| 528 |  |  |  |  |  |  | =item i_postlevels(im, levels) | 
| 529 |  |  |  |  |  |  |  | 
| 530 |  |  |  |  |  |  | Quantizes Images to fewer levels. | 
| 531 |  |  |  |  |  |  |  | 
| 532 |  |  |  |  |  |  | im      - target image | 
| 533 |  |  |  |  |  |  | levels  - number of levels | 
| 534 |  |  |  |  |  |  |  | 
| 535 |  |  |  |  |  |  | =cut | 
| 536 |  |  |  |  |  |  | */ | 
| 537 |  |  |  |  |  |  |  | 
| 538 |  |  |  |  |  |  | void | 
| 539 | 1 |  |  |  |  |  | i_postlevels(i_img *im, int levels) { | 
| 540 |  |  |  |  |  |  | i_img_dim x, y; | 
| 541 |  |  |  |  |  |  | int ch; | 
| 542 |  |  |  |  |  |  | float pv; | 
| 543 |  |  |  |  |  |  | int rv; | 
| 544 |  |  |  |  |  |  | float av; | 
| 545 |  |  |  |  |  |  |  | 
| 546 |  |  |  |  |  |  | i_color rcolor; | 
| 547 |  |  |  |  |  |  |  | 
| 548 | 1 |  |  |  |  |  | rv = (int) ((float)(256 / levels)); | 
| 549 | 1 |  |  |  |  |  | av = (float)levels; | 
| 550 |  |  |  |  |  |  |  | 
| 551 | 22651 | 100 |  |  |  |  | for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) { | 
|  |  | 100 |  |  |  |  |  | 
| 552 | 22500 |  |  |  |  |  | i_gpix(im, x, y, &rcolor); | 
| 553 |  |  |  |  |  |  |  | 
| 554 | 90000 | 100 |  |  |  |  | for(ch = 0; ch < im->channels; ch++) { | 
| 555 | 67500 |  |  |  |  |  | pv = (((float)rcolor.channel[ch] / 255)) * av; | 
| 556 | 67500 |  |  |  |  |  | pv = (int) ((int)pv * rv); | 
| 557 |  |  |  |  |  |  |  | 
| 558 | 67500 | 50 |  |  |  |  | if(pv < 0) pv = 0; | 
| 559 | 67500 | 50 |  |  |  |  | else if(pv > 255) pv = 255; | 
| 560 |  |  |  |  |  |  |  | 
| 561 | 67500 |  |  |  |  |  | rcolor.channel[ch] = (unsigned char) pv; | 
| 562 |  |  |  |  |  |  | } | 
| 563 | 22500 |  |  |  |  |  | i_ppix(im, x, y, &rcolor); | 
| 564 |  |  |  |  |  |  | } | 
| 565 | 1 |  |  |  |  |  | } | 
| 566 |  |  |  |  |  |  |  | 
| 567 |  |  |  |  |  |  |  | 
| 568 |  |  |  |  |  |  | /* | 
| 569 |  |  |  |  |  |  | =item i_mosaic(im, size) | 
| 570 |  |  |  |  |  |  |  | 
| 571 |  |  |  |  |  |  | Makes an image looks like a mosaic with tilesize of size | 
| 572 |  |  |  |  |  |  |  | 
| 573 |  |  |  |  |  |  | im      - target image | 
| 574 |  |  |  |  |  |  | size    - size of tiles | 
| 575 |  |  |  |  |  |  |  | 
| 576 |  |  |  |  |  |  | =cut | 
| 577 |  |  |  |  |  |  | */ | 
| 578 |  |  |  |  |  |  |  | 
| 579 |  |  |  |  |  |  | void | 
| 580 | 1 |  |  |  |  |  | i_mosaic(i_img *im, i_img_dim size) { | 
| 581 |  |  |  |  |  |  | i_img_dim x, y; | 
| 582 |  |  |  |  |  |  | int ch, z; | 
| 583 |  |  |  |  |  |  | i_img_dim lx, ly; | 
| 584 |  |  |  |  |  |  | long sqrsize; | 
| 585 |  |  |  |  |  |  |  | 
| 586 |  |  |  |  |  |  | i_color rcolor; | 
| 587 |  |  |  |  |  |  | long col[256]; | 
| 588 |  |  |  |  |  |  |  | 
| 589 | 1 |  |  |  |  |  | sqrsize = size * size; | 
| 590 |  |  |  |  |  |  |  | 
| 591 | 381 | 100 |  |  |  |  | for(y = 0; y < im->ysize; y += size) for(x = 0; x < im->xsize; x += size) { | 
|  |  | 100 |  |  |  |  |  | 
| 592 | 92777 | 100 |  |  |  |  | for(z = 0; z < 256; z++) col[z] = 0; | 
| 593 |  |  |  |  |  |  |  | 
| 594 | 3249 | 100 |  |  |  |  | for(lx = 0; lx < size; lx++) { | 
| 595 | 25992 | 100 |  |  |  |  | for(ly = 0; ly < size; ly++) { | 
| 596 | 23104 |  |  |  |  |  | i_gpix(im, (x + lx), (y + ly), &rcolor); | 
| 597 |  |  |  |  |  |  |  | 
| 598 | 92416 | 100 |  |  |  |  | for(ch = 0; ch < im->channels; ch++) { | 
| 599 | 69312 |  |  |  |  |  | col[ch] += rcolor.channel[ch]; | 
| 600 |  |  |  |  |  |  | } | 
| 601 |  |  |  |  |  |  | } | 
| 602 |  |  |  |  |  |  | } | 
| 603 |  |  |  |  |  |  |  | 
| 604 | 1444 | 100 |  |  |  |  | for(ch = 0; ch < im->channels; ch++) | 
| 605 | 1083 |  |  |  |  |  | rcolor.channel[ch] = (int) ((float)col[ch] / sqrsize); | 
| 606 |  |  |  |  |  |  |  | 
| 607 |  |  |  |  |  |  |  | 
| 608 | 3249 | 100 |  |  |  |  | for(lx = 0; lx < size; lx++) | 
| 609 | 25992 | 100 |  |  |  |  | for(ly = 0; ly < size; ly++) | 
| 610 | 23104 |  |  |  |  |  | i_ppix(im, (x + lx), (y + ly), &rcolor); | 
| 611 |  |  |  |  |  |  |  | 
| 612 |  |  |  |  |  |  | } | 
| 613 | 1 |  |  |  |  |  | } | 
| 614 |  |  |  |  |  |  |  | 
| 615 |  |  |  |  |  |  |  | 
| 616 |  |  |  |  |  |  | /* | 
| 617 |  |  |  |  |  |  | =item i_watermark(im, wmark, tx, ty, pixdiff) | 
| 618 |  |  |  |  |  |  |  | 
| 619 |  |  |  |  |  |  | Applies a watermark to the target image | 
| 620 |  |  |  |  |  |  |  | 
| 621 |  |  |  |  |  |  | im      - target image | 
| 622 |  |  |  |  |  |  | wmark   - watermark image | 
| 623 |  |  |  |  |  |  | tx      - x coordinate of where watermark should be applied | 
| 624 |  |  |  |  |  |  | ty      - y coordinate of where watermark should be applied | 
| 625 |  |  |  |  |  |  | pixdiff - the magnitude of the watermark, controls how visible it is | 
| 626 |  |  |  |  |  |  |  | 
| 627 |  |  |  |  |  |  | =cut | 
| 628 |  |  |  |  |  |  | */ | 
| 629 |  |  |  |  |  |  |  | 
| 630 |  |  |  |  |  |  | void | 
| 631 | 1 |  |  |  |  |  | i_watermark(i_img *im, i_img *wmark, i_img_dim tx, i_img_dim ty, int pixdiff) { | 
| 632 |  |  |  |  |  |  | i_img_dim vx, vy; | 
| 633 |  |  |  |  |  |  | int ch; | 
| 634 |  |  |  |  |  |  | i_color val, wval; | 
| 635 |  |  |  |  |  |  |  | 
| 636 | 1 |  |  |  |  |  | i_img_dim mx = wmark->xsize; | 
| 637 | 1 |  |  |  |  |  | i_img_dim my = wmark->ysize; | 
| 638 |  |  |  |  |  |  |  | 
| 639 | 22651 | 100 |  |  |  |  | for(vx=0;vx | 
|  |  | 100 |  |  |  |  |  | 
| 640 |  |  |  |  |  |  |  | 
| 641 | 22500 |  |  |  |  |  | i_gpix(im,    tx+vx, ty+vy,&val ); | 
| 642 | 22500 |  |  |  |  |  | i_gpix(wmark, vx,    vy,   &wval); | 
| 643 |  |  |  |  |  |  |  | 
| 644 | 90000 | 100 |  |  |  |  | for(ch=0;chchannels;ch++) | 
| 645 | 67500 |  |  |  |  |  | val.channel[ch] = saturate( val.channel[ch] + (pixdiff* (wval.channel[0]-128) )/128 ); | 
| 646 |  |  |  |  |  |  |  | 
| 647 | 22500 |  |  |  |  |  | i_ppix(im,tx+vx,ty+vy,&val); | 
| 648 |  |  |  |  |  |  | } | 
| 649 | 1 |  |  |  |  |  | } | 
| 650 |  |  |  |  |  |  |  | 
| 651 |  |  |  |  |  |  | /* | 
| 652 |  |  |  |  |  |  | =item i_autolevels_mono(im, lsat, usat) | 
| 653 |  |  |  |  |  |  |  | 
| 654 |  |  |  |  |  |  | Do autolevels, but monochromatically. | 
| 655 |  |  |  |  |  |  |  | 
| 656 |  |  |  |  |  |  | =cut | 
| 657 |  |  |  |  |  |  | */ | 
| 658 |  |  |  |  |  |  |  | 
| 659 |  |  |  |  |  |  | void | 
| 660 | 3 |  |  |  |  |  | i_autolevels_mono(i_img *im, float lsat, float usat) { | 
| 661 |  |  |  |  |  |  | i_color val; | 
| 662 |  |  |  |  |  |  | i_img_dim i, x, y, hist[256]; | 
| 663 |  |  |  |  |  |  | i_img_dim sum_lum, min_lum, max_lum; | 
| 664 |  |  |  |  |  |  | i_img_dim upper_accum, lower_accum; | 
| 665 |  |  |  |  |  |  | i_color *row; | 
| 666 | 3 |  |  |  |  |  | dIMCTXim(im); | 
| 667 | 3 | 50 |  |  |  |  | int adapt_channels = im->channels == 4 ? 2 : 1; | 
| 668 | 3 |  |  |  |  |  | int color_channels = i_img_color_channels(im); | 
| 669 | 3 |  |  |  |  |  | i_img_dim color_samples = im->xsize * color_channels; | 
| 670 |  |  |  |  |  |  |  | 
| 671 |  |  |  |  |  |  |  | 
| 672 | 3 |  |  |  |  |  | im_log((aIMCTX, 1,"i_autolevels_mono(im %p, lsat %f,usat %f)\n", im, lsat,usat)); | 
| 673 |  |  |  |  |  |  |  | 
| 674 |  |  |  |  |  |  | /* build the histogram in 8-bits, unless the image has a very small | 
| 675 |  |  |  |  |  |  | range it should make little difference to the result */ | 
| 676 | 3 |  |  |  |  |  | sum_lum = 0; | 
| 677 | 771 | 100 |  |  |  |  | for (i = 0; i < 256; i++) | 
| 678 | 768 |  |  |  |  |  | hist[i] = 0; | 
| 679 |  |  |  |  |  |  |  | 
| 680 | 3 |  |  |  |  |  | row = mymalloc(im->xsize * sizeof(i_color)); | 
| 681 |  |  |  |  |  |  | /* create histogram for each channel */ | 
| 682 | 173 | 100 |  |  |  |  | for (y = 0; y < im->ysize; y++) { | 
| 683 | 170 |  |  |  |  |  | i_color *p = row; | 
| 684 | 170 |  |  |  |  |  | i_glin(im, 0, im->xsize, y, row); | 
| 685 | 170 | 50 |  |  |  |  | if (im->channels > 2) | 
| 686 | 170 |  |  |  |  |  | i_adapt_colors(adapt_channels, im->channels, row, im->xsize); | 
| 687 | 22870 | 100 |  |  |  |  | for (x = 0; x < im->xsize; x++) { | 
| 688 | 22700 |  |  |  |  |  | hist[p->channel[0]]++; | 
| 689 | 22700 |  |  |  |  |  | ++p; | 
| 690 |  |  |  |  |  |  | } | 
| 691 |  |  |  |  |  |  | } | 
| 692 | 3 |  |  |  |  |  | myfree(row); | 
| 693 |  |  |  |  |  |  |  | 
| 694 | 771 | 100 |  |  |  |  | for(i = 0; i < 256; i++) { | 
| 695 | 768 |  |  |  |  |  | sum_lum += hist[i]; | 
| 696 |  |  |  |  |  |  | } | 
| 697 |  |  |  |  |  |  |  | 
| 698 | 3 |  |  |  |  |  | min_lum = 0; | 
| 699 | 3 |  |  |  |  |  | lower_accum = 0; | 
| 700 | 771 | 100 |  |  |  |  | for (i = 0; i < 256; ++i) { | 
| 701 | 768 | 100 |  |  |  |  | if (lower_accum < sum_lum * lsat) | 
| 702 | 131 |  |  |  |  |  | min_lum = i; | 
| 703 | 768 |  |  |  |  |  | lower_accum += hist[i]; | 
| 704 |  |  |  |  |  |  | } | 
| 705 |  |  |  |  |  |  |  | 
| 706 | 3 |  |  |  |  |  | max_lum = 255; | 
| 707 | 3 |  |  |  |  |  | upper_accum = 0; | 
| 708 | 771 | 100 |  |  |  |  | for(i = 255; i >= 0; i--) { | 
| 709 | 768 | 100 |  |  |  |  | if (upper_accum < sum_lum * usat) | 
| 710 | 205 |  |  |  |  |  | max_lum = i; | 
| 711 | 768 |  |  |  |  |  | upper_accum  += hist[i]; | 
| 712 |  |  |  |  |  |  | } | 
| 713 |  |  |  |  |  |  |  | 
| 714 | 3 | 100 |  |  |  |  | #code im->bits <= 8 | 
| 715 | 3 |  |  |  |  |  | IM_SAMPLE_T *srow = mymalloc(color_samples * sizeof(IM_SAMPLE_T)); | 
| 716 |  |  |  |  |  |  | #ifdef IM_EIGHT_BIT | 
| 717 | 2 |  |  |  |  |  | IM_WORK_T low = min_lum; | 
| 718 |  |  |  |  |  |  | i_sample_t lookup[256]; | 
| 719 |  |  |  |  |  |  | #else | 
| 720 | 1 |  |  |  |  |  | IM_WORK_T low = min_lum / 255.0 * IM_SAMPLE_MAX; | 
| 721 |  |  |  |  |  |  | #endif | 
| 722 | 3 |  |  |  |  |  | double scale = 255.0 / (max_lum - min_lum); | 
| 723 |  |  |  |  |  |  |  | 
| 724 |  |  |  |  |  |  | #ifdef IM_EIGHT_BIT | 
| 725 | 514 | 100 |  |  |  |  | for (i = 0; i < 256; ++i) { | 
| 726 | 512 |  |  |  |  |  | IM_WORK_T tmp = (i - low) * scale; | 
| 727 | 512 | 100 |  |  |  |  | lookup[i] = IM_LIMIT(tmp); | 
| 728 |  |  |  |  |  |  | } | 
| 729 |  |  |  |  |  |  | #endif | 
| 730 |  |  |  |  |  |  |  | 
| 731 | 173 | 100 |  |  |  |  | for(y = 0; y < im->ysize; y++) { | 
|  |  | 100 |  |  |  |  |  | 
| 732 | 170 |  |  |  |  |  | IM_GSAMP(im, 0, im->xsize, y, srow, NULL, color_channels); | 
| 733 | 68270 | 100 |  |  |  |  | for(i = 0; i < color_samples; ++i) { | 
|  |  | 100 |  |  |  |  |  | 
| 734 |  |  |  |  |  |  | #ifdef IM_EIGHT_BIT | 
| 735 | 67800 |  |  |  |  |  | srow[i] = lookup[srow[i]]; | 
| 736 |  |  |  |  |  |  | #else | 
| 737 | 300 |  |  |  |  |  | IM_WORK_T tmp = (srow[i] - low) * scale; | 
| 738 | 300 | 50 |  |  |  |  | srow[i] = IM_LIMIT(tmp); | 
|  |  | 50 |  |  |  |  |  | 
| 739 |  |  |  |  |  |  | #endif | 
| 740 |  |  |  |  |  |  | } | 
| 741 | 170 |  |  |  |  |  | IM_PSAMP(im, 0, im->xsize, y, srow, NULL, color_channels); | 
| 742 |  |  |  |  |  |  | } | 
| 743 | 3 |  |  |  |  |  | myfree(srow); | 
| 744 |  |  |  |  |  |  | #/code | 
| 745 | 3 |  |  |  |  |  | } | 
| 746 |  |  |  |  |  |  |  | 
| 747 |  |  |  |  |  |  |  | 
| 748 |  |  |  |  |  |  | /* | 
| 749 |  |  |  |  |  |  | =item i_autolevels(im, lsat, usat, skew) | 
| 750 |  |  |  |  |  |  |  | 
| 751 |  |  |  |  |  |  | Scales and translates each color such that it fills the range completely. | 
| 752 |  |  |  |  |  |  | Skew is not implemented yet - purpose is to control the color skew that can | 
| 753 |  |  |  |  |  |  | occur when changing the contrast. | 
| 754 |  |  |  |  |  |  |  | 
| 755 |  |  |  |  |  |  | im   - target image | 
| 756 |  |  |  |  |  |  | lsat - fraction of pixels that will be truncated at the lower end of the spectrum | 
| 757 |  |  |  |  |  |  | usat - fraction of pixels that will be truncated at the higher end of the spectrum | 
| 758 |  |  |  |  |  |  | skew - not used yet | 
| 759 |  |  |  |  |  |  |  | 
| 760 |  |  |  |  |  |  | Note: this code calculates levels and adjusts each channel separately, | 
| 761 |  |  |  |  |  |  | which will typically cause a color shift. | 
| 762 |  |  |  |  |  |  |  | 
| 763 |  |  |  |  |  |  | =cut | 
| 764 |  |  |  |  |  |  | */ | 
| 765 |  |  |  |  |  |  |  | 
| 766 |  |  |  |  |  |  | void | 
| 767 | 1 |  |  |  |  |  | i_autolevels(i_img *im, float lsat, float usat, float skew) { | 
| 768 |  |  |  |  |  |  | i_color val; | 
| 769 |  |  |  |  |  |  | i_img_dim i, x, y, rhist[256], ghist[256], bhist[256]; | 
| 770 |  |  |  |  |  |  | i_img_dim rsum, rmin, rmax; | 
| 771 |  |  |  |  |  |  | i_img_dim gsum, gmin, gmax; | 
| 772 |  |  |  |  |  |  | i_img_dim bsum, bmin, bmax; | 
| 773 |  |  |  |  |  |  | i_img_dim rcl, rcu, gcl, gcu, bcl, bcu; | 
| 774 | 1 |  |  |  |  |  | dIMCTXim(im); | 
| 775 |  |  |  |  |  |  |  | 
| 776 | 1 |  |  |  |  |  | im_log((aIMCTX, 1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew)); | 
| 777 |  |  |  |  |  |  |  | 
| 778 | 1 |  |  |  |  |  | rsum=gsum=bsum=0; | 
| 779 | 257 | 100 |  |  |  |  | for(i=0;i<256;i++) rhist[i]=ghist[i]=bhist[i] = 0; | 
| 780 |  |  |  |  |  |  | /* create histogram for each channel */ | 
| 781 | 22651 | 100 |  |  |  |  | for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) { | 
|  |  | 100 |  |  |  |  |  | 
| 782 | 22500 |  |  |  |  |  | i_gpix(im, x, y, &val); | 
| 783 | 22500 |  |  |  |  |  | rhist[val.channel[0]]++; | 
| 784 | 22500 |  |  |  |  |  | ghist[val.channel[1]]++; | 
| 785 | 22500 |  |  |  |  |  | bhist[val.channel[2]]++; | 
| 786 |  |  |  |  |  |  | } | 
| 787 |  |  |  |  |  |  |  | 
| 788 | 257 | 100 |  |  |  |  | for(i=0;i<256;i++) { | 
| 789 | 256 |  |  |  |  |  | rsum+=rhist[i]; | 
| 790 | 256 |  |  |  |  |  | gsum+=ghist[i]; | 
| 791 | 256 |  |  |  |  |  | bsum+=bhist[i]; | 
| 792 |  |  |  |  |  |  | } | 
| 793 |  |  |  |  |  |  |  | 
| 794 | 1 |  |  |  |  |  | rmin = gmin = bmin = 0; | 
| 795 | 1 |  |  |  |  |  | rmax = gmax = bmax = 255; | 
| 796 |  |  |  |  |  |  |  | 
| 797 | 1 |  |  |  |  |  | rcu = rcl = gcu = gcl = bcu = bcl = 0; | 
| 798 |  |  |  |  |  |  |  | 
| 799 | 257 | 100 |  |  |  |  | for(i=0; i<256; i++) { | 
| 800 | 256 | 50 |  |  |  |  | rcl += rhist[i];     if ( (rcl | 
| 801 | 256 | 100 |  |  |  |  | rcu += rhist[255-i]; if ( (rcu | 
| 802 |  |  |  |  |  |  |  | 
| 803 | 256 | 50 |  |  |  |  | gcl += ghist[i];     if ( (gcl | 
| 804 | 256 | 100 |  |  |  |  | gcu += ghist[255-i]; if ( (gcu | 
| 805 |  |  |  |  |  |  |  | 
| 806 | 256 | 50 |  |  |  |  | bcl += bhist[i];     if ( (bcl | 
| 807 | 256 | 100 |  |  |  |  | bcu += bhist[255-i]; if ( (bcu | 
| 808 |  |  |  |  |  |  | } | 
| 809 |  |  |  |  |  |  |  | 
| 810 | 22651 | 100 |  |  |  |  | for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) { | 
|  |  | 100 |  |  |  |  |  | 
| 811 | 22500 |  |  |  |  |  | i_gpix(im, x, y, &val); | 
| 812 | 22500 |  |  |  |  |  | val.channel[0]=saturate((val.channel[0]-rmin)*255/(rmax-rmin)); | 
| 813 | 22500 |  |  |  |  |  | val.channel[1]=saturate((val.channel[1]-gmin)*255/(gmax-gmin)); | 
| 814 | 22500 |  |  |  |  |  | val.channel[2]=saturate((val.channel[2]-bmin)*255/(bmax-bmin)); | 
| 815 | 22500 |  |  |  |  |  | i_ppix(im, x, y, &val); | 
| 816 |  |  |  |  |  |  | } | 
| 817 | 1 |  |  |  |  |  | } | 
| 818 |  |  |  |  |  |  |  | 
| 819 |  |  |  |  |  |  | /* | 
| 820 |  |  |  |  |  |  | =item Noise(x,y) | 
| 821 |  |  |  |  |  |  |  | 
| 822 |  |  |  |  |  |  | Pseudo noise utility function used to generate perlin noise. (internal) | 
| 823 |  |  |  |  |  |  |  | 
| 824 |  |  |  |  |  |  | x - x coordinate | 
| 825 |  |  |  |  |  |  | y - y coordinate | 
| 826 |  |  |  |  |  |  |  | 
| 827 |  |  |  |  |  |  | =cut | 
| 828 |  |  |  |  |  |  | */ | 
| 829 |  |  |  |  |  |  |  | 
| 830 |  |  |  |  |  |  | static | 
| 831 |  |  |  |  |  |  | double | 
| 832 | 8100000 |  |  |  |  |  | Noise(i_img_dim x, i_img_dim y) { | 
| 833 | 8100000 |  |  |  |  |  | i_img_dim n = x + y * 57; | 
| 834 | 8100000 |  |  |  |  |  | n = (n<<13) ^ n; | 
| 835 | 8100000 |  |  |  |  |  | return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0); | 
| 836 |  |  |  |  |  |  | } | 
| 837 |  |  |  |  |  |  |  | 
| 838 |  |  |  |  |  |  | /* | 
| 839 |  |  |  |  |  |  | =item SmoothedNoise1(x,y) | 
| 840 |  |  |  |  |  |  |  | 
| 841 |  |  |  |  |  |  | Pseudo noise utility function used to generate perlin noise. (internal) | 
| 842 |  |  |  |  |  |  |  | 
| 843 |  |  |  |  |  |  | x - x coordinate | 
| 844 |  |  |  |  |  |  | y - y coordinate | 
| 845 |  |  |  |  |  |  |  | 
| 846 |  |  |  |  |  |  | =cut | 
| 847 |  |  |  |  |  |  | */ | 
| 848 |  |  |  |  |  |  |  | 
| 849 |  |  |  |  |  |  | static | 
| 850 |  |  |  |  |  |  | double | 
| 851 | 900000 |  |  |  |  |  | SmoothedNoise1(double x, double y) { | 
| 852 | 900000 |  |  |  |  |  | double corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16; | 
| 853 | 900000 |  |  |  |  |  | double sides   = ( Noise(x-1, y)  +Noise(x+1, y)  +Noise(x, y-1)  +Noise(x, y+1) ) /  8; | 
| 854 | 900000 |  |  |  |  |  | double center  =  Noise(x, y) / 4; | 
| 855 | 900000 |  |  |  |  |  | return corners + sides + center; | 
| 856 |  |  |  |  |  |  | } | 
| 857 |  |  |  |  |  |  |  | 
| 858 |  |  |  |  |  |  |  | 
| 859 |  |  |  |  |  |  | /* | 
| 860 |  |  |  |  |  |  | =item G_Interpolate(a, b, x) | 
| 861 |  |  |  |  |  |  |  | 
| 862 |  |  |  |  |  |  | Utility function used to generate perlin noise. (internal) | 
| 863 |  |  |  |  |  |  |  | 
| 864 |  |  |  |  |  |  | =cut | 
| 865 |  |  |  |  |  |  | */ | 
| 866 |  |  |  |  |  |  |  | 
| 867 |  |  |  |  |  |  | static | 
| 868 |  |  |  |  |  |  | double | 
| 869 | 675000 |  |  |  |  |  | C_Interpolate(double a, double b, double x) { | 
| 870 |  |  |  |  |  |  | /*  float ft = x * 3.1415927; */ | 
| 871 | 675000 |  |  |  |  |  | double ft = x * PI; | 
| 872 | 675000 |  |  |  |  |  | double f = (1 - cos(ft)) * .5; | 
| 873 | 675000 |  |  |  |  |  | return  a*(1-f) + b*f; | 
| 874 |  |  |  |  |  |  | } | 
| 875 |  |  |  |  |  |  |  | 
| 876 |  |  |  |  |  |  |  | 
| 877 |  |  |  |  |  |  | /* | 
| 878 |  |  |  |  |  |  | =item InterpolatedNoise(x, y) | 
| 879 |  |  |  |  |  |  |  | 
| 880 |  |  |  |  |  |  | Utility function used to generate perlin noise. (internal) | 
| 881 |  |  |  |  |  |  |  | 
| 882 |  |  |  |  |  |  | =cut | 
| 883 |  |  |  |  |  |  | */ | 
| 884 |  |  |  |  |  |  |  | 
| 885 |  |  |  |  |  |  | static | 
| 886 |  |  |  |  |  |  | double | 
| 887 | 225000 |  |  |  |  |  | InterpolatedNoise(double x, double y) { | 
| 888 |  |  |  |  |  |  |  | 
| 889 | 225000 |  |  |  |  |  | i_img_dim integer_X = x; | 
| 890 | 225000 |  |  |  |  |  | double fractional_X = x - integer_X; | 
| 891 | 225000 |  |  |  |  |  | i_img_dim integer_Y = y; | 
| 892 | 225000 |  |  |  |  |  | double fractional_Y = y - integer_Y; | 
| 893 |  |  |  |  |  |  |  | 
| 894 | 225000 |  |  |  |  |  | double v1 = SmoothedNoise1(integer_X,     integer_Y); | 
| 895 | 225000 |  |  |  |  |  | double v2 = SmoothedNoise1(integer_X + 1, integer_Y); | 
| 896 | 225000 |  |  |  |  |  | double v3 = SmoothedNoise1(integer_X,     integer_Y + 1); | 
| 897 | 225000 |  |  |  |  |  | double v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1); | 
| 898 |  |  |  |  |  |  |  | 
| 899 | 225000 |  |  |  |  |  | double i1 = C_Interpolate(v1 , v2 , fractional_X); | 
| 900 | 225000 |  |  |  |  |  | double i2 = C_Interpolate(v3 , v4 , fractional_X); | 
| 901 |  |  |  |  |  |  |  | 
| 902 | 225000 |  |  |  |  |  | return C_Interpolate(i1 , i2 , fractional_Y); | 
| 903 |  |  |  |  |  |  | } | 
| 904 |  |  |  |  |  |  |  | 
| 905 |  |  |  |  |  |  |  | 
| 906 |  |  |  |  |  |  |  | 
| 907 |  |  |  |  |  |  | /* | 
| 908 |  |  |  |  |  |  | =item PerlinNoise_2D(x, y) | 
| 909 |  |  |  |  |  |  |  | 
| 910 |  |  |  |  |  |  | Utility function used to generate perlin noise. (internal) | 
| 911 |  |  |  |  |  |  |  | 
| 912 |  |  |  |  |  |  | =cut | 
| 913 |  |  |  |  |  |  | */ | 
| 914 |  |  |  |  |  |  |  | 
| 915 |  |  |  |  |  |  | static | 
| 916 |  |  |  |  |  |  | float | 
| 917 | 45000 |  |  |  |  |  | PerlinNoise_2D(float x, float y) { | 
| 918 |  |  |  |  |  |  | int i; | 
| 919 |  |  |  |  |  |  | double frequency; | 
| 920 |  |  |  |  |  |  | double amplitude; | 
| 921 | 45000 |  |  |  |  |  | double total = 0; | 
| 922 | 45000 |  |  |  |  |  | int Number_Of_Octaves=6; | 
| 923 | 45000 |  |  |  |  |  | int n = Number_Of_Octaves - 1; | 
| 924 |  |  |  |  |  |  |  | 
| 925 | 270000 | 100 |  |  |  |  | for(i=0;i | 
| 926 | 225000 |  |  |  |  |  | frequency = 2.0 * i; | 
| 927 | 225000 |  |  |  |  |  | amplitude = PI; | 
| 928 | 225000 |  |  |  |  |  | total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude; | 
| 929 |  |  |  |  |  |  | } | 
| 930 |  |  |  |  |  |  |  | 
| 931 | 45000 |  |  |  |  |  | return total; | 
| 932 |  |  |  |  |  |  | } | 
| 933 |  |  |  |  |  |  |  | 
| 934 |  |  |  |  |  |  |  | 
| 935 |  |  |  |  |  |  | /* | 
| 936 |  |  |  |  |  |  | =item i_radnoise(im, xo, yo, rscale, ascale) | 
| 937 |  |  |  |  |  |  |  | 
| 938 |  |  |  |  |  |  | Perlin-like radial noise. | 
| 939 |  |  |  |  |  |  |  | 
| 940 |  |  |  |  |  |  | im     - target image | 
| 941 |  |  |  |  |  |  | xo     - x coordinate of center | 
| 942 |  |  |  |  |  |  | yo     - y coordinate of center | 
| 943 |  |  |  |  |  |  | rscale - radial scale | 
| 944 |  |  |  |  |  |  | ascale - angular scale | 
| 945 |  |  |  |  |  |  |  | 
| 946 |  |  |  |  |  |  | =cut | 
| 947 |  |  |  |  |  |  | */ | 
| 948 |  |  |  |  |  |  |  | 
| 949 |  |  |  |  |  |  | void | 
| 950 | 1 |  |  |  |  |  | i_radnoise(i_img *im, i_img_dim xo, i_img_dim yo, double rscale, double ascale) { | 
| 951 |  |  |  |  |  |  | i_img_dim x, y; | 
| 952 |  |  |  |  |  |  | int ch; | 
| 953 |  |  |  |  |  |  | i_color val; | 
| 954 |  |  |  |  |  |  | unsigned char v; | 
| 955 |  |  |  |  |  |  | double xc, yc, r; | 
| 956 |  |  |  |  |  |  | double a; | 
| 957 |  |  |  |  |  |  |  | 
| 958 | 22651 | 100 |  |  |  |  | for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) { | 
|  |  | 100 |  |  |  |  |  | 
| 959 | 22500 |  |  |  |  |  | xc = (double)x-xo+0.5; | 
| 960 | 22500 |  |  |  |  |  | yc = (double)y-yo+0.5; | 
| 961 | 22500 |  |  |  |  |  | r = rscale*sqrt(xc*xc+yc*yc)+1.2; | 
| 962 | 22500 |  |  |  |  |  | a = (PI+atan2(yc,xc))*ascale; | 
| 963 | 22500 |  |  |  |  |  | v = saturate(128+100*(PerlinNoise_2D(a,r))); | 
| 964 |  |  |  |  |  |  | /* v=saturate(120+12*PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale));  Good soft marble */ | 
| 965 | 90000 | 100 |  |  |  |  | for(ch=0; chchannels; ch++) val.channel[ch]=v; | 
| 966 | 22500 |  |  |  |  |  | i_ppix(im, x, y, &val); | 
| 967 |  |  |  |  |  |  | } | 
| 968 | 1 |  |  |  |  |  | } | 
| 969 |  |  |  |  |  |  |  | 
| 970 |  |  |  |  |  |  |  | 
| 971 |  |  |  |  |  |  | /* | 
| 972 |  |  |  |  |  |  | =item i_turbnoise(im, xo, yo, scale) | 
| 973 |  |  |  |  |  |  |  | 
| 974 |  |  |  |  |  |  | Perlin-like 2d noise noise. | 
| 975 |  |  |  |  |  |  |  | 
| 976 |  |  |  |  |  |  | im     - target image | 
| 977 |  |  |  |  |  |  | xo     - x coordinate translation | 
| 978 |  |  |  |  |  |  | yo     - y coordinate translation | 
| 979 |  |  |  |  |  |  | scale  - scale of noise | 
| 980 |  |  |  |  |  |  |  | 
| 981 |  |  |  |  |  |  | =cut | 
| 982 |  |  |  |  |  |  | */ | 
| 983 |  |  |  |  |  |  |  | 
| 984 |  |  |  |  |  |  | void | 
| 985 | 1 |  |  |  |  |  | i_turbnoise(i_img *im, double xo, double yo, double scale) { | 
| 986 |  |  |  |  |  |  | i_img_dim x,y; | 
| 987 |  |  |  |  |  |  | int ch; | 
| 988 |  |  |  |  |  |  | unsigned char v; | 
| 989 |  |  |  |  |  |  | i_color val; | 
| 990 |  |  |  |  |  |  |  | 
| 991 | 22651 | 100 |  |  |  |  | for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) { | 
|  |  | 100 |  |  |  |  |  | 
| 992 |  |  |  |  |  |  | /*    v=saturate(125*(1.0+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))); */ | 
| 993 | 22500 |  |  |  |  |  | v = saturate(120*(1.0+sin(xo+(double)x/scale+PerlinNoise_2D(xo+(double)x/scale,yo+(float)y/scale)))); | 
| 994 | 90000 | 100 |  |  |  |  | for(ch=0; chchannels; ch++) val.channel[ch] = v; | 
| 995 | 22500 |  |  |  |  |  | i_ppix(im, x, y, &val); | 
| 996 |  |  |  |  |  |  | } | 
| 997 | 1 |  |  |  |  |  | } | 
| 998 |  |  |  |  |  |  |  | 
| 999 |  |  |  |  |  |  |  | 
| 1000 |  |  |  |  |  |  |  | 
| 1001 |  |  |  |  |  |  | /* | 
| 1002 |  |  |  |  |  |  | =item i_gradgen(im, num, xo, yo, ival, dmeasure) | 
| 1003 |  |  |  |  |  |  |  | 
| 1004 |  |  |  |  |  |  | Gradient generating function. | 
| 1005 |  |  |  |  |  |  |  | 
| 1006 |  |  |  |  |  |  | im     - target image | 
| 1007 |  |  |  |  |  |  | num    - number of points given | 
| 1008 |  |  |  |  |  |  | xo     - array of x coordinates | 
| 1009 |  |  |  |  |  |  | yo     - array of y coordinates | 
| 1010 |  |  |  |  |  |  | ival   - array of i_color objects | 
| 1011 |  |  |  |  |  |  | dmeasure - distance measure to be used. | 
| 1012 |  |  |  |  |  |  | 0 = Euclidean | 
| 1013 |  |  |  |  |  |  | 1 = Euclidean squared | 
| 1014 |  |  |  |  |  |  | 2 = Manhattan distance | 
| 1015 |  |  |  |  |  |  |  | 
| 1016 |  |  |  |  |  |  | =cut | 
| 1017 |  |  |  |  |  |  | */ | 
| 1018 |  |  |  |  |  |  |  | 
| 1019 |  |  |  |  |  |  |  | 
| 1020 |  |  |  |  |  |  | void | 
| 1021 | 1 |  |  |  |  |  | i_gradgen(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure) { | 
| 1022 |  |  |  |  |  |  |  | 
| 1023 |  |  |  |  |  |  | i_color val; | 
| 1024 |  |  |  |  |  |  | int p, ch; | 
| 1025 |  |  |  |  |  |  | i_img_dim x, y; | 
| 1026 | 1 |  |  |  |  |  | int channels = im->channels; | 
| 1027 | 1 |  |  |  |  |  | i_img_dim xsize    = im->xsize; | 
| 1028 | 1 |  |  |  |  |  | i_img_dim ysize    = im->ysize; | 
| 1029 |  |  |  |  |  |  | size_t bytes; | 
| 1030 |  |  |  |  |  |  |  | 
| 1031 |  |  |  |  |  |  | double *fdist; | 
| 1032 | 1 |  |  |  |  |  | dIMCTXim(im); | 
| 1033 |  |  |  |  |  |  |  | 
| 1034 | 1 |  |  |  |  |  | im_log((aIMCTX, 1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure)); | 
| 1035 |  |  |  |  |  |  |  | 
| 1036 | 4 | 100 |  |  |  |  | for(p = 0; p | 
| 1037 | 3 |  |  |  |  |  | im_log((aIMCTX,1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p]))); | 
| 1038 | 3 |  |  |  |  |  | ICL_info(&ival[p]); | 
| 1039 |  |  |  |  |  |  | } | 
| 1040 |  |  |  |  |  |  |  | 
| 1041 |  |  |  |  |  |  | /* on the systems I have sizeof(float) == sizeof(int) and thus | 
| 1042 |  |  |  |  |  |  | this would be same size as the arrays xo and yo point at, but this | 
| 1043 |  |  |  |  |  |  | may not be true for other systems | 
| 1044 |  |  |  |  |  |  |  | 
| 1045 |  |  |  |  |  |  | since the arrays here are caller controlled, I assume that on | 
| 1046 |  |  |  |  |  |  | overflow is a programming error rather than an end-user error, so | 
| 1047 |  |  |  |  |  |  | calling exit() is justified. | 
| 1048 |  |  |  |  |  |  | */ | 
| 1049 | 1 |  |  |  |  |  | bytes = sizeof(double) * num; | 
| 1050 | 1 | 50 |  |  |  |  | if (bytes / num != sizeof(double)) { | 
| 1051 | 0 |  |  |  |  |  | fprintf(stderr, "integer overflow calculating memory allocation"); | 
| 1052 | 0 |  |  |  |  |  | exit(1); | 
| 1053 |  |  |  |  |  |  | } | 
| 1054 | 1 |  |  |  |  |  | fdist = mymalloc( bytes ); /* checked 14jul05 tonyc */ | 
| 1055 |  |  |  |  |  |  |  | 
| 1056 | 22651 | 100 |  |  |  |  | for(y = 0; y | 
|  |  | 100 |  |  |  |  |  | 
| 1057 | 22500 |  |  |  |  |  | double cs = 0; | 
| 1058 | 22500 |  |  |  |  |  | double csd = 0; | 
| 1059 | 90000 | 100 |  |  |  |  | for(p = 0; p | 
| 1060 | 67500 |  |  |  |  |  | i_img_dim xd    = x-xo[p]; | 
| 1061 | 67500 |  |  |  |  |  | i_img_dim yd    = y-yo[p]; | 
| 1062 | 67500 |  |  |  |  |  | switch (dmeasure) { | 
| 1063 |  |  |  |  |  |  | case 0: /* euclidean */ | 
| 1064 | 0 |  |  |  |  |  | fdist[p]  = sqrt(xd*xd + yd*yd); /* euclidean distance */ | 
| 1065 | 0 |  |  |  |  |  | break; | 
| 1066 |  |  |  |  |  |  | case 1: /* euclidean squared */ | 
| 1067 | 67500 |  |  |  |  |  | fdist[p]  = xd*xd + yd*yd; /* euclidean distance */ | 
| 1068 | 67500 |  |  |  |  |  | break; | 
| 1069 |  |  |  |  |  |  | case 2: /* euclidean squared */ | 
| 1070 | 0 |  |  |  |  |  | fdist[p]  = i_max(xd*xd, yd*yd); /* manhattan distance */ | 
| 1071 | 0 |  |  |  |  |  | break; | 
| 1072 |  |  |  |  |  |  | default: | 
| 1073 | 0 |  |  |  |  |  | im_fatal(aIMCTX, 3,"i_gradgen: Unknown distance measure\n"); | 
| 1074 |  |  |  |  |  |  | } | 
| 1075 | 67500 |  |  |  |  |  | cs += fdist[p]; | 
| 1076 |  |  |  |  |  |  | } | 
| 1077 |  |  |  |  |  |  |  | 
| 1078 | 22500 |  |  |  |  |  | csd = 1/((num-1)*cs); | 
| 1079 |  |  |  |  |  |  |  | 
| 1080 | 90000 | 100 |  |  |  |  | for(p = 0; p | 
| 1081 |  |  |  |  |  |  |  | 
| 1082 | 90000 | 100 |  |  |  |  | for(ch = 0; ch | 
| 1083 | 67500 |  |  |  |  |  | int tres = 0; | 
| 1084 | 270000 | 100 |  |  |  |  | for(p = 0; p | 
| 1085 | 67500 |  |  |  |  |  | val.channel[ch] = saturate(tres); | 
| 1086 |  |  |  |  |  |  | } | 
| 1087 | 22500 |  |  |  |  |  | i_ppix(im, x, y, &val); | 
| 1088 |  |  |  |  |  |  | } | 
| 1089 | 1 |  |  |  |  |  | myfree(fdist); | 
| 1090 |  |  |  |  |  |  |  | 
| 1091 | 1 |  |  |  |  |  | } | 
| 1092 |  |  |  |  |  |  |  | 
| 1093 |  |  |  |  |  |  | void | 
| 1094 | 1 |  |  |  |  |  | i_nearest_color_foo(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure) { | 
| 1095 |  |  |  |  |  |  |  | 
| 1096 |  |  |  |  |  |  | int p; | 
| 1097 |  |  |  |  |  |  | i_img_dim x, y; | 
| 1098 | 1 |  |  |  |  |  | i_img_dim xsize    = im->xsize; | 
| 1099 | 1 |  |  |  |  |  | i_img_dim ysize    = im->ysize; | 
| 1100 | 1 |  |  |  |  |  | dIMCTXim(im); | 
| 1101 |  |  |  |  |  |  |  | 
| 1102 | 1 |  |  |  |  |  | im_log((aIMCTX,1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure)); | 
| 1103 |  |  |  |  |  |  |  | 
| 1104 | 4 | 100 |  |  |  |  | for(p = 0; p | 
| 1105 | 3 |  |  |  |  |  | im_log((aIMCTX, 1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p]))); | 
| 1106 | 3 |  |  |  |  |  | ICL_info(&ival[p]); | 
| 1107 |  |  |  |  |  |  | } | 
| 1108 |  |  |  |  |  |  |  | 
| 1109 | 22651 | 100 |  |  |  |  | for(y = 0; y | 
|  |  | 100 |  |  |  |  |  | 
| 1110 | 22500 |  |  |  |  |  | int    midx    = 0; | 
| 1111 | 22500 |  |  |  |  |  | double mindist = 0; | 
| 1112 | 22500 |  |  |  |  |  | double curdist = 0; | 
| 1113 |  |  |  |  |  |  |  | 
| 1114 | 22500 |  |  |  |  |  | i_img_dim xd        = x-xo[0]; | 
| 1115 | 22500 |  |  |  |  |  | i_img_dim yd        = y-yo[0]; | 
| 1116 |  |  |  |  |  |  |  | 
| 1117 | 22500 |  |  |  |  |  | switch (dmeasure) { | 
| 1118 |  |  |  |  |  |  | case 0: /* euclidean */ | 
| 1119 | 0 |  |  |  |  |  | mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */ | 
| 1120 | 0 |  |  |  |  |  | break; | 
| 1121 |  |  |  |  |  |  | case 1: /* euclidean squared */ | 
| 1122 | 22500 |  |  |  |  |  | mindist = xd*xd + yd*yd; /* euclidean distance */ | 
| 1123 | 22500 |  |  |  |  |  | break; | 
| 1124 |  |  |  |  |  |  | case 2: /* euclidean squared */ | 
| 1125 | 0 |  |  |  |  |  | mindist = i_max(xd*xd, yd*yd); /* manhattan distance */ | 
| 1126 | 0 |  |  |  |  |  | break; | 
| 1127 |  |  |  |  |  |  | default: | 
| 1128 | 0 |  |  |  |  |  | im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n"); | 
| 1129 |  |  |  |  |  |  | } | 
| 1130 |  |  |  |  |  |  |  | 
| 1131 | 67500 | 100 |  |  |  |  | for(p = 1; p | 
| 1132 | 45000 |  |  |  |  |  | xd = x-xo[p]; | 
| 1133 | 45000 |  |  |  |  |  | yd = y-yo[p]; | 
| 1134 | 45000 |  |  |  |  |  | switch (dmeasure) { | 
| 1135 |  |  |  |  |  |  | case 0: /* euclidean */ | 
| 1136 | 0 |  |  |  |  |  | curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */ | 
| 1137 | 0 |  |  |  |  |  | break; | 
| 1138 |  |  |  |  |  |  | case 1: /* euclidean squared */ | 
| 1139 | 45000 |  |  |  |  |  | curdist = xd*xd + yd*yd; /* euclidean distance */ | 
| 1140 | 45000 |  |  |  |  |  | break; | 
| 1141 |  |  |  |  |  |  | case 2: /* euclidean squared */ | 
| 1142 | 0 |  |  |  |  |  | curdist = i_max(xd*xd, yd*yd); /* manhattan distance */ | 
| 1143 | 0 |  |  |  |  |  | break; | 
| 1144 |  |  |  |  |  |  | default: | 
| 1145 | 0 |  |  |  |  |  | im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n"); | 
| 1146 |  |  |  |  |  |  | } | 
| 1147 | 45000 | 100 |  |  |  |  | if (curdist < mindist) { | 
| 1148 | 23182 |  |  |  |  |  | mindist = curdist; | 
| 1149 | 23182 |  |  |  |  |  | midx = p; | 
| 1150 |  |  |  |  |  |  | } | 
| 1151 |  |  |  |  |  |  | } | 
| 1152 | 22500 |  |  |  |  |  | i_ppix(im, x, y, &ival[midx]); | 
| 1153 |  |  |  |  |  |  | } | 
| 1154 | 1 |  |  |  |  |  | } | 
| 1155 |  |  |  |  |  |  |  | 
| 1156 |  |  |  |  |  |  | /* | 
| 1157 |  |  |  |  |  |  | =item i_nearest_color(im, num, xo, yo, oval, dmeasure) | 
| 1158 |  |  |  |  |  |  |  | 
| 1159 |  |  |  |  |  |  | This wasn't document - quoth Addi: | 
| 1160 |  |  |  |  |  |  |  | 
| 1161 |  |  |  |  |  |  | An arty type of filter | 
| 1162 |  |  |  |  |  |  |  | 
| 1163 |  |  |  |  |  |  | FIXME: check IRC logs for actual text. | 
| 1164 |  |  |  |  |  |  |  | 
| 1165 |  |  |  |  |  |  | Inputs: | 
| 1166 |  |  |  |  |  |  |  | 
| 1167 |  |  |  |  |  |  | =over | 
| 1168 |  |  |  |  |  |  |  | 
| 1169 |  |  |  |  |  |  | =item * | 
| 1170 |  |  |  |  |  |  |  | 
| 1171 |  |  |  |  |  |  | i_img *im - image to render on. | 
| 1172 |  |  |  |  |  |  |  | 
| 1173 |  |  |  |  |  |  | =item * | 
| 1174 |  |  |  |  |  |  |  | 
| 1175 |  |  |  |  |  |  | int num - number of points/colors in xo, yo, oval | 
| 1176 |  |  |  |  |  |  |  | 
| 1177 |  |  |  |  |  |  | =item * | 
| 1178 |  |  |  |  |  |  |  | 
| 1179 |  |  |  |  |  |  | i_img_dim *xo - array of I x positions | 
| 1180 |  |  |  |  |  |  |  | 
| 1181 |  |  |  |  |  |  | =item * | 
| 1182 |  |  |  |  |  |  |  | 
| 1183 |  |  |  |  |  |  | i_img_dim *yo - array of I y positions | 
| 1184 |  |  |  |  |  |  |  | 
| 1185 |  |  |  |  |  |  | =item * | 
| 1186 |  |  |  |  |  |  |  | 
| 1187 |  |  |  |  |  |  | i_color *oval - array of I colors | 
| 1188 |  |  |  |  |  |  |  | 
| 1189 |  |  |  |  |  |  | xo, yo, oval correspond to each other, the point xo[i], yo[i] has a | 
| 1190 |  |  |  |  |  |  | color something like oval[i], at least closer to that color than other | 
| 1191 |  |  |  |  |  |  | points. | 
| 1192 |  |  |  |  |  |  |  | 
| 1193 |  |  |  |  |  |  | =item * | 
| 1194 |  |  |  |  |  |  |  | 
| 1195 |  |  |  |  |  |  | int dmeasure - how we measure the distance from some point P(x,y) to | 
| 1196 |  |  |  |  |  |  | any (xo[i], yo[i]). | 
| 1197 |  |  |  |  |  |  |  | 
| 1198 |  |  |  |  |  |  | Valid values are: | 
| 1199 |  |  |  |  |  |  |  | 
| 1200 |  |  |  |  |  |  | =over | 
| 1201 |  |  |  |  |  |  |  | 
| 1202 |  |  |  |  |  |  | =item 0 | 
| 1203 |  |  |  |  |  |  |  | 
| 1204 |  |  |  |  |  |  | euclidean distance: sqrt((x2-x1)**2 + (y2-y1)**2) | 
| 1205 |  |  |  |  |  |  |  | 
| 1206 |  |  |  |  |  |  | =item 1 | 
| 1207 |  |  |  |  |  |  |  | 
| 1208 |  |  |  |  |  |  | square of euclidean distance: ((x2-x1)**2 + (y2-y1)**2) | 
| 1209 |  |  |  |  |  |  |  | 
| 1210 |  |  |  |  |  |  | =item 2 | 
| 1211 |  |  |  |  |  |  |  | 
| 1212 |  |  |  |  |  |  | manhattan distance: max((y2-y1)**2, (x2-x1)**2) | 
| 1213 |  |  |  |  |  |  |  | 
| 1214 |  |  |  |  |  |  | =back | 
| 1215 |  |  |  |  |  |  |  | 
| 1216 |  |  |  |  |  |  | An invalid value causes an error exit (the program is aborted). | 
| 1217 |  |  |  |  |  |  |  | 
| 1218 |  |  |  |  |  |  | =back | 
| 1219 |  |  |  |  |  |  |  | 
| 1220 |  |  |  |  |  |  | =cut | 
| 1221 |  |  |  |  |  |  | */ | 
| 1222 |  |  |  |  |  |  |  | 
| 1223 |  |  |  |  |  |  | int | 
| 1224 | 1 |  |  |  |  |  | i_nearest_color(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *oval, int dmeasure) { | 
| 1225 |  |  |  |  |  |  | i_color *ival; | 
| 1226 |  |  |  |  |  |  | float *tval; | 
| 1227 |  |  |  |  |  |  | double c1, c2; | 
| 1228 |  |  |  |  |  |  | i_color val; | 
| 1229 |  |  |  |  |  |  | int p, ch; | 
| 1230 |  |  |  |  |  |  | i_img_dim x, y; | 
| 1231 | 1 |  |  |  |  |  | i_img_dim xsize    = im->xsize; | 
| 1232 | 1 |  |  |  |  |  | i_img_dim ysize    = im->ysize; | 
| 1233 |  |  |  |  |  |  | int *cmatch; | 
| 1234 |  |  |  |  |  |  | size_t ival_bytes, tval_bytes; | 
| 1235 | 1 |  |  |  |  |  | dIMCTXim(im); | 
| 1236 |  |  |  |  |  |  |  | 
| 1237 | 1 |  |  |  |  |  | im_log((aIMCTX, 1,"i_nearest_color(im %p, num %d, xo %p, yo %p, oval %p, dmeasure %d)\n", im, num, xo, yo, oval, dmeasure)); | 
| 1238 |  |  |  |  |  |  |  | 
| 1239 | 1 |  |  |  |  |  | i_clear_error(); | 
| 1240 |  |  |  |  |  |  |  | 
| 1241 | 1 | 50 |  |  |  |  | if (num <= 0) { | 
| 1242 | 0 |  |  |  |  |  | i_push_error(0, "no points supplied to nearest_color filter"); | 
| 1243 | 0 |  |  |  |  |  | return 0; | 
| 1244 |  |  |  |  |  |  | } | 
| 1245 |  |  |  |  |  |  |  | 
| 1246 | 1 | 50 |  |  |  |  | if (dmeasure < 0 || dmeasure > i_dmeasure_limit) { | 
|  |  | 50 |  |  |  |  |  | 
| 1247 | 0 |  |  |  |  |  | i_push_error(0, "distance measure invalid"); | 
| 1248 | 0 |  |  |  |  |  | return 0; | 
| 1249 |  |  |  |  |  |  | } | 
| 1250 |  |  |  |  |  |  |  | 
| 1251 | 1 |  |  |  |  |  | tval_bytes = sizeof(float)*num*im->channels; | 
| 1252 | 1 | 50 |  |  |  |  | if (tval_bytes / num != sizeof(float) * im->channels) { | 
| 1253 | 0 |  |  |  |  |  | i_push_error(0, "integer overflow calculating memory allocation"); | 
| 1254 | 0 |  |  |  |  |  | return 0; | 
| 1255 |  |  |  |  |  |  | } | 
| 1256 | 1 |  |  |  |  |  | ival_bytes  = sizeof(i_color) * num; | 
| 1257 | 1 | 50 |  |  |  |  | if (ival_bytes / sizeof(i_color) != num) { | 
| 1258 | 0 |  |  |  |  |  | i_push_error(0, "integer overflow calculating memory allocation"); | 
| 1259 | 0 |  |  |  |  |  | return 0; | 
| 1260 |  |  |  |  |  |  | } | 
| 1261 | 1 |  |  |  |  |  | tval   = mymalloc( tval_bytes ); /* checked 17feb2005 tonyc */ | 
| 1262 | 1 |  |  |  |  |  | ival   = mymalloc( ival_bytes ); /* checked 17feb2005 tonyc */ | 
| 1263 | 1 |  |  |  |  |  | cmatch = mymalloc( sizeof(int)*num     ); /* checked 17feb2005 tonyc */ | 
| 1264 |  |  |  |  |  |  |  | 
| 1265 | 4 | 100 |  |  |  |  | for(p = 0; p | 
| 1266 | 12 | 100 |  |  |  |  | for(ch = 0; chchannels; ch++) tval[ p * im->channels + ch] = 0; | 
| 1267 | 3 |  |  |  |  |  | cmatch[p] = 0; | 
| 1268 |  |  |  |  |  |  | } | 
| 1269 |  |  |  |  |  |  |  | 
| 1270 |  |  |  |  |  |  |  | 
| 1271 | 22651 | 100 |  |  |  |  | for(y = 0; y | 
|  |  | 100 |  |  |  |  |  | 
| 1272 | 22500 |  |  |  |  |  | int   midx    = 0; | 
| 1273 | 22500 |  |  |  |  |  | double mindist = 0; | 
| 1274 | 22500 |  |  |  |  |  | double curdist = 0; | 
| 1275 |  |  |  |  |  |  |  | 
| 1276 | 22500 |  |  |  |  |  | i_img_dim xd        = x-xo[0]; | 
| 1277 | 22500 |  |  |  |  |  | i_img_dim yd        = y-yo[0]; | 
| 1278 |  |  |  |  |  |  |  | 
| 1279 | 22500 |  |  |  |  |  | switch (dmeasure) { | 
| 1280 |  |  |  |  |  |  | case 0: /* euclidean */ | 
| 1281 | 0 |  |  |  |  |  | mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */ | 
| 1282 | 0 |  |  |  |  |  | break; | 
| 1283 |  |  |  |  |  |  | case 1: /* euclidean squared */ | 
| 1284 | 22500 |  |  |  |  |  | mindist = xd*xd + yd*yd; /* euclidean distance */ | 
| 1285 | 22500 |  |  |  |  |  | break; | 
| 1286 |  |  |  |  |  |  | case 2: /* manhatten distance */ | 
| 1287 | 0 |  |  |  |  |  | mindist = i_max(xd*xd, yd*yd); /* manhattan distance */ | 
| 1288 | 0 |  |  |  |  |  | break; | 
| 1289 |  |  |  |  |  |  | default: | 
| 1290 | 0 |  |  |  |  |  | im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n"); | 
| 1291 |  |  |  |  |  |  | } | 
| 1292 |  |  |  |  |  |  |  | 
| 1293 | 67500 | 100 |  |  |  |  | for(p = 1; p | 
| 1294 | 45000 |  |  |  |  |  | xd = x-xo[p]; | 
| 1295 | 45000 |  |  |  |  |  | yd = y-yo[p]; | 
| 1296 | 45000 |  |  |  |  |  | switch (dmeasure) { | 
| 1297 |  |  |  |  |  |  | case 0: /* euclidean */ | 
| 1298 | 0 |  |  |  |  |  | curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */ | 
| 1299 | 0 |  |  |  |  |  | break; | 
| 1300 |  |  |  |  |  |  | case 1: /* euclidean squared */ | 
| 1301 | 45000 |  |  |  |  |  | curdist = xd*xd + yd*yd; /* euclidean distance */ | 
| 1302 | 45000 |  |  |  |  |  | break; | 
| 1303 |  |  |  |  |  |  | case 2: /* euclidean squared */ | 
| 1304 | 0 |  |  |  |  |  | curdist = i_max(xd*xd, yd*yd); /* manhattan distance */ | 
| 1305 | 0 |  |  |  |  |  | break; | 
| 1306 |  |  |  |  |  |  | default: | 
| 1307 | 0 |  |  |  |  |  | im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n"); | 
| 1308 |  |  |  |  |  |  | } | 
| 1309 | 45000 | 100 |  |  |  |  | if (curdist < mindist) { | 
| 1310 | 23182 |  |  |  |  |  | mindist = curdist; | 
| 1311 | 23182 |  |  |  |  |  | midx = p; | 
| 1312 |  |  |  |  |  |  | } | 
| 1313 |  |  |  |  |  |  | } | 
| 1314 |  |  |  |  |  |  |  | 
| 1315 | 22500 |  |  |  |  |  | cmatch[midx]++; | 
| 1316 | 22500 |  |  |  |  |  | i_gpix(im, x, y, &val); | 
| 1317 | 22500 |  |  |  |  |  | c2 = 1.0/(float)(cmatch[midx]); | 
| 1318 | 22500 |  |  |  |  |  | c1 = 1.0-c2; | 
| 1319 |  |  |  |  |  |  |  | 
| 1320 | 90000 | 100 |  |  |  |  | for(ch = 0; chchannels; ch++) | 
| 1321 | 135000 |  |  |  |  |  | tval[midx*im->channels + ch] = | 
| 1322 | 67500 |  |  |  |  |  | c1*tval[midx*im->channels + ch] + c2 * (float) val.channel[ch]; | 
| 1323 |  |  |  |  |  |  |  | 
| 1324 |  |  |  |  |  |  | } | 
| 1325 |  |  |  |  |  |  |  | 
| 1326 | 4 | 100 |  |  |  |  | for(p = 0; p | 
| 1327 | 12 | 100 |  |  |  |  | for(ch = 0; chchannels; ch++) | 
| 1328 | 9 |  |  |  |  |  | ival[p].channel[ch] = tval[p*im->channels + ch]; | 
| 1329 |  |  |  |  |  |  |  | 
| 1330 |  |  |  |  |  |  | /* avoid uninitialized value messages from valgrind */ | 
| 1331 | 6 | 100 |  |  |  |  | while (ch < MAXCHANNELS) | 
| 1332 | 3 |  |  |  |  |  | ival[p].channel[ch++] = 0; | 
| 1333 |  |  |  |  |  |  | } | 
| 1334 |  |  |  |  |  |  |  | 
| 1335 | 1 |  |  |  |  |  | i_nearest_color_foo(im, num, xo, yo, ival, dmeasure); | 
| 1336 |  |  |  |  |  |  |  | 
| 1337 | 1 |  |  |  |  |  | myfree(cmatch); | 
| 1338 | 1 |  |  |  |  |  | myfree(ival); | 
| 1339 | 1 |  |  |  |  |  | myfree(tval); | 
| 1340 |  |  |  |  |  |  |  | 
| 1341 | 1 |  |  |  |  |  | return 1; | 
| 1342 |  |  |  |  |  |  | } | 
| 1343 |  |  |  |  |  |  |  | 
| 1344 |  |  |  |  |  |  | /* | 
| 1345 |  |  |  |  |  |  | =item i_unsharp_mask(im, stddev, scale) | 
| 1346 |  |  |  |  |  |  |  | 
| 1347 |  |  |  |  |  |  | Perform an usharp mask, which is defined as subtracting the blurred | 
| 1348 |  |  |  |  |  |  | image from double the original. | 
| 1349 |  |  |  |  |  |  |  | 
| 1350 |  |  |  |  |  |  | =cut | 
| 1351 |  |  |  |  |  |  | */ | 
| 1352 |  |  |  |  |  |  |  | 
| 1353 |  |  |  |  |  |  | void | 
| 1354 | 1 |  |  |  |  |  | i_unsharp_mask(i_img *im, double stddev, double scale) { | 
| 1355 |  |  |  |  |  |  | i_img *copy; | 
| 1356 |  |  |  |  |  |  | i_img_dim x, y; | 
| 1357 |  |  |  |  |  |  | int ch; | 
| 1358 |  |  |  |  |  |  |  | 
| 1359 | 1 | 50 |  |  |  |  | if (scale < 0) | 
| 1360 | 0 |  |  |  |  |  | return; | 
| 1361 |  |  |  |  |  |  | /* it really shouldn't ever be more than 1.0, but maybe ... */ | 
| 1362 | 1 | 50 |  |  |  |  | if (scale > 100) | 
| 1363 | 0 |  |  |  |  |  | scale = 100; | 
| 1364 |  |  |  |  |  |  |  | 
| 1365 | 1 |  |  |  |  |  | copy = i_copy(im); | 
| 1366 | 1 |  |  |  |  |  | i_gaussian(copy, stddev); | 
| 1367 | 1 | 50 |  |  |  |  | if (im->bits == i_8_bits) { | 
| 1368 | 1 |  |  |  |  |  | i_color *blur = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */ | 
| 1369 | 1 |  |  |  |  |  | i_color *out = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */ | 
| 1370 |  |  |  |  |  |  |  | 
| 1371 | 151 | 100 |  |  |  |  | for (y = 0; y < im->ysize; ++y) { | 
| 1372 | 150 |  |  |  |  |  | i_glin(copy, 0, copy->xsize, y, blur); | 
| 1373 | 150 |  |  |  |  |  | i_glin(im, 0, im->xsize, y, out); | 
| 1374 | 22650 | 100 |  |  |  |  | for (x = 0; x < im->xsize; ++x) { | 
| 1375 | 90000 | 100 |  |  |  |  | for (ch = 0; ch < im->channels; ++ch) { | 
| 1376 |  |  |  |  |  |  | /*int temp = out[x].channel[ch] + | 
| 1377 |  |  |  |  |  |  | scale * (out[x].channel[ch] - blur[x].channel[ch]);*/ | 
| 1378 | 67500 |  |  |  |  |  | int temp = out[x].channel[ch] * 2 - blur[x].channel[ch]; | 
| 1379 | 67500 | 100 |  |  |  |  | if (temp < 0) | 
| 1380 | 4602 |  |  |  |  |  | temp = 0; | 
| 1381 | 62898 | 100 |  |  |  |  | else if (temp > 255) | 
| 1382 | 3167 |  |  |  |  |  | temp = 255; | 
| 1383 | 67500 |  |  |  |  |  | out[x].channel[ch] = temp; | 
| 1384 |  |  |  |  |  |  | } | 
| 1385 |  |  |  |  |  |  | } | 
| 1386 | 150 |  |  |  |  |  | i_plin(im, 0, im->xsize, y, out); | 
| 1387 |  |  |  |  |  |  | } | 
| 1388 |  |  |  |  |  |  |  | 
| 1389 | 1 |  |  |  |  |  | myfree(blur); | 
| 1390 | 1 |  |  |  |  |  | myfree(out); | 
| 1391 |  |  |  |  |  |  | } | 
| 1392 |  |  |  |  |  |  | else { | 
| 1393 | 0 |  |  |  |  |  | i_fcolor *blur = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */ | 
| 1394 | 0 |  |  |  |  |  | i_fcolor *out = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */ | 
| 1395 |  |  |  |  |  |  |  | 
| 1396 | 0 | 0 |  |  |  |  | for (y = 0; y < im->ysize; ++y) { | 
| 1397 | 0 |  |  |  |  |  | i_glinf(copy, 0, copy->xsize, y, blur); | 
| 1398 | 0 |  |  |  |  |  | i_glinf(im, 0, im->xsize, y, out); | 
| 1399 | 0 | 0 |  |  |  |  | for (x = 0; x < im->xsize; ++x) { | 
| 1400 | 0 | 0 |  |  |  |  | for (ch = 0; ch < im->channels; ++ch) { | 
| 1401 | 0 |  |  |  |  |  | double temp = out[x].channel[ch] + | 
| 1402 | 0 |  |  |  |  |  | scale * (out[x].channel[ch] - blur[x].channel[ch]); | 
| 1403 | 0 | 0 |  |  |  |  | if (temp < 0) | 
| 1404 | 0 |  |  |  |  |  | temp = 0; | 
| 1405 | 0 | 0 |  |  |  |  | else if (temp > 1.0) | 
| 1406 | 0 |  |  |  |  |  | temp = 1.0; | 
| 1407 | 0 |  |  |  |  |  | out[x].channel[ch] = temp; | 
| 1408 |  |  |  |  |  |  | } | 
| 1409 |  |  |  |  |  |  | } | 
| 1410 | 0 |  |  |  |  |  | i_plinf(im, 0, im->xsize, y, out); | 
| 1411 |  |  |  |  |  |  | } | 
| 1412 |  |  |  |  |  |  |  | 
| 1413 | 0 |  |  |  |  |  | myfree(blur); | 
| 1414 | 0 |  |  |  |  |  | myfree(out); | 
| 1415 |  |  |  |  |  |  | } | 
| 1416 | 1 |  |  |  |  |  | i_img_destroy(copy); | 
| 1417 |  |  |  |  |  |  | } | 
| 1418 |  |  |  |  |  |  |  | 
| 1419 |  |  |  |  |  |  | /* | 
| 1420 |  |  |  |  |  |  | =item i_diff_image(im1, im2, mindist) | 
| 1421 |  |  |  |  |  |  |  | 
| 1422 |  |  |  |  |  |  | Creates a new image that is transparent, except where the pixel in im2 | 
| 1423 |  |  |  |  |  |  | is different from im1, where it is the pixel from im2. | 
| 1424 |  |  |  |  |  |  |  | 
| 1425 |  |  |  |  |  |  | The samples must differ by at least mindiff to be considered different. | 
| 1426 |  |  |  |  |  |  |  | 
| 1427 |  |  |  |  |  |  | =cut | 
| 1428 |  |  |  |  |  |  | */ | 
| 1429 |  |  |  |  |  |  |  | 
| 1430 |  |  |  |  |  |  | i_img * | 
| 1431 | 5 |  |  |  |  |  | i_diff_image(i_img *im1, i_img *im2, double mindist) { | 
| 1432 |  |  |  |  |  |  | i_img *out; | 
| 1433 |  |  |  |  |  |  | int outchans, diffchans; | 
| 1434 |  |  |  |  |  |  | i_img_dim xsize, ysize; | 
| 1435 | 5 |  |  |  |  |  | dIMCTXim(im1); | 
| 1436 |  |  |  |  |  |  |  | 
| 1437 | 5 |  |  |  |  |  | i_clear_error(); | 
| 1438 | 5 | 50 |  |  |  |  | if (im1->channels != im2->channels) { | 
| 1439 | 0 |  |  |  |  |  | i_push_error(0, "different number of channels"); | 
| 1440 | 0 |  |  |  |  |  | return NULL; | 
| 1441 |  |  |  |  |  |  | } | 
| 1442 |  |  |  |  |  |  |  | 
| 1443 | 5 |  |  |  |  |  | outchans = diffchans = im1->channels; | 
| 1444 | 5 | 50 |  |  |  |  | if (outchans == 1 || outchans == 3) | 
|  |  | 50 |  |  |  |  |  | 
| 1445 | 5 |  |  |  |  |  | ++outchans; | 
| 1446 |  |  |  |  |  |  |  | 
| 1447 | 5 |  |  |  |  |  | xsize = i_min(im1->xsize, im2->xsize); | 
| 1448 | 5 |  |  |  |  |  | ysize = i_min(im1->ysize, im2->ysize); | 
| 1449 |  |  |  |  |  |  |  | 
| 1450 | 5 |  |  |  |  |  | out = i_sametype_chans(im1, xsize, ysize, outchans); | 
| 1451 |  |  |  |  |  |  |  | 
| 1452 | 8 | 100 |  |  |  |  | if (im1->bits == i_8_bits && im2->bits == i_8_bits) { | 
|  |  | 50 |  |  |  |  |  | 
| 1453 | 3 |  |  |  |  |  | i_color *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */ | 
| 1454 | 3 |  |  |  |  |  | i_color *line2 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */ | 
| 1455 |  |  |  |  |  |  | i_color empty; | 
| 1456 |  |  |  |  |  |  | i_img_dim x, y; | 
| 1457 |  |  |  |  |  |  | int ch; | 
| 1458 | 3 |  |  |  |  |  | int imindist = (int)mindist; | 
| 1459 |  |  |  |  |  |  |  | 
| 1460 | 15 | 100 |  |  |  |  | for (ch = 0; ch < MAXCHANNELS; ++ch) | 
| 1461 | 12 |  |  |  |  |  | empty.channel[ch] = 0; | 
| 1462 |  |  |  |  |  |  |  | 
| 1463 | 157 | 100 |  |  |  |  | for (y = 0; y < ysize; ++y) { | 
| 1464 | 154 |  |  |  |  |  | i_glin(im1, 0, xsize, y, line1); | 
| 1465 | 154 |  |  |  |  |  | i_glin(im2, 0, xsize, y, line2); | 
| 1466 | 154 | 50 |  |  |  |  | if (outchans != diffchans) { | 
| 1467 |  |  |  |  |  |  | /* give the output an alpha channel since it doesn't have one */ | 
| 1468 | 22666 | 100 |  |  |  |  | for (x = 0; x < xsize; ++x) | 
| 1469 | 22512 |  |  |  |  |  | line2[x].channel[diffchans] = 255; | 
| 1470 |  |  |  |  |  |  | } | 
| 1471 | 22666 | 100 |  |  |  |  | for (x = 0; x < xsize; ++x) { | 
| 1472 | 22512 |  |  |  |  |  | int diff = 0; | 
| 1473 | 88719 | 100 |  |  |  |  | for (ch = 0; ch < diffchans; ++ch) { | 
| 1474 | 66651 | 100 |  |  |  |  | if (line1[x].channel[ch] != line2[x].channel[ch] | 
| 1475 | 445 | 100 |  |  |  |  | && abs(line1[x].channel[ch] - line2[x].channel[ch]) > imindist) { | 
| 1476 | 444 |  |  |  |  |  | diff = 1; | 
| 1477 | 444 |  |  |  |  |  | break; | 
| 1478 |  |  |  |  |  |  | } | 
| 1479 |  |  |  |  |  |  | } | 
| 1480 | 22512 | 100 |  |  |  |  | if (!diff) | 
| 1481 | 22068 |  |  |  |  |  | line2[x] = empty; | 
| 1482 |  |  |  |  |  |  | } | 
| 1483 | 154 |  |  |  |  |  | i_plin(out, 0, xsize, y, line2); | 
| 1484 |  |  |  |  |  |  | } | 
| 1485 | 3 |  |  |  |  |  | myfree(line1); | 
| 1486 | 3 |  |  |  |  |  | myfree(line2); | 
| 1487 |  |  |  |  |  |  | } | 
| 1488 |  |  |  |  |  |  | else { | 
| 1489 | 2 |  |  |  |  |  | i_fcolor *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */ | 
| 1490 | 2 |  |  |  |  |  | i_fcolor *line2 = mymalloc(xsize * sizeof(*line2)); /* checked 17feb2005 tonyc */ | 
| 1491 |  |  |  |  |  |  | i_fcolor empty; | 
| 1492 |  |  |  |  |  |  | i_img_dim x, y; | 
| 1493 |  |  |  |  |  |  | int ch; | 
| 1494 | 2 |  |  |  |  |  | double dist = mindist / 255.0; | 
| 1495 |  |  |  |  |  |  |  | 
| 1496 | 10 | 100 |  |  |  |  | for (ch = 0; ch < MAXCHANNELS; ++ch) | 
| 1497 | 8 |  |  |  |  |  | empty.channel[ch] = 0; | 
| 1498 |  |  |  |  |  |  |  | 
| 1499 | 6 | 100 |  |  |  |  | for (y = 0; y < ysize; ++y) { | 
| 1500 | 4 |  |  |  |  |  | i_glinf(im1, 0, xsize, y, line1); | 
| 1501 | 4 |  |  |  |  |  | i_glinf(im2, 0, xsize, y, line2); | 
| 1502 | 4 | 50 |  |  |  |  | if (outchans != diffchans) { | 
| 1503 |  |  |  |  |  |  | /* give the output an alpha channel since it doesn't have one */ | 
| 1504 | 16 | 100 |  |  |  |  | for (x = 0; x < xsize; ++x) | 
| 1505 | 12 |  |  |  |  |  | line2[x].channel[diffchans] = 1.0; | 
| 1506 |  |  |  |  |  |  | } | 
| 1507 | 16 | 100 |  |  |  |  | for (x = 0; x < xsize; ++x) { | 
| 1508 | 12 |  |  |  |  |  | int diff = 0; | 
| 1509 | 42 | 100 |  |  |  |  | for (ch = 0; ch < diffchans; ++ch) { | 
| 1510 | 33 | 100 |  |  |  |  | if (line1[x].channel[ch] != line2[x].channel[ch] | 
| 1511 | 4 | 100 |  |  |  |  | && fabs(line1[x].channel[ch] - line2[x].channel[ch]) > dist) { | 
| 1512 | 3 |  |  |  |  |  | diff = 1; | 
| 1513 | 3 |  |  |  |  |  | break; | 
| 1514 |  |  |  |  |  |  | } | 
| 1515 |  |  |  |  |  |  | } | 
| 1516 | 12 | 100 |  |  |  |  | if (!diff) | 
| 1517 | 9 |  |  |  |  |  | line2[x] = empty; | 
| 1518 |  |  |  |  |  |  | } | 
| 1519 | 4 |  |  |  |  |  | i_plinf(out, 0, xsize, y, line2); | 
| 1520 |  |  |  |  |  |  | } | 
| 1521 | 2 |  |  |  |  |  | myfree(line1); | 
| 1522 | 2 |  |  |  |  |  | myfree(line2); | 
| 1523 |  |  |  |  |  |  | } | 
| 1524 |  |  |  |  |  |  |  | 
| 1525 | 5 |  |  |  |  |  | return out; | 
| 1526 |  |  |  |  |  |  | } | 
| 1527 |  |  |  |  |  |  |  | 
| 1528 |  |  |  |  |  |  | /* | 
| 1529 |  |  |  |  |  |  | =item i_rgbdiff_image(im1, im2) | 
| 1530 |  |  |  |  |  |  |  | 
| 1531 |  |  |  |  |  |  | Creates a new image that is black, except where the pixel in im2 is | 
| 1532 |  |  |  |  |  |  | different from im1, where it is the arithmetical difference to im2 per | 
| 1533 |  |  |  |  |  |  | color. | 
| 1534 |  |  |  |  |  |  |  | 
| 1535 |  |  |  |  |  |  | =cut | 
| 1536 |  |  |  |  |  |  | */ | 
| 1537 |  |  |  |  |  |  |  | 
| 1538 |  |  |  |  |  |  | i_img * | 
| 1539 | 1 |  |  |  |  |  | i_rgbdiff_image(i_img *im1, i_img *im2) { | 
| 1540 |  |  |  |  |  |  | i_img *out; | 
| 1541 |  |  |  |  |  |  | int outchans, diffchans; | 
| 1542 |  |  |  |  |  |  | i_img_dim xsize, ysize; | 
| 1543 | 1 |  |  |  |  |  | dIMCTXim(im1); | 
| 1544 |  |  |  |  |  |  |  | 
| 1545 | 1 |  |  |  |  |  | i_clear_error(); | 
| 1546 | 1 | 50 |  |  |  |  | if (im1->channels != im2->channels) { | 
| 1547 | 0 |  |  |  |  |  | i_push_error(0, "different number of channels"); | 
| 1548 | 0 |  |  |  |  |  | return NULL; | 
| 1549 |  |  |  |  |  |  | } | 
| 1550 |  |  |  |  |  |  |  | 
| 1551 | 1 |  |  |  |  |  | outchans = diffchans = im1->channels; | 
| 1552 | 1 | 50 |  |  |  |  | if (outchans == 2 || outchans == 4) | 
|  |  | 50 |  |  |  |  |  | 
| 1553 | 1 |  |  |  |  |  | --outchans; | 
| 1554 |  |  |  |  |  |  |  | 
| 1555 | 1 |  |  |  |  |  | xsize = i_min(im1->xsize, im2->xsize); | 
| 1556 | 1 |  |  |  |  |  | ysize = i_min(im1->ysize, im2->ysize); | 
| 1557 |  |  |  |  |  |  |  | 
| 1558 | 1 |  |  |  |  |  | out = i_sametype_chans(im1, xsize, ysize, outchans); | 
| 1559 |  |  |  |  |  |  |  | 
| 1560 | 2 | 50 |  |  |  |  | #code im1->bits == i_8_bits && im2->bits == i_8_bits | 
|  |  | 50 |  |  |  |  |  | 
| 1561 | 1 |  |  |  |  |  | IM_COLOR *line1 = mymalloc(xsize * sizeof(*line1)); | 
| 1562 | 1 |  |  |  |  |  | IM_COLOR *line2 = mymalloc(xsize * sizeof(*line1)); | 
| 1563 |  |  |  |  |  |  | i_img_dim x, y; | 
| 1564 |  |  |  |  |  |  | int ch; | 
| 1565 |  |  |  |  |  |  |  | 
| 1566 | 3 | 100 |  |  |  |  | for (y = 0; y < ysize; ++y) { | 
|  |  | 0 |  |  |  |  |  | 
| 1567 | 2 |  |  |  |  |  | IM_GLIN(im1, 0, xsize, y, line1); | 
| 1568 | 2 |  |  |  |  |  | IM_GLIN(im2, 0, xsize, y, line2); | 
| 1569 | 8 | 100 |  |  |  |  | for (x = 0; x < xsize; ++x) { | 
|  |  | 0 |  |  |  |  |  | 
| 1570 | 24 | 100 |  |  |  |  | for (ch = 0; ch < outchans; ++ch) { | 
|  |  | 0 |  |  |  |  |  | 
| 1571 | 18 |  |  |  |  |  | line2[x].channel[ch] = IM_ABS(line1[x].channel[ch] - line2[x].channel[ch]); | 
| 1572 |  |  |  |  |  |  | } | 
| 1573 |  |  |  |  |  |  | } | 
| 1574 | 2 |  |  |  |  |  | IM_PLIN(out, 0, xsize, y, line2); | 
| 1575 |  |  |  |  |  |  | } | 
| 1576 | 1 |  |  |  |  |  | myfree(line1); | 
| 1577 | 1 |  |  |  |  |  | myfree(line2); | 
| 1578 |  |  |  |  |  |  | #/code | 
| 1579 |  |  |  |  |  |  |  | 
| 1580 | 1 |  |  |  |  |  | return out; | 
| 1581 |  |  |  |  |  |  | } | 
| 1582 |  |  |  |  |  |  |  | 
| 1583 |  |  |  |  |  |  | struct fount_state; | 
| 1584 |  |  |  |  |  |  | static double linear_fount_f(double x, double y, struct fount_state *state); | 
| 1585 |  |  |  |  |  |  | static double bilinear_fount_f(double x, double y, struct fount_state *state); | 
| 1586 |  |  |  |  |  |  | static double radial_fount_f(double x, double y, struct fount_state *state); | 
| 1587 |  |  |  |  |  |  | static double square_fount_f(double x, double y, struct fount_state *state); | 
| 1588 |  |  |  |  |  |  | static double revolution_fount_f(double x, double y, | 
| 1589 |  |  |  |  |  |  | struct fount_state *state); | 
| 1590 |  |  |  |  |  |  | static double conical_fount_f(double x, double y, struct fount_state *state); | 
| 1591 |  |  |  |  |  |  |  | 
| 1592 |  |  |  |  |  |  | typedef double (*fount_func)(double, double, struct fount_state *); | 
| 1593 |  |  |  |  |  |  | static fount_func fount_funcs[] = | 
| 1594 |  |  |  |  |  |  | { | 
| 1595 |  |  |  |  |  |  | linear_fount_f, | 
| 1596 |  |  |  |  |  |  | bilinear_fount_f, | 
| 1597 |  |  |  |  |  |  | radial_fount_f, | 
| 1598 |  |  |  |  |  |  | square_fount_f, | 
| 1599 |  |  |  |  |  |  | revolution_fount_f, | 
| 1600 |  |  |  |  |  |  | conical_fount_f, | 
| 1601 |  |  |  |  |  |  | }; | 
| 1602 |  |  |  |  |  |  |  | 
| 1603 |  |  |  |  |  |  | static double linear_interp(double pos, i_fountain_seg *seg); | 
| 1604 |  |  |  |  |  |  | static double sine_interp(double pos, i_fountain_seg *seg); | 
| 1605 |  |  |  |  |  |  | static double sphereup_interp(double pos, i_fountain_seg *seg); | 
| 1606 |  |  |  |  |  |  | static double spheredown_interp(double pos, i_fountain_seg *seg); | 
| 1607 |  |  |  |  |  |  | typedef double (*fount_interp)(double pos, i_fountain_seg *seg); | 
| 1608 |  |  |  |  |  |  | static fount_interp fount_interps[] = | 
| 1609 |  |  |  |  |  |  | { | 
| 1610 |  |  |  |  |  |  | linear_interp, | 
| 1611 |  |  |  |  |  |  | linear_interp, | 
| 1612 |  |  |  |  |  |  | sine_interp, | 
| 1613 |  |  |  |  |  |  | sphereup_interp, | 
| 1614 |  |  |  |  |  |  | spheredown_interp, | 
| 1615 |  |  |  |  |  |  | }; | 
| 1616 |  |  |  |  |  |  |  | 
| 1617 |  |  |  |  |  |  | static void direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg); | 
| 1618 |  |  |  |  |  |  | static void hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg); | 
| 1619 |  |  |  |  |  |  | static void hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg); | 
| 1620 |  |  |  |  |  |  | typedef void (*fount_cinterp)(i_fcolor *out, double pos, i_fountain_seg *seg); | 
| 1621 |  |  |  |  |  |  | static fount_cinterp fount_cinterps[] = | 
| 1622 |  |  |  |  |  |  | { | 
| 1623 |  |  |  |  |  |  | direct_cinterp, | 
| 1624 |  |  |  |  |  |  | hue_up_cinterp, | 
| 1625 |  |  |  |  |  |  | hue_down_cinterp, | 
| 1626 |  |  |  |  |  |  | }; | 
| 1627 |  |  |  |  |  |  |  | 
| 1628 |  |  |  |  |  |  | typedef double (*fount_repeat)(double v); | 
| 1629 |  |  |  |  |  |  | static double fount_r_none(double v); | 
| 1630 |  |  |  |  |  |  | static double fount_r_sawtooth(double v); | 
| 1631 |  |  |  |  |  |  | static double fount_r_triangle(double v); | 
| 1632 |  |  |  |  |  |  | static double fount_r_saw_both(double v); | 
| 1633 |  |  |  |  |  |  | static double fount_r_tri_both(double v); | 
| 1634 |  |  |  |  |  |  | static fount_repeat fount_repeats[] = | 
| 1635 |  |  |  |  |  |  | { | 
| 1636 |  |  |  |  |  |  | fount_r_none, | 
| 1637 |  |  |  |  |  |  | fount_r_sawtooth, | 
| 1638 |  |  |  |  |  |  | fount_r_triangle, | 
| 1639 |  |  |  |  |  |  | fount_r_saw_both, | 
| 1640 |  |  |  |  |  |  | fount_r_tri_both, | 
| 1641 |  |  |  |  |  |  | }; | 
| 1642 |  |  |  |  |  |  |  | 
| 1643 |  |  |  |  |  |  | static int simple_ssample(i_fcolor *out, double x, double y, | 
| 1644 |  |  |  |  |  |  | struct fount_state *state); | 
| 1645 |  |  |  |  |  |  | static int random_ssample(i_fcolor *out, double x, double y, | 
| 1646 |  |  |  |  |  |  | struct fount_state *state); | 
| 1647 |  |  |  |  |  |  | static int circle_ssample(i_fcolor *out, double x, double y, | 
| 1648 |  |  |  |  |  |  | struct fount_state *state); | 
| 1649 |  |  |  |  |  |  | typedef int (*fount_ssample)(i_fcolor *out, double x, double y, | 
| 1650 |  |  |  |  |  |  | struct fount_state *state); | 
| 1651 |  |  |  |  |  |  | static fount_ssample fount_ssamples[] = | 
| 1652 |  |  |  |  |  |  | { | 
| 1653 |  |  |  |  |  |  | NULL, | 
| 1654 |  |  |  |  |  |  | simple_ssample, | 
| 1655 |  |  |  |  |  |  | random_ssample, | 
| 1656 |  |  |  |  |  |  | circle_ssample, | 
| 1657 |  |  |  |  |  |  | }; | 
| 1658 |  |  |  |  |  |  |  | 
| 1659 |  |  |  |  |  |  | static int | 
| 1660 |  |  |  |  |  |  | fount_getat(i_fcolor *out, double x, double y, struct fount_state *state); | 
| 1661 |  |  |  |  |  |  |  | 
| 1662 |  |  |  |  |  |  | /* | 
| 1663 |  |  |  |  |  |  | Keep state information used by each type of fountain fill | 
| 1664 |  |  |  |  |  |  | */ | 
| 1665 |  |  |  |  |  |  | struct fount_state { | 
| 1666 |  |  |  |  |  |  | /* precalculated for the equation of the line perpendicular to the line AB */ | 
| 1667 |  |  |  |  |  |  | double lA, lB, lC; | 
| 1668 |  |  |  |  |  |  | double AB; | 
| 1669 |  |  |  |  |  |  | double sqrtA2B2; | 
| 1670 |  |  |  |  |  |  | double mult; | 
| 1671 |  |  |  |  |  |  | double cos; | 
| 1672 |  |  |  |  |  |  | double sin; | 
| 1673 |  |  |  |  |  |  | double theta; | 
| 1674 |  |  |  |  |  |  | i_img_dim xa, ya; | 
| 1675 |  |  |  |  |  |  | void *ssample_data; | 
| 1676 |  |  |  |  |  |  | fount_func ffunc; | 
| 1677 |  |  |  |  |  |  | fount_repeat rpfunc; | 
| 1678 |  |  |  |  |  |  | fount_ssample ssfunc; | 
| 1679 |  |  |  |  |  |  | double parm; | 
| 1680 |  |  |  |  |  |  | i_fountain_seg *segs; | 
| 1681 |  |  |  |  |  |  | int count; | 
| 1682 |  |  |  |  |  |  | }; | 
| 1683 |  |  |  |  |  |  |  | 
| 1684 |  |  |  |  |  |  | static void | 
| 1685 |  |  |  |  |  |  | fount_init_state(struct fount_state *state, double xa, double ya, | 
| 1686 |  |  |  |  |  |  | double xb, double yb, i_fountain_type type, | 
| 1687 |  |  |  |  |  |  | i_fountain_repeat repeat, int combine, int super_sample, | 
| 1688 |  |  |  |  |  |  | double ssample_param, int count, i_fountain_seg *segs); | 
| 1689 |  |  |  |  |  |  |  | 
| 1690 |  |  |  |  |  |  | static void | 
| 1691 |  |  |  |  |  |  | fount_finish_state(struct fount_state *state); | 
| 1692 |  |  |  |  |  |  |  | 
| 1693 |  |  |  |  |  |  | #define EPSILON (1e-6) | 
| 1694 |  |  |  |  |  |  |  | 
| 1695 |  |  |  |  |  |  | /* | 
| 1696 |  |  |  |  |  |  | =item i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs) | 
| 1697 |  |  |  |  |  |  |  | 
| 1698 |  |  |  |  |  |  | Draws a fountain fill using A(xa, ya) and B(xb, yb) as reference points. | 
| 1699 |  |  |  |  |  |  |  | 
| 1700 |  |  |  |  |  |  | I controls how the reference points are used: | 
| 1701 |  |  |  |  |  |  |  | 
| 1702 |  |  |  |  |  |  | =over | 
| 1703 |  |  |  |  |  |  |  | 
| 1704 |  |  |  |  |  |  | =item i_ft_linear | 
| 1705 |  |  |  |  |  |  |  | 
| 1706 |  |  |  |  |  |  | linear, where A is 0 and B is 1. | 
| 1707 |  |  |  |  |  |  |  | 
| 1708 |  |  |  |  |  |  | =item i_ft_bilinear | 
| 1709 |  |  |  |  |  |  |  | 
| 1710 |  |  |  |  |  |  | linear in both directions from A. | 
| 1711 |  |  |  |  |  |  |  | 
| 1712 |  |  |  |  |  |  | =item i_ft_radial | 
| 1713 |  |  |  |  |  |  |  | 
| 1714 |  |  |  |  |  |  | circular, where A is the centre of the fill, and B is a point | 
| 1715 |  |  |  |  |  |  | on the radius. | 
| 1716 |  |  |  |  |  |  |  | 
| 1717 |  |  |  |  |  |  | =item i_ft_radial_square | 
| 1718 |  |  |  |  |  |  |  | 
| 1719 |  |  |  |  |  |  | where A is the centre of the fill and B is the centre of | 
| 1720 |  |  |  |  |  |  | one side of the square. | 
| 1721 |  |  |  |  |  |  |  | 
| 1722 |  |  |  |  |  |  | =item i_ft_revolution | 
| 1723 |  |  |  |  |  |  |  | 
| 1724 |  |  |  |  |  |  | where A is the centre of the fill and B defines the 0/1.0 | 
| 1725 |  |  |  |  |  |  | angle of the fill. | 
| 1726 |  |  |  |  |  |  |  | 
| 1727 |  |  |  |  |  |  | =item i_ft_conical | 
| 1728 |  |  |  |  |  |  |  | 
| 1729 |  |  |  |  |  |  | similar to i_ft_revolution, except that the revolution goes in both | 
| 1730 |  |  |  |  |  |  | directions | 
| 1731 |  |  |  |  |  |  |  | 
| 1732 |  |  |  |  |  |  | =back | 
| 1733 |  |  |  |  |  |  |  | 
| 1734 |  |  |  |  |  |  | I can be one of: | 
| 1735 |  |  |  |  |  |  |  | 
| 1736 |  |  |  |  |  |  | =over | 
| 1737 |  |  |  |  |  |  |  | 
| 1738 |  |  |  |  |  |  | =item i_fr_none | 
| 1739 |  |  |  |  |  |  |  | 
| 1740 |  |  |  |  |  |  | values < 0 are treated as zero, values > 1 are treated as 1. | 
| 1741 |  |  |  |  |  |  |  | 
| 1742 |  |  |  |  |  |  | =item i_fr_sawtooth | 
| 1743 |  |  |  |  |  |  |  | 
| 1744 |  |  |  |  |  |  | negative values are treated as 0, positive values are modulo 1.0 | 
| 1745 |  |  |  |  |  |  |  | 
| 1746 |  |  |  |  |  |  | =item i_fr_triangle | 
| 1747 |  |  |  |  |  |  |  | 
| 1748 |  |  |  |  |  |  | negative values are treated as zero, if (int)value is odd then the value is treated as 1-(value | 
| 1749 |  |  |  |  |  |  | mod 1.0), otherwise the same as for sawtooth. | 
| 1750 |  |  |  |  |  |  |  | 
| 1751 |  |  |  |  |  |  | =item i_fr_saw_both | 
| 1752 |  |  |  |  |  |  |  | 
| 1753 |  |  |  |  |  |  | like i_fr_sawtooth, except that the sawtooth pattern repeats into | 
| 1754 |  |  |  |  |  |  | negative values. | 
| 1755 |  |  |  |  |  |  |  | 
| 1756 |  |  |  |  |  |  | =item i_fr_tri_both | 
| 1757 |  |  |  |  |  |  |  | 
| 1758 |  |  |  |  |  |  | Like i_fr_triangle, except that negative values are handled as their | 
| 1759 |  |  |  |  |  |  | absolute values. | 
| 1760 |  |  |  |  |  |  |  | 
| 1761 |  |  |  |  |  |  | =back | 
| 1762 |  |  |  |  |  |  |  | 
| 1763 |  |  |  |  |  |  | If combine is non-zero then non-opaque values are combined with the | 
| 1764 |  |  |  |  |  |  | underlying color. | 
| 1765 |  |  |  |  |  |  |  | 
| 1766 |  |  |  |  |  |  | I controls super sampling, if any.  At some point I'll | 
| 1767 |  |  |  |  |  |  | probably add a adaptive super-sampler.  Current possible values are: | 
| 1768 |  |  |  |  |  |  |  | 
| 1769 |  |  |  |  |  |  | =over | 
| 1770 |  |  |  |  |  |  |  | 
| 1771 |  |  |  |  |  |  | =item i_fts_none | 
| 1772 |  |  |  |  |  |  |  | 
| 1773 |  |  |  |  |  |  | No super-sampling is done. | 
| 1774 |  |  |  |  |  |  |  | 
| 1775 |  |  |  |  |  |  | =item i_fts_grid | 
| 1776 |  |  |  |  |  |  |  | 
| 1777 |  |  |  |  |  |  | A square grid of points withing the pixel are sampled. | 
| 1778 |  |  |  |  |  |  |  | 
| 1779 |  |  |  |  |  |  | =item i_fts_random | 
| 1780 |  |  |  |  |  |  |  | 
| 1781 |  |  |  |  |  |  | Random points within the pixel are sampled. | 
| 1782 |  |  |  |  |  |  |  | 
| 1783 |  |  |  |  |  |  | =item i_fts_circle | 
| 1784 |  |  |  |  |  |  |  | 
| 1785 |  |  |  |  |  |  | Points on the radius of a circle are sampled.  This produces fairly | 
| 1786 |  |  |  |  |  |  | good results, but is fairly slow since sin() and cos() are evaluated | 
| 1787 |  |  |  |  |  |  | for each point. | 
| 1788 |  |  |  |  |  |  |  | 
| 1789 |  |  |  |  |  |  | =back | 
| 1790 |  |  |  |  |  |  |  | 
| 1791 |  |  |  |  |  |  | I is intended to be roughly the number of points | 
| 1792 |  |  |  |  |  |  | sampled within the pixel. | 
| 1793 |  |  |  |  |  |  |  | 
| 1794 |  |  |  |  |  |  | I and I define the segments of the fill. | 
| 1795 |  |  |  |  |  |  |  | 
| 1796 |  |  |  |  |  |  | =cut | 
| 1797 |  |  |  |  |  |  |  | 
| 1798 |  |  |  |  |  |  | */ | 
| 1799 |  |  |  |  |  |  |  | 
| 1800 |  |  |  |  |  |  | int | 
| 1801 | 9 |  |  |  |  |  | i_fountain(i_img *im, double xa, double ya, double xb, double yb, | 
| 1802 |  |  |  |  |  |  | i_fountain_type type, i_fountain_repeat repeat, | 
| 1803 |  |  |  |  |  |  | int combine, int super_sample, double ssample_param, | 
| 1804 |  |  |  |  |  |  | int count, i_fountain_seg *segs) { | 
| 1805 |  |  |  |  |  |  | struct fount_state state; | 
| 1806 |  |  |  |  |  |  | i_img_dim x, y; | 
| 1807 | 9 |  |  |  |  |  | i_fcolor *line = NULL; | 
| 1808 | 9 |  |  |  |  |  | i_fcolor *work = NULL; | 
| 1809 |  |  |  |  |  |  | size_t line_bytes; | 
| 1810 | 9 |  |  |  |  |  | i_fill_combine_f combine_func = NULL; | 
| 1811 | 9 |  |  |  |  |  | i_fill_combinef_f combinef_func = NULL; | 
| 1812 | 9 |  |  |  |  |  | dIMCTXim(im); | 
| 1813 |  |  |  |  |  |  |  | 
| 1814 | 9 |  |  |  |  |  | i_clear_error(); | 
| 1815 |  |  |  |  |  |  |  | 
| 1816 |  |  |  |  |  |  | /* i_fountain() allocates floating colors even for 8-bit images, | 
| 1817 |  |  |  |  |  |  | so we need to do this check */ | 
| 1818 | 9 |  |  |  |  |  | line_bytes = sizeof(i_fcolor) * im->xsize; | 
| 1819 | 9 | 50 |  |  |  |  | if (line_bytes / sizeof(i_fcolor) != im->xsize) { | 
| 1820 | 0 |  |  |  |  |  | i_push_error(0, "integer overflow calculating memory allocation"); | 
| 1821 | 0 |  |  |  |  |  | return 0; | 
| 1822 |  |  |  |  |  |  | } | 
| 1823 |  |  |  |  |  |  |  | 
| 1824 | 9 |  |  |  |  |  | line = mymalloc(line_bytes); /* checked 17feb2005 tonyc */ | 
| 1825 |  |  |  |  |  |  |  | 
| 1826 | 9 |  |  |  |  |  | i_get_combine(combine, &combine_func, &combinef_func); | 
| 1827 | 9 | 100 |  |  |  |  | if (combinef_func) { | 
| 1828 | 2 |  |  |  |  |  | work = mymalloc(line_bytes); /* checked 17feb2005 tonyc */ | 
| 1829 |  |  |  |  |  |  | } | 
| 1830 |  |  |  |  |  |  |  | 
| 1831 | 9 |  |  |  |  |  | fount_init_state(&state, xa, ya, xb, yb, type, repeat, combine, | 
| 1832 |  |  |  |  |  |  | super_sample, ssample_param, count, segs); | 
| 1833 |  |  |  |  |  |  |  | 
| 1834 | 1109 | 100 |  |  |  |  | for (y = 0; y < im->ysize; ++y) { | 
| 1835 | 1100 |  |  |  |  |  | i_glinf(im, 0, im->xsize, y, line); | 
| 1836 | 146100 | 100 |  |  |  |  | for (x = 0; x < im->xsize; ++x) { | 
| 1837 |  |  |  |  |  |  | i_fcolor c; | 
| 1838 |  |  |  |  |  |  | int got_one; | 
| 1839 | 145000 | 100 |  |  |  |  | if (super_sample == i_fts_none) | 
| 1840 | 77500 |  |  |  |  |  | got_one = fount_getat(&c, x, y, &state); | 
| 1841 |  |  |  |  |  |  | else | 
| 1842 | 67500 |  |  |  |  |  | got_one = state.ssfunc(&c, x, y, &state); | 
| 1843 | 145000 | 50 |  |  |  |  | if (got_one) { | 
| 1844 | 145000 | 100 |  |  |  |  | if (combinef_func) | 
| 1845 | 45000 |  |  |  |  |  | work[x] = c; | 
| 1846 |  |  |  |  |  |  | else | 
| 1847 | 100000 |  |  |  |  |  | line[x] = c; | 
| 1848 |  |  |  |  |  |  | } | 
| 1849 |  |  |  |  |  |  | } | 
| 1850 | 1100 | 100 |  |  |  |  | if (combinef_func) | 
| 1851 | 300 |  |  |  |  |  | combinef_func(line, work, im->channels, im->xsize); | 
| 1852 | 1100 |  |  |  |  |  | i_plinf(im, 0, im->xsize, y, line); | 
| 1853 |  |  |  |  |  |  | } | 
| 1854 | 9 |  |  |  |  |  | fount_finish_state(&state); | 
| 1855 | 9 |  |  |  |  |  | myfree(work); | 
| 1856 | 9 |  |  |  |  |  | myfree(line); | 
| 1857 |  |  |  |  |  |  |  | 
| 1858 | 9 |  |  |  |  |  | return 1; | 
| 1859 |  |  |  |  |  |  | } | 
| 1860 |  |  |  |  |  |  |  | 
| 1861 |  |  |  |  |  |  | typedef struct { | 
| 1862 |  |  |  |  |  |  | i_fill_t base; | 
| 1863 |  |  |  |  |  |  | struct fount_state state; | 
| 1864 |  |  |  |  |  |  | } i_fill_fountain_t; | 
| 1865 |  |  |  |  |  |  |  | 
| 1866 |  |  |  |  |  |  | static void | 
| 1867 |  |  |  |  |  |  | fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, | 
| 1868 |  |  |  |  |  |  | i_fcolor *data); | 
| 1869 |  |  |  |  |  |  | static void | 
| 1870 |  |  |  |  |  |  | fount_fill_destroy(i_fill_t *fill); | 
| 1871 |  |  |  |  |  |  |  | 
| 1872 |  |  |  |  |  |  | static i_fill_fountain_t | 
| 1873 |  |  |  |  |  |  | fount_fill_proto = | 
| 1874 |  |  |  |  |  |  | { | 
| 1875 |  |  |  |  |  |  | { | 
| 1876 |  |  |  |  |  |  | NULL, | 
| 1877 |  |  |  |  |  |  | fill_fountf, | 
| 1878 |  |  |  |  |  |  | fount_fill_destroy | 
| 1879 |  |  |  |  |  |  | } | 
| 1880 |  |  |  |  |  |  | }; | 
| 1881 |  |  |  |  |  |  |  | 
| 1882 |  |  |  |  |  |  |  | 
| 1883 |  |  |  |  |  |  | /* | 
| 1884 |  |  |  |  |  |  | =item i_new_fill_fount(C, C, C, C, C, C, C, C, C, C, C) | 
| 1885 |  |  |  |  |  |  |  | 
| 1886 |  |  |  |  |  |  | =category Fills | 
| 1887 |  |  |  |  |  |  | =synopsis fill = i_new_fill_fount(0, 0, 100, 100, i_ft_linear, i_ft_linear, | 
| 1888 |  |  |  |  |  |  | =synopsis                         i_fr_triangle, 0, i_fts_grid, 9, 1, segs); | 
| 1889 |  |  |  |  |  |  |  | 
| 1890 |  |  |  |  |  |  |  | 
| 1891 |  |  |  |  |  |  | Creates a new general fill which fills with a fountain fill. | 
| 1892 |  |  |  |  |  |  |  | 
| 1893 |  |  |  |  |  |  | =cut | 
| 1894 |  |  |  |  |  |  | */ | 
| 1895 |  |  |  |  |  |  |  | 
| 1896 |  |  |  |  |  |  | i_fill_t * | 
| 1897 | 5 |  |  |  |  |  | i_new_fill_fount(double xa, double ya, double xb, double yb, | 
| 1898 |  |  |  |  |  |  | i_fountain_type type, i_fountain_repeat repeat, | 
| 1899 |  |  |  |  |  |  | int combine, int super_sample, double ssample_param, | 
| 1900 |  |  |  |  |  |  | int count, i_fountain_seg *segs) { | 
| 1901 | 5 |  |  |  |  |  | i_fill_fountain_t *fill = mymalloc(sizeof(i_fill_fountain_t)); | 
| 1902 |  |  |  |  |  |  |  | 
| 1903 | 5 |  |  |  |  |  | *fill = fount_fill_proto; | 
| 1904 | 5 | 50 |  |  |  |  | if (combine) | 
| 1905 | 0 |  |  |  |  |  | i_get_combine(combine, &fill->base.combine, &fill->base.combinef); | 
| 1906 |  |  |  |  |  |  | else { | 
| 1907 | 5 |  |  |  |  |  | fill->base.combine = NULL; | 
| 1908 | 5 |  |  |  |  |  | fill->base.combinef = NULL; | 
| 1909 |  |  |  |  |  |  | } | 
| 1910 | 5 |  |  |  |  |  | fount_init_state(&fill->state, xa, ya, xb, yb, type, repeat, combine, | 
| 1911 |  |  |  |  |  |  | super_sample, ssample_param, count, segs); | 
| 1912 |  |  |  |  |  |  |  | 
| 1913 | 5 |  |  |  |  |  | return &fill->base; | 
| 1914 |  |  |  |  |  |  | } | 
| 1915 |  |  |  |  |  |  |  | 
| 1916 |  |  |  |  |  |  | /* | 
| 1917 |  |  |  |  |  |  | =back | 
| 1918 |  |  |  |  |  |  |  | 
| 1919 |  |  |  |  |  |  | =head1 INTERNAL FUNCTIONS | 
| 1920 |  |  |  |  |  |  |  | 
| 1921 |  |  |  |  |  |  | =over | 
| 1922 |  |  |  |  |  |  |  | 
| 1923 |  |  |  |  |  |  | =item fount_init_state(...) | 
| 1924 |  |  |  |  |  |  |  | 
| 1925 |  |  |  |  |  |  | Used by both the fountain fill filter and the fountain fill. | 
| 1926 |  |  |  |  |  |  |  | 
| 1927 |  |  |  |  |  |  | =cut | 
| 1928 |  |  |  |  |  |  | */ | 
| 1929 |  |  |  |  |  |  |  | 
| 1930 |  |  |  |  |  |  | static void | 
| 1931 | 14 |  |  |  |  |  | fount_init_state(struct fount_state *state, double xa, double ya, | 
| 1932 |  |  |  |  |  |  | double xb, double yb, i_fountain_type type, | 
| 1933 |  |  |  |  |  |  | i_fountain_repeat repeat, int combine, int super_sample, | 
| 1934 |  |  |  |  |  |  | double ssample_param, int count, i_fountain_seg *segs) { | 
| 1935 |  |  |  |  |  |  | int i, j; | 
| 1936 |  |  |  |  |  |  | size_t bytes; | 
| 1937 | 14 |  |  |  |  |  | i_fountain_seg *my_segs = mymalloc(sizeof(i_fountain_seg) * count); /* checked 2jul06 - duplicating original */ | 
| 1938 |  |  |  |  |  |  | /*int have_alpha = im->channels == 2 || im->channels == 4;*/ | 
| 1939 |  |  |  |  |  |  |  | 
| 1940 | 14 |  |  |  |  |  | memset(state, 0, sizeof(*state)); | 
| 1941 |  |  |  |  |  |  | /* we keep a local copy that we can adjust for speed */ | 
| 1942 | 31 | 100 |  |  |  |  | for (i = 0; i < count; ++i) { | 
| 1943 | 17 |  |  |  |  |  | i_fountain_seg *seg = my_segs + i; | 
| 1944 |  |  |  |  |  |  |  | 
| 1945 | 17 |  |  |  |  |  | *seg = segs[i]; | 
| 1946 | 17 | 100 |  |  |  |  | if (seg->type < 0 || seg->type >= i_fst_end) | 
| 1947 | 1 |  |  |  |  |  | seg->type = i_fst_linear; | 
| 1948 | 17 | 50 |  |  |  |  | if (seg->color < 0 || seg->color >= i_fc_end) | 
| 1949 | 0 |  |  |  |  |  | seg->color = i_fc_direct; | 
| 1950 | 17 | 100 |  |  |  |  | if (seg->color == i_fc_hue_up || seg->color == i_fc_hue_down) { | 
|  |  | 100 |  |  |  |  |  | 
| 1951 |  |  |  |  |  |  | /* so we don't have to translate to HSV on each request, do it here */ | 
| 1952 | 9 | 100 |  |  |  |  | for (j = 0; j < 2; ++j) { | 
| 1953 | 6 |  |  |  |  |  | i_rgb_to_hsvf(seg->c+j); | 
| 1954 |  |  |  |  |  |  | } | 
| 1955 | 3 | 100 |  |  |  |  | if (seg->color == i_fc_hue_up) { | 
| 1956 | 2 | 50 |  |  |  |  | if (seg->c[1].channel[0] <= seg->c[0].channel[0]) | 
| 1957 | 2 |  |  |  |  |  | seg->c[1].channel[0] += 1.0; | 
| 1958 |  |  |  |  |  |  | } | 
| 1959 |  |  |  |  |  |  | else { | 
| 1960 | 1 | 50 |  |  |  |  | if (seg->c[0].channel[0] <= seg->c[0].channel[1]) | 
| 1961 | 1 |  |  |  |  |  | seg->c[0].channel[0] += 1.0; | 
| 1962 |  |  |  |  |  |  | } | 
| 1963 |  |  |  |  |  |  | } | 
| 1964 |  |  |  |  |  |  | /*printf("start %g mid %g end %g c0(%g,%g,%g,%g) c1(%g,%g,%g,%g) type %d color %d\n", | 
| 1965 |  |  |  |  |  |  | seg->start, seg->middle, seg->end, seg->c[0].channel[0], | 
| 1966 |  |  |  |  |  |  | seg->c[0].channel[1], seg->c[0].channel[2], seg->c[0].channel[3], | 
| 1967 |  |  |  |  |  |  | seg->c[1].channel[0], seg->c[1].channel[1], seg->c[1].channel[2], | 
| 1968 |  |  |  |  |  |  | seg->c[1].channel[3], seg->type, seg->color);*/ | 
| 1969 |  |  |  |  |  |  |  | 
| 1970 |  |  |  |  |  |  | } | 
| 1971 |  |  |  |  |  |  |  | 
| 1972 |  |  |  |  |  |  | /* initialize each engine */ | 
| 1973 |  |  |  |  |  |  | /* these are so common ... */ | 
| 1974 | 14 |  |  |  |  |  | state->lA = xb - xa; | 
| 1975 | 14 |  |  |  |  |  | state->lB = yb - ya; | 
| 1976 | 14 |  |  |  |  |  | state->AB = sqrt(state->lA * state->lA + state->lB * state->lB); | 
| 1977 | 14 |  |  |  |  |  | state->xa = xa; | 
| 1978 | 14 |  |  |  |  |  | state->ya = ya; | 
| 1979 | 14 |  |  |  |  |  | switch (type) { | 
| 1980 |  |  |  |  |  |  | default: | 
| 1981 | 0 |  |  |  |  |  | type = i_ft_linear; /* make the invalid value valid */ | 
| 1982 |  |  |  |  |  |  | case i_ft_linear: | 
| 1983 |  |  |  |  |  |  | case i_ft_bilinear: | 
| 1984 | 10 |  |  |  |  |  | state->lC = ya * ya - ya * yb + xa * xa - xa * xb; | 
| 1985 | 10 |  |  |  |  |  | state->mult = 1; | 
| 1986 | 10 |  |  |  |  |  | state->mult = 1/linear_fount_f(xb, yb, state); | 
| 1987 | 10 |  |  |  |  |  | break; | 
| 1988 |  |  |  |  |  |  |  | 
| 1989 |  |  |  |  |  |  | case i_ft_radial: | 
| 1990 | 4 |  |  |  |  |  | state->mult = 1.0 / sqrt((double)(xb-xa)*(xb-xa) | 
| 1991 | 2 |  |  |  |  |  | + (double)(yb-ya)*(yb-ya)); | 
| 1992 | 2 |  |  |  |  |  | break; | 
| 1993 |  |  |  |  |  |  |  | 
| 1994 |  |  |  |  |  |  | case i_ft_radial_square: | 
| 1995 | 1 |  |  |  |  |  | state->cos = state->lA / state->AB; | 
| 1996 | 1 |  |  |  |  |  | state->sin = state->lB / state->AB; | 
| 1997 | 1 |  |  |  |  |  | state->mult = 1.0 / state->AB; | 
| 1998 | 1 |  |  |  |  |  | break; | 
| 1999 |  |  |  |  |  |  |  | 
| 2000 |  |  |  |  |  |  | case i_ft_revolution: | 
| 2001 | 1 |  |  |  |  |  | state->theta = atan2(yb-ya, xb-xa); | 
| 2002 | 1 |  |  |  |  |  | state->mult = 1.0 / (PI * 2); | 
| 2003 | 1 |  |  |  |  |  | break; | 
| 2004 |  |  |  |  |  |  |  | 
| 2005 |  |  |  |  |  |  | case i_ft_conical: | 
| 2006 | 0 |  |  |  |  |  | state->theta = atan2(yb-ya, xb-xa); | 
| 2007 | 0 |  |  |  |  |  | state->mult = 1.0 / PI; | 
| 2008 | 0 |  |  |  |  |  | break; | 
| 2009 |  |  |  |  |  |  | } | 
| 2010 | 14 |  |  |  |  |  | state->ffunc = fount_funcs[type]; | 
| 2011 | 14 | 50 |  |  |  |  | if (super_sample < 0 | 
| 2012 | 14 | 50 |  |  |  |  | || super_sample >= (int)(sizeof(fount_ssamples)/sizeof(*fount_ssamples))) { | 
| 2013 | 0 |  |  |  |  |  | super_sample = 0; | 
| 2014 |  |  |  |  |  |  | } | 
| 2015 | 14 |  |  |  |  |  | state->ssample_data = NULL; | 
| 2016 | 14 |  |  |  |  |  | switch (super_sample) { | 
| 2017 |  |  |  |  |  |  | case i_fts_grid: | 
| 2018 | 2 |  |  |  |  |  | ssample_param = floor(0.5 + sqrt(ssample_param)); | 
| 2019 | 2 | 50 |  |  |  |  | if (ssample_param > 1000) { | 
| 2020 | 0 |  |  |  |  |  | ssample_param = 1000; | 
| 2021 |  |  |  |  |  |  | } | 
| 2022 | 2 |  |  |  |  |  | state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param * ssample_param); /* checked 1jul06 tonyc */ | 
| 2023 | 2 |  |  |  |  |  | break; | 
| 2024 |  |  |  |  |  |  |  | 
| 2025 |  |  |  |  |  |  | case i_fts_random: | 
| 2026 |  |  |  |  |  |  | case i_fts_circle: | 
| 2027 | 1 |  |  |  |  |  | ssample_param = floor(0.5+ssample_param); | 
| 2028 | 1 | 50 |  |  |  |  | if (ssample_param > 1000) { | 
| 2029 | 0 |  |  |  |  |  | ssample_param = 1000; | 
| 2030 |  |  |  |  |  |  | } | 
| 2031 | 1 |  |  |  |  |  | bytes = sizeof(i_fcolor) * ssample_param; | 
| 2032 | 1 |  |  |  |  |  | state->ssample_data = mymalloc(bytes); | 
| 2033 | 1 |  |  |  |  |  | break; | 
| 2034 |  |  |  |  |  |  | } | 
| 2035 | 14 |  |  |  |  |  | state->parm = ssample_param; | 
| 2036 | 14 |  |  |  |  |  | state->ssfunc = fount_ssamples[super_sample]; | 
| 2037 | 14 | 50 |  |  |  |  | if (repeat < 0 || repeat >= (sizeof(fount_repeats)/sizeof(*fount_repeats))) | 
| 2038 | 0 |  |  |  |  |  | repeat = 0; | 
| 2039 | 14 |  |  |  |  |  | state->rpfunc = fount_repeats[repeat]; | 
| 2040 | 14 |  |  |  |  |  | state->segs = my_segs; | 
| 2041 | 14 |  |  |  |  |  | state->count = count; | 
| 2042 | 14 |  |  |  |  |  | } | 
| 2043 |  |  |  |  |  |  |  | 
| 2044 |  |  |  |  |  |  | static void | 
| 2045 | 14 |  |  |  |  |  | fount_finish_state(struct fount_state *state) { | 
| 2046 | 14 | 100 |  |  |  |  | if (state->ssample_data) | 
| 2047 | 3 |  |  |  |  |  | myfree(state->ssample_data); | 
| 2048 | 14 |  |  |  |  |  | myfree(state->segs); | 
| 2049 | 14 |  |  |  |  |  | } | 
| 2050 |  |  |  |  |  |  |  | 
| 2051 |  |  |  |  |  |  |  | 
| 2052 |  |  |  |  |  |  | /* | 
| 2053 |  |  |  |  |  |  | =item fount_getat(out, x, y, ffunc, rpfunc, state, segs, count) | 
| 2054 |  |  |  |  |  |  |  | 
| 2055 |  |  |  |  |  |  | Evaluates the fountain fill at the given point. | 
| 2056 |  |  |  |  |  |  |  | 
| 2057 |  |  |  |  |  |  | This is called by both the non-super-sampling and super-sampling code. | 
| 2058 |  |  |  |  |  |  |  | 
| 2059 |  |  |  |  |  |  | You might think that it would make sense to sample the fill parameter | 
| 2060 |  |  |  |  |  |  | instead, and combine those, but this breaks badly. | 
| 2061 |  |  |  |  |  |  |  | 
| 2062 |  |  |  |  |  |  | =cut | 
| 2063 |  |  |  |  |  |  | */ | 
| 2064 |  |  |  |  |  |  |  | 
| 2065 |  |  |  |  |  |  | static int | 
| 2066 | 635417 |  |  |  |  |  | fount_getat(i_fcolor *out, double x, double y, struct fount_state *state) { | 
| 2067 | 635417 |  |  |  |  |  | double v = (state->rpfunc)((state->ffunc)(x, y, state)); | 
| 2068 |  |  |  |  |  |  | int i; | 
| 2069 |  |  |  |  |  |  |  | 
| 2070 | 635417 |  |  |  |  |  | i = 0; | 
| 2071 | 736658 | 50 |  |  |  |  | while (i < state->count | 
| 2072 | 736658 | 50 |  |  |  |  | && (v < state->segs[i].start || v > state->segs[i].end)) { | 
|  |  | 100 |  |  |  |  |  | 
| 2073 | 101241 |  |  |  |  |  | ++i; | 
| 2074 |  |  |  |  |  |  | } | 
| 2075 | 635417 | 50 |  |  |  |  | if (i < state->count) { | 
| 2076 | 635417 |  |  |  |  |  | v = (fount_interps[state->segs[i].type])(v, state->segs+i); | 
| 2077 | 635417 |  |  |  |  |  | (fount_cinterps[state->segs[i].color])(out, v, state->segs+i); | 
| 2078 | 635417 |  |  |  |  |  | return 1; | 
| 2079 |  |  |  |  |  |  | } | 
| 2080 |  |  |  |  |  |  | else | 
| 2081 | 0 |  |  |  |  |  | return 0; | 
| 2082 |  |  |  |  |  |  | } | 
| 2083 |  |  |  |  |  |  |  | 
| 2084 |  |  |  |  |  |  | /* | 
| 2085 |  |  |  |  |  |  | =item linear_fount_f(x, y, state) | 
| 2086 |  |  |  |  |  |  |  | 
| 2087 |  |  |  |  |  |  | Calculate the fill parameter for a linear fountain fill. | 
| 2088 |  |  |  |  |  |  |  | 
| 2089 |  |  |  |  |  |  | Uses the point to line distance function, with some precalculation | 
| 2090 |  |  |  |  |  |  | done in i_fountain(). | 
| 2091 |  |  |  |  |  |  |  | 
| 2092 |  |  |  |  |  |  | =cut | 
| 2093 |  |  |  |  |  |  | */ | 
| 2094 |  |  |  |  |  |  | static double | 
| 2095 | 521941 |  |  |  |  |  | linear_fount_f(double x, double y, struct fount_state *state) { | 
| 2096 | 521941 |  |  |  |  |  | return (state->lA * x + state->lB * y + state->lC) / state->AB * state->mult; | 
| 2097 |  |  |  |  |  |  | } | 
| 2098 |  |  |  |  |  |  |  | 
| 2099 |  |  |  |  |  |  | /* | 
| 2100 |  |  |  |  |  |  | =item bilinear_fount_f(x, y, state) | 
| 2101 |  |  |  |  |  |  |  | 
| 2102 |  |  |  |  |  |  | Calculate the fill parameter for a bi-linear fountain fill. | 
| 2103 |  |  |  |  |  |  |  | 
| 2104 |  |  |  |  |  |  | =cut | 
| 2105 |  |  |  |  |  |  | */ | 
| 2106 |  |  |  |  |  |  | static double | 
| 2107 | 0 |  |  |  |  |  | bilinear_fount_f(double x, double y, struct fount_state *state) { | 
| 2108 | 0 |  |  |  |  |  | return fabs((state->lA * x + state->lB * y + state->lC) / state->AB * state->mult); | 
| 2109 |  |  |  |  |  |  | } | 
| 2110 |  |  |  |  |  |  |  | 
| 2111 |  |  |  |  |  |  | /* | 
| 2112 |  |  |  |  |  |  | =item radial_fount_f(x, y, state) | 
| 2113 |  |  |  |  |  |  |  | 
| 2114 |  |  |  |  |  |  | Calculate the fill parameter for a radial fountain fill. | 
| 2115 |  |  |  |  |  |  |  | 
| 2116 |  |  |  |  |  |  | Simply uses the distance function. | 
| 2117 |  |  |  |  |  |  |  | 
| 2118 |  |  |  |  |  |  | =cut | 
| 2119 |  |  |  |  |  |  | */ | 
| 2120 |  |  |  |  |  |  | static double | 
| 2121 | 13486 |  |  |  |  |  | radial_fount_f(double x, double y, struct fount_state *state) { | 
| 2122 | 13486 |  |  |  |  |  | return sqrt((double)(state->xa-x)*(state->xa-x) | 
| 2123 | 26972 |  |  |  |  |  | + (double)(state->ya-y)*(state->ya-y)) * state->mult; | 
| 2124 |  |  |  |  |  |  | } | 
| 2125 |  |  |  |  |  |  |  | 
| 2126 |  |  |  |  |  |  | /* | 
| 2127 |  |  |  |  |  |  | =item square_fount_f(x, y, state) | 
| 2128 |  |  |  |  |  |  |  | 
| 2129 |  |  |  |  |  |  | Calculate the fill parameter for a square fountain fill. | 
| 2130 |  |  |  |  |  |  |  | 
| 2131 |  |  |  |  |  |  | Works by rotating the reference co-ordinate around the centre of the | 
| 2132 |  |  |  |  |  |  | square. | 
| 2133 |  |  |  |  |  |  |  | 
| 2134 |  |  |  |  |  |  | =cut | 
| 2135 |  |  |  |  |  |  | */ | 
| 2136 |  |  |  |  |  |  | static double | 
| 2137 | 90000 |  |  |  |  |  | square_fount_f(double x, double y, struct fount_state *state) { | 
| 2138 |  |  |  |  |  |  | i_img_dim xc, yc; /* centred on A */ | 
| 2139 |  |  |  |  |  |  | double xt, yt; /* rotated by theta */ | 
| 2140 | 90000 |  |  |  |  |  | xc = x - state->xa; | 
| 2141 | 90000 |  |  |  |  |  | yc = y - state->ya; | 
| 2142 | 90000 |  |  |  |  |  | xt = fabs(xc * state->cos + yc * state->sin); | 
| 2143 | 90000 |  |  |  |  |  | yt = fabs(-xc * state->sin + yc * state->cos); | 
| 2144 | 90000 | 100 |  |  |  |  | return (xt > yt ? xt : yt) * state->mult; | 
| 2145 |  |  |  |  |  |  | } | 
| 2146 |  |  |  |  |  |  |  | 
| 2147 |  |  |  |  |  |  | /* | 
| 2148 |  |  |  |  |  |  | =item revolution_fount_f(x, y, state) | 
| 2149 |  |  |  |  |  |  |  | 
| 2150 |  |  |  |  |  |  | Calculates the fill parameter for the revolution fountain fill. | 
| 2151 |  |  |  |  |  |  |  | 
| 2152 |  |  |  |  |  |  | =cut | 
| 2153 |  |  |  |  |  |  | */ | 
| 2154 |  |  |  |  |  |  | static double | 
| 2155 | 10000 |  |  |  |  |  | revolution_fount_f(double x, double y, struct fount_state *state) { | 
| 2156 | 10000 |  |  |  |  |  | double angle = atan2(y - state->ya, x - state->xa); | 
| 2157 |  |  |  |  |  |  |  | 
| 2158 | 10000 |  |  |  |  |  | angle -= state->theta; | 
| 2159 | 10000 | 100 |  |  |  |  | if (angle < 0) { | 
| 2160 | 2500 |  |  |  |  |  | angle = fmod(angle+ PI * 4, PI*2); | 
| 2161 |  |  |  |  |  |  | } | 
| 2162 |  |  |  |  |  |  |  | 
| 2163 | 10000 |  |  |  |  |  | return angle * state->mult; | 
| 2164 |  |  |  |  |  |  | } | 
| 2165 |  |  |  |  |  |  |  | 
| 2166 |  |  |  |  |  |  | /* | 
| 2167 |  |  |  |  |  |  | =item conical_fount_f(x, y, state) | 
| 2168 |  |  |  |  |  |  |  | 
| 2169 |  |  |  |  |  |  | Calculates the fill parameter for the conical fountain fill. | 
| 2170 |  |  |  |  |  |  |  | 
| 2171 |  |  |  |  |  |  | =cut | 
| 2172 |  |  |  |  |  |  | */ | 
| 2173 |  |  |  |  |  |  | static double | 
| 2174 | 0 |  |  |  |  |  | conical_fount_f(double x, double y, struct fount_state *state) { | 
| 2175 | 0 |  |  |  |  |  | double angle = atan2(y - state->ya, x - state->xa); | 
| 2176 |  |  |  |  |  |  |  | 
| 2177 | 0 |  |  |  |  |  | angle -= state->theta; | 
| 2178 | 0 | 0 |  |  |  |  | if (angle < -PI) | 
| 2179 | 0 |  |  |  |  |  | angle += PI * 2; | 
| 2180 | 0 | 0 |  |  |  |  | else if (angle > PI) | 
| 2181 | 0 |  |  |  |  |  | angle -= PI * 2; | 
| 2182 |  |  |  |  |  |  |  | 
| 2183 | 0 |  |  |  |  |  | return fabs(angle) * state->mult; | 
| 2184 |  |  |  |  |  |  | } | 
| 2185 |  |  |  |  |  |  |  | 
| 2186 |  |  |  |  |  |  | /* | 
| 2187 |  |  |  |  |  |  | =item linear_interp(pos, seg) | 
| 2188 |  |  |  |  |  |  |  | 
| 2189 |  |  |  |  |  |  | Calculates linear interpolation on the fill parameter.  Breaks the | 
| 2190 |  |  |  |  |  |  | segment into 2 regions based in the I value. | 
| 2191 |  |  |  |  |  |  |  | 
| 2192 |  |  |  |  |  |  | =cut | 
| 2193 |  |  |  |  |  |  | */ | 
| 2194 |  |  |  |  |  |  | static double | 
| 2195 | 635417 |  |  |  |  |  | linear_interp(double pos, i_fountain_seg *seg) { | 
| 2196 | 635417 | 100 |  |  |  |  | if (pos < seg->middle) { | 
| 2197 | 380737 |  |  |  |  |  | double len = seg->middle - seg->start; | 
| 2198 | 380737 | 50 |  |  |  |  | if (len < EPSILON) | 
| 2199 | 0 |  |  |  |  |  | return 0.0; | 
| 2200 |  |  |  |  |  |  | else | 
| 2201 | 380737 |  |  |  |  |  | return (pos - seg->start) / len / 2; | 
| 2202 |  |  |  |  |  |  | } | 
| 2203 |  |  |  |  |  |  | else { | 
| 2204 | 254680 |  |  |  |  |  | double len = seg->end - seg->middle; | 
| 2205 | 254680 | 50 |  |  |  |  | if (len < EPSILON) | 
| 2206 | 0 |  |  |  |  |  | return 1.0; | 
| 2207 |  |  |  |  |  |  | else | 
| 2208 | 254680 |  |  |  |  |  | return 0.5 + (pos - seg->middle) / len / 2; | 
| 2209 |  |  |  |  |  |  | } | 
| 2210 |  |  |  |  |  |  | } | 
| 2211 |  |  |  |  |  |  |  | 
| 2212 |  |  |  |  |  |  | /* | 
| 2213 |  |  |  |  |  |  | =item sine_interp(pos, seg) | 
| 2214 |  |  |  |  |  |  |  | 
| 2215 |  |  |  |  |  |  | Calculates sine function interpolation on the fill parameter. | 
| 2216 |  |  |  |  |  |  |  | 
| 2217 |  |  |  |  |  |  | =cut | 
| 2218 |  |  |  |  |  |  | */ | 
| 2219 |  |  |  |  |  |  | static double | 
| 2220 | 0 |  |  |  |  |  | sine_interp(double pos, i_fountain_seg *seg) { | 
| 2221 |  |  |  |  |  |  | /* I wonder if there's a simple way to smooth the transition for this */ | 
| 2222 | 0 |  |  |  |  |  | double work = linear_interp(pos, seg); | 
| 2223 |  |  |  |  |  |  |  | 
| 2224 | 0 |  |  |  |  |  | return (1-cos(work * PI))/2; | 
| 2225 |  |  |  |  |  |  | } | 
| 2226 |  |  |  |  |  |  |  | 
| 2227 |  |  |  |  |  |  | /* | 
| 2228 |  |  |  |  |  |  | =item sphereup_interp(pos, seg) | 
| 2229 |  |  |  |  |  |  |  | 
| 2230 |  |  |  |  |  |  | Calculates spherical interpolation on the fill parameter, with the cusp | 
| 2231 |  |  |  |  |  |  | at the low-end. | 
| 2232 |  |  |  |  |  |  |  | 
| 2233 |  |  |  |  |  |  | =cut | 
| 2234 |  |  |  |  |  |  | */ | 
| 2235 |  |  |  |  |  |  | static double | 
| 2236 | 0 |  |  |  |  |  | sphereup_interp(double pos, i_fountain_seg *seg) { | 
| 2237 | 0 |  |  |  |  |  | double work = linear_interp(pos, seg); | 
| 2238 |  |  |  |  |  |  |  | 
| 2239 | 0 |  |  |  |  |  | return sqrt(1.0 - (1-work) * (1-work)); | 
| 2240 |  |  |  |  |  |  | } | 
| 2241 |  |  |  |  |  |  |  | 
| 2242 |  |  |  |  |  |  | /* | 
| 2243 |  |  |  |  |  |  | =item spheredown_interp(pos, seg) | 
| 2244 |  |  |  |  |  |  |  | 
| 2245 |  |  |  |  |  |  | Calculates spherical interpolation on the fill parameter, with the cusp | 
| 2246 |  |  |  |  |  |  | at the high-end. | 
| 2247 |  |  |  |  |  |  |  | 
| 2248 |  |  |  |  |  |  | =cut | 
| 2249 |  |  |  |  |  |  | */ | 
| 2250 |  |  |  |  |  |  | static double | 
| 2251 | 18864 |  |  |  |  |  | spheredown_interp(double pos, i_fountain_seg *seg) { | 
| 2252 | 18864 |  |  |  |  |  | double work = linear_interp(pos, seg); | 
| 2253 |  |  |  |  |  |  |  | 
| 2254 | 18864 |  |  |  |  |  | return 1-sqrt(1.0 - work * work); | 
| 2255 |  |  |  |  |  |  | } | 
| 2256 |  |  |  |  |  |  |  | 
| 2257 |  |  |  |  |  |  | /* | 
| 2258 |  |  |  |  |  |  | =item direct_cinterp(out, pos, seg) | 
| 2259 |  |  |  |  |  |  |  | 
| 2260 |  |  |  |  |  |  | Calculates the fountain color based on direct scaling of the channels | 
| 2261 |  |  |  |  |  |  | of the color channels. | 
| 2262 |  |  |  |  |  |  |  | 
| 2263 |  |  |  |  |  |  | =cut | 
| 2264 |  |  |  |  |  |  | */ | 
| 2265 |  |  |  |  |  |  | static void | 
| 2266 | 594053 |  |  |  |  |  | direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) { | 
| 2267 |  |  |  |  |  |  | int ch; | 
| 2268 | 2970265 | 100 |  |  |  |  | for (ch = 0; ch < MAXCHANNELS; ++ch) { | 
| 2269 | 4752424 |  |  |  |  |  | out->channel[ch] = seg->c[0].channel[ch] * (1 - pos) | 
| 2270 | 2376212 |  |  |  |  |  | + seg->c[1].channel[ch] * pos; | 
| 2271 |  |  |  |  |  |  | } | 
| 2272 | 594053 |  |  |  |  |  | } | 
| 2273 |  |  |  |  |  |  |  | 
| 2274 |  |  |  |  |  |  | /* | 
| 2275 |  |  |  |  |  |  | =item hue_up_cinterp(put, pos, seg) | 
| 2276 |  |  |  |  |  |  |  | 
| 2277 |  |  |  |  |  |  | Calculates the fountain color based on scaling a HSV value.  The hue | 
| 2278 |  |  |  |  |  |  | increases as the fill parameter increases. | 
| 2279 |  |  |  |  |  |  |  | 
| 2280 |  |  |  |  |  |  | =cut | 
| 2281 |  |  |  |  |  |  | */ | 
| 2282 |  |  |  |  |  |  | static void | 
| 2283 | 30189 |  |  |  |  |  | hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) { | 
| 2284 |  |  |  |  |  |  | int ch; | 
| 2285 | 150945 | 100 |  |  |  |  | for (ch = 0; ch < MAXCHANNELS; ++ch) { | 
| 2286 | 241512 |  |  |  |  |  | out->channel[ch] = seg->c[0].channel[ch] * (1 - pos) | 
| 2287 | 120756 |  |  |  |  |  | + seg->c[1].channel[ch] * pos; | 
| 2288 |  |  |  |  |  |  | } | 
| 2289 | 30189 |  |  |  |  |  | i_hsv_to_rgbf(out); | 
| 2290 | 30189 |  |  |  |  |  | } | 
| 2291 |  |  |  |  |  |  |  | 
| 2292 |  |  |  |  |  |  | /* | 
| 2293 |  |  |  |  |  |  | =item hue_down_cinterp(put, pos, seg) | 
| 2294 |  |  |  |  |  |  |  | 
| 2295 |  |  |  |  |  |  | Calculates the fountain color based on scaling a HSV value.  The hue | 
| 2296 |  |  |  |  |  |  | decreases as the fill parameter increases. | 
| 2297 |  |  |  |  |  |  |  | 
| 2298 |  |  |  |  |  |  | =cut | 
| 2299 |  |  |  |  |  |  | */ | 
| 2300 |  |  |  |  |  |  | static void | 
| 2301 | 11175 |  |  |  |  |  | hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) { | 
| 2302 |  |  |  |  |  |  | int ch; | 
| 2303 | 55875 | 100 |  |  |  |  | for (ch = 0; ch < MAXCHANNELS; ++ch) { | 
| 2304 | 89400 |  |  |  |  |  | out->channel[ch] = seg->c[0].channel[ch] * (1 - pos) | 
| 2305 | 44700 |  |  |  |  |  | + seg->c[1].channel[ch] * pos; | 
| 2306 |  |  |  |  |  |  | } | 
| 2307 | 11175 |  |  |  |  |  | i_hsv_to_rgbf(out); | 
| 2308 | 11175 |  |  |  |  |  | } | 
| 2309 |  |  |  |  |  |  |  | 
| 2310 |  |  |  |  |  |  | /* | 
| 2311 |  |  |  |  |  |  | =item simple_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count) | 
| 2312 |  |  |  |  |  |  |  | 
| 2313 |  |  |  |  |  |  | Simple grid-based super-sampling. | 
| 2314 |  |  |  |  |  |  |  | 
| 2315 |  |  |  |  |  |  | =cut | 
| 2316 |  |  |  |  |  |  | */ | 
| 2317 |  |  |  |  |  |  | static int | 
| 2318 | 45000 |  |  |  |  |  | simple_ssample(i_fcolor *out, double x, double y, struct fount_state *state) { | 
| 2319 | 45000 |  |  |  |  |  | i_fcolor *work = state->ssample_data; | 
| 2320 |  |  |  |  |  |  | i_img_dim dx, dy; | 
| 2321 | 45000 |  |  |  |  |  | int grid = state->parm; | 
| 2322 | 45000 |  |  |  |  |  | double base = -0.5 + 0.5 / grid; | 
| 2323 | 45000 |  |  |  |  |  | double step = 1.0 / grid; | 
| 2324 |  |  |  |  |  |  | int ch, i; | 
| 2325 | 45000 |  |  |  |  |  | int samp_count = 0; | 
| 2326 |  |  |  |  |  |  |  | 
| 2327 | 135000 | 100 |  |  |  |  | for (dx = 0; dx < grid; ++dx) { | 
| 2328 | 270000 | 100 |  |  |  |  | for (dy = 0; dy < grid; ++dy) { | 
| 2329 | 180000 | 50 |  |  |  |  | if (fount_getat(work+samp_count, x + base + step * dx, | 
| 2330 | 180000 |  |  |  |  |  | y + base + step * dy, state)) { | 
| 2331 | 180000 |  |  |  |  |  | ++samp_count; | 
| 2332 |  |  |  |  |  |  | } | 
| 2333 |  |  |  |  |  |  | } | 
| 2334 |  |  |  |  |  |  | } | 
| 2335 | 225000 | 100 |  |  |  |  | for (ch = 0; ch < MAXCHANNELS; ++ch) { | 
| 2336 | 180000 |  |  |  |  |  | out->channel[ch] = 0; | 
| 2337 | 900000 | 100 |  |  |  |  | for (i = 0; i < samp_count; ++i) { | 
| 2338 | 720000 |  |  |  |  |  | out->channel[ch] += work[i].channel[ch]; | 
| 2339 |  |  |  |  |  |  | } | 
| 2340 |  |  |  |  |  |  | /* we divide by 4 rather than samp_count since if there's only one valid | 
| 2341 |  |  |  |  |  |  | sample it should be mostly transparent */ | 
| 2342 | 180000 |  |  |  |  |  | out->channel[ch] /= grid * grid; | 
| 2343 |  |  |  |  |  |  | } | 
| 2344 | 45000 |  |  |  |  |  | return samp_count; | 
| 2345 |  |  |  |  |  |  | } | 
| 2346 |  |  |  |  |  |  |  | 
| 2347 |  |  |  |  |  |  | /* | 
| 2348 |  |  |  |  |  |  | =item random_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count) | 
| 2349 |  |  |  |  |  |  |  | 
| 2350 |  |  |  |  |  |  | Random super-sampling. | 
| 2351 |  |  |  |  |  |  |  | 
| 2352 |  |  |  |  |  |  | =cut | 
| 2353 |  |  |  |  |  |  | */ | 
| 2354 |  |  |  |  |  |  | static int | 
| 2355 | 0 |  |  |  |  |  | random_ssample(i_fcolor *out, double x, double y, | 
| 2356 |  |  |  |  |  |  | struct fount_state *state) { | 
| 2357 | 0 |  |  |  |  |  | i_fcolor *work = state->ssample_data; | 
| 2358 |  |  |  |  |  |  | int i, ch; | 
| 2359 | 0 |  |  |  |  |  | int maxsamples = state->parm; | 
| 2360 | 0 |  |  |  |  |  | double rand_scale = 1.0 / RAND_MAX; | 
| 2361 | 0 |  |  |  |  |  | int samp_count = 0; | 
| 2362 | 0 | 0 |  |  |  |  | for (i = 0; i < maxsamples; ++i) { | 
| 2363 | 0 | 0 |  |  |  |  | if (fount_getat(work+samp_count, x - 0.5 + rand() * rand_scale, | 
| 2364 | 0 |  |  |  |  |  | y - 0.5 + rand() * rand_scale, state)) { | 
| 2365 | 0 |  |  |  |  |  | ++samp_count; | 
| 2366 |  |  |  |  |  |  | } | 
| 2367 |  |  |  |  |  |  | } | 
| 2368 | 0 | 0 |  |  |  |  | for (ch = 0; ch < MAXCHANNELS; ++ch) { | 
| 2369 | 0 |  |  |  |  |  | out->channel[ch] = 0; | 
| 2370 | 0 | 0 |  |  |  |  | for (i = 0; i < samp_count; ++i) { | 
| 2371 | 0 |  |  |  |  |  | out->channel[ch] += work[i].channel[ch]; | 
| 2372 |  |  |  |  |  |  | } | 
| 2373 |  |  |  |  |  |  | /* we divide by maxsamples rather than samp_count since if there's | 
| 2374 |  |  |  |  |  |  | only one valid sample it should be mostly transparent */ | 
| 2375 | 0 |  |  |  |  |  | out->channel[ch] /= maxsamples; | 
| 2376 |  |  |  |  |  |  | } | 
| 2377 | 0 |  |  |  |  |  | return samp_count; | 
| 2378 |  |  |  |  |  |  | } | 
| 2379 |  |  |  |  |  |  |  | 
| 2380 |  |  |  |  |  |  | /* | 
| 2381 |  |  |  |  |  |  | =item circle_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count) | 
| 2382 |  |  |  |  |  |  |  | 
| 2383 |  |  |  |  |  |  | Super-sampling around the circumference of a circle. | 
| 2384 |  |  |  |  |  |  |  | 
| 2385 |  |  |  |  |  |  | I considered saving the sin()/cos() values and transforming step-size | 
| 2386 |  |  |  |  |  |  | around the circle, but that's inaccurate, though it may not matter | 
| 2387 |  |  |  |  |  |  | much. | 
| 2388 |  |  |  |  |  |  |  | 
| 2389 |  |  |  |  |  |  | =cut | 
| 2390 |  |  |  |  |  |  | */ | 
| 2391 |  |  |  |  |  |  | static int | 
| 2392 | 22500 |  |  |  |  |  | circle_ssample(i_fcolor *out, double x, double y, | 
| 2393 |  |  |  |  |  |  | struct fount_state *state) { | 
| 2394 | 22500 |  |  |  |  |  | i_fcolor *work = state->ssample_data; | 
| 2395 |  |  |  |  |  |  | int i, ch; | 
| 2396 | 22500 |  |  |  |  |  | int maxsamples = state->parm; | 
| 2397 | 22500 |  |  |  |  |  | double angle = 2 * PI / maxsamples; | 
| 2398 | 22500 |  |  |  |  |  | double radius = 0.3; /* semi-random */ | 
| 2399 | 22500 |  |  |  |  |  | int samp_count = 0; | 
| 2400 | 382500 | 100 |  |  |  |  | for (i = 0; i < maxsamples; ++i) { | 
| 2401 | 360000 | 50 |  |  |  |  | if (fount_getat(work+samp_count, x + radius * cos(angle * i), | 
| 2402 | 360000 |  |  |  |  |  | y + radius * sin(angle * i), state)) { | 
| 2403 | 360000 |  |  |  |  |  | ++samp_count; | 
| 2404 |  |  |  |  |  |  | } | 
| 2405 |  |  |  |  |  |  | } | 
| 2406 | 112500 | 100 |  |  |  |  | for (ch = 0; ch < MAXCHANNELS; ++ch) { | 
| 2407 | 90000 |  |  |  |  |  | out->channel[ch] = 0; | 
| 2408 | 1530000 | 100 |  |  |  |  | for (i = 0; i < samp_count; ++i) { | 
| 2409 | 1440000 |  |  |  |  |  | out->channel[ch] += work[i].channel[ch]; | 
| 2410 |  |  |  |  |  |  | } | 
| 2411 |  |  |  |  |  |  | /* we divide by maxsamples rather than samp_count since if there's | 
| 2412 |  |  |  |  |  |  | only one valid sample it should be mostly transparent */ | 
| 2413 | 90000 |  |  |  |  |  | out->channel[ch] /= maxsamples; | 
| 2414 |  |  |  |  |  |  | } | 
| 2415 | 22500 |  |  |  |  |  | return samp_count; | 
| 2416 |  |  |  |  |  |  | } | 
| 2417 |  |  |  |  |  |  |  | 
| 2418 |  |  |  |  |  |  | /* | 
| 2419 |  |  |  |  |  |  | =item fount_r_none(v) | 
| 2420 |  |  |  |  |  |  |  | 
| 2421 |  |  |  |  |  |  | Implements no repeats.  Simply clamps the fill value. | 
| 2422 |  |  |  |  |  |  |  | 
| 2423 |  |  |  |  |  |  | =cut | 
| 2424 |  |  |  |  |  |  | */ | 
| 2425 |  |  |  |  |  |  | static double | 
| 2426 | 265417 |  |  |  |  |  | fount_r_none(double v) { | 
| 2427 | 265417 | 100 |  |  |  |  | return v < 0 ? 0 : v > 1 ? 1 : v; | 
|  |  | 100 |  |  |  |  |  | 
| 2428 |  |  |  |  |  |  | } | 
| 2429 |  |  |  |  |  |  |  | 
| 2430 |  |  |  |  |  |  | /* | 
| 2431 |  |  |  |  |  |  | =item fount_r_sawtooth(v) | 
| 2432 |  |  |  |  |  |  |  | 
| 2433 |  |  |  |  |  |  | Implements sawtooth repeats.  Clamps negative values and uses fmod() | 
| 2434 |  |  |  |  |  |  | on others. | 
| 2435 |  |  |  |  |  |  |  | 
| 2436 |  |  |  |  |  |  | =cut | 
| 2437 |  |  |  |  |  |  | */ | 
| 2438 |  |  |  |  |  |  | static double | 
| 2439 | 10000 |  |  |  |  |  | fount_r_sawtooth(double v) { | 
| 2440 | 10000 | 50 |  |  |  |  | return v < 0 ? 0 : fmod(v, 1.0); | 
| 2441 |  |  |  |  |  |  | } | 
| 2442 |  |  |  |  |  |  |  | 
| 2443 |  |  |  |  |  |  | /* | 
| 2444 |  |  |  |  |  |  | =item fount_r_triangle(v) | 
| 2445 |  |  |  |  |  |  |  | 
| 2446 |  |  |  |  |  |  | Implements triangle repeats.  Clamps negative values, uses fmod to get | 
| 2447 |  |  |  |  |  |  | a range 0 through 2 and then adjusts values > 1. | 
| 2448 |  |  |  |  |  |  |  | 
| 2449 |  |  |  |  |  |  | =cut | 
| 2450 |  |  |  |  |  |  | */ | 
| 2451 |  |  |  |  |  |  | static double | 
| 2452 | 360000 |  |  |  |  |  | fount_r_triangle(double v) { | 
| 2453 | 360000 | 100 |  |  |  |  | if (v < 0) | 
| 2454 | 179064 |  |  |  |  |  | return 0; | 
| 2455 |  |  |  |  |  |  | else { | 
| 2456 | 180936 |  |  |  |  |  | v = fmod(v, 2.0); | 
| 2457 | 180936 | 100 |  |  |  |  | return v > 1.0 ? 2.0 - v : v; | 
| 2458 |  |  |  |  |  |  | } | 
| 2459 |  |  |  |  |  |  | } | 
| 2460 |  |  |  |  |  |  |  | 
| 2461 |  |  |  |  |  |  | /* | 
| 2462 |  |  |  |  |  |  | =item fount_r_saw_both(v) | 
| 2463 |  |  |  |  |  |  |  | 
| 2464 |  |  |  |  |  |  | Implements sawtooth repeats in the both postive and negative directions. | 
| 2465 |  |  |  |  |  |  |  | 
| 2466 |  |  |  |  |  |  | Adjusts the value to be postive and then just uses fmod(). | 
| 2467 |  |  |  |  |  |  |  | 
| 2468 |  |  |  |  |  |  | =cut | 
| 2469 |  |  |  |  |  |  | */ | 
| 2470 |  |  |  |  |  |  | static double | 
| 2471 | 0 |  |  |  |  |  | fount_r_saw_both(double v) { | 
| 2472 | 0 | 0 |  |  |  |  | if (v < 0) | 
| 2473 | 0 |  |  |  |  |  | v += 1+(int)(-v); | 
| 2474 | 0 |  |  |  |  |  | return fmod(v, 1.0); | 
| 2475 |  |  |  |  |  |  | } | 
| 2476 |  |  |  |  |  |  |  | 
| 2477 |  |  |  |  |  |  | /* | 
| 2478 |  |  |  |  |  |  | =item fount_r_tri_both(v) | 
| 2479 |  |  |  |  |  |  |  | 
| 2480 |  |  |  |  |  |  | Implements triangle repeats in the both postive and negative directions. | 
| 2481 |  |  |  |  |  |  |  | 
| 2482 |  |  |  |  |  |  | Uses fmod on the absolute value, and then adjusts values > 1. | 
| 2483 |  |  |  |  |  |  |  | 
| 2484 |  |  |  |  |  |  | =cut | 
| 2485 |  |  |  |  |  |  | */ | 
| 2486 |  |  |  |  |  |  | static double | 
| 2487 | 0 |  |  |  |  |  | fount_r_tri_both(double v) { | 
| 2488 | 0 |  |  |  |  |  | v = fmod(fabs(v), 2.0); | 
| 2489 | 0 | 0 |  |  |  |  | return v > 1.0 ? 2.0 - v : v; | 
| 2490 |  |  |  |  |  |  | } | 
| 2491 |  |  |  |  |  |  |  | 
| 2492 |  |  |  |  |  |  | /* | 
| 2493 |  |  |  |  |  |  | =item fill_fountf(fill, x, y, width, channels, data) | 
| 2494 |  |  |  |  |  |  |  | 
| 2495 |  |  |  |  |  |  | The fill function for fountain fills. | 
| 2496 |  |  |  |  |  |  |  | 
| 2497 |  |  |  |  |  |  | =cut | 
| 2498 |  |  |  |  |  |  | */ | 
| 2499 |  |  |  |  |  |  | static void | 
| 2500 | 292 |  |  |  |  |  | fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, | 
| 2501 |  |  |  |  |  |  | int channels, i_fcolor *data) { | 
| 2502 | 292 |  |  |  |  |  | i_fill_fountain_t *f = (i_fill_fountain_t *)fill; | 
| 2503 |  |  |  |  |  |  |  | 
| 2504 | 18209 | 100 |  |  |  |  | while (width--) { | 
| 2505 |  |  |  |  |  |  | i_fcolor c; | 
| 2506 |  |  |  |  |  |  | int got_one; | 
| 2507 |  |  |  |  |  |  |  | 
| 2508 | 17917 | 50 |  |  |  |  | if (f->state.ssfunc) | 
| 2509 | 0 |  |  |  |  |  | got_one = f->state.ssfunc(&c, x, y, &f->state); | 
| 2510 |  |  |  |  |  |  | else | 
| 2511 | 17917 |  |  |  |  |  | got_one = fount_getat(&c, x, y, &f->state); | 
| 2512 |  |  |  |  |  |  |  | 
| 2513 | 17917 | 50 |  |  |  |  | if (got_one) | 
| 2514 | 17917 |  |  |  |  |  | *data++ = c; | 
| 2515 |  |  |  |  |  |  |  | 
| 2516 | 17917 |  |  |  |  |  | ++x; | 
| 2517 |  |  |  |  |  |  | } | 
| 2518 | 292 |  |  |  |  |  | } | 
| 2519 |  |  |  |  |  |  |  | 
| 2520 |  |  |  |  |  |  | /* | 
| 2521 |  |  |  |  |  |  | =item fount_fill_destroy(fill) | 
| 2522 |  |  |  |  |  |  |  | 
| 2523 |  |  |  |  |  |  | =cut | 
| 2524 |  |  |  |  |  |  | */ | 
| 2525 |  |  |  |  |  |  | static void | 
| 2526 | 5 |  |  |  |  |  | fount_fill_destroy(i_fill_t *fill) { | 
| 2527 | 5 |  |  |  |  |  | i_fill_fountain_t *f = (i_fill_fountain_t *)fill; | 
| 2528 | 5 |  |  |  |  |  | fount_finish_state(&f->state); | 
| 2529 | 5 |  |  |  |  |  | } | 
| 2530 |  |  |  |  |  |  |  | 
| 2531 |  |  |  |  |  |  | /* | 
| 2532 |  |  |  |  |  |  | =back | 
| 2533 |  |  |  |  |  |  |  | 
| 2534 |  |  |  |  |  |  | =head1 AUTHOR | 
| 2535 |  |  |  |  |  |  |  | 
| 2536 |  |  |  |  |  |  | Arnar M. Hrafnkelsson | 
| 2537 |  |  |  |  |  |  |  | 
| 2538 |  |  |  |  |  |  | Tony Cook  (i_fountain()) | 
| 2539 |  |  |  |  |  |  |  | 
| 2540 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 2541 |  |  |  |  |  |  |  | 
| 2542 |  |  |  |  |  |  | Imager(3) | 
| 2543 |  |  |  |  |  |  |  | 
| 2544 |  |  |  |  |  |  | =cut | 
| 2545 |  |  |  |  |  |  | */ |