github.com/cellofellow/gopkg@v0.0.0-20140722061823-eec0544a62ad/image/draw/draw_pyrdown_average.go (about) 1 // Copyright 2014 <chaishushan{AT}gmail.com>. 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 draw 6 7 import ( 8 "image" 9 "image/color" 10 "image/draw" 11 "reflect" 12 13 "github.com/chai2010/gopkg/builtin" 14 image_ext "github.com/chai2010/gopkg/image" 15 color_ext "github.com/chai2010/gopkg/image/color" 16 ) 17 18 func drawPyrDownGray_Average(dst *image.Gray, r image.Rectangle, src image.Image, sp image.Point) { 19 switch src := src.(type) { 20 case *image.Gray: 21 // 64 is a magic, see go test -bench=. 22 if r.Dx() >= 64 && r.In(dst.Bounds()) && image.Rect(sp.X, sp.Y, sp.X+r.Dx()*2, sp.Y+r.Dy()*2).In(src.Bounds()) { 23 drawPyrDownGray_Average_fast(dst, r, src, sp) 24 return 25 } 26 drawPyrDownGray_Average_slow(dst, r, src, sp) 27 return 28 default: 29 drawPyrDown_Average(dst, r, src, sp) 30 } 31 } 32 33 func drawPyrDownGray_Average_slow(dst *image.Gray, r image.Rectangle, src *image.Gray, sp image.Point) { 34 for y := r.Min.Y; y < r.Max.Y; y++ { 35 for x := r.Min.X; x < r.Max.X; x++ { 36 x0 := (x-r.Min.X)*2 + sp.X 37 y0 := (y-r.Min.Y)*2 + sp.Y 38 39 y00 := uint16(src.GrayAt(x0+0, y0+0).Y) 40 y01 := uint16(src.GrayAt(x0+0, y0+1).Y) 41 y11 := uint16(src.GrayAt(x0+1, y0+1).Y) 42 y10 := uint16(src.GrayAt(x0+1, y0+0).Y) 43 44 dst.SetGray(x, y, color.Gray{ 45 Y: uint8((y00 + y01 + y11 + y10) / 4), 46 }) 47 } 48 } 49 } 50 51 func drawPyrDownGray_Average_fast(dst *image.Gray, r image.Rectangle, src *image.Gray, sp image.Point) { 52 off0 := dst.PixOffset(r.Min.X, r.Min.Y) 53 off1 := src.PixOffset(sp.X, sp.Y) 54 off2 := off1 + src.Stride 55 56 if padding := r.Dx() % 4; padding != 0 { 57 for y := r.Min.Y; y < r.Max.Y; y++ { 58 dstLineX := builtin.Slice(dst.Pix[off0:][:r.Dx()*1], reflect.TypeOf([]uint32(nil))).([]uint32) 59 srcLine0 := builtin.Slice(src.Pix[off1:][:r.Dx()*2], reflect.TypeOf([]uint32(nil))).([]uint32) 60 srcLine1 := builtin.Slice(src.Pix[off2:][:r.Dx()*2], reflect.TypeOf([]uint32(nil))).([]uint32) 61 62 i, j := 0, 0 63 for ; i < len(dstLineX); i++ { 64 dstLineX[i] = mergeRgbaFast( 65 mergeRgbaFast(srcLine0[j+0], srcLine0[j+1]), 66 mergeRgbaFast(srcLine1[j+0], srcLine1[j+1]), 67 ) 68 j += 2 69 } 70 for k := 0; k < padding; k++ { 71 y00 := uint16(src.Pix[off1:][j*4+k*2+0]) 72 y01 := uint16(src.Pix[off1:][j*4+k*2+1]) 73 y11 := uint16(src.Pix[off2:][j*4+k*2+1]) 74 y10 := uint16(src.Pix[off2:][j*4+k*2+0]) 75 dst.Pix[off0:][i*4+k] = uint8((y00 + y01 + y11 + y10) / 4) 76 } 77 off0 += dst.Stride * 1 78 off1 += src.Stride * 2 79 off2 += src.Stride * 2 80 } 81 } else { 82 for y := r.Min.Y; y < r.Max.Y; y++ { 83 dstLineX := builtin.Slice(dst.Pix[off0:][:r.Dx()*1], reflect.TypeOf([]uint32(nil))).([]uint32) 84 srcLine0 := builtin.Slice(src.Pix[off1:][:r.Dx()*2], reflect.TypeOf([]uint32(nil))).([]uint32) 85 srcLine1 := builtin.Slice(src.Pix[off2:][:r.Dx()*2], reflect.TypeOf([]uint32(nil))).([]uint32) 86 87 for i, j := 0, 0; i < len(dstLineX); i, j = i+1, j+2 { 88 dstLineX[i] = mergeRgbaFast( 89 mergeRgbaFast(srcLine0[j+0], srcLine0[j+1]), 90 mergeRgbaFast(srcLine1[j+0], srcLine1[j+1]), 91 ) 92 } 93 off0 += dst.Stride * 1 94 off1 += src.Stride * 2 95 off2 += src.Stride * 2 96 } 97 } 98 } 99 100 func drawPyrDownGray16_Average(dst *image.Gray16, r image.Rectangle, src image.Image, sp image.Point) { 101 switch src := src.(type) { 102 case *image.Gray16: 103 for y := r.Min.Y; y < r.Max.Y; y++ { 104 for x := r.Min.X; x < r.Max.X; x++ { 105 x0 := (x-r.Min.X)*2 + sp.X 106 y0 := (y-r.Min.Y)*2 + sp.Y 107 108 y00 := uint32(src.Gray16At(x0+0, y0+0).Y) 109 y01 := uint32(src.Gray16At(x0+0, y0+1).Y) 110 y11 := uint32(src.Gray16At(x0+1, y0+1).Y) 111 y10 := uint32(src.Gray16At(x0+1, y0+0).Y) 112 113 dst.SetGray16(x, y, color.Gray16{ 114 Y: uint16((y00 + y01 + y11 + y10) / 4), 115 }) 116 } 117 } 118 default: 119 drawPyrDown_Average(dst, r, src, sp) 120 } 121 } 122 123 func drawPyrDownGray32f_Average(dst *image_ext.Gray32f, r image.Rectangle, src image.Image, sp image.Point) { 124 switch src := src.(type) { 125 case *image_ext.Gray32f: 126 for y := r.Min.Y; y < r.Max.Y; y++ { 127 for x := r.Min.X; x < r.Max.X; x++ { 128 x0 := (x-r.Min.X)*2 + sp.X 129 y0 := (y-r.Min.Y)*2 + sp.Y 130 131 y00 := src.Gray32fAt(x0+0, y0+0).Y 132 y01 := src.Gray32fAt(x0+0, y0+1).Y 133 y11 := src.Gray32fAt(x0+1, y0+1).Y 134 y10 := src.Gray32fAt(x0+1, y0+0).Y 135 136 dst.SetGray32f(x, y, color_ext.Gray32f{ 137 Y: (y00 + y01 + y11 + y10) / 4, 138 }) 139 } 140 } 141 default: 142 drawPyrDown_Average(dst, r, src, sp) 143 } 144 } 145 146 func drawPyrDownRGB_Average(dst *image_ext.RGB, r image.Rectangle, src image.Image, sp image.Point) { 147 switch src := src.(type) { 148 case *image_ext.RGB: 149 for y := r.Min.Y; y < r.Max.Y; y++ { 150 for x := r.Min.X; x < r.Max.X; x++ { 151 x0 := (x-r.Min.X)*2 + sp.X 152 y0 := (y-r.Min.Y)*2 + sp.Y 153 154 rgb00 := src.RGBAt(x0+0, y0+0) 155 rgb01 := src.RGBAt(x0+0, y0+1) 156 rgb11 := src.RGBAt(x0+1, y0+1) 157 rgb10 := src.RGBAt(x0+1, y0+0) 158 159 dst.SetRGB(x, y, color_ext.RGB{ 160 R: uint8((uint16(rgb00.R) + uint16(rgb01.R) + uint16(rgb11.R) + uint16(rgb10.R)) / 4), 161 G: uint8((uint16(rgb00.G) + uint16(rgb01.G) + uint16(rgb11.G) + uint16(rgb10.G)) / 4), 162 B: uint8((uint16(rgb00.B) + uint16(rgb01.B) + uint16(rgb11.B) + uint16(rgb10.B)) / 4), 163 }) 164 } 165 } 166 return 167 default: 168 drawPyrDown_Average(dst, r, src, sp) 169 return 170 } 171 } 172 173 func drawPyrDownRGB48_Average(dst *image_ext.RGB48, r image.Rectangle, src image.Image, sp image.Point) { 174 switch src := src.(type) { 175 case *image_ext.RGB48: 176 for y := r.Min.Y; y < r.Max.Y; y++ { 177 for x := r.Min.X; x < r.Max.X; x++ { 178 x0 := (x-r.Min.X)*2 + sp.X 179 y0 := (y-r.Min.Y)*2 + sp.Y 180 181 rgb00 := src.RGB48At(x0+0, y0+0) 182 rgb01 := src.RGB48At(x0+0, y0+1) 183 rgb11 := src.RGB48At(x0+1, y0+1) 184 rgb10 := src.RGB48At(x0+1, y0+0) 185 186 dst.SetRGB48(x, y, color_ext.RGB48{ 187 R: uint16((uint32(rgb00.R) + uint32(rgb01.R) + uint32(rgb11.R) + uint32(rgb10.R)) / 4), 188 G: uint16((uint32(rgb00.G) + uint32(rgb01.G) + uint32(rgb11.G) + uint32(rgb10.G)) / 4), 189 B: uint16((uint32(rgb00.B) + uint32(rgb01.B) + uint32(rgb11.B) + uint32(rgb10.B)) / 4), 190 }) 191 } 192 } 193 default: 194 drawPyrDown_Average(dst, r, src, sp) 195 } 196 } 197 198 func drawPyrDownRGB96f_Average(dst *image_ext.RGB96f, r image.Rectangle, src image.Image, sp image.Point) { 199 switch src := src.(type) { 200 case *image_ext.RGB96f: 201 for y := r.Min.Y; y < r.Max.Y; y++ { 202 for x := r.Min.X; x < r.Max.X; x++ { 203 x0 := (x-r.Min.X)*2 + sp.X 204 y0 := (y-r.Min.Y)*2 + sp.Y 205 206 rgb00 := src.RGB96fAt(x0+0, y0+0) 207 rgb01 := src.RGB96fAt(x0+0, y0+1) 208 rgb11 := src.RGB96fAt(x0+1, y0+1) 209 rgb10 := src.RGB96fAt(x0+1, y0+0) 210 211 dst.SetRGB96f(x, y, color_ext.RGB96f{ 212 R: (rgb00.R + rgb01.R + rgb11.R + rgb10.R) / 4, 213 G: (rgb00.G + rgb01.G + rgb11.G + rgb10.G) / 4, 214 B: (rgb00.B + rgb01.B + rgb11.B + rgb10.B) / 4, 215 }) 216 } 217 } 218 default: 219 drawPyrDown_Average(dst, r, src, sp) 220 } 221 } 222 223 func drawPyrDownRGBA_Average(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Point) { 224 switch src := src.(type) { 225 case *image.RGBA: 226 // 32 is a magic, see go test -bench=. 227 if r.Dx() >= 32 && r.In(dst.Bounds()) && image.Rect(sp.X, sp.Y, sp.X+r.Dx()*2, sp.Y+r.Dy()*2).In(src.Bounds()) { 228 drawPyrDownRGBA_Average_fast(dst, r, src, sp) 229 return 230 } 231 drawPyrDownRGBA_Average_slow(dst, r, src, sp) 232 return 233 default: 234 drawPyrDown_Average(dst, r, src, sp) 235 return 236 } 237 } 238 239 func drawPyrDownRGBA_Average_slow(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) { 240 for y := r.Min.Y; y < r.Max.Y; y++ { 241 for x := r.Min.X; x < r.Max.X; x++ { 242 x0 := (x-r.Min.X)*2 + sp.X 243 y0 := (y-r.Min.Y)*2 + sp.Y 244 245 rgba00 := src.RGBAAt(x0+0, y0+0) 246 rgba01 := src.RGBAAt(x0+0, y0+1) 247 rgba11 := src.RGBAAt(x0+1, y0+1) 248 rgba10 := src.RGBAAt(x0+1, y0+0) 249 250 dst.SetRGBA(x, y, color.RGBA{ 251 R: uint8((uint16(rgba00.R) + uint16(rgba01.R) + uint16(rgba11.R) + uint16(rgba10.R)) / 4), 252 G: uint8((uint16(rgba00.G) + uint16(rgba01.G) + uint16(rgba11.G) + uint16(rgba10.G)) / 4), 253 B: uint8((uint16(rgba00.B) + uint16(rgba01.B) + uint16(rgba11.B) + uint16(rgba10.B)) / 4), 254 A: uint8((uint16(rgba00.A) + uint16(rgba01.A) + uint16(rgba11.A) + uint16(rgba10.A)) / 4), 255 }) 256 } 257 } 258 } 259 260 func drawPyrDownRGBA_Average_fast(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) { 261 off0 := dst.PixOffset(r.Min.X, r.Min.Y) 262 off1 := src.PixOffset(sp.X, sp.Y) 263 off2 := off1 + src.Stride 264 265 for y := r.Min.Y; y < r.Max.Y; y++ { 266 dstLineX := builtin.Slice(dst.Pix[off0:][:r.Dx()*4], reflect.TypeOf([]uint32(nil))).([]uint32) 267 srcLine0 := builtin.Slice(src.Pix[off1:][:r.Dx()*8], reflect.TypeOf([]uint32(nil))).([]uint32) 268 srcLine1 := builtin.Slice(src.Pix[off2:][:r.Dx()*8], reflect.TypeOf([]uint32(nil))).([]uint32) 269 270 for i, j := 0, 0; i < len(dstLineX); i, j = i+1, j+2 { 271 dstLineX[i] = mergeRgbaFast( 272 mergeRgbaFast(srcLine0[j+0], srcLine0[j+1]), 273 mergeRgbaFast(srcLine1[j+0], srcLine1[j+1]), 274 ) 275 } 276 off0 += dst.Stride * 1 277 off1 += src.Stride * 2 278 off2 += src.Stride * 2 279 } 280 } 281 282 func drawPyrDownRGBA64_Average(dst *image.RGBA64, r image.Rectangle, src image.Image, sp image.Point) { 283 switch src := src.(type) { 284 case *image.RGBA64: 285 for y := r.Min.Y; y < r.Max.Y; y++ { 286 for x := r.Min.X; x < r.Max.X; x++ { 287 x0 := (x-r.Min.X)*2 + sp.X 288 y0 := (y-r.Min.Y)*2 + sp.Y 289 290 rgba00 := src.RGBA64At(x0+0, y0+0) 291 rgba01 := src.RGBA64At(x0+0, y0+1) 292 rgba11 := src.RGBA64At(x0+1, y0+1) 293 rgba10 := src.RGBA64At(x0+1, y0+0) 294 295 dst.SetRGBA64(x, y, color.RGBA64{ 296 R: uint16((uint32(rgba00.R) + uint32(rgba01.R) + uint32(rgba11.R) + uint32(rgba10.R)) / 4), 297 G: uint16((uint32(rgba00.G) + uint32(rgba01.G) + uint32(rgba11.G) + uint32(rgba10.G)) / 4), 298 B: uint16((uint32(rgba00.B) + uint32(rgba01.B) + uint32(rgba11.B) + uint32(rgba10.B)) / 4), 299 A: uint16((uint32(rgba00.A) + uint32(rgba01.A) + uint32(rgba11.A) + uint32(rgba10.A)) / 4), 300 }) 301 } 302 } 303 default: 304 drawPyrDown_Average(dst, r, src, sp) 305 } 306 } 307 308 func drawPyrDownRGBA128f_Average(dst *image_ext.RGBA128f, r image.Rectangle, src image.Image, sp image.Point) { 309 switch src := src.(type) { 310 case *image_ext.RGBA128f: 311 for y := r.Min.Y; y < r.Max.Y; y++ { 312 for x := r.Min.X; x < r.Max.X; x++ { 313 x0 := (x-r.Min.X)*2 + sp.X 314 y0 := (y-r.Min.Y)*2 + sp.Y 315 316 rgba00 := src.RGBA128fAt(x0+0, y0+0) 317 rgba01 := src.RGBA128fAt(x0+0, y0+1) 318 rgba11 := src.RGBA128fAt(x0+1, y0+1) 319 rgba10 := src.RGBA128fAt(x0+1, y0+0) 320 321 dst.SetRGBA128f(x, y, color_ext.RGBA128f{ 322 R: (rgba00.R + rgba01.R + rgba11.R + rgba10.R) / 4, 323 G: (rgba00.G + rgba01.G + rgba11.G + rgba10.G) / 4, 324 B: (rgba00.B + rgba01.B + rgba11.B + rgba10.B) / 4, 325 A: (rgba00.A + rgba01.A + rgba11.A + rgba10.A) / 4, 326 }) 327 } 328 } 329 default: 330 drawPyrDown_Average(dst, r, src, sp) 331 } 332 } 333 334 func drawPyrDownYCbCr_Average(dst *yCbCr, r image.Rectangle, src image.Image, sp image.Point) { 335 drawPyrDown_Average(dst, r, src, sp) 336 } 337 338 func drawPyrDown_Average(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) { 339 for y := r.Min.Y; y < r.Max.Y; y++ { 340 for x := r.Min.X; x < r.Max.X; x++ { 341 x0 := (x-r.Min.X)*2 + sp.X 342 y0 := (y-r.Min.Y)*2 + sp.Y 343 344 r00, g00, b00, a00 := src.At(x0+0, y0+0).RGBA() 345 r01, g01, b01, a01 := src.At(x0+0, y0+1).RGBA() 346 r11, g11, b11, a11 := src.At(x0+1, y0+1).RGBA() 347 r10, g10, b10, a10 := src.At(x0+1, y0+0).RGBA() 348 349 dst.Set(x, y, color.RGBA64{ 350 R: uint16((r00 + r01 + r11 + r10) / 4), 351 G: uint16((g00 + g01 + g11 + g10) / 4), 352 B: uint16((b00 + b01 + b11 + b10) / 4), 353 A: uint16((a00 + a01 + a11 + a10) / 4), 354 }) 355 } 356 } 357 }