1package gift
2
3import (
4 "image"
5 "image/draw"
6 "math"
7 "runtime"
8 "sync"
9 "sync/atomic"
10)
11
12// parallelize parallelizes the data processing if enabled is true.
13func parallelize(enabled bool, datamin, datamax int, fn func(pmin, pmax int)) {
14 datasize := datamax - datamin
15 partsize := datasize
16
17 numGoroutines := 1
18 if enabled {
19 numProcs := runtime.GOMAXPROCS(0)
20 if numProcs > 1 {
21 numGoroutines = numProcs
22 partsize = partsize / numGoroutines
23 if partsize < 1 {
24 partsize = 1
25 }
26 }
27 }
28
29 if numGoroutines == 1 {
30 fn(datamin, datamax)
31 } else {
32 var wg sync.WaitGroup
33 wg.Add(numGoroutines)
34 idx := int64(datamin)
35
36 for p := 0; p < numGoroutines; p++ {
37 go func() {
38 defer wg.Done()
39 for {
40 pmin := int(atomic.AddInt64(&idx, int64(partsize))) - partsize
41 if pmin >= datamax {
42 break
43 }
44 pmax := pmin + partsize
45 if pmax > datamax {
46 pmax = datamax
47 }
48 fn(pmin, pmax)
49 }
50 }()
51 }
52
53 wg.Wait()
54 }
55}
56
57func absf32(x float32) float32 {
58 if x < 0 {
59 return -x
60 }
61 return x
62}
63
64func minf32(x, y float32) float32 {
65 if x < y {
66 return x
67 }
68 return y
69}
70
71func maxf32(x, y float32) float32 {
72 if x > y {
73 return x
74 }
75 return y
76}
77
78func powf32(x, y float32) float32 {
79 return float32(math.Pow(float64(x), float64(y)))
80}
81
82func logf32(x float32) float32 {
83 return float32(math.Log(float64(x)))
84}
85
86func expf32(x float32) float32 {
87 return float32(math.Exp(float64(x)))
88}
89
90func sincosf32(a float32) (float32, float32) {
91 sin, cos := math.Sincos(math.Pi * float64(a) / 180)
92 return float32(sin), float32(cos)
93}
94
95func floorf32(x float32) float32 {
96 return float32(math.Floor(float64(x)))
97}
98
99func sqrtf32(x float32) float32 {
100 return float32(math.Sqrt(float64(x)))
101}
102
103func minint(x, y int) int {
104 if x < y {
105 return x
106 }
107 return y
108}
109
110func maxint(x, y int) int {
111 if x > y {
112 return x
113 }
114 return y
115}
116
117func sort(data []float32) {
118 n := len(data)
119
120 if n < 2 {
121 return
122 }
123
124 if n <= 20 {
125 for i := 1; i < n; i++ {
126 x := data[i]
127 j := i - 1
128 for ; j >= 0 && data[j] > x; j-- {
129 data[j+1] = data[j]
130 }
131 data[j+1] = x
132 }
133 return
134 }
135
136 i := 0
137 j := n - 1
138 x := data[n/2]
139 for i <= j {
140 for data[i] < x {
141 i++
142 }
143 for data[j] > x {
144 j--
145 }
146 if i <= j {
147 data[i], data[j] = data[j], data[i]
148 i++
149 j--
150 }
151 }
152 if j > 0 {
153 sort(data[:j+1])
154 }
155 if i < n-1 {
156 sort(data[i:])
157 }
158}
159
160// createTempImage creates a temporary image.
161func createTempImage(r image.Rectangle) draw.Image {
162 return image.NewNRGBA64(r)
163}
164
165// isOpaque checks if the given image is opaque.
166func isOpaque(img image.Image) bool {
167 switch img := img.(type) {
168 case *image.NRGBA:
169 return img.Opaque()
170 case *image.NRGBA64:
171 return img.Opaque()
172 case *image.RGBA:
173 return img.Opaque()
174 case *image.RGBA64:
175 return img.Opaque()
176 case *image.Gray:
177 return true
178 case *image.Gray16:
179 return true
180 case *image.YCbCr:
181 return true
182 case *image.Paletted:
183 return img.Opaque()
184 }
185 return false
186}
187
188// genDisk generates a disk-shaped kernel.
189func genDisk(ksize int) []float32 {
190 if ksize%2 == 0 {
191 ksize--
192 }
193 if ksize < 1 {
194 return []float32{}
195 }
196 disk := make([]float32, ksize*ksize)
197 kcenter := ksize / 2
198 for i := 0; i < ksize; i++ {
199 for j := 0; j < ksize; j++ {
200 x := kcenter - i
201 y := kcenter - j
202 r := math.Sqrt(float64(x*x + y*y))
203 if r <= float64(ksize/2) {
204 disk[j*ksize+i] = 1
205 }
206 }
207 }
208 return disk
209}
210
211// copyimage copies an image from src to dst.
212func copyimage(dst draw.Image, src image.Image, options *Options) {
213 if options == nil {
214 options = &defaultOptions
215 }
216
217 srcb := src.Bounds()
218 dstb := dst.Bounds()
219 pixGetter := newPixelGetter(src)
220 pixSetter := newPixelSetter(dst)
221
222 parallelize(options.Parallelization, srcb.Min.Y, srcb.Max.Y, func(pmin, pmax int) {
223 for srcy := pmin; srcy < pmax; srcy++ {
224 for srcx := srcb.Min.X; srcx < srcb.Max.X; srcx++ {
225 dstx := dstb.Min.X + srcx - srcb.Min.X
226 dsty := dstb.Min.Y + srcy - srcb.Min.Y
227 pixSetter.setPixel(dstx, dsty, pixGetter.getPixel(srcx, srcy))
228 }
229 }
230 })
231}
232
233type copyimageFilter struct{}
234
235func (p *copyimageFilter) Bounds(srcBounds image.Rectangle) (dstBounds image.Rectangle) {
236 dstBounds = image.Rect(0, 0, srcBounds.Dx(), srcBounds.Dy())
237 return
238}
239
240func (p *copyimageFilter) Draw(dst draw.Image, src image.Image, options *Options) {
241 copyimage(dst, src, options)
242}