Parcourir la source

Use RGBA, RGBA64 image types as output.

These image types use premultiplied alpha values which are also used during the interpolation. If we'd use NRGBA, NRGBA64 as output, we'd have to reverse the premultiplication.
nfnt il y a 9 ans
Parent
révision
0f9f918da3
3 fichiers modifiés avec 62 ajouts et 114 suppressions
  1. 29
    81
      converter.go
  2. 25
    25
      resize.go
  3. 8
    8
      resize_test.go

+ 29
- 81
converter.go Voir le fichier

@@ -43,7 +43,7 @@ func clampUint16(in int64) uint16 {
43 43
 	return 0
44 44
 }
45 45
 
46
-func resizeGeneric(in image.Image, out *image.NRGBA64, scale float64, coeffs []int32, offset []int, filterLength int) {
46
+func resizeGeneric(in image.Image, out *image.RGBA64, scale float64, coeffs []int32, offset []int, filterLength int) {
47 47
 	newBounds := out.Bounds()
48 48
 	maxX := in.Bounds().Dx() - 1
49 49
 
@@ -63,7 +63,7 @@ func resizeGeneric(in image.Image, out *image.NRGBA64, scale float64, coeffs []i
63 63
 					case xi >= maxX:
64 64
 						xi = maxX
65 65
 					}
66
-					// Forward alpha-premultiplication (if needed)
66
+
67 67
 					r, g, b, a := in.At(xi+in.Bounds().Min.X, x+in.Bounds().Min.Y).RGBA()
68 68
 
69 69
 					rgba[0] += int64(coeff) * int64(r)
@@ -75,34 +75,24 @@ func resizeGeneric(in image.Image, out *image.NRGBA64, scale float64, coeffs []i
75 75
 			}
76 76
 
77 77
 			offset := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
78
-			// Reverse alpha-premultiplication
79
-			r := rgba[0] / sum
80
-			g := rgba[1] / sum
81
-			b := rgba[2] / sum
82
-			a := rgba[3] / sum
83
-
84
-			if a != 0 {
85
-				r = r * 0xffff / a
86
-				g = g * 0xffff / a
87
-				b = b * 0xffff / a
88
-			}
89
-			value := clampUint16(r)
78
+
79
+			value := clampUint16(rgba[0] / sum)
90 80
 			out.Pix[offset+0] = uint8(value >> 8)
91 81
 			out.Pix[offset+1] = uint8(value)
92
-			value = clampUint16(g)
82
+			value = clampUint16(rgba[1] / sum)
93 83
 			out.Pix[offset+2] = uint8(value >> 8)
94 84
 			out.Pix[offset+3] = uint8(value)
95
-			value = clampUint16(b)
85
+			value = clampUint16(rgba[2] / sum)
96 86
 			out.Pix[offset+4] = uint8(value >> 8)
97 87
 			out.Pix[offset+5] = uint8(value)
98
-			value = clampUint16(a)
88
+			value = clampUint16(rgba[3] / sum)
99 89
 			out.Pix[offset+6] = uint8(value >> 8)
100 90
 			out.Pix[offset+7] = uint8(value)
101 91
 		}
102 92
 	}
103 93
 }
104 94
 
105
-func resizeRGBA(in *image.RGBA, out *image.NRGBA, scale float64, coeffs []int16, offset []int, filterLength int) {
95
+func resizeRGBA(in *image.RGBA, out *image.RGBA, scale float64, coeffs []int16, offset []int, filterLength int) {
106 96
 	newBounds := out.Bounds()
107 97
 	maxX := in.Bounds().Dx() - 1
108 98
 
@@ -135,27 +125,16 @@ func resizeRGBA(in *image.RGBA, out *image.NRGBA, scale float64, coeffs []int16,
135 125
 			}
136 126
 
137 127
 			xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*4
138
-			// Reverse alpha-premultiplication
139
-			r := rgba[0] / sum
140
-			g := rgba[1] / sum
141
-			b := rgba[2] / sum
142
-			a := rgba[3] / sum
143
-
144
-			if a != 0 {
145
-				r = r * 0xff / a
146
-				g = g * 0xff / a
147
-				b = b * 0xff / a
148
-			}
149 128
 
150
-			out.Pix[xo+0] = clampUint8(r)
151
-			out.Pix[xo+1] = clampUint8(g)
152
-			out.Pix[xo+2] = clampUint8(b)
153
-			out.Pix[xo+3] = clampUint8(a)
129
+			out.Pix[xo+0] = clampUint8(rgba[0] / sum)
130
+			out.Pix[xo+1] = clampUint8(rgba[1] / sum)
131
+			out.Pix[xo+2] = clampUint8(rgba[2] / sum)
132
+			out.Pix[xo+3] = clampUint8(rgba[3] / sum)
154 133
 		}
155 134
 	}
156 135
 }
157 136
 
158
-func resizeNRGBA(in *image.NRGBA, out *image.NRGBA, scale float64, coeffs []int16, offset []int, filterLength int) {
137
+func resizeNRGBA(in *image.NRGBA, out *image.RGBA, scale float64, coeffs []int16, offset []int, filterLength int) {
159 138
 	newBounds := out.Bounds()
160 139
 	maxX := in.Bounds().Dx() - 1
161 140
 
@@ -190,27 +169,16 @@ func resizeNRGBA(in *image.NRGBA, out *image.NRGBA, scale float64, coeffs []int1
190 169
 			}
191 170
 
192 171
 			xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*4
193
-			// Reverse alpha-premultiplication
194
-			r := rgba[0] / sum
195
-			g := rgba[1] / sum
196
-			b := rgba[2] / sum
197
-			a := rgba[3] / sum
198
-
199
-			if a != 0 {
200
-				r = r * 0xff / a
201
-				g = g * 0xff / a
202
-				b = b * 0xff / a
203
-			}
204 172
 
205
-			out.Pix[xo+0] = clampUint8(r)
206
-			out.Pix[xo+1] = clampUint8(g)
207
-			out.Pix[xo+2] = clampUint8(b)
208
-			out.Pix[xo+3] = clampUint8(a)
173
+			out.Pix[xo+0] = clampUint8(rgba[0] / sum)
174
+			out.Pix[xo+1] = clampUint8(rgba[1] / sum)
175
+			out.Pix[xo+2] = clampUint8(rgba[2] / sum)
176
+			out.Pix[xo+3] = clampUint8(rgba[3] / sum)
209 177
 		}
210 178
 	}
211 179
 }
212 180
 
213
-func resizeRGBA64(in *image.RGBA64, out *image.NRGBA64, scale float64, coeffs []int32, offset []int, filterLength int) {
181
+func resizeRGBA64(in *image.RGBA64, out *image.RGBA64, scale float64, coeffs []int32, offset []int, filterLength int) {
214 182
 	newBounds := out.Bounds()
215 183
 	maxX := in.Bounds().Dx() - 1
216 184
 
@@ -243,34 +211,24 @@ func resizeRGBA64(in *image.RGBA64, out *image.NRGBA64, scale float64, coeffs []
243 211
 			}
244 212
 
245 213
 			xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
246
-			// Reverse alpha-premultiplication
247
-			r := rgba[0] / sum
248
-			g := rgba[1] / sum
249
-			b := rgba[2] / sum
250
-			a := rgba[3] / sum
251
-
252
-			if a != 0 {
253
-				r = r * 0xffff / a
254
-				g = g * 0xffff / a
255
-				b = b * 0xffff / a
256
-			}
257
-			value := clampUint16(r)
214
+
215
+			value := clampUint16(rgba[0] / sum)
258 216
 			out.Pix[xo+0] = uint8(value >> 8)
259 217
 			out.Pix[xo+1] = uint8(value)
260
-			value = clampUint16(g)
218
+			value = clampUint16(rgba[1] / sum)
261 219
 			out.Pix[xo+2] = uint8(value >> 8)
262 220
 			out.Pix[xo+3] = uint8(value)
263
-			value = clampUint16(b)
221
+			value = clampUint16(rgba[2] / sum)
264 222
 			out.Pix[xo+4] = uint8(value >> 8)
265 223
 			out.Pix[xo+5] = uint8(value)
266
-			value = clampUint16(a)
224
+			value = clampUint16(rgba[3] / sum)
267 225
 			out.Pix[xo+6] = uint8(value >> 8)
268 226
 			out.Pix[xo+7] = uint8(value)
269 227
 		}
270 228
 	}
271 229
 }
272 230
 
273
-func resizeNRGBA64(in *image.NRGBA64, out *image.NRGBA64, scale float64, coeffs []int32, offset []int, filterLength int) {
231
+func resizeNRGBA64(in *image.NRGBA64, out *image.RGBA64, scale float64, coeffs []int32, offset []int, filterLength int) {
274 232
 	newBounds := out.Bounds()
275 233
 	maxX := in.Bounds().Dx() - 1
276 234
 
@@ -305,27 +263,17 @@ func resizeNRGBA64(in *image.NRGBA64, out *image.NRGBA64, scale float64, coeffs
305 263
 			}
306 264
 
307 265
 			xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
308
-			// Reverse alpha-premultiplication
309
-			r := rgba[0] / sum
310
-			g := rgba[1] / sum
311
-			b := rgba[2] / sum
312
-			a := rgba[3] / sum
313
-
314
-			if a != 0 {
315
-				r = r * 0xffff / a
316
-				g = g * 0xffff / a
317
-				b = b * 0xffff / a
318
-			}
319
-			value := clampUint16(r)
266
+
267
+			value := clampUint16(rgba[0] / sum)
320 268
 			out.Pix[xo+0] = uint8(value >> 8)
321 269
 			out.Pix[xo+1] = uint8(value)
322
-			value = clampUint16(g)
270
+			value = clampUint16(rgba[1] / sum)
323 271
 			out.Pix[xo+2] = uint8(value >> 8)
324 272
 			out.Pix[xo+3] = uint8(value)
325
-			value = clampUint16(b)
273
+			value = clampUint16(rgba[2] / sum)
326 274
 			out.Pix[xo+4] = uint8(value >> 8)
327 275
 			out.Pix[xo+5] = uint8(value)
328
-			value = clampUint16(a)
276
+			value = clampUint16(rgba[3] / sum)
329 277
 			out.Pix[xo+6] = uint8(value >> 8)
330 278
 			out.Pix[xo+7] = uint8(value)
331 279
 		}

+ 25
- 25
resize.go Voir le fichier

@@ -105,14 +105,14 @@ func Resize(width, height uint, img image.Image, interp InterpolationFunction) i
105 105
 	switch input := img.(type) {
106 106
 	case *image.RGBA:
107 107
 		// 8-bit precision
108
-		temp := image.NewNRGBA(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
109
-		result := image.NewNRGBA(image.Rect(0, 0, int(width), int(height)))
108
+		temp := image.NewRGBA(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
109
+		result := image.NewRGBA(image.Rect(0, 0, int(width), int(height)))
110 110
 
111 111
 		// horizontal filter, results in transposed temporary image
112 112
 		coeffs, offset, filterLength := createWeights8(temp.Bounds().Dy(), taps, blur, scaleX, kernel)
113 113
 		wg.Add(cpus)
114 114
 		for i := 0; i < cpus; i++ {
115
-			slice := makeSlice(temp, i, cpus).(*image.NRGBA)
115
+			slice := makeSlice(temp, i, cpus).(*image.RGBA)
116 116
 			go func() {
117 117
 				defer wg.Done()
118 118
 				resizeRGBA(input, slice, scaleX, coeffs, offset, filterLength)
@@ -124,24 +124,24 @@ func Resize(width, height uint, img image.Image, interp InterpolationFunction) i
124 124
 		coeffs, offset, filterLength = createWeights8(result.Bounds().Dy(), taps, blur, scaleY, kernel)
125 125
 		wg.Add(cpus)
126 126
 		for i := 0; i < cpus; i++ {
127
-			slice := makeSlice(result, i, cpus).(*image.NRGBA)
127
+			slice := makeSlice(result, i, cpus).(*image.RGBA)
128 128
 			go func() {
129 129
 				defer wg.Done()
130
-				resizeNRGBA(temp, slice, scaleY, coeffs, offset, filterLength)
130
+				resizeRGBA(temp, slice, scaleY, coeffs, offset, filterLength)
131 131
 			}()
132 132
 		}
133 133
 		wg.Wait()
134 134
 		return result
135 135
 	case *image.NRGBA:
136 136
 		// 8-bit precision
137
-		temp := image.NewNRGBA(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
138
-		result := image.NewNRGBA(image.Rect(0, 0, int(width), int(height)))
137
+		temp := image.NewRGBA(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
138
+		result := image.NewRGBA(image.Rect(0, 0, int(width), int(height)))
139 139
 
140 140
 		// horizontal filter, results in transposed temporary image
141 141
 		coeffs, offset, filterLength := createWeights8(temp.Bounds().Dy(), taps, blur, scaleX, kernel)
142 142
 		wg.Add(cpus)
143 143
 		for i := 0; i < cpus; i++ {
144
-			slice := makeSlice(temp, i, cpus).(*image.NRGBA)
144
+			slice := makeSlice(temp, i, cpus).(*image.RGBA)
145 145
 			go func() {
146 146
 				defer wg.Done()
147 147
 				resizeNRGBA(input, slice, scaleX, coeffs, offset, filterLength)
@@ -153,10 +153,10 @@ func Resize(width, height uint, img image.Image, interp InterpolationFunction) i
153 153
 		coeffs, offset, filterLength = createWeights8(result.Bounds().Dy(), taps, blur, scaleY, kernel)
154 154
 		wg.Add(cpus)
155 155
 		for i := 0; i < cpus; i++ {
156
-			slice := makeSlice(result, i, cpus).(*image.NRGBA)
156
+			slice := makeSlice(result, i, cpus).(*image.RGBA)
157 157
 			go func() {
158 158
 				defer wg.Done()
159
-				resizeNRGBA(temp, slice, scaleY, coeffs, offset, filterLength)
159
+				resizeRGBA(temp, slice, scaleY, coeffs, offset, filterLength)
160 160
 			}()
161 161
 		}
162 162
 		wg.Wait()
@@ -194,14 +194,14 @@ func Resize(width, height uint, img image.Image, interp InterpolationFunction) i
194 194
 		return result.YCbCr()
195 195
 	case *image.RGBA64:
196 196
 		// 16-bit precision
197
-		temp := image.NewNRGBA64(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
198
-		result := image.NewNRGBA64(image.Rect(0, 0, int(width), int(height)))
197
+		temp := image.NewRGBA64(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
198
+		result := image.NewRGBA64(image.Rect(0, 0, int(width), int(height)))
199 199
 
200 200
 		// horizontal filter, results in transposed temporary image
201 201
 		coeffs, offset, filterLength := createWeights16(temp.Bounds().Dy(), taps, blur, scaleX, kernel)
202 202
 		wg.Add(cpus)
203 203
 		for i := 0; i < cpus; i++ {
204
-			slice := makeSlice(temp, i, cpus).(*image.NRGBA64)
204
+			slice := makeSlice(temp, i, cpus).(*image.RGBA64)
205 205
 			go func() {
206 206
 				defer wg.Done()
207 207
 				resizeRGBA64(input, slice, scaleX, coeffs, offset, filterLength)
@@ -213,24 +213,24 @@ func Resize(width, height uint, img image.Image, interp InterpolationFunction) i
213 213
 		coeffs, offset, filterLength = createWeights16(result.Bounds().Dy(), taps, blur, scaleY, kernel)
214 214
 		wg.Add(cpus)
215 215
 		for i := 0; i < cpus; i++ {
216
-			slice := makeSlice(result, i, cpus).(*image.NRGBA64)
216
+			slice := makeSlice(result, i, cpus).(*image.RGBA64)
217 217
 			go func() {
218 218
 				defer wg.Done()
219
-				resizeNRGBA64(temp, slice, scaleY, coeffs, offset, filterLength)
219
+				resizeRGBA64(temp, slice, scaleY, coeffs, offset, filterLength)
220 220
 			}()
221 221
 		}
222 222
 		wg.Wait()
223 223
 		return result
224 224
 	case *image.NRGBA64:
225 225
 		// 16-bit precision
226
-		temp := image.NewNRGBA64(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
227
-		result := image.NewNRGBA64(image.Rect(0, 0, int(width), int(height)))
226
+		temp := image.NewRGBA64(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
227
+		result := image.NewRGBA64(image.Rect(0, 0, int(width), int(height)))
228 228
 
229 229
 		// horizontal filter, results in transposed temporary image
230 230
 		coeffs, offset, filterLength := createWeights16(temp.Bounds().Dy(), taps, blur, scaleX, kernel)
231 231
 		wg.Add(cpus)
232 232
 		for i := 0; i < cpus; i++ {
233
-			slice := makeSlice(temp, i, cpus).(*image.NRGBA64)
233
+			slice := makeSlice(temp, i, cpus).(*image.RGBA64)
234 234
 			go func() {
235 235
 				defer wg.Done()
236 236
 				resizeNRGBA64(input, slice, scaleX, coeffs, offset, filterLength)
@@ -242,10 +242,10 @@ func Resize(width, height uint, img image.Image, interp InterpolationFunction) i
242 242
 		coeffs, offset, filterLength = createWeights16(result.Bounds().Dy(), taps, blur, scaleY, kernel)
243 243
 		wg.Add(cpus)
244 244
 		for i := 0; i < cpus; i++ {
245
-			slice := makeSlice(result, i, cpus).(*image.NRGBA64)
245
+			slice := makeSlice(result, i, cpus).(*image.RGBA64)
246 246
 			go func() {
247 247
 				defer wg.Done()
248
-				resizeNRGBA64(temp, slice, scaleY, coeffs, offset, filterLength)
248
+				resizeRGBA64(temp, slice, scaleY, coeffs, offset, filterLength)
249 249
 			}()
250 250
 		}
251 251
 		wg.Wait()
@@ -310,14 +310,14 @@ func Resize(width, height uint, img image.Image, interp InterpolationFunction) i
310 310
 		return result
311 311
 	default:
312 312
 		// 16-bit precision
313
-		temp := image.NewNRGBA64(image.Rect(0, 0, img.Bounds().Dy(), int(width)))
314
-		result := image.NewNRGBA64(image.Rect(0, 0, int(width), int(height)))
313
+		temp := image.NewRGBA64(image.Rect(0, 0, img.Bounds().Dy(), int(width)))
314
+		result := image.NewRGBA64(image.Rect(0, 0, int(width), int(height)))
315 315
 
316 316
 		// horizontal filter, results in transposed temporary image
317 317
 		coeffs, offset, filterLength := createWeights16(temp.Bounds().Dy(), taps, blur, scaleX, kernel)
318 318
 		wg.Add(cpus)
319 319
 		for i := 0; i < cpus; i++ {
320
-			slice := makeSlice(temp, i, cpus).(*image.NRGBA64)
320
+			slice := makeSlice(temp, i, cpus).(*image.RGBA64)
321 321
 			go func() {
322 322
 				defer wg.Done()
323 323
 				resizeGeneric(img, slice, scaleX, coeffs, offset, filterLength)
@@ -329,10 +329,10 @@ func Resize(width, height uint, img image.Image, interp InterpolationFunction) i
329 329
 		coeffs, offset, filterLength = createWeights16(result.Bounds().Dy(), taps, blur, scaleY, kernel)
330 330
 		wg.Add(cpus)
331 331
 		for i := 0; i < cpus; i++ {
332
-			slice := makeSlice(result, i, cpus).(*image.NRGBA64)
332
+			slice := makeSlice(result, i, cpus).(*image.RGBA64)
333 333
 			go func() {
334 334
 				defer wg.Done()
335
-				resizeNRGBA64(temp, slice, scaleY, coeffs, offset, filterLength)
335
+				resizeRGBA64(temp, slice, scaleY, coeffs, offset, filterLength)
336 336
 			}()
337 337
 		}
338 338
 		wg.Wait()

+ 8
- 8
resize_test.go Voir le fichier

@@ -56,7 +56,7 @@ func Test_SameColorWithRGBA(t *testing.T) {
56 56
 	out := Resize(10, 10, img, Lanczos3)
57 57
 	for y := out.Bounds().Min.Y; y < out.Bounds().Max.Y; y++ {
58 58
 		for x := out.Bounds().Min.X; x < out.Bounds().Max.X; x++ {
59
-			color := out.At(x, y).(color.NRGBA)
59
+			color := out.At(x, y).(color.RGBA)
60 60
 			if color.R != 0x80 || color.G != 0x80 || color.B != 0x80 || color.A != 0xFF {
61 61
 				t.Errorf("%+v", color)
62 62
 			}
@@ -74,7 +74,7 @@ func Test_SameColorWithNRGBA(t *testing.T) {
74 74
 	out := Resize(10, 10, img, Lanczos3)
75 75
 	for y := out.Bounds().Min.Y; y < out.Bounds().Max.Y; y++ {
76 76
 		for x := out.Bounds().Min.X; x < out.Bounds().Max.X; x++ {
77
-			color := out.At(x, y).(color.NRGBA)
77
+			color := out.At(x, y).(color.RGBA)
78 78
 			if color.R != 0x80 || color.G != 0x80 || color.B != 0x80 || color.A != 0xFF {
79 79
 				t.Errorf("%+v", color)
80 80
 			}
@@ -92,7 +92,7 @@ func Test_SameColorWithRGBA64(t *testing.T) {
92 92
 	out := Resize(10, 10, img, Lanczos3)
93 93
 	for y := out.Bounds().Min.Y; y < out.Bounds().Max.Y; y++ {
94 94
 		for x := out.Bounds().Min.X; x < out.Bounds().Max.X; x++ {
95
-			color := out.At(x, y).(color.NRGBA64)
95
+			color := out.At(x, y).(color.RGBA64)
96 96
 			if color.R != 0x8000 || color.G != 0x8000 || color.B != 0x8000 || color.A != 0xFFFF {
97 97
 				t.Errorf("%+v", color)
98 98
 			}
@@ -110,7 +110,7 @@ func Test_SameColorWithNRGBA64(t *testing.T) {
110 110
 	out := Resize(10, 10, img, Lanczos3)
111 111
 	for y := out.Bounds().Min.Y; y < out.Bounds().Max.Y; y++ {
112 112
 		for x := out.Bounds().Min.X; x < out.Bounds().Max.X; x++ {
113
-			color := out.At(x, y).(color.NRGBA64)
113
+			color := out.At(x, y).(color.RGBA64)
114 114
 			if color.R != 0x8000 || color.G != 0x8000 || color.B != 0x8000 || color.A != 0xFFFF {
115 115
 				t.Errorf("%+v", color)
116 116
 			}
@@ -204,8 +204,8 @@ func Test_ResizeWithPremultipliedAlpha(t *testing.T) {
204 204
 
205 205
 	out := Resize(1, 2, img, MitchellNetravali)
206 206
 
207
-	outputColor := out.At(0, 0).(color.NRGBA)
208
-	if outputColor.R != 0xFF {
207
+	outputColor := out.At(0, 0).(color.RGBA)
208
+	if outputColor.R != 0x80 {
209 209
 		t.Fail()
210 210
 	}
211 211
 }
@@ -213,8 +213,8 @@ func Test_ResizeWithPremultipliedAlpha(t *testing.T) {
213 213
 func Test_ResizeWithTranslucentColor(t *testing.T) {
214 214
 	img := image.NewNRGBA(image.Rect(0, 0, 1, 2))
215 215
 
216
-    // Set the pixel colors to an "invisible green" and white.
217
-    // After resizing, the green shouldn't be visible.
216
+	// Set the pixel colors to an "invisible green" and white.
217
+	// After resizing, the green shouldn't be visible.
218 218
 	img.SetNRGBA(0, 0, color.NRGBA{0x00, 0xFF, 0x00, 0x00})
219 219
 	img.SetNRGBA(0, 1, color.NRGBA{0x00, 0x00, 0x00, 0xFF})
220 220