text changes to registration mail content
[namibia] / public / scripts / blueimp-jQuery-File-Upload / server / gae-go / resize / resize.go
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package resize
6
7 import (
8         "image"
9         "image/color"
10 )
11
12 // Resize returns a scaled copy of the image slice r of m.
13 // The returned image has width w and height h.
14 func Resize(m image.Image, r image.Rectangle, w, h int) image.Image {
15         if w < 0 || h < 0 {
16                 return nil
17         }
18         if w == 0 || h == 0 || r.Dx() <= 0 || r.Dy() <= 0 {
19                 return image.NewRGBA64(image.Rect(0, 0, w, h))
20         }
21         switch m := m.(type) {
22         case *image.RGBA:
23                 return resizeRGBA(m, r, w, h)
24         case *image.YCbCr:
25                 if m, ok := resizeYCbCr(m, r, w, h); ok {
26                         return m
27                 }
28         }
29         ww, hh := uint64(w), uint64(h)
30         dx, dy := uint64(r.Dx()), uint64(r.Dy())
31         // The scaling algorithm is to nearest-neighbor magnify the dx * dy source
32         // to a (ww*dx) * (hh*dy) intermediate image and then minify the intermediate
33         // image back down to a ww * hh destination with a simple box filter.
34         // The intermediate image is implied, we do not physically allocate a slice
35         // of length ww*dx*hh*dy.
36         // For example, consider a 4*3 source image. Label its pixels from a-l:
37         //      abcd
38         //      efgh
39         //      ijkl
40         // To resize this to a 3*2 destination image, the intermediate is 12*6.
41         // Whitespace has been added to delineate the destination pixels:
42         //      aaab bbcc cddd
43         //      aaab bbcc cddd
44         //      eeef ffgg ghhh
45         //
46         //      eeef ffgg ghhh
47         //      iiij jjkk klll
48         //      iiij jjkk klll
49         // Thus, the 'b' source pixel contributes one third of its value to the
50         // (0, 0) destination pixel and two thirds to (1, 0).
51         // The implementation is a two-step process. First, the source pixels are
52         // iterated over and each source pixel's contribution to 1 or more
53         // destination pixels are summed. Second, the sums are divided by a scaling
54         // factor to yield the destination pixels.
55         // TODO: By interleaving the two steps, instead of doing all of
56         // step 1 first and all of step 2 second, we could allocate a smaller sum
57         // slice of length 4*w*2 instead of 4*w*h, although the resultant code
58         // would become more complicated.
59         n, sum := dx*dy, make([]uint64, 4*w*h)
60         for y := r.Min.Y; y < r.Max.Y; y++ {
61                 for x := r.Min.X; x < r.Max.X; x++ {
62                         // Get the source pixel.
63                         r32, g32, b32, a32 := m.At(x, y).RGBA()
64                         r64 := uint64(r32)
65                         g64 := uint64(g32)
66                         b64 := uint64(b32)
67                         a64 := uint64(a32)
68                         // Spread the source pixel over 1 or more destination rows.
69                         py := uint64(y) * hh
70                         for remy := hh; remy > 0; {
71                                 qy := dy - (py % dy)
72                                 if qy > remy {
73                                         qy = remy
74                                 }
75                                 // Spread the source pixel over 1 or more destination columns.
76                                 px := uint64(x) * ww
77                                 index := 4 * ((py/dy)*ww + (px / dx))
78                                 for remx := ww; remx > 0; {
79                                         qx := dx - (px % dx)
80                                         if qx > remx {
81                                                 qx = remx
82                                         }
83                                         sum[index+0] += r64 * qx * qy
84                                         sum[index+1] += g64 * qx * qy
85                                         sum[index+2] += b64 * qx * qy
86                                         sum[index+3] += a64 * qx * qy
87                                         index += 4
88                                         px += qx
89                                         remx -= qx
90                                 }
91                                 py += qy
92                                 remy -= qy
93                         }
94                 }
95         }
96         return average(sum, w, h, n*0x0101)
97 }
98
99 // average convert the sums to averages and returns the result.
100 func average(sum []uint64, w, h int, n uint64) image.Image {
101         ret := image.NewRGBA(image.Rect(0, 0, w, h))
102         for y := 0; y < h; y++ {
103                 for x := 0; x < w; x++ {
104                         index := 4 * (y*w + x)
105                         ret.SetRGBA(x, y, color.RGBA{
106                                 uint8(sum[index+0] / n),
107                                 uint8(sum[index+1] / n),
108                                 uint8(sum[index+2] / n),
109                                 uint8(sum[index+3] / n),
110                         })
111                 }
112         }
113         return ret
114 }
115
116 // resizeYCbCr returns a scaled copy of the YCbCr image slice r of m.
117 // The returned image has width w and height h.
118 func resizeYCbCr(m *image.YCbCr, r image.Rectangle, w, h int) (image.Image, bool) {
119         var verticalRes int
120         switch m.SubsampleRatio {
121         case image.YCbCrSubsampleRatio420:
122                 verticalRes = 2
123         case image.YCbCrSubsampleRatio422:
124                 verticalRes = 1
125         default:
126                 return nil, false
127         }
128         ww, hh := uint64(w), uint64(h)
129         dx, dy := uint64(r.Dx()), uint64(r.Dy())
130         // See comment in Resize.
131         n, sum := dx*dy, make([]uint64, 4*w*h)
132         for y := r.Min.Y; y < r.Max.Y; y++ {
133                 Y := m.Y[y*m.YStride:]
134                 Cb := m.Cb[y/verticalRes*m.CStride:]
135                 Cr := m.Cr[y/verticalRes*m.CStride:]
136                 for x := r.Min.X; x < r.Max.X; x++ {
137                         // Get the source pixel.
138                         r8, g8, b8 := color.YCbCrToRGB(Y[x], Cb[x/2], Cr[x/2])
139                         r64 := uint64(r8)
140                         g64 := uint64(g8)
141                         b64 := uint64(b8)
142                         // Spread the source pixel over 1 or more destination rows.
143                         py := uint64(y) * hh
144                         for remy := hh; remy > 0; {
145                                 qy := dy - (py % dy)
146                                 if qy > remy {
147                                         qy = remy
148                                 }
149                                 // Spread the source pixel over 1 or more destination columns.
150                                 px := uint64(x) * ww
151                                 index := 4 * ((py/dy)*ww + (px / dx))
152                                 for remx := ww; remx > 0; {
153                                         qx := dx - (px % dx)
154                                         if qx > remx {
155                                                 qx = remx
156                                         }
157                                         qxy := qx * qy
158                                         sum[index+0] += r64 * qxy
159                                         sum[index+1] += g64 * qxy
160                                         sum[index+2] += b64 * qxy
161                                         sum[index+3] += 0xFFFF * qxy
162                                         index += 4
163                                         px += qx
164                                         remx -= qx
165                                 }
166                                 py += qy
167                                 remy -= qy
168                         }
169                 }
170         }
171         return average(sum, w, h, n), true
172 }
173
174 // resizeRGBA returns a scaled copy of the RGBA image slice r of m.
175 // The returned image has width w and height h.
176 func resizeRGBA(m *image.RGBA, r image.Rectangle, w, h int) image.Image {
177         ww, hh := uint64(w), uint64(h)
178         dx, dy := uint64(r.Dx()), uint64(r.Dy())
179         // See comment in Resize.
180         n, sum := dx*dy, make([]uint64, 4*w*h)
181         for y := r.Min.Y; y < r.Max.Y; y++ {
182                 pixOffset := m.PixOffset(r.Min.X, y)
183                 for x := r.Min.X; x < r.Max.X; x++ {
184                         // Get the source pixel.
185                         r64 := uint64(m.Pix[pixOffset+0])
186                         g64 := uint64(m.Pix[pixOffset+1])
187                         b64 := uint64(m.Pix[pixOffset+2])
188                         a64 := uint64(m.Pix[pixOffset+3])
189                         pixOffset += 4
190                         // Spread the source pixel over 1 or more destination rows.
191                         py := uint64(y) * hh
192                         for remy := hh; remy > 0; {
193                                 qy := dy - (py % dy)
194                                 if qy > remy {
195                                         qy = remy
196                                 }
197                                 // Spread the source pixel over 1 or more destination columns.
198                                 px := uint64(x) * ww
199                                 index := 4 * ((py/dy)*ww + (px / dx))
200                                 for remx := ww; remx > 0; {
201                                         qx := dx - (px % dx)
202                                         if qx > remx {
203                                                 qx = remx
204                                         }
205                                         qxy := qx * qy
206                                         sum[index+0] += r64 * qxy
207                                         sum[index+1] += g64 * qxy
208                                         sum[index+2] += b64 * qxy
209                                         sum[index+3] += a64 * qxy
210                                         index += 4
211                                         px += qx
212                                         remx -= qx
213                                 }
214                                 py += qy
215                                 remy -= qy
216                         }
217                 }
218         }
219         return average(sum, w, h, n)
220 }
221
222 // Resample returns a resampled copy of the image slice r of m.
223 // The returned image has width w and height h.
224 func Resample(m image.Image, r image.Rectangle, w, h int) image.Image {
225         if w < 0 || h < 0 {
226                 return nil
227         }
228         if w == 0 || h == 0 || r.Dx() <= 0 || r.Dy() <= 0 {
229                 return image.NewRGBA64(image.Rect(0, 0, w, h))
230         }
231         curw, curh := r.Dx(), r.Dy()
232         img := image.NewRGBA(image.Rect(0, 0, w, h))
233         for y := 0; y < h; y++ {
234                 for x := 0; x < w; x++ {
235                         // Get a source pixel.
236                         subx := x * curw / w
237                         suby := y * curh / h
238                         r32, g32, b32, a32 := m.At(subx, suby).RGBA()
239                         r := uint8(r32 >> 8)
240                         g := uint8(g32 >> 8)
241                         b := uint8(b32 >> 8)
242                         a := uint8(a32 >> 8)
243                         img.SetRGBA(x, y, color.RGBA{r, g, b, a})
244                 }
245         }
246         return img
247 }