aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/Pillow/py2/libImaging/RankFilter.c
blob: 0164861bb07af1b2ac6def5cf26e6aed6078f5db (plain) (blame)
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
/*
 * The Python Imaging Library
 * $Id$
 *
 * min, max, median filters
 *
 * history:
 * 2002-06-08 fl    Created
 *
 * Copyright (c) Secret Labs AB 2002.  All rights reserved.
 *
 * See the README file for information on usage and redistribution.
 */

#include "Imaging.h"

/* Fast rank algorithm (due to Wirth), based on public domain code
   by Nicolas Devillard, available at http://ndevilla.free.fr */

#define SWAP(type,a,b) { register type t=(a);(a)=(b);(b)=t; }

#define MakeRankFunction(type)\
static type Rank##type(type a[], int n, int k)\
{\
    register int i, j, l, m;\
    register type x;\
    l = 0; m = n-1;\
    while (l < m) {\
        x = a[k];\
        i = l;\
        j = m;\
        do {\
            while (a[i] < x) i++;\
            while (x < a[j]) j--;\
            if (i <= j) {\
                SWAP(type, a[i], a[j]);\
                i++; j--;\
            }\
        } while (i <= j);\
        if (j < k) l = i;\
        if (k < i) m = j;\
    }\
    return a[k];\
}

MakeRankFunction(UINT8)
MakeRankFunction(INT32)
MakeRankFunction(FLOAT32)

Imaging
ImagingRankFilter(Imaging im, int size, int rank)
{
    Imaging imOut = NULL;
    int x, y;
    int i, margin, size2;

    if (!im || im->bands != 1 || im->type == IMAGING_TYPE_SPECIAL)
        return (Imaging) ImagingError_ModeError();

    if (!(size & 1))
        return (Imaging) ImagingError_ValueError("bad filter size");

    /* malloc check ok, for overflow in the define below */
    if (size > INT_MAX / size ||
        size > INT_MAX / (size * sizeof(FLOAT32))) {
        return (Imaging) ImagingError_ValueError("filter size too large");
    }

    size2 = size * size;
    margin = (size-1) / 2;

    if (rank < 0 || rank >= size2)
        return (Imaging) ImagingError_ValueError("bad rank value");

    imOut = ImagingNew(im->mode, im->xsize - 2*margin, im->ysize - 2*margin);
    if (!imOut)
        return NULL;

    /* malloc check ok, checked above */
#define RANK_BODY(type) do {\
    type* buf = malloc(size2 * sizeof(type));\
    if (!buf)\
        goto nomemory;\
    for (y = 0; y < imOut->ysize; y++)\
        for (x = 0; x < imOut->xsize; x++) {\
            for (i = 0; i < size; i++)\
                memcpy(buf + i*size, &IMAGING_PIXEL_##type(im, x, y+i),\
                       size * sizeof(type));\
            IMAGING_PIXEL_##type(imOut, x, y) = Rank##type(buf, size2, rank);\
        }\
    free(buf); \
} while (0)

    if (im->image8)
        RANK_BODY(UINT8);
    else if (im->type == IMAGING_TYPE_INT32)
        RANK_BODY(INT32);
    else if (im->type == IMAGING_TYPE_FLOAT32)
        RANK_BODY(FLOAT32);
    else {
        /* safety net (we shouldn't end up here) */
        ImagingDelete(imOut);
        return (Imaging) ImagingError_ModeError();
    }

    ImagingCopyPalette(imOut, im);

    return imOut;

nomemory:
    ImagingDelete(imOut);
    return (Imaging) ImagingError_MemoryError();
}