136 lines
4.0 KiB
Go
136 lines
4.0 KiB
Go
|
package goimagehash
|
||
|
|
||
|
import (
|
||
|
"image"
|
||
|
)
|
||
|
|
||
|
type WebPUpsampleLinePairFunc func(top_y []uint8, bottom_y []uint8,
|
||
|
top_u []uint8, top_v []uint8,
|
||
|
bottom_u []uint8, bottom_v []uint8,
|
||
|
top_dst []uint8, bottom_dst []uint8, len int)
|
||
|
|
||
|
func FancyUpscale(yuv *image.YCbCr) *image.RGBA {
|
||
|
rgb := image.NewRGBA(image.Rect(0, 0, yuv.Rect.Dx(), yuv.Rect.Dy()))
|
||
|
var (
|
||
|
upsample WebPUpsampleLinePairFunc = UpsampleRgbaLinePair
|
||
|
|
||
|
last_row int = yuv.Rect.Dy()
|
||
|
mb_w int = yuv.Rect.Dx()
|
||
|
)
|
||
|
// First line is special cased. We mirror the u/v samples at boundary.
|
||
|
upsample(yuv.Y[:yuv.YStride], nil,
|
||
|
yuv.Cb[:yuv.CStride], yuv.Cr[:yuv.CStride],
|
||
|
yuv.Cb[:yuv.CStride], yuv.Cr[:yuv.CStride],
|
||
|
rgb.Pix[:rgb.Stride], nil,
|
||
|
mb_w,
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
top_c int
|
||
|
bottom_c int
|
||
|
top_y int
|
||
|
bottom_y int
|
||
|
top_dst int
|
||
|
bottom_dst int
|
||
|
)
|
||
|
// Loop over each output pairs of row.
|
||
|
for row := 1; row+1 < last_row; row += 2 {
|
||
|
top_c = yuv.COffset(0, row)
|
||
|
bottom_c = top_c + yuv.CStride
|
||
|
|
||
|
top_y = yuv.YOffset(0, row)
|
||
|
bottom_y = top_y + yuv.YStride
|
||
|
|
||
|
top_dst = rgb.PixOffset(0, row)
|
||
|
bottom_dst = top_dst + rgb.Stride
|
||
|
|
||
|
upsample(yuv.Y[top_y:bottom_y], yuv.Y[bottom_y:bottom_y+yuv.YStride],
|
||
|
yuv.Cb[top_c:bottom_c], yuv.Cr[top_c:bottom_c],
|
||
|
yuv.Cb[bottom_c:bottom_c+yuv.CStride], yuv.Cr[bottom_c:bottom_c+yuv.CStride],
|
||
|
rgb.Pix[top_dst:bottom_dst], rgb.Pix[bottom_dst:bottom_dst+rgb.Stride],
|
||
|
mb_w,
|
||
|
)
|
||
|
|
||
|
}
|
||
|
|
||
|
// Process the very last row of even-sized picture
|
||
|
if last_row%2 == 0 {
|
||
|
upsample(yuv.Y[len(yuv.Y)-yuv.YStride:], nil,
|
||
|
yuv.Cb[len(yuv.Cb)-yuv.CStride:], yuv.Cr[len(yuv.Cr)-yuv.CStride:],
|
||
|
yuv.Cb[len(yuv.Cb)-yuv.CStride:], yuv.Cr[len(yuv.Cr)-yuv.CStride:],
|
||
|
rgb.Pix[len(rgb.Pix)-rgb.Stride:], nil,
|
||
|
mb_w,
|
||
|
)
|
||
|
}
|
||
|
return rgb
|
||
|
}
|
||
|
|
||
|
func UpsampleRgbaLinePair(top_y []uint8, bottom_y []uint8,
|
||
|
top_u []uint8, top_v []uint8,
|
||
|
bottom_u []uint8, bottom_v []uint8,
|
||
|
top_dst []uint8, bottom_dst []uint8, rowLength int,
|
||
|
) {
|
||
|
var (
|
||
|
x int
|
||
|
last_pixel_pair int = (rowLength - 1) >> 1
|
||
|
tl_uv uint32 = (uint32(top_u[0]) | (uint32(top_v[0]) << 16)) /* top-left sample */
|
||
|
l_uv uint32 = (uint32(bottom_u[0]) | (uint32(bottom_v[0]) << 16)) /* left-sample */
|
||
|
)
|
||
|
{
|
||
|
var uv0 uint32 = (3*tl_uv + l_uv + 0x00020002) >> 2
|
||
|
dst := VP8YuvToRgba(top_y[0], uint8(uv0&0xff), uint8((uv0 >> 16)))
|
||
|
copy(top_dst[0:], dst[:])
|
||
|
}
|
||
|
if bottom_y != nil {
|
||
|
var uv0 uint32 = (3*l_uv + tl_uv + 0x00020002) >> 2
|
||
|
dst := VP8YuvToRgba(bottom_y[0], uint8(uv0&0xff), uint8(uv0>>16))
|
||
|
copy(bottom_dst[0:], dst[:])
|
||
|
}
|
||
|
|
||
|
for x = 1; x <= last_pixel_pair; x++ {
|
||
|
var (
|
||
|
t_uv uint32 = (uint32(top_u[x]) | (uint32(top_v[x]) << 16)) /* top sample */
|
||
|
uv uint32 = (uint32(bottom_u[x]) | (uint32(bottom_v[x]) << 16)) /* sample */
|
||
|
|
||
|
/* precompute invariant values associated with first and second diagonals*/
|
||
|
avg uint32 = tl_uv + t_uv + l_uv + uv + 0x00080008
|
||
|
diag_12 uint32 = (avg + 2*(t_uv+l_uv)) >> 3
|
||
|
diag_03 uint32 = (avg + 2*(tl_uv+uv)) >> 3
|
||
|
)
|
||
|
{
|
||
|
var (
|
||
|
uv0 uint32 = (diag_12 + tl_uv) >> 1
|
||
|
uv1 uint32 = (diag_03 + t_uv) >> 1
|
||
|
)
|
||
|
dst := VP8YuvToRgba(top_y[2*x-1], uint8(uv0&0xff), uint8(uv0>>16))
|
||
|
copy(top_dst[(2*x-1)*4:], dst[:])
|
||
|
dst = VP8YuvToRgba(top_y[2*x-0], uint8(uv1&0xff), uint8(uv1>>16))
|
||
|
copy(top_dst[(2*x-0)*4:], dst[:])
|
||
|
}
|
||
|
if bottom_y != nil {
|
||
|
var (
|
||
|
uv0 uint32 = (diag_03 + l_uv) >> 1
|
||
|
uv1 uint32 = (diag_12 + uv) >> 1
|
||
|
)
|
||
|
dst := VP8YuvToRgba(bottom_y[2*x-1], uint8(uv0&0xff), uint8(uv0>>16))
|
||
|
copy(bottom_dst[(2*x-1)*4:], dst[:])
|
||
|
dst = VP8YuvToRgba(bottom_y[2*x+0], uint8(uv1&0xff), uint8(uv1>>16))
|
||
|
copy(bottom_dst[(2*x+0)*4:], dst[:])
|
||
|
}
|
||
|
tl_uv = t_uv
|
||
|
l_uv = uv
|
||
|
}
|
||
|
if rowLength%2 == 0 {
|
||
|
{
|
||
|
var uv0 uint32 = (3*tl_uv + l_uv + 0x00020002) >> 2
|
||
|
dst := VP8YuvToRgba(top_y[rowLength-1], uint8(uv0&0xff), uint8(uv0>>16))
|
||
|
copy(top_dst[(rowLength-1)*4:], dst[:])
|
||
|
}
|
||
|
if bottom_y != nil {
|
||
|
var uv0 uint32 = (3*l_uv + tl_uv + 0x00020002) >> 2
|
||
|
dst := VP8YuvToRgba(bottom_y[rowLength-1], uint8(uv0&0xff), uint8(uv0>>16))
|
||
|
copy(bottom_dst[(rowLength-1)*4:], dst[:])
|
||
|
}
|
||
|
}
|
||
|
}
|