Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/Imaging/libImaging/Effects.c
diff options
context:
space:
mode:
Diffstat (limited to 'Imaging/libImaging/Effects.c')
-rw-r--r--Imaging/libImaging/Effects.c370
1 files changed, 370 insertions, 0 deletions
diff --git a/Imaging/libImaging/Effects.c b/Imaging/libImaging/Effects.c
new file mode 100644
index 0000000..2ec08c7
--- /dev/null
+++ b/Imaging/libImaging/Effects.c
@@ -0,0 +1,370 @@
+/*
+ * The Python Imaging Library
+ * $Id: Effects.c 2134 2004-10-06 08:55:20Z fredrik $
+ *
+ * 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 */
+
+/* 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;
+}
+