// Copyright 2017 The goimagehash Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package transforms

import (
	"image"
	"image/color"
)

var FastYCBCR = true

func toGray(r, g, b uint8) uint8 {
	// 19595 + 38470 + 7471 equals 65536.
	return uint8((19595*uint32(r) + 38470*uint32(g) + 7471*uint32(b) + 1<<15) >> 16)
}

// Rgb2Gray function converts RGB to a gray scale array.
func Rgb2Gray(colorImg image.Image, pixels []uint8) []uint8 {
	colorImg.Bounds().Dx()
	bounds := colorImg.Bounds()
	w, h := bounds.Dx(), bounds.Dy()
	if pixels == nil {
		pixels = make([]uint8, h*w)
	}
	switch img := colorImg.(type) {
	case *image.YCbCr:
		var R, G, B uint8
		var yi, ci int
		for i := 0; i < h*w; i++ {
			x, y := i%w, i/w
			yi = img.YOffset(x, y)
			if FastYCBCR {
				pixels[i] = img.Y[yi]
			} else {
				ci = img.COffset(x, y)

				R, G, B = color.YCbCrToRGB(img.Y[yi], img.Cb[ci], img.Cr[ci])

				// Pillow only operates on 8bit data, operating on higher bit data produces rounding differences
				pixels[i] = toGray(R, G, B)
			}
		}
	default:
		var R, G, B uint32
		for i := 0; i < h*w; i++ {
			x, y := i%w, i/w
			switch v := img.At(x, y).(type) {
			case color.NRGBA: // pillow discards alpha during conversion and provides no way to pre-multiply it
				R, G, B = uint32(v.R)<<8, uint32(v.G)<<8, uint32(v.B)<<8
			default:
				R, G, B, _ = v.RGBA()
			}

			// Pillow only operates on 8bit data, operating on higher bit data produces rounding differences
			pixels[i] = toGray(uint8(R>>8), uint8(G>>8), uint8(B>>8))
		}
	}

	return pixels
}
