Explorar el Código

helpers: refactor cloning

Grigory Dryapak hace 8 años
padre
commit
87daf87edf
Se han modificado 1 ficheros con 232 adiciones y 179 borrados
  1. 232 179
      helpers.go

+ 232 - 179
helpers.go

@@ -168,213 +168,266 @@ func New(width, height int, fillColor color.Color) *image.NRGBA {
 
 // Clone returns a copy of the given image.
 func Clone(img image.Image) *image.NRGBA {
-	srcBounds := img.Bounds()
-	srcMinX := srcBounds.Min.X
-	srcMinY := srcBounds.Min.Y
-
-	dstBounds := srcBounds.Sub(srcBounds.Min)
-	dstW := dstBounds.Dx()
-	dstH := dstBounds.Dy()
+	dstBounds := img.Bounds().Sub(img.Bounds().Min)
 	dst := image.NewNRGBA(dstBounds)
 
 	switch src := img.(type) {
-
 	case *image.NRGBA:
-		rowSize := srcBounds.Dx() * 4
-		parallel(dstH, func(partStart, partEnd int) {
-			for dstY := partStart; dstY < partEnd; dstY++ {
-				di := dst.PixOffset(0, dstY)
-				si := src.PixOffset(srcMinX, srcMinY+dstY)
-				copy(dst.Pix[di:di+rowSize], src.Pix[si:si+rowSize])
+		copyNRGBA(dst, src)
+	case *image.NRGBA64:
+		copyNRGBA64(dst, src)
+	case *image.RGBA:
+		copyRGBA(dst, src)
+	case *image.RGBA64:
+		copyRGBA64(dst, src)
+	case *image.Gray:
+		copyGray(dst, src)
+	case *image.Gray16:
+		copyGray16(dst, src)
+	case *image.YCbCr:
+		copyYCbCr(dst, src)
+	case *image.Paletted:
+		copyPaletted(dst, src)
+	default:
+		copyImage(dst, src)
+	}
+
+	return dst
+}
+
+func copyNRGBA(dst *image.NRGBA, src *image.NRGBA) {
+	srcMinX := src.Rect.Min.X
+	srcMinY := src.Rect.Min.Y
+	dstW := dst.Rect.Dx()
+	dstH := dst.Rect.Dy()
+	rowSize := dstW * 4
+	parallel(dstH, func(partStart, partEnd int) {
+		for dstY := partStart; dstY < partEnd; dstY++ {
+			di := dst.PixOffset(0, dstY)
+			si := src.PixOffset(srcMinX, srcMinY+dstY)
+			copy(dst.Pix[di:di+rowSize], src.Pix[si:si+rowSize])
+		}
+	})
+}
+
+func copyNRGBA64(dst *image.NRGBA, src *image.NRGBA64) {
+	srcMinX := src.Rect.Min.X
+	srcMinY := src.Rect.Min.Y
+	dstW := dst.Rect.Dx()
+	dstH := dst.Rect.Dy()
+	parallel(dstH, func(partStart, partEnd int) {
+		for dstY := partStart; dstY < partEnd; dstY++ {
+			di := dst.PixOffset(0, dstY)
+			si := src.PixOffset(srcMinX, srcMinY+dstY)
+			for dstX := 0; dstX < dstW; dstX++ {
+				dst.Pix[di+0] = src.Pix[si+0]
+				dst.Pix[di+1] = src.Pix[si+2]
+				dst.Pix[di+2] = src.Pix[si+4]
+				dst.Pix[di+3] = src.Pix[si+6]
+				di += 4
+				si += 8
 			}
-		})
+		}
+	})
+}
 
-	case *image.NRGBA64:
-		parallel(dstH, func(partStart, partEnd int) {
-			for dstY := partStart; dstY < partEnd; dstY++ {
-				di := dst.PixOffset(0, dstY)
-				si := src.PixOffset(srcMinX, srcMinY+dstY)
-				for dstX := 0; dstX < dstW; dstX++ {
+func copyRGBA(dst *image.NRGBA, src *image.RGBA) {
+	srcMinX := src.Rect.Min.X
+	srcMinY := src.Rect.Min.Y
+	dstW := dst.Rect.Dx()
+	dstH := dst.Rect.Dy()
+	parallel(dstH, func(partStart, partEnd int) {
+		for dstY := partStart; dstY < partEnd; dstY++ {
+			di := dst.PixOffset(0, dstY)
+			si := src.PixOffset(srcMinX, srcMinY+dstY)
+			for dstX := 0; dstX < dstW; dstX++ {
+				a := src.Pix[si+3]
+				dst.Pix[di+3] = a
+
+				switch a {
+				case 0:
+					dst.Pix[di+0] = 0
+					dst.Pix[di+1] = 0
+					dst.Pix[di+2] = 0
+				case 0xff:
 					dst.Pix[di+0] = src.Pix[si+0]
-					dst.Pix[di+1] = src.Pix[si+2]
-					dst.Pix[di+2] = src.Pix[si+4]
-					dst.Pix[di+3] = src.Pix[si+6]
-					di += 4
-					si += 8
+					dst.Pix[di+1] = src.Pix[si+1]
+					dst.Pix[di+2] = src.Pix[si+2]
+				default:
+					var tmp uint16
+					tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
+					dst.Pix[di+0] = uint8(tmp)
+					tmp = uint16(src.Pix[si+1]) * 0xff / uint16(a)
+					dst.Pix[di+1] = uint8(tmp)
+					tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
+					dst.Pix[di+2] = uint8(tmp)
 				}
-			}
-		})
 
-	case *image.RGBA:
-		parallel(dstH, func(partStart, partEnd int) {
-			for dstY := partStart; dstY < partEnd; dstY++ {
-				di := dst.PixOffset(0, dstY)
-				si := src.PixOffset(srcMinX, srcMinY+dstY)
-				for dstX := 0; dstX < dstW; dstX++ {
-					a := src.Pix[si+3]
-					dst.Pix[di+3] = a
-
-					switch a {
-					case 0:
-						dst.Pix[di+0] = 0
-						dst.Pix[di+1] = 0
-						dst.Pix[di+2] = 0
-					case 0xff:
-						dst.Pix[di+0] = src.Pix[si+0]
-						dst.Pix[di+1] = src.Pix[si+1]
-						dst.Pix[di+2] = src.Pix[si+2]
-					default:
-						var tmp uint16
-						tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
-						dst.Pix[di+0] = uint8(tmp)
-						tmp = uint16(src.Pix[si+1]) * 0xff / uint16(a)
-						dst.Pix[di+1] = uint8(tmp)
-						tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
-						dst.Pix[di+2] = uint8(tmp)
-					}
-
-					di += 4
-					si += 4
-				}
+				di += 4
+				si += 4
 			}
-		})
+		}
+	})
+}
 
-	case *image.RGBA64:
-		parallel(dstH, func(partStart, partEnd int) {
-			for dstY := partStart; dstY < partEnd; dstY++ {
-				di := dst.PixOffset(0, dstY)
-				si := src.PixOffset(srcMinX, srcMinY+dstY)
-				for dstX := 0; dstX < dstW; dstX++ {
-					a := src.Pix[si+6]
-					dst.Pix[di+3] = a
-
-					switch a {
-					case 0:
-						dst.Pix[di+0] = 0
-						dst.Pix[di+1] = 0
-						dst.Pix[di+2] = 0
-					case 0xff:
-						dst.Pix[di+0] = src.Pix[si+0]
-						dst.Pix[di+1] = src.Pix[si+2]
-						dst.Pix[di+2] = src.Pix[si+4]
-					default:
-						var tmp uint16
-						tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
-						dst.Pix[di+0] = uint8(tmp)
-						tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
-						dst.Pix[di+1] = uint8(tmp)
-						tmp = uint16(src.Pix[si+4]) * 0xff / uint16(a)
-						dst.Pix[di+2] = uint8(tmp)
-					}
-
-					di += 4
-					si += 8
+func copyRGBA64(dst *image.NRGBA, src *image.RGBA64) {
+	srcMinX := src.Rect.Min.X
+	srcMinY := src.Rect.Min.Y
+	dstW := dst.Rect.Dx()
+	dstH := dst.Rect.Dy()
+	parallel(dstH, func(partStart, partEnd int) {
+		for dstY := partStart; dstY < partEnd; dstY++ {
+			di := dst.PixOffset(0, dstY)
+			si := src.PixOffset(srcMinX, srcMinY+dstY)
+			for dstX := 0; dstX < dstW; dstX++ {
+				a := src.Pix[si+6]
+				dst.Pix[di+3] = a
+
+				switch a {
+				case 0:
+					dst.Pix[di+0] = 0
+					dst.Pix[di+1] = 0
+					dst.Pix[di+2] = 0
+				case 0xff:
+					dst.Pix[di+0] = src.Pix[si+0]
+					dst.Pix[di+1] = src.Pix[si+2]
+					dst.Pix[di+2] = src.Pix[si+4]
+				default:
+					var tmp uint16
+					tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
+					dst.Pix[di+0] = uint8(tmp)
+					tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
+					dst.Pix[di+1] = uint8(tmp)
+					tmp = uint16(src.Pix[si+4]) * 0xff / uint16(a)
+					dst.Pix[di+2] = uint8(tmp)
 				}
-			}
-		})
 
-	case *image.Gray:
-		parallel(dstH, func(partStart, partEnd int) {
-			for dstY := partStart; dstY < partEnd; dstY++ {
-				di := dst.PixOffset(0, dstY)
-				si := src.PixOffset(srcMinX, srcMinY+dstY)
-				for dstX := 0; dstX < dstW; dstX++ {
-					c := src.Pix[si]
-					dst.Pix[di+0] = c
-					dst.Pix[di+1] = c
-					dst.Pix[di+2] = c
-					dst.Pix[di+3] = 0xff
-					di += 4
-					si += 1
-				}
+				di += 4
+				si += 8
 			}
-		})
+		}
+	})
+}
 
-	case *image.Gray16:
-		parallel(dstH, func(partStart, partEnd int) {
-			for dstY := partStart; dstY < partEnd; dstY++ {
-				di := dst.PixOffset(0, dstY)
-				si := src.PixOffset(srcMinX, srcMinY+dstY)
-				for dstX := 0; dstX < dstW; dstX++ {
-					c := src.Pix[si]
-					dst.Pix[di+0] = c
-					dst.Pix[di+1] = c
-					dst.Pix[di+2] = c
-					dst.Pix[di+3] = 0xff
-					di += 4
-					si += 2
-				}
+func copyGray(dst *image.NRGBA, src *image.Gray) {
+	srcMinX := src.Rect.Min.X
+	srcMinY := src.Rect.Min.Y
+	dstW := dst.Rect.Dx()
+	dstH := dst.Rect.Dy()
+	parallel(dstH, func(partStart, partEnd int) {
+		for dstY := partStart; dstY < partEnd; dstY++ {
+			di := dst.PixOffset(0, dstY)
+			si := src.PixOffset(srcMinX, srcMinY+dstY)
+			for dstX := 0; dstX < dstW; dstX++ {
+				c := src.Pix[si]
+				dst.Pix[di+0] = c
+				dst.Pix[di+1] = c
+				dst.Pix[di+2] = c
+				dst.Pix[di+3] = 0xff
+				di += 4
+				si++
 			}
-		})
+		}
+	})
+}
 
-	case *image.YCbCr:
-		parallel(dstH, func(partStart, partEnd int) {
-			for dstY := partStart; dstY < partEnd; dstY++ {
-				di := dst.PixOffset(0, dstY)
-				for dstX := 0; dstX < dstW; dstX++ {
-					srcX := srcMinX + dstX
-					srcY := srcMinY + dstY
-					siy := src.YOffset(srcX, srcY)
-					sic := src.COffset(srcX, srcY)
-					r, g, b := color.YCbCrToRGB(src.Y[siy], src.Cb[sic], src.Cr[sic])
-					dst.Pix[di+0] = r
-					dst.Pix[di+1] = g
-					dst.Pix[di+2] = b
-					dst.Pix[di+3] = 0xff
-					di += 4
-				}
+func copyGray16(dst *image.NRGBA, src *image.Gray16) {
+	srcMinX := src.Rect.Min.X
+	srcMinY := src.Rect.Min.Y
+	dstW := dst.Rect.Dx()
+	dstH := dst.Rect.Dy()
+	parallel(dstH, func(partStart, partEnd int) {
+		for dstY := partStart; dstY < partEnd; dstY++ {
+			di := dst.PixOffset(0, dstY)
+			si := src.PixOffset(srcMinX, srcMinY+dstY)
+			for dstX := 0; dstX < dstW; dstX++ {
+				c := src.Pix[si]
+				dst.Pix[di+0] = c
+				dst.Pix[di+1] = c
+				dst.Pix[di+2] = c
+				dst.Pix[di+3] = 0xff
+				di += 4
+				si += 2
 			}
-		})
-
-	case *image.Paletted:
-		plen := len(src.Palette)
-		pnew := make([]color.NRGBA, plen)
-		for i := 0; i < plen; i++ {
-			pnew[i] = color.NRGBAModel.Convert(src.Palette[i]).(color.NRGBA)
 		}
-		parallel(dstH, func(partStart, partEnd int) {
-			for dstY := partStart; dstY < partEnd; dstY++ {
-				di := dst.PixOffset(0, dstY)
-				si := src.PixOffset(srcMinX, srcMinY+dstY)
-				for dstX := 0; dstX < dstW; dstX++ {
-					c := pnew[src.Pix[si]]
-					dst.Pix[di+0] = c.R
-					dst.Pix[di+1] = c.G
-					dst.Pix[di+2] = c.B
-					dst.Pix[di+3] = c.A
-					di += 4
-					si += 1
-				}
-			}
-		})
+	})
+}
 
-	default:
-		parallel(dstH, func(partStart, partEnd int) {
-			for dstY := partStart; dstY < partEnd; dstY++ {
-				di := dst.PixOffset(0, dstY)
-				for dstX := 0; dstX < dstW; dstX++ {
-					c := color.NRGBAModel.Convert(img.At(srcMinX+dstX, srcMinY+dstY)).(color.NRGBA)
-					dst.Pix[di+0] = c.R
-					dst.Pix[di+1] = c.G
-					dst.Pix[di+2] = c.B
-					dst.Pix[di+3] = c.A
-					di += 4
-				}
+func copyYCbCr(dst *image.NRGBA, src *image.YCbCr) {
+	srcMinX := src.Rect.Min.X
+	srcMinY := src.Rect.Min.Y
+	dstW := dst.Rect.Dx()
+	dstH := dst.Rect.Dy()
+	parallel(dstH, func(partStart, partEnd int) {
+		for dstY := partStart; dstY < partEnd; dstY++ {
+			di := dst.PixOffset(0, dstY)
+			for dstX := 0; dstX < dstW; dstX++ {
+				srcX := srcMinX + dstX
+				srcY := srcMinY + dstY
+				siy := src.YOffset(srcX, srcY)
+				sic := src.COffset(srcX, srcY)
+				r, g, b := color.YCbCrToRGB(src.Y[siy], src.Cb[sic], src.Cr[sic])
+				dst.Pix[di+0] = r
+				dst.Pix[di+1] = g
+				dst.Pix[di+2] = b
+				dst.Pix[di+3] = 0xff
+				di += 4
 			}
-		})
+		}
+	})
+}
 
+func copyPaletted(dst *image.NRGBA, src *image.Paletted) {
+	srcMinX := src.Rect.Min.X
+	srcMinY := src.Rect.Min.Y
+	dstW := dst.Rect.Dx()
+	dstH := dst.Rect.Dy()
+	plen := len(src.Palette)
+	pnew := make([]color.NRGBA, plen)
+	for i := 0; i < plen; i++ {
+		pnew[i] = color.NRGBAModel.Convert(src.Palette[i]).(color.NRGBA)
 	}
+	parallel(dstH, func(partStart, partEnd int) {
+		for dstY := partStart; dstY < partEnd; dstY++ {
+			di := dst.PixOffset(0, dstY)
+			si := src.PixOffset(srcMinX, srcMinY+dstY)
+			for dstX := 0; dstX < dstW; dstX++ {
+				c := pnew[src.Pix[si]]
+				dst.Pix[di+0] = c.R
+				dst.Pix[di+1] = c.G
+				dst.Pix[di+2] = c.B
+				dst.Pix[di+3] = c.A
+				di += 4
+				si++
+			}
+		}
+	})
+}
 
-	return dst
+func copyImage(dst *image.NRGBA, src image.Image) {
+	srcMinX := src.Bounds().Min.X
+	srcMinY := src.Bounds().Min.Y
+	dstW := dst.Bounds().Dx()
+	dstH := dst.Bounds().Dy()
+	parallel(dstH, func(partStart, partEnd int) {
+		for dstY := partStart; dstY < partEnd; dstY++ {
+			di := dst.PixOffset(0, dstY)
+			for dstX := 0; dstX < dstW; dstX++ {
+				c := color.NRGBAModel.Convert(src.At(srcMinX+dstX, srcMinY+dstY)).(color.NRGBA)
+				dst.Pix[di+0] = c.R
+				dst.Pix[di+1] = c.G
+				dst.Pix[di+2] = c.B
+				dst.Pix[di+3] = c.A
+				di += 4
+			}
+		}
+	})
 }
 
 // toNRGBA converts any image type to *image.NRGBA with min-point at (0, 0).
 func toNRGBA(img image.Image) *image.NRGBA {
-	srcBounds := img.Bounds()
-	if srcBounds.Min.X == 0 && srcBounds.Min.Y == 0 {
-		if src0, ok := img.(*image.NRGBA); ok {
-			return src0
-		}
+	if img, ok := img.(*image.NRGBA); ok && img.Bounds().Min.Eq(image.ZP) {
+		return img
 	}
 	return Clone(img)
 }