Example #1
0
func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) {
	// An image.YCbCr is always fully opaque, and so if the mask is implicitly nil
	// (i.e. fully opaque) then the op is effectively always Src.
	x0 := (r.Min.X - dst.Rect.Min.X) * 4
	x1 := (r.Max.X - dst.Rect.Min.X) * 4
	y0 := r.Min.Y - dst.Rect.Min.Y
	y1 := r.Max.Y - dst.Rect.Min.Y
	switch src.SubsampleRatio {
	case image.YCbCrSubsampleRatio422:
		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
			dpix := dst.Pix[y*dst.Stride:]
			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
			ciBase := (sy-src.Rect.Min.Y)*src.CStride - src.Rect.Min.X/2
			for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
				ci := ciBase + sx/2
				rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
				dpix[x+0] = rr
				dpix[x+1] = gg
				dpix[x+2] = bb
				dpix[x+3] = 255
			}
		}
	case image.YCbCrSubsampleRatio420:
		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
			dpix := dst.Pix[y*dst.Stride:]
			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
			ciBase := (sy/2-src.Rect.Min.Y/2)*src.CStride - src.Rect.Min.X/2
			for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
				ci := ciBase + sx/2
				rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
				dpix[x+0] = rr
				dpix[x+1] = gg
				dpix[x+2] = bb
				dpix[x+3] = 255
			}
		}
	default:
		// Default to 4:4:4 subsampling.
		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
			dpix := dst.Pix[y*dst.Stride:]
			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
			ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X)
			for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
				rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
				dpix[x+0] = rr
				dpix[x+1] = gg
				dpix[x+2] = bb
				dpix[x+3] = 255
			}
		}
	}
}
Example #2
0
func Multicolour(p Pixel) (r, g, b uint8) {
	if p.Inside {
		return 0, 0, 0
	}

	var y, cb, cr, iterations uint8

	iterations = uint8(p.Iterations % 64)
	y = 193

	switch {
	case iterations < 16:
		cb = iterations * 16
		cr = 0
	case iterations < 32:
		cb = 255
		cr = uint8((iterations % 16) * 16)
	case iterations < 48:
		cb = uint8((15 - (iterations % 16)) * 16)
		cr = 255
	case true:
		cb = 0
		cr = uint8((15 - (iterations % 16)) * 16)
	}

	return color.YCbCrToRGB(y, cb, cr)
}
Example #3
0
func encodeYCbCrStream(w io.Writer, img *image.YCbCr) error {
	var yy, cb, cr uint8
	var i, j int
	dx, dy := img.Rect.Dx(), img.Rect.Dy()
	buf := make([]byte, 3*dx*dy)
	bi := 0
	for y := 0; y < dy; y++ {
		for x := 0; x < dx; x++ {
			i, j = x, y
			switch img.SubsampleRatio {
			case image.YCbCrSubsampleRatio420:
				j /= 2
				fallthrough
			case image.YCbCrSubsampleRatio422:
				i /= 2
			}
			yy = img.Y[y*img.YStride+x]
			cb = img.Cb[j*img.CStride+i]
			cr = img.Cr[j*img.CStride+i]

			buf[bi+0], buf[bi+1], buf[bi+2] = color.YCbCrToRGB(yy, cb, cr)
			bi += 3
		}
	}
	_, err := w.Write(buf)
	return err
}
Example #4
0
func (c Color) RGBA() (r, g, b, a uint32) {
	r8, g8, b8 := color.YCbCrToRGB(c.Y, c.Cb, c.Cr)
	a = uint32(c.A) * 0x101
	r = uint32(r8) * 0x101 * a / 0xffff
	g = uint32(g8) * 0x101 * a / 0xffff
	b = uint32(b8) * 0x101 * a / 0xffff
	return
}
Example #5
0
// resizeYCbCr returns a scaled copy of the YCbCr image slice r of m.
// The returned image has width w and height h.
func resizeYCbCr(m *image.YCbCr, r image.Rectangle, w, h int) (image.Image, bool) {
	var verticalRes int
	switch m.SubsampleRatio {
	case image.YCbCrSubsampleRatio420:
		verticalRes = 2
	case image.YCbCrSubsampleRatio422:
		verticalRes = 1
	default:
		return nil, false
	}
	ww, hh := uint64(w), uint64(h)
	dx, dy := uint64(r.Dx()), uint64(r.Dy())
	// See comment in Resize.
	n, sum := dx*dy, make([]uint64, 4*w*h)
	for y := r.Min.Y; y < r.Max.Y; y++ {
		Y := m.Y[y*m.YStride:]
		Cb := m.Cb[y/verticalRes*m.CStride:]
		Cr := m.Cr[y/verticalRes*m.CStride:]
		for x := r.Min.X; x < r.Max.X; x++ {
			// Get the source pixel.
			r8, g8, b8 := color.YCbCrToRGB(Y[x], Cb[x/2], Cr[x/2])
			r64 := uint64(r8)
			g64 := uint64(g8)
			b64 := uint64(b8)
			// Spread the source pixel over 1 or more destination rows.
			py := uint64(y) * hh
			for remy := hh; remy > 0; {
				qy := dy - (py % dy)
				if qy > remy {
					qy = remy
				}
				// Spread the source pixel over 1 or more destination columns.
				px := uint64(x) * ww
				index := 4 * ((py/dy)*ww + (px / dx))
				for remx := ww; remx > 0; {
					qx := dx - (px % dx)
					if qx > remx {
						qx = remx
					}
					qxy := qx * qy
					sum[index+0] += r64 * qxy
					sum[index+1] += g64 * qxy
					sum[index+2] += b64 * qxy
					sum[index+3] += 0xFFFF * qxy
					index += 4
					px += qx
					remx -= qx
				}
				py += qy
				remy -= qy
			}
		}
	}
	return average(sum, w, h, n), true
}
Example #6
0
func (c *ycbcrConverter) at(x, y int, result *colorArray) {
	xx, yy := replicateBorder(x, y, c.src.Rect)
	yi := c.src.YOffset(xx, yy)
	ci := c.src.COffset(xx, yy)
	r, g, b := color.YCbCrToRGB(c.src.Y[yi], c.src.Cb[ci], c.src.Cr[ci])
	result[0] = float32(uint16(r) * 0x101)
	result[1] = float32(uint16(g) * 0x101)
	result[2] = float32(uint16(b) * 0x101)
	result[3] = float32(0xffff)
	return
}
Example #7
0
func (c *ycbcrConverter) at(x, y int) colorArray {
	xx, yy := replicateBorder(x, y, c.src.Rect)
	yi := c.src.YOffset(xx, yy)
	ci := c.src.COffset(xx, yy)
	r, g, b := color.YCbCrToRGB(c.src.Y[yi], c.src.Cb[ci], c.src.Cr[ci])
	return colorArray{
		float32(uint16(r) * 0x101),
		float32(uint16(g) * 0x101),
		float32(uint16(b) * 0x101),
		float32(0xffff),
	}
}
Example #8
0
func (c *ycbcrConverter) at(x, y int) colorArray {
	if !(image.Point{x, y}.In(c.src.Rect)) {
		return colorArray{0, 0, 0, 0}
	}
	yi := c.src.YOffset(x, y)
	ci := c.src.COffset(x, y)
	r, g, b := color.YCbCrToRGB(c.src.Y[yi], c.src.Cb[ci], c.src.Cr[ci])
	return colorArray{
		float32(uint16(r) * 0x101),
		float32(uint16(g) * 0x101),
		float32(uint16(b) * 0x101),
		float32(0xffff),
	}
}
Example #9
0
func convertYCbCr(dest *Image, src *image.YCbCr) {
	var r, g, b uint8
	var x, y, i, yi, ci int

	for x = dest.Rect.Min.X; x < dest.Rect.Max.X; x++ {
		for y = dest.Rect.Min.Y; y < dest.Rect.Max.Y; y++ {
			yi, ci = src.YOffset(x, y), src.COffset(x, y)
			r, g, b = color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
			i = dest.PixOffset(x, y)
			dest.Pix[i+0] = b
			dest.Pix[i+1] = g
			dest.Pix[i+2] = r
			dest.Pix[i+3] = 0xff
		}
	}
}
Example #10
0
func HistogramYCbCr(img *image.YCbCr, rect image.Rectangle, rgb bool) []int {
	var verticalRes int
	var horizontalRes int
	switch img.SubsampleRatio {
	case image.YCbCrSubsampleRatio420:
		verticalRes = 2
		horizontalRes = 2
	case image.YCbCrSubsampleRatio422:
		verticalRes = 1
		horizontalRes = 2
	case image.YCbCrSubsampleRatio444:
		verticalRes = 1
		horizontalRes = 1
	default:
		return nil
	}

	hist := make([]int, 256*3)
	for y := rect.Min.Y; y < rect.Max.Y; y++ {
		Y := img.Y[y*img.YStride:]
		Cb := img.Cb[y/verticalRes*img.CStride:]
		Cr := img.Cr[y/verticalRes*img.CStride:]
		for x := rect.Min.X; x < rect.Max.X; x++ {
			if rgb {
				r, g, b := color.YCbCrToRGB(Y[x], Cb[x/horizontalRes], Cr[x/horizontalRes])
				hist[r] += 1
				hist[int(g)+256] += 1
				hist[int(b)+512] += 1
			} else {
				hist[Y[x]] += 1
				hist[int(Cb[x/horizontalRes])+256] += 1
				hist[int(Cr[x/horizontalRes])+512] += 1
			}
		}
	}

	return hist
}
Example #11
0
// 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()
	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])
			}
		})

	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++ {

					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.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:
						dst.Pix[di+0] = uint8(uint16(src.Pix[si+0]) * 0xff / uint16(a))
						dst.Pix[di+1] = uint8(uint16(src.Pix[si+1]) * 0xff / uint16(a))
						dst.Pix[di+2] = uint8(uint16(src.Pix[si+2]) * 0xff / uint16(a))
					}

					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:
						dst.Pix[di+0] = uint8(uint16(src.Pix[si+0]) * 0xff / uint16(a))
						dst.Pix[di+1] = uint8(uint16(src.Pix[si+2]) * 0xff / uint16(a))
						dst.Pix[di+2] = uint8(uint16(src.Pix[si+4]) * 0xff / uint16(a))
					}

					di += 4
					si += 8

				}
			}
		})

	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

				}
			}
		})

	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

				}
			}
		})

	case *image.YCbCr:
		parallel(dstH, func(partStart, partEnd int) {
			for dstY := partStart; dstY < partEnd; dstY++ {
				di := dst.PixOffset(0, dstY)
				switch src.SubsampleRatio {
				case image.YCbCrSubsampleRatio422:
					siy0 := dstY * src.YStride
					sic0 := dstY * src.CStride
					for dstX := 0; dstX < dstW; dstX = dstX + 1 {
						siy := siy0 + dstX
						sic := sic0 + ((srcMinX+dstX)/2 - srcMinX/2)
						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
					}
				case image.YCbCrSubsampleRatio420:
					siy0 := dstY * src.YStride
					sic0 := ((srcMinY+dstY)/2 - srcMinY/2) * src.CStride
					for dstX := 0; dstX < dstW; dstX = dstX + 1 {
						siy := siy0 + dstX
						sic := sic0 + ((srcMinX+dstX)/2 - srcMinX/2)
						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
					}
				case image.YCbCrSubsampleRatio440:
					siy0 := dstY * src.YStride
					sic0 := ((srcMinY+dstY)/2 - srcMinY/2) * src.CStride
					for dstX := 0; dstX < dstW; dstX = dstX + 1 {
						siy := siy0 + dstX
						sic := sic0 + dstX
						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
					}
				default:
					siy0 := dstY * src.YStride
					sic0 := dstY * src.CStride
					for dstX := 0; dstX < dstW; dstX++ {
						siy := siy0 + dstX
						sic := sic0 + dstX
						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
					}
				}
			}
		})

	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

				}
			}
		})

	}

	return dst
}
Example #12
0
// Clone returns a copy of the given image.
func Clone(img image.Image) *image.NRGBA {
	srcBounds := img.Bounds()
	dstBounds := srcBounds.Sub(srcBounds.Min)

	dst := image.NewNRGBA(dstBounds)

	dstMinX := dstBounds.Min.X
	dstMinY := dstBounds.Min.Y

	srcMinX := srcBounds.Min.X
	srcMinY := srcBounds.Min.Y
	srcMaxX := srcBounds.Max.X
	srcMaxY := srcBounds.Max.Y

	switch src0 := img.(type) {

	case *image.NRGBA:
		rowSize := srcBounds.Dx() * 4
		numRows := srcBounds.Dy()

		i0 := dst.PixOffset(dstMinX, dstMinY)
		j0 := src0.PixOffset(srcMinX, srcMinY)

		di := dst.Stride
		dj := src0.Stride

		for row := 0; row < numRows; row++ {
			copy(dst.Pix[i0:i0+rowSize], src0.Pix[j0:j0+rowSize])
			i0 += di
			j0 += dj
		}

	case *image.NRGBA64:
		i0 := dst.PixOffset(dstMinX, dstMinY)
		for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride {
			for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 {

				j := src0.PixOffset(x, y)

				dst.Pix[i+0] = src0.Pix[j+0]
				dst.Pix[i+1] = src0.Pix[j+2]
				dst.Pix[i+2] = src0.Pix[j+4]
				dst.Pix[i+3] = src0.Pix[j+6]

			}
		}

	case *image.RGBA:
		i0 := dst.PixOffset(dstMinX, dstMinY)
		for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride {
			for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 {

				j := src0.PixOffset(x, y)
				a := src0.Pix[j+3]
				dst.Pix[i+3] = a

				switch a {
				case 0:
					dst.Pix[i+0] = 0
					dst.Pix[i+1] = 0
					dst.Pix[i+2] = 0
				case 0xff:
					dst.Pix[i+0] = src0.Pix[j+0]
					dst.Pix[i+1] = src0.Pix[j+1]
					dst.Pix[i+2] = src0.Pix[j+2]
				default:
					dst.Pix[i+0] = uint8(uint16(src0.Pix[j+0]) * 0xff / uint16(a))
					dst.Pix[i+1] = uint8(uint16(src0.Pix[j+1]) * 0xff / uint16(a))
					dst.Pix[i+2] = uint8(uint16(src0.Pix[j+2]) * 0xff / uint16(a))
				}
			}
		}

	case *image.RGBA64:
		i0 := dst.PixOffset(dstMinX, dstMinY)
		for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride {
			for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 {

				j := src0.PixOffset(x, y)
				a := src0.Pix[j+6]
				dst.Pix[i+3] = a

				switch a {
				case 0:
					dst.Pix[i+0] = 0
					dst.Pix[i+1] = 0
					dst.Pix[i+2] = 0
				case 0xff:
					dst.Pix[i+0] = src0.Pix[j+0]
					dst.Pix[i+1] = src0.Pix[j+2]
					dst.Pix[i+2] = src0.Pix[j+4]
				default:
					dst.Pix[i+0] = uint8(uint16(src0.Pix[j+0]) * 0xff / uint16(a))
					dst.Pix[i+1] = uint8(uint16(src0.Pix[j+2]) * 0xff / uint16(a))
					dst.Pix[i+2] = uint8(uint16(src0.Pix[j+4]) * 0xff / uint16(a))
				}
			}
		}

	case *image.Gray:
		i0 := dst.PixOffset(dstMinX, dstMinY)
		for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride {
			for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 {

				j := src0.PixOffset(x, y)
				c := src0.Pix[j]
				dst.Pix[i+0] = c
				dst.Pix[i+1] = c
				dst.Pix[i+2] = c
				dst.Pix[i+3] = 0xff

			}
		}

	case *image.Gray16:
		i0 := dst.PixOffset(dstMinX, dstMinY)
		for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride {
			for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 {

				j := src0.PixOffset(x, y)
				c := src0.Pix[j]
				dst.Pix[i+0] = c
				dst.Pix[i+1] = c
				dst.Pix[i+2] = c
				dst.Pix[i+3] = 0xff

			}
		}

	case *image.YCbCr:
		i0 := dst.PixOffset(dstMinX, dstMinY)
		for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride {
			for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 {

				yj := src0.YOffset(x, y)
				cj := src0.COffset(x, y)
				r, g, b := color.YCbCrToRGB(src0.Y[yj], src0.Cb[cj], src0.Cr[cj])

				dst.Pix[i+0] = r
				dst.Pix[i+1] = g
				dst.Pix[i+2] = b
				dst.Pix[i+3] = 0xff

			}
		}

	case *image.Paletted:
		plen := len(src0.Palette)
		pnew := make([]color.NRGBA, plen)
		for i := 0; i < plen; i++ {
			pnew[i] = color.NRGBAModel.Convert(src0.Palette[i]).(color.NRGBA)
		}

		i0 := dst.PixOffset(dstMinX, dstMinY)
		for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride {
			for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 {

				j := src0.PixOffset(x, y)
				c := pnew[src0.Pix[j]]

				dst.Pix[i+0] = c.R
				dst.Pix[i+1] = c.G
				dst.Pix[i+2] = c.B
				dst.Pix[i+3] = c.A

			}
		}

	default:
		i0 := dst.PixOffset(dstMinX, dstMinY)
		for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride {
			for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 {

				c := color.NRGBAModel.Convert(img.At(x, y)).(color.NRGBA)

				dst.Pix[i+0] = c.R
				dst.Pix[i+1] = c.G
				dst.Pix[i+2] = c.B
				dst.Pix[i+3] = c.A

			}
		}
	}

	return dst
}
Example #13
0
func (p *pixelGetter) getPixel(x, y int) (px pixel) {
	switch p.imgType {
	case itNRGBA:
		i := p.imgNRGBA.PixOffset(x, y)
		r := float32(p.imgNRGBA.Pix[i+0]) * qf8
		g := float32(p.imgNRGBA.Pix[i+1]) * qf8
		b := float32(p.imgNRGBA.Pix[i+2]) * qf8
		a := float32(p.imgNRGBA.Pix[i+3]) * qf8
		px = pixel{r, g, b, a}

	case itNRGBA64:
		i := p.imgNRGBA64.PixOffset(x, y)
		r := float32(uint16(p.imgNRGBA64.Pix[i+0])<<8|uint16(p.imgNRGBA64.Pix[i+1])) * qf16
		g := float32(uint16(p.imgNRGBA64.Pix[i+2])<<8|uint16(p.imgNRGBA64.Pix[i+3])) * qf16
		b := float32(uint16(p.imgNRGBA64.Pix[i+4])<<8|uint16(p.imgNRGBA64.Pix[i+5])) * qf16
		a := float32(uint16(p.imgNRGBA64.Pix[i+6])<<8|uint16(p.imgNRGBA64.Pix[i+7])) * qf16
		px = pixel{r, g, b, a}

	case itRGBA:
		i := p.imgRGBA.PixOffset(x, y)
		a8 := p.imgRGBA.Pix[i+3]
		switch a8 {
		case 0:
			px = pixel{0.0, 0.0, 0.0, 0.0}
		case 255:
			r := float32(p.imgRGBA.Pix[i+0]) * qf8
			g := float32(p.imgRGBA.Pix[i+1]) * qf8
			b := float32(p.imgRGBA.Pix[i+2]) * qf8
			px = pixel{r, g, b, 1.0}
		default:
			q := float32(1.0) / float32(a8)
			r := float32(p.imgRGBA.Pix[i+0]) * q
			g := float32(p.imgRGBA.Pix[i+1]) * q
			b := float32(p.imgRGBA.Pix[i+2]) * q
			a := float32(a8) * qf8
			px = pixel{r, g, b, a}
		}

	case itRGBA64:
		i := p.imgRGBA64.PixOffset(x, y)
		a16 := uint16(p.imgRGBA64.Pix[i+6])<<8 | uint16(p.imgRGBA64.Pix[i+7])
		switch a16 {
		case 0:
			px = pixel{0.0, 0.0, 0.0, 0.0}
		case 65535:
			r := float32(uint16(p.imgRGBA64.Pix[i+0])<<8|uint16(p.imgRGBA64.Pix[i+1])) * qf16
			g := float32(uint16(p.imgRGBA64.Pix[i+2])<<8|uint16(p.imgRGBA64.Pix[i+3])) * qf16
			b := float32(uint16(p.imgRGBA64.Pix[i+4])<<8|uint16(p.imgRGBA64.Pix[i+5])) * qf16
			px = pixel{r, g, b, 1.0}
		default:
			q := float32(1.0) / float32(a16)
			r := float32(uint16(p.imgRGBA64.Pix[i+0])<<8|uint16(p.imgRGBA64.Pix[i+1])) * q
			g := float32(uint16(p.imgRGBA64.Pix[i+2])<<8|uint16(p.imgRGBA64.Pix[i+3])) * q
			b := float32(uint16(p.imgRGBA64.Pix[i+4])<<8|uint16(p.imgRGBA64.Pix[i+5])) * q
			a := float32(a16) * qf16
			px = pixel{r, g, b, a}
		}

	case itGray:
		i := p.imgGray.PixOffset(x, y)
		v := float32(p.imgGray.Pix[i]) * qf8
		px = pixel{v, v, v, 1.0}

	case itGray16:
		i := p.imgGray16.PixOffset(x, y)
		v := float32(uint16(p.imgGray16.Pix[i+0])<<8|uint16(p.imgGray16.Pix[i+1])) * qf16
		px = pixel{v, v, v, 1.0}

	case itYCbCr:
		iy := p.imgYCbCr.YOffset(x, y)
		ic := p.imgYCbCr.COffset(x, y)
		r8, g8, b8 := color.YCbCrToRGB(p.imgYCbCr.Y[iy], p.imgYCbCr.Cb[ic], p.imgYCbCr.Cr[ic])
		r := float32(r8) * qf8
		g := float32(g8) * qf8
		b := float32(b8) * qf8
		px = pixel{r, g, b, 1.0}

	case itPaletted:
		i := p.imgPaletted.PixOffset(x, y)
		k := p.imgPaletted.Pix[i]
		px = p.imgPalette[k]

	case itGeneric:
		r16, g16, b16, a16 := p.imgGeneric.At(x, y).RGBA()
		switch a16 {
		case 0:
			px = pixel{0.0, 0.0, 0.0, 0.0}
		case 65535:
			r := float32(r16) * qf16
			g := float32(g16) * qf16
			b := float32(b16) * qf16
			px = pixel{r, g, b, 1.0}
		default:
			q := float32(1.0) / float32(a16)
			r := float32(r16) * q
			g := float32(g16) * q
			b := float32(b16) * q
			a := float32(a16) * qf16
			px = pixel{r, g, b, a}
		}
	}
	return
}
Example #14
0
// This function converts any image type to *image.NRGBA for faster pixel access
// Optimized for most standard image types: NRGBA64, RGBA, RGBA64, YCbCr, Gray, Gray16
// If clone is true, the new image bounds will start at (0,0), also, a new copy
// will be created even if the source image's type is already NRGBA
func toNRGBA(src image.Image, clone bool) *image.NRGBA {
	if !clone {
		if src0, ok := src.(*image.NRGBA); ok {
			return src0
		}
	}

	srcBounds := src.Bounds()
	dstBounds := srcBounds

	// if we need a copy - translate Min point to (0, 0)
	if clone {
		dstBounds = dstBounds.Sub(dstBounds.Min)
	}

	dst := image.NewNRGBA(dstBounds)

	dstMinX := dstBounds.Min.X
	dstMinY := dstBounds.Min.Y

	srcMinX := srcBounds.Min.X
	srcMinY := srcBounds.Min.Y
	srcMaxX := srcBounds.Max.X
	srcMaxY := srcBounds.Max.Y

	switch src0 := src.(type) {

	case *image.NRGBA:
		rowSize := srcBounds.Dx() * 4
		numRows := srcBounds.Dy()

		i0 := dst.PixOffset(dstMinX, dstMinY)
		j0 := src0.PixOffset(srcMinX, srcMinY)

		di := dst.Stride
		dj := src0.Stride

		for row := 0; row < numRows; row++ {
			copy(dst.Pix[i0:i0+rowSize], src0.Pix[j0:j0+rowSize])
			i0 += di
			j0 += dj
		}

	case *image.NRGBA64:
		i0 := dst.PixOffset(dstMinX, dstMinY)
		for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride {
			for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 {

				j := src0.PixOffset(x, y)

				dst.Pix[i+0] = src0.Pix[j+0]
				dst.Pix[i+1] = src0.Pix[j+2]
				dst.Pix[i+2] = src0.Pix[j+4]
				dst.Pix[i+3] = src0.Pix[j+6]

			}
		}

	case *image.RGBA:
		i0 := dst.PixOffset(dstMinX, dstMinY)
		for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride {
			for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 {

				j := src0.PixOffset(x, y)
				a := src0.Pix[j+3]
				dst.Pix[i+3] = a

				switch a {
				case 0:
					dst.Pix[i+0] = 0
					dst.Pix[i+1] = 0
					dst.Pix[i+2] = 0
				case 0xff:
					dst.Pix[i+0] = src0.Pix[j+0]
					dst.Pix[i+1] = src0.Pix[j+1]
					dst.Pix[i+2] = src0.Pix[j+2]
				default:
					dst.Pix[i+0] = uint8(uint16(src0.Pix[j+0]) * 0xff / uint16(a))
					dst.Pix[i+1] = uint8(uint16(src0.Pix[j+1]) * 0xff / uint16(a))
					dst.Pix[i+2] = uint8(uint16(src0.Pix[j+2]) * 0xff / uint16(a))
				}
			}
		}

	case *image.RGBA64:
		i0 := dst.PixOffset(dstMinX, dstMinY)
		for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride {
			for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 {

				j := src0.PixOffset(x, y)
				a := src0.Pix[j+6]
				dst.Pix[i+3] = a

				switch a {
				case 0:
					dst.Pix[i+0] = 0
					dst.Pix[i+1] = 0
					dst.Pix[i+2] = 0
				case 0xff:
					dst.Pix[i+0] = src0.Pix[j+0]
					dst.Pix[i+1] = src0.Pix[j+2]
					dst.Pix[i+2] = src0.Pix[j+4]
				default:
					dst.Pix[i+0] = uint8(uint16(src0.Pix[j+0]) * 0xff / uint16(a))
					dst.Pix[i+1] = uint8(uint16(src0.Pix[j+2]) * 0xff / uint16(a))
					dst.Pix[i+2] = uint8(uint16(src0.Pix[j+4]) * 0xff / uint16(a))
				}
			}
		}

	case *image.Gray:
		i0 := dst.PixOffset(dstMinX, dstMinY)
		for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride {
			for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 {

				j := src0.PixOffset(x, y)
				c := src0.Pix[j]
				dst.Pix[i+0] = c
				dst.Pix[i+1] = c
				dst.Pix[i+2] = c
				dst.Pix[i+3] = 0xff

			}
		}

	case *image.Gray16:
		i0 := dst.PixOffset(dstMinX, dstMinY)
		for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride {
			for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 {

				j := src0.PixOffset(x, y)
				c := src0.Pix[j]
				dst.Pix[i+0] = c
				dst.Pix[i+1] = c
				dst.Pix[i+2] = c
				dst.Pix[i+3] = 0xff

			}
		}

	case *image.YCbCr:
		i0 := dst.PixOffset(dstMinX, dstMinY)
		for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride {
			for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 {

				yj := src0.YOffset(x, y)
				cj := src0.COffset(x, y)
				r, g, b := color.YCbCrToRGB(src0.Y[yj], src0.Cb[cj], src0.Cr[cj])

				dst.Pix[i+0] = r
				dst.Pix[i+1] = g
				dst.Pix[i+2] = b
				dst.Pix[i+3] = 0xff

			}
		}

	default:
		i0 := dst.PixOffset(dstMinX, dstMinY)
		for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride {
			for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 {

				c := color.NRGBAModel.Convert(src.At(x, y)).(color.NRGBA)

				dst.Pix[i+0] = c.R
				dst.Pix[i+1] = c.G
				dst.Pix[i+2] = c.B
				dst.Pix[i+3] = c.A

			}
		}
	}

	return dst
}