summaryrefslogtreecommitdiff
path: root/gst/dvbsubenc/libimagequant/blur.c
blob: 1e711dd27a4b753e54ccb4779a2d618e4bf8f887 (plain)
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

#include "libimagequant.h"
#include "pam.h"
#include "blur.h"

/*
 Blurs image horizontally (width 2*size+1) and writes it transposed to dst (called twice gives 2d blur)
 */
static void
transposing_1d_blur (unsigned char *restrict src, unsigned char *restrict dst,
    unsigned int width, unsigned int height, const unsigned int size)
{
  for (unsigned int j = 0; j < height; j++) {
    unsigned char *restrict row = src + j * width;

    // accumulate sum for pixels outside line
    unsigned int sum;
    sum = row[0] * size;
    for (unsigned int i = 0; i < size; i++) {
      sum += row[i];
    }

    // blur with left side outside line
    for (unsigned int i = 0; i < size; i++) {
      sum -= row[0];
      sum += row[i + size];

      dst[i * height + j] = sum / (size * 2);
    }

    for (unsigned int i = size; i < width - size; i++) {
      sum -= row[i - size];
      sum += row[i + size];

      dst[i * height + j] = sum / (size * 2);
    }

    // blur with right side outside line
    for (unsigned int i = width - size; i < width; i++) {
      sum -= row[i - size];
      sum += row[width - 1];

      dst[i * height + j] = sum / (size * 2);
    }
  }
}

/**
 * Picks maximum of neighboring pixels (blur + lighten)
 */
LIQ_PRIVATE void
liq_max3 (unsigned char *src, unsigned char *dst, unsigned int width,
    unsigned int height)
{
  unsigned int i, j;

  for (j = 0; j < height; j++) {
    const unsigned char *row = src + j * width;
    unsigned char t1, t2;
    unsigned char prev, curr, next;

    const unsigned char *prevrow = src + (j > 1 ? j - 1 : 0) * width;
    const unsigned char *nextrow = src + MIN (height - 1, j + 1) * width;

    curr = row[0];
    next = row[0];

    for (i = 0; i < width - 1; i++) {
      prev = curr;
      curr = next;
      next = row[i + 1];

      t1 = MAX (prev, next);
      t2 = MAX (nextrow[i], prevrow[i]);
      *dst++ = MAX (curr, MAX (t1, t2));
    }

    t1 = MAX (curr, next);
    t2 = MAX (nextrow[width - 1], prevrow[width - 1]);
    *dst++ = MAX (t1, t2);
  }
}

/**
 * Picks minimum of neighboring pixels (blur + darken)
 */
LIQ_PRIVATE void
liq_min3 (unsigned char *src, unsigned char *dst, unsigned int width,
    unsigned int height)
{
  unsigned int j;

  for (j = 0; j < height; j++) {
    unsigned char t1, t2;
    const unsigned char *row = src + j * width,
        *prevrow = src + (j > 1 ? j - 1 : 0) * width,
        *nextrow = src + MIN (height - 1, j + 1) * width;

    unsigned char prev, curr = row[0], next = row[0];

    for (unsigned int i = 0; i < width - 1; i++) {
      prev = curr;
      curr = next;
      next = row[i + 1];

      t1 = MIN (prev, next);
      t2 = MIN (nextrow[i], prevrow[i]);
      *dst++ = MIN (curr, MIN (t1, t2));
    }

    t1 = MIN (curr, next);
    t2 = MIN (nextrow[width - 1], prevrow[width - 1]);
    *dst++ = MIN (t1, t2);
  }
}

/*
 Filters src image and saves it to dst, overwriting tmp in the process.
 Image must be width*height pixels high. Size controls radius of box blur.
 */
LIQ_PRIVATE void
liq_blur (unsigned char *src, unsigned char *tmp, unsigned char *dst,
    unsigned int width, unsigned int height, unsigned int size)
{
  assert (size > 0);
  if (width < 2 * size + 1 || height < 2 * size + 1) {
    return;
  }
  transposing_1d_blur (src, tmp, width, height, size);
  transposing_1d_blur (tmp, dst, height, width, size);
}