1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
|
/*
* The Python Imaging Library
* $Id$
*
* various special effects and image generators
*
* history:
* 1997-05-21 fl Just for fun
* 1997-06-05 fl Added mandelbrot generator
* 2003-05-24 fl Added perlin_turbulence generator (in progress)
*
* Copyright (c) 1997-2003 by Fredrik Lundh.
* Copyright (c) 1997 by Secret Labs AB.
*
* See the README file for information on usage and redistribution.
*/
#include "Imaging.h"
#include <math.h>
Imaging
ImagingEffectMandelbrot(int xsize, int ysize, double extent[4], int quality)
{
/* Generate a Mandelbrot set covering the given extent */
Imaging im;
int x, y, k;
double width, height;
double x1, y1, xi2, yi2, cr, ci, radius;
double dr, di;
/* Check arguments */
width = extent[2] - extent[0];
height = extent[3] - extent[1];
if (width < 0.0 || height < 0.0 || quality < 2)
return (Imaging) ImagingError_ValueError(NULL);
im = ImagingNew("L", xsize, ysize);
if (!im)
return NULL;
dr = width/(xsize-1);
di = height/(ysize-1);
radius = 100.0;
for (y = 0; y < ysize; y++) {
UINT8* buf = im->image8[y];
for (x = 0; x < xsize; x++) {
x1 = y1 = xi2 = yi2 = 0.0;
cr = x*dr + extent[0];
ci = y*di + extent[1];
for (k = 1;; k++) {
y1 = 2*x1*y1 + ci;
x1 = xi2 - yi2 + cr;
xi2 = x1*x1;
yi2 = y1*y1;
if ((xi2 + yi2) > radius) {
buf[x] = k*255/quality;
break;
}
if (k > quality) {
buf[x] = 0;
break;
}
}
}
}
return im;
}
Imaging
ImagingEffectNoise(int xsize, int ysize, float sigma)
{
/* Generate gaussian noise centered around 128 */
Imaging imOut;
int x, y;
int nextok;
double this, next;
imOut = ImagingNew("L", xsize, ysize);
if (!imOut)
return NULL;
next = 0.0;
nextok = 0;
for (y = 0; y < imOut->ysize; y++) {
UINT8* out = imOut->image8[y];
for (x = 0; x < imOut->xsize; x++) {
if (nextok) {
this = next;
nextok = 0;
} else {
/* after numerical recepies */
double v1, v2, radius, factor;
do {
v1 = rand()*(2.0/32767.0) - 1.0;
v2 = rand()*(2.0/32767.0) - 1.0;
radius= v1*v1 + v2*v2;
} while (radius >= 1.0);
factor = sqrt(-2.0*log(radius)/radius);
this = factor * v1;
next = factor * v2;
}
out[x] = (unsigned char) (128 + sigma * this);
}
}
return imOut;
}
Imaging
ImagingEffectPerlinTurbulence(int xsize, int ysize)
{
/* Perlin turbulence (In progress) */
return NULL;
}
Imaging
ImagingEffectSpread(Imaging imIn, int distance)
{
/* Randomly spread pixels in an image */
Imaging imOut;
int x, y;
imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize);
if (!imOut)
return NULL;
#define SPREAD(type, image)\
for (y = 0; y < imIn->ysize; y++)\
for (x = 0; x < imIn->xsize; x++) {\
int xx = x + (rand() % distance) - distance/2;\
int yy = y + (rand() % distance) - distance/2;\
if (xx >= 0 && xx < imIn->xsize && yy >= 0 && yy < imIn->ysize) {\
imOut->image[yy][xx] = imIn->image[y][x];\
imOut->image[y][x] = imIn->image[yy][xx];\
} else\
imOut->image[y][x] = imIn->image[y][x];\
}
if (imIn->image8) {
SPREAD(UINT8, image8);
} else {
SPREAD(INT32, image32);
}
ImagingCopyInfo(imOut, imIn);
return imOut;
}
/* -------------------------------------------------------------------- */
/* Taken from the "C" code in the W3C SVG specification. Translated
to C89 by Fredrik Lundh */
#if 0
/* Produces results in the range [1, 2**31 - 2].
Algorithm is: r = (a * r) mod m
where a = 16807 and m = 2**31 - 1 = 2147483647
See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988
To test: the algorithm should produce the result 1043618065
as the 10,000th generated number if the original seed is 1.
*/
#define RAND_m 2147483647 /* 2**31 - 1 */
#define RAND_a 16807 /* 7**5; primitive root of m */
#define RAND_q 127773 /* m / a */
#define RAND_r 2836 /* m % a */
static long
perlin_setup_seed(long lSeed)
{
if (lSeed <= 0) lSeed = -(lSeed % (RAND_m - 1)) + 1;
if (lSeed > RAND_m - 1) lSeed = RAND_m - 1;
return lSeed;
}
static long
perlin_random(long lSeed)
{
long result;
result = RAND_a * (lSeed % RAND_q) - RAND_r * (lSeed / RAND_q);
if (result <= 0) result += RAND_m;
return result;
}
#define BSize 0x100
#define BM 0xff
#define PerlinN 0x1000
#define NP 12 /* 2^PerlinN */
#define NM 0xfff
static int perlin_uLatticeSelector[BSize + BSize + 2];
static double perlin_fGradient[4][BSize + BSize + 2][2];
typedef struct
{
int nWidth; /* How much to subtract to wrap for stitching. */
int nHeight;
int nWrapX; /* Minimum value to wrap. */
int nWrapY;
} StitchInfo;
static void
perlin_init(long lSeed)
{
double s;
int i, j, k;
lSeed = perlin_setup_seed(lSeed);
for(k = 0; k < 4; k++)
{
for(i = 0; i < BSize; i++)
{
perlin_uLatticeSelector[i] = i;
for (j = 0; j < 2; j++)
perlin_fGradient[k][i][j] = (double)(((lSeed = perlin_random(lSeed)) % (BSize + BSize)) - BSize) / BSize;
s = (double) (sqrt(perlin_fGradient[k][i][0] * perlin_fGradient[k][i][0] + perlin_fGradient[k][i][1] * perlin_fGradient[k][i][1]));
perlin_fGradient[k][i][0] /= s;
perlin_fGradient[k][i][1] /= s;
}
}
while(--i)
{
k = perlin_uLatticeSelector[i];
perlin_uLatticeSelector[i] = perlin_uLatticeSelector[j = (lSeed = perlin_random(lSeed)) % BSize];
perlin_uLatticeSelector[j] = k;
}
for(i = 0; i < BSize + 2; i++)
{
perlin_uLatticeSelector[BSize + i] = perlin_uLatticeSelector[i];
for(k = 0; k < 4; k++)
for(j = 0; j < 2; j++)
perlin_fGradient[k][BSize + i][j] = perlin_fGradient[k][i][j];
}
}
#define s_curve(t) ( t * t * (3. - 2. * t) )
#define lerp(t, a, b) ( a + t * (b - a) )
static double
perlin_noise2(int nColorChannel, double vec[2], StitchInfo *pStitchInfo)
{
int bx0, bx1, by0, by1, b00, b10, b01, b11;
double rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v;
register int i, j;
t = vec[0] + (double) PerlinN;
bx0 = (int)t;
bx1 = bx0+1;
rx0 = t - (int)t;
rx1 = rx0 - 1.0f;
t = vec[1] + (double) PerlinN;
by0 = (int)t;
by1 = by0+1;
ry0 = t - (int)t;
ry1 = ry0 - 1.0f;
/* If stitching, adjust lattice points accordingly. */
if(pStitchInfo != NULL)
{
if(bx0 >= pStitchInfo->nWrapX)
bx0 -= pStitchInfo->nWidth;
if(bx1 >= pStitchInfo->nWrapX)
bx1 -= pStitchInfo->nWidth;
if(by0 >= pStitchInfo->nWrapY)
by0 -= pStitchInfo->nHeight;
if(by1 >= pStitchInfo->nWrapY)
by1 -= pStitchInfo->nHeight;
}
bx0 &= BM;
bx1 &= BM;
by0 &= BM;
by1 &= BM;
i = perlin_uLatticeSelector[bx0];
j = perlin_uLatticeSelector[bx1];
b00 = perlin_uLatticeSelector[i + by0];
b10 = perlin_uLatticeSelector[j + by0];
b01 = perlin_uLatticeSelector[i + by1];
b11 = perlin_uLatticeSelector[j + by1];
sx = (double) (s_curve(rx0));
sy = (double) (s_curve(ry0));
q = perlin_fGradient[nColorChannel][b00]; u = rx0 * q[0] + ry0 * q[1];
q = perlin_fGradient[nColorChannel][b10]; v = rx1 * q[0] + ry0 * q[1];
a = lerp(sx, u, v);
q = perlin_fGradient[nColorChannel][b01]; u = rx0 * q[0] + ry1 * q[1];
q = perlin_fGradient[nColorChannel][b11]; v = rx1 * q[0] + ry1 * q[1];
b = lerp(sx, u, v);
return lerp(sy, a, b);
}
double
perlin_turbulence(
int nColorChannel, double *point, double fBaseFreqX, double fBaseFreqY,
int nNumOctaves, int bFractalSum, int bDoStitching,
double fTileX, double fTileY, double fTileWidth, double fTileHeight)
{
StitchInfo stitch;
StitchInfo *pStitchInfo = NULL; /* Not stitching when NULL. */
double fSum = 0.0f;
double vec[2];
double ratio = 1;
int nOctave;
vec[0] = point[0] * fBaseFreqX;
vec[1] = point[1] * fBaseFreqY;
/* Adjust the base frequencies if necessary for stitching. */
if(bDoStitching)
{
/* When stitching tiled turbulence, the frequencies must be adjusted */
/* so that the tile borders will be continuous. */
if(fBaseFreqX != 0.0)
{
double fLoFreq = (double) (floor(fTileWidth * fBaseFreqX)) / fTileWidth;
double fHiFreq = (double) (ceil(fTileWidth * fBaseFreqX)) / fTileWidth;
if(fBaseFreqX / fLoFreq < fHiFreq / fBaseFreqX)
fBaseFreqX = fLoFreq;
else
fBaseFreqX = fHiFreq;
}
if(fBaseFreqY != 0.0)
{
double fLoFreq = (double) (floor(fTileHeight * fBaseFreqY)) / fTileHeight;
double fHiFreq = (double) (ceil(fTileHeight * fBaseFreqY)) / fTileHeight;
if(fBaseFreqY / fLoFreq < fHiFreq / fBaseFreqY)
fBaseFreqY = fLoFreq;
else
fBaseFreqY = fHiFreq;
}
/* Set up initial stitch values. */
pStitchInfo = &stitch;
stitch.nWidth = (int) (fTileWidth * fBaseFreqX + 0.5f);
stitch.nWrapX = (int) (fTileX * fBaseFreqX + PerlinN + stitch.nWidth);
stitch.nHeight = (int) (fTileHeight * fBaseFreqY + 0.5f);
stitch.nWrapY = (int) (fTileY * fBaseFreqY + PerlinN + stitch.nHeight);
}
for(nOctave = 0; nOctave < nNumOctaves; nOctave++)
{
if(bFractalSum)
fSum += (double) (perlin_noise2(nColorChannel, vec, pStitchInfo) / ratio);
else
fSum += (double) (fabs(perlin_noise2(nColorChannel, vec, pStitchInfo)) / ratio);
vec[0] *= 2;
vec[1] *= 2;
ratio *= 2;
if(pStitchInfo != NULL)
{
/* Update stitch values. Subtracting PerlinN before the multiplication and */
/* adding it afterward simplifies to subtracting it once. */
stitch.nWidth *= 2;
stitch.nWrapX = 2 * stitch.nWrapX - PerlinN;
stitch.nHeight *= 2;
stitch.nWrapY = 2 * stitch.nWrapY - PerlinN;
}
}
return fSum;
}
#endif
|