From 412d2e5532a9c4af088a5a981145a7a6fc2826e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Dec 2025 20:23:42 +0000 Subject: [PATCH] Bump golang.org/x/image from 0.6.0 to 0.18.0 Bumps [golang.org/x/image](https://github.com/golang/image) from 0.6.0 to 0.18.0. - [Commits](https://github.com/golang/image/compare/v0.6.0...v0.18.0) --- updated-dependencies: - dependency-name: golang.org/x/image dependency-version: 0.18.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- go.mod | 4 +- go.sum | 27 +- vendor/golang.org/x/image/draw/draw.go | 6 + vendor/golang.org/x/image/draw/draw_go117.go | 27 - vendor/golang.org/x/image/draw/impl.go | 2678 ++++++++++++++--- .../x/image/font/basicfont/basicfont.go | 65 +- vendor/golang.org/x/image/font/font.go | 79 +- .../x/image/font/opentype/opentype.go | 19 +- vendor/golang.org/x/image/font/sfnt/sfnt.go | 12 +- vendor/golang.org/x/image/tiff/fuzz.go | 1 - vendor/golang.org/x/image/tiff/reader.go | 47 +- vendor/golang.org/x/image/vector/acc_amd64.go | 1 - vendor/golang.org/x/image/vector/acc_other.go | 1 - vendor/modules.txt | 18 +- 14 files changed, 2354 insertions(+), 631 deletions(-) delete mode 100644 vendor/golang.org/x/image/draw/draw_go117.go diff --git a/go.mod b/go.mod index 113ba807..199f5ce0 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/spf13/cobra v1.6.1 github.com/vmihailenco/msgpack/v5 v5.3.5 golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect - golang.org/x/image v0.6.0 // indirect + golang.org/x/image v0.18.0 // indirect golang.org/x/net v0.8.0 // indirect gonum.org/v1/plot v0.12.0 gopkg.in/yaml.v2 v2.4.0 @@ -38,6 +38,6 @@ require ( github.com/stretchr/testify v1.8.2 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect golang.org/x/sys v0.6.0 // indirect - golang.org/x/text v0.8.0 // indirect + golang.org/x/text v0.16.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect ) diff --git a/go.sum b/go.sum index 3822f22b..5569e244 100644 --- a/go.sum +++ b/go.sum @@ -92,63 +92,44 @@ github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.6.0 h1:bR8b5okrPI3g/gyZakLZHeWxAR8Dn5CyxXv1hLH5g/4= -golang.org/x/image v0.6.0/go.mod h1:MXLdDR43H7cDJq5GEGXEVeeNhPgi+YYEQ2pC1byI1x0= +golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ= +golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/vendor/golang.org/x/image/draw/draw.go b/vendor/golang.org/x/image/draw/draw.go index cd5aaba6..42d5d7e0 100644 --- a/vendor/golang.org/x/image/draw/draw.go +++ b/vendor/golang.org/x/image/draw/draw.go @@ -47,6 +47,12 @@ func (floydSteinberg) Draw(dst Image, r image.Rectangle, src image.Image, sp ima // Image is an image.Image with a Set method to change a single pixel. type Image = draw.Image +// RGBA64Image extends both the Image and image.RGBA64Image interfaces with a +// SetRGBA64 method to change a single pixel. SetRGBA64 is equivalent to +// calling Set, but it can avoid allocations from converting concrete color +// types to the color.Color interface type. +type RGBA64Image = draw.RGBA64Image + // Op is a Porter-Duff compositing operator. type Op = draw.Op diff --git a/vendor/golang.org/x/image/draw/draw_go117.go b/vendor/golang.org/x/image/draw/draw_go117.go deleted file mode 100644 index fa836486..00000000 --- a/vendor/golang.org/x/image/draw/draw_go117.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.17 -// +build go1.17 - -package draw - -import ( - "image/draw" -) - -// The package documentation, in draw.go, gives the intent of this package: -// -// This package is a superset of and a drop-in replacement for the -// image/draw package in the standard library. -// -// "Drop-in replacement" means that we use type aliases in this file. -// -// TODO: move the type aliases to draw.go once Go 1.16 is no longer supported. - -// RGBA64Image extends both the Image and image.RGBA64Image interfaces with a -// SetRGBA64 method to change a single pixel. SetRGBA64 is equivalent to -// calling Set, but it can avoid allocations from converting concrete color -// types to the color.Color interface type. -type RGBA64Image = draw.RGBA64Image diff --git a/vendor/golang.org/x/image/draw/impl.go b/vendor/golang.org/x/image/draw/impl.go index 75498adb..94ee8265 100644 --- a/vendor/golang.org/x/image/draw/impl.go +++ b/vendor/golang.org/x/image/draw/impl.go @@ -59,9 +59,16 @@ func (z nnInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr z.scale_RGBA_NRGBA_Over(dst, dr, adr, src, sr, &o) case *image.RGBA: z.scale_RGBA_RGBA_Over(dst, dr, adr, src, sr, &o) + case image.RGBA64Image: + z.scale_RGBA_RGBA64Image_Over(dst, dr, adr, src, sr, &o) default: z.scale_RGBA_Image_Over(dst, dr, adr, src, sr, &o) } + case RGBA64Image: + switch src := src.(type) { + case image.RGBA64Image: + z.scale_RGBA64Image_RGBA64Image_Over(dst, dr, adr, src, sr, &o) + } default: switch src := src.(type) { default: @@ -91,9 +98,16 @@ func (z nnInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr case image.YCbCrSubsampleRatio440: z.scale_RGBA_YCbCr440_Src(dst, dr, adr, src, sr, &o) } + case image.RGBA64Image: + z.scale_RGBA_RGBA64Image_Src(dst, dr, adr, src, sr, &o) default: z.scale_RGBA_Image_Src(dst, dr, adr, src, sr, &o) } + case RGBA64Image: + switch src := src.(type) { + case image.RGBA64Image: + z.scale_RGBA64Image_RGBA64Image_Src(dst, dr, adr, src, sr, &o) + } default: switch src := src.(type) { default: @@ -170,9 +184,16 @@ func (z nnInterpolator) Transform(dst Image, s2d f64.Aff3, src image.Image, sr i z.transform_RGBA_NRGBA_Over(dst, dr, adr, &d2s, src, sr, bias, &o) case *image.RGBA: z.transform_RGBA_RGBA_Over(dst, dr, adr, &d2s, src, sr, bias, &o) + case image.RGBA64Image: + z.transform_RGBA_RGBA64Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o) default: z.transform_RGBA_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o) } + case RGBA64Image: + switch src := src.(type) { + case image.RGBA64Image: + z.transform_RGBA64Image_RGBA64Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o) + } default: switch src := src.(type) { default: @@ -202,9 +223,16 @@ func (z nnInterpolator) Transform(dst Image, s2d f64.Aff3, src image.Image, sr i case image.YCbCrSubsampleRatio440: z.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias, &o) } + case image.RGBA64Image: + z.transform_RGBA_RGBA64Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o) default: z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o) } + case RGBA64Image: + switch src := src.(type) { + case image.RGBA64Image: + z.transform_RGBA64Image_RGBA64Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o) + } default: switch src := src.(type) { default: @@ -502,6 +530,45 @@ func (nnInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rec } } +func (nnInterpolator) scale_RGBA_RGBA64Image_Over(dst *image.RGBA, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) { + dw2 := uint64(dr.Dx()) * 2 + dh2 := uint64(dr.Dy()) * 2 + sw := uint64(sr.Dx()) + sh := uint64(sr.Dy()) + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + sy := (2*uint64(dy) + 1) * sh / dh2 + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + sx := (2*uint64(dx) + 1) * sw / dw2 + p := src.RGBA64At(sr.Min.X+int(sx), sr.Min.Y+int(sy)) + pa1 := (0xffff - uint32(p.A)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + uint32(p.R)) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + uint32(p.G)) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + uint32(p.B)) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + uint32(p.A)) >> 8) + } + } +} + +func (nnInterpolator) scale_RGBA_RGBA64Image_Src(dst *image.RGBA, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) { + dw2 := uint64(dr.Dx()) * 2 + dh2 := uint64(dr.Dy()) * 2 + sw := uint64(sr.Dx()) + sh := uint64(sr.Dy()) + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + sy := (2*uint64(dy) + 1) * sh / dh2 + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + sx := (2*uint64(dx) + 1) * sw / dw2 + p := src.RGBA64At(sr.Min.X+int(sx), sr.Min.Y+int(sy)) + dst.Pix[d+0] = uint8(p.R >> 8) + dst.Pix[d+1] = uint8(p.G >> 8) + dst.Pix[d+2] = uint8(p.B >> 8) + dst.Pix[d+3] = uint8(p.A >> 8) + } + } +} + func (nnInterpolator) scale_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) { dw2 := uint64(dr.Dx()) * 2 dh2 := uint64(dr.Dy()) * 2 @@ -541,6 +608,86 @@ func (nnInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectan } } +func (nnInterpolator) scale_RGBA64Image_RGBA64Image_Over(dst RGBA64Image, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) { + dw2 := uint64(dr.Dx()) * 2 + dh2 := uint64(dr.Dy()) * 2 + sw := uint64(sr.Dx()) + sh := uint64(sr.Dy()) + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + sy := (2*uint64(dy) + 1) * sh / dh2 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + sx := (2*uint64(dx) + 1) * sw / dw2 + p := src.RGBA64At(sr.Min.X+int(sx), sr.Min.Y+int(sy)) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx), smp.Y+sr.Min.Y+int(sy)).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + } + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy)) + if dstMask != nil { + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + } + pa1 := 0xffff - uint32(p.A) + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R)) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G)) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B)) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A)) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } + } +} + +func (nnInterpolator) scale_RGBA64Image_RGBA64Image_Src(dst RGBA64Image, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) { + dw2 := uint64(dr.Dx()) * 2 + dh2 := uint64(dr.Dy()) * 2 + sw := uint64(sr.Dx()) + sh := uint64(sr.Dy()) + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + sy := (2*uint64(dy) + 1) * sh / dh2 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + sx := (2*uint64(dx) + 1) * sw / dw2 + p := src.RGBA64At(sr.Min.X+int(sx), sr.Min.Y+int(sy)) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx), smp.Y+sr.Min.Y+int(sy)).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + } + if dstMask != nil { + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy)) + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + pa1 := 0xffff - ma + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R)) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G)) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B)) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A)) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } else { + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), p) + } + } + } +} + func (nnInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) { dw2 := uint64(dr.Dx()) * 2 dh2 := uint64(dr.Dy()) * 2 @@ -921,6 +1068,47 @@ func (nnInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image } } +func (nnInterpolator) transform_RGBA_RGBA64Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) { + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X + sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + if !(image.Point{sx0, sy0}).In(sr) { + continue + } + p := src.RGBA64At(sx0, sy0) + pa1 := (0xffff - uint32(p.A)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + uint32(p.R)) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + uint32(p.G)) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + uint32(p.B)) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + uint32(p.A)) >> 8) + } + } +} + +func (nnInterpolator) transform_RGBA_RGBA64Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) { + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X + sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + if !(image.Point{sx0, sy0}).In(sr) { + continue + } + p := src.RGBA64At(sx0, sy0) + dst.Pix[d+0] = uint8(p.R >> 8) + dst.Pix[d+1] = uint8(p.G >> 8) + dst.Pix[d+2] = uint8(p.B >> 8) + dst.Pix[d+3] = uint8(p.A >> 8) + } + } +} + func (nnInterpolator) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { dyf := float64(dr.Min.Y+int(dy)) + 0.5 @@ -962,6 +1150,88 @@ func (nnInterpolator) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Re } } +func (nnInterpolator) transform_RGBA64Image_RGBA64Image_Over(dst RGBA64Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) { + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X + sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + if !(image.Point{sx0, sy0}).In(sr) { + continue + } + p := src.RGBA64At(sx0, sy0) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + } + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy)) + if dstMask != nil { + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + } + pa1 := 0xffff - uint32(p.A) + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R)) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G)) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B)) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A)) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } + } +} + +func (nnInterpolator) transform_RGBA64Image_RGBA64Image_Src(dst RGBA64Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) { + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X + sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y + if !(image.Point{sx0, sy0}).In(sr) { + continue + } + p := src.RGBA64At(sx0, sy0) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + } + if dstMask != nil { + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy)) + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + pa1 := 0xffff - ma + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R)) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G)) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B)) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A)) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } else { + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), p) + } + } + } +} + func (nnInterpolator) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) { srcMask, smp := opts.SrcMask, opts.SrcMaskP dstMask, dmp := opts.DstMask, opts.DstMaskP @@ -1097,9 +1367,16 @@ func (z ablInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, s z.scale_RGBA_NRGBA_Over(dst, dr, adr, src, sr, &o) case *image.RGBA: z.scale_RGBA_RGBA_Over(dst, dr, adr, src, sr, &o) + case image.RGBA64Image: + z.scale_RGBA_RGBA64Image_Over(dst, dr, adr, src, sr, &o) default: z.scale_RGBA_Image_Over(dst, dr, adr, src, sr, &o) } + case RGBA64Image: + switch src := src.(type) { + case image.RGBA64Image: + z.scale_RGBA64Image_RGBA64Image_Over(dst, dr, adr, src, sr, &o) + } default: switch src := src.(type) { default: @@ -1129,9 +1406,16 @@ func (z ablInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, s case image.YCbCrSubsampleRatio440: z.scale_RGBA_YCbCr440_Src(dst, dr, adr, src, sr, &o) } + case image.RGBA64Image: + z.scale_RGBA_RGBA64Image_Src(dst, dr, adr, src, sr, &o) default: z.scale_RGBA_Image_Src(dst, dr, adr, src, sr, &o) } + case RGBA64Image: + switch src := src.(type) { + case image.RGBA64Image: + z.scale_RGBA64Image_RGBA64Image_Src(dst, dr, adr, src, sr, &o) + } default: switch src := src.(type) { default: @@ -1208,9 +1492,16 @@ func (z ablInterpolator) Transform(dst Image, s2d f64.Aff3, src image.Image, sr z.transform_RGBA_NRGBA_Over(dst, dr, adr, &d2s, src, sr, bias, &o) case *image.RGBA: z.transform_RGBA_RGBA_Over(dst, dr, adr, &d2s, src, sr, bias, &o) + case image.RGBA64Image: + z.transform_RGBA_RGBA64Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o) default: z.transform_RGBA_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o) } + case RGBA64Image: + switch src := src.(type) { + case image.RGBA64Image: + z.transform_RGBA64Image_RGBA64Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o) + } default: switch src := src.(type) { default: @@ -1240,9 +1531,16 @@ func (z ablInterpolator) Transform(dst Image, s2d f64.Aff3, src image.Image, sr case image.YCbCrSubsampleRatio440: z.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias, &o) } + case image.RGBA64Image: + z.transform_RGBA_RGBA64Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o) default: z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o) } + case RGBA64Image: + switch src := src.(type) { + case image.RGBA64Image: + z.transform_RGBA64Image_RGBA64Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o) + } default: switch src := src.(type) { default: @@ -2415,7 +2713,7 @@ func (ablInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Re } } -func (ablInterpolator) scale_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) { +func (ablInterpolator) scale_RGBA_RGBA64Image_Over(dst *image.RGBA, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) { sw := int32(sr.Dx()) sh := int32(sr.Dy()) yscale := float64(sh) / float64(dr.Dy()) @@ -2454,30 +2752,30 @@ func (ablInterpolator) scale_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rect xFrac0, xFrac1 = 1, 0 } - s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA() - s00r := float64(s00ru) - s00g := float64(s00gu) - s00b := float64(s00bu) - s00a := float64(s00au) - s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA() - s10r := float64(s10ru) - s10g := float64(s10gu) - s10b := float64(s10bu) - s10a := float64(s10au) + s00u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)) + s00r := float64(s00u.R) + s00g := float64(s00u.G) + s00b := float64(s00u.B) + s00a := float64(s00u.A) + s10u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)) + s10r := float64(s10u.R) + s10g := float64(s10u.G) + s10b := float64(s10u.B) + s10a := float64(s10u.A) s10r = xFrac1*s00r + xFrac0*s10r s10g = xFrac1*s00g + xFrac0*s10g s10b = xFrac1*s00b + xFrac0*s10b s10a = xFrac1*s00a + xFrac0*s10a - s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA() - s01r := float64(s01ru) - s01g := float64(s01gu) - s01b := float64(s01bu) - s01a := float64(s01au) - s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA() - s11r := float64(s11ru) - s11g := float64(s11gu) - s11b := float64(s11bu) - s11a := float64(s11au) + s01u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)) + s01r := float64(s01u.R) + s01g := float64(s01u.G) + s01b := float64(s01u.B) + s01a := float64(s01u.A) + s11u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)) + s11r := float64(s11u.R) + s11g := float64(s11u.G) + s11b := float64(s11u.B) + s11a := float64(s11u.A) s11r = xFrac1*s01r + xFrac0*s11r s11g = xFrac1*s01g + xFrac0*s11g s11b = xFrac1*s01b + xFrac0*s11b @@ -2486,20 +2784,17 @@ func (ablInterpolator) scale_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rect s11g = yFrac1*s10g + yFrac0*s11g s11b = yFrac1*s10b + yFrac0*s11b s11a = yFrac1*s10a + yFrac0*s11a - pr := uint32(s11r) - pg := uint32(s11g) - pb := uint32(s11b) - pa := uint32(s11a) - pa1 := (0xffff - pa) * 0x101 - dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8) - dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8) - dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8) - dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8) + p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)} + pa1 := (0xffff - uint32(p.A)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + uint32(p.R)) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + uint32(p.G)) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + uint32(p.B)) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + uint32(p.A)) >> 8) } } } -func (ablInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) { +func (ablInterpolator) scale_RGBA_RGBA64Image_Src(dst *image.RGBA, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) { sw := int32(sr.Dx()) sh := int32(sr.Dy()) yscale := float64(sh) / float64(dr.Dy()) @@ -2538,30 +2833,30 @@ func (ablInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Recta xFrac0, xFrac1 = 1, 0 } - s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA() - s00r := float64(s00ru) - s00g := float64(s00gu) - s00b := float64(s00bu) - s00a := float64(s00au) - s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA() - s10r := float64(s10ru) - s10g := float64(s10gu) - s10b := float64(s10bu) - s10a := float64(s10au) + s00u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)) + s00r := float64(s00u.R) + s00g := float64(s00u.G) + s00b := float64(s00u.B) + s00a := float64(s00u.A) + s10u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)) + s10r := float64(s10u.R) + s10g := float64(s10u.G) + s10b := float64(s10u.B) + s10a := float64(s10u.A) s10r = xFrac1*s00r + xFrac0*s10r s10g = xFrac1*s00g + xFrac0*s10g s10b = xFrac1*s00b + xFrac0*s10b s10a = xFrac1*s00a + xFrac0*s10a - s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA() - s01r := float64(s01ru) - s01g := float64(s01gu) - s01b := float64(s01bu) - s01a := float64(s01au) - s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA() - s11r := float64(s11ru) - s11g := float64(s11gu) - s11b := float64(s11bu) - s11a := float64(s11au) + s01u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)) + s01r := float64(s01u.R) + s01g := float64(s01u.G) + s01b := float64(s01u.B) + s01a := float64(s01u.A) + s11u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)) + s11r := float64(s11u.R) + s11g := float64(s11u.G) + s11b := float64(s11u.B) + s11a := float64(s11u.A) s11r = xFrac1*s01r + xFrac0*s11r s11g = xFrac1*s01g + xFrac0*s11g s11b = xFrac1*s01b + xFrac0*s11b @@ -2570,28 +2865,21 @@ func (ablInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Recta s11g = yFrac1*s10g + yFrac0*s11g s11b = yFrac1*s10b + yFrac0*s11b s11a = yFrac1*s10a + yFrac0*s11a - pr := uint32(s11r) - pg := uint32(s11g) - pb := uint32(s11b) - pa := uint32(s11a) - dst.Pix[d+0] = uint8(pr >> 8) - dst.Pix[d+1] = uint8(pg >> 8) - dst.Pix[d+2] = uint8(pb >> 8) - dst.Pix[d+3] = uint8(pa >> 8) + p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)} + dst.Pix[d+0] = uint8(p.R >> 8) + dst.Pix[d+1] = uint8(p.G >> 8) + dst.Pix[d+2] = uint8(p.B >> 8) + dst.Pix[d+3] = uint8(p.A >> 8) } } } -func (ablInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) { +func (ablInterpolator) scale_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) { sw := int32(sr.Dx()) sh := int32(sr.Dy()) yscale := float64(sh) / float64(dr.Dy()) xscale := float64(sw) / float64(dr.Dx()) swMinus1, shMinus1 := sw-1, sh-1 - srcMask, smp := opts.SrcMask, opts.SrcMaskP - dstMask, dmp := opts.DstMask, opts.DstMaskP - dstColorRGBA64 := &color.RGBA64{} - dstColor := color.Color(dstColorRGBA64) for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { sy := (float64(dy)+0.5)*yscale - 0.5 @@ -2609,8 +2897,9 @@ func (ablInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle sy0, sy1 = shMinus1, shMinus1 yFrac0, yFrac1 = 1, 0 } + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 - for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { sx := (float64(dx)+0.5)*xscale - 0.5 sx0 := int32(sx) xFrac0 := sx - float64(sx0) @@ -2625,25 +2914,11 @@ func (ablInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle } s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA() - if srcMask != nil { - _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy0)).RGBA() - s00ru = s00ru * ma / 0xffff - s00gu = s00gu * ma / 0xffff - s00bu = s00bu * ma / 0xffff - s00au = s00au * ma / 0xffff - } s00r := float64(s00ru) s00g := float64(s00gu) s00b := float64(s00bu) s00a := float64(s00au) s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA() - if srcMask != nil { - _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy0)).RGBA() - s10ru = s10ru * ma / 0xffff - s10gu = s10gu * ma / 0xffff - s10bu = s10bu * ma / 0xffff - s10au = s10au * ma / 0xffff - } s10r := float64(s10ru) s10g := float64(s10gu) s10b := float64(s10bu) @@ -2653,25 +2928,11 @@ func (ablInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle s10b = xFrac1*s00b + xFrac0*s10b s10a = xFrac1*s00a + xFrac0*s10a s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA() - if srcMask != nil { - _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy1)).RGBA() - s01ru = s01ru * ma / 0xffff - s01gu = s01gu * ma / 0xffff - s01bu = s01bu * ma / 0xffff - s01au = s01au * ma / 0xffff - } s01r := float64(s01ru) s01g := float64(s01gu) s01b := float64(s01bu) s01a := float64(s01au) s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA() - if srcMask != nil { - _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy1)).RGBA() - s11ru = s11ru * ma / 0xffff - s11gu = s11gu * ma / 0xffff - s11bu = s11bu * ma / 0xffff - s11au = s11au * ma / 0xffff - } s11r := float64(s11ru) s11g := float64(s11gu) s11b := float64(s11bu) @@ -2688,25 +2949,341 @@ func (ablInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle pg := uint32(s11g) pb := uint32(s11b) pa := uint32(s11a) - qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA() - if dstMask != nil { + pa1 := (0xffff - pa) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8) + } + } +} + +func (ablInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) { + sw := int32(sr.Dx()) + sh := int32(sr.Dy()) + yscale := float64(sh) / float64(dr.Dy()) + xscale := float64(sw) / float64(dr.Dx()) + swMinus1, shMinus1 := sw-1, sh-1 + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + sy := (float64(dy)+0.5)*yscale - 0.5 + // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if + // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for + // sx, below. + sy0 := int32(sy) + yFrac0 := sy - float64(sy0) + yFrac1 := 1 - yFrac0 + sy1 := sy0 + 1 + if sy < 0 { + sy0, sy1 = 0, 0 + yFrac0, yFrac1 = 0, 1 + } else if sy1 > shMinus1 { + sy0, sy1 = shMinus1, shMinus1 + yFrac0, yFrac1 = 1, 0 + } + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + sx := (float64(dx)+0.5)*xscale - 0.5 + sx0 := int32(sx) + xFrac0 := sx - float64(sx0) + xFrac1 := 1 - xFrac0 + sx1 := sx0 + 1 + if sx < 0 { + sx0, sx1 = 0, 0 + xFrac0, xFrac1 = 0, 1 + } else if sx1 > swMinus1 { + sx0, sx1 = swMinus1, swMinus1 + xFrac0, xFrac1 = 1, 0 + } + + s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA() + s00r := float64(s00ru) + s00g := float64(s00gu) + s00b := float64(s00bu) + s00a := float64(s00au) + s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA() + s10r := float64(s10ru) + s10g := float64(s10gu) + s10b := float64(s10bu) + s10a := float64(s10au) + s10r = xFrac1*s00r + xFrac0*s10r + s10g = xFrac1*s00g + xFrac0*s10g + s10b = xFrac1*s00b + xFrac0*s10b + s10a = xFrac1*s00a + xFrac0*s10a + s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA() + s01r := float64(s01ru) + s01g := float64(s01gu) + s01b := float64(s01bu) + s01a := float64(s01au) + s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA() + s11r := float64(s11ru) + s11g := float64(s11gu) + s11b := float64(s11bu) + s11a := float64(s11au) + s11r = xFrac1*s01r + xFrac0*s11r + s11g = xFrac1*s01g + xFrac0*s11g + s11b = xFrac1*s01b + xFrac0*s11b + s11a = xFrac1*s01a + xFrac0*s11a + s11r = yFrac1*s10r + yFrac0*s11r + s11g = yFrac1*s10g + yFrac0*s11g + s11b = yFrac1*s10b + yFrac0*s11b + s11a = yFrac1*s10a + yFrac0*s11a + pr := uint32(s11r) + pg := uint32(s11g) + pb := uint32(s11b) + pa := uint32(s11a) + dst.Pix[d+0] = uint8(pr >> 8) + dst.Pix[d+1] = uint8(pg >> 8) + dst.Pix[d+2] = uint8(pb >> 8) + dst.Pix[d+3] = uint8(pa >> 8) + } + } +} + +func (ablInterpolator) scale_RGBA64Image_RGBA64Image_Over(dst RGBA64Image, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) { + sw := int32(sr.Dx()) + sh := int32(sr.Dy()) + yscale := float64(sh) / float64(dr.Dy()) + xscale := float64(sw) / float64(dr.Dx()) + swMinus1, shMinus1 := sw-1, sh-1 + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + sy := (float64(dy)+0.5)*yscale - 0.5 + // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if + // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for + // sx, below. + sy0 := int32(sy) + yFrac0 := sy - float64(sy0) + yFrac1 := 1 - yFrac0 + sy1 := sy0 + 1 + if sy < 0 { + sy0, sy1 = 0, 0 + yFrac0, yFrac1 = 0, 1 + } else if sy1 > shMinus1 { + sy0, sy1 = shMinus1, shMinus1 + yFrac0, yFrac1 = 1, 0 + } + + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + sx := (float64(dx)+0.5)*xscale - 0.5 + sx0 := int32(sx) + xFrac0 := sx - float64(sx0) + xFrac1 := 1 - xFrac0 + sx1 := sx0 + 1 + if sx < 0 { + sx0, sx1 = 0, 0 + xFrac0, xFrac1 = 0, 1 + } else if sx1 > swMinus1 { + sx0, sx1 = swMinus1, swMinus1 + xFrac0, xFrac1 = 1, 0 + } + + s00u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy0)).RGBA() + s00u.R = uint16(uint32(s00u.R) * ma / 0xffff) + s00u.G = uint16(uint32(s00u.G) * ma / 0xffff) + s00u.B = uint16(uint32(s00u.B) * ma / 0xffff) + s00u.A = uint16(uint32(s00u.A) * ma / 0xffff) + } + s00r := float64(s00u.R) + s00g := float64(s00u.G) + s00b := float64(s00u.B) + s00a := float64(s00u.A) + s10u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy0)).RGBA() + s10u.R = uint16(uint32(s10u.R) * ma / 0xffff) + s10u.G = uint16(uint32(s10u.G) * ma / 0xffff) + s10u.B = uint16(uint32(s10u.B) * ma / 0xffff) + s10u.A = uint16(uint32(s10u.A) * ma / 0xffff) + } + s10r := float64(s10u.R) + s10g := float64(s10u.G) + s10b := float64(s10u.B) + s10a := float64(s10u.A) + s10r = xFrac1*s00r + xFrac0*s10r + s10g = xFrac1*s00g + xFrac0*s10g + s10b = xFrac1*s00b + xFrac0*s10b + s10a = xFrac1*s00a + xFrac0*s10a + s01u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy1)).RGBA() + s01u.R = uint16(uint32(s01u.R) * ma / 0xffff) + s01u.G = uint16(uint32(s01u.G) * ma / 0xffff) + s01u.B = uint16(uint32(s01u.B) * ma / 0xffff) + s01u.A = uint16(uint32(s01u.A) * ma / 0xffff) + } + s01r := float64(s01u.R) + s01g := float64(s01u.G) + s01b := float64(s01u.B) + s01a := float64(s01u.A) + s11u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy1)).RGBA() + s11u.R = uint16(uint32(s11u.R) * ma / 0xffff) + s11u.G = uint16(uint32(s11u.G) * ma / 0xffff) + s11u.B = uint16(uint32(s11u.B) * ma / 0xffff) + s11u.A = uint16(uint32(s11u.A) * ma / 0xffff) + } + s11r := float64(s11u.R) + s11g := float64(s11u.G) + s11b := float64(s11u.B) + s11a := float64(s11u.A) + s11r = xFrac1*s01r + xFrac0*s11r + s11g = xFrac1*s01g + xFrac0*s11g + s11b = xFrac1*s01b + xFrac0*s11b + s11a = xFrac1*s01a + xFrac0*s11a + s11r = yFrac1*s10r + yFrac0*s11r + s11g = yFrac1*s10g + yFrac0*s11g + s11b = yFrac1*s10b + yFrac0*s11b + s11a = yFrac1*s10a + yFrac0*s11a + p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)} + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy)) + if dstMask != nil { _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() - pr = pr * ma / 0xffff - pg = pg * ma / 0xffff - pb = pb * ma / 0xffff - pa = pa * ma / 0xffff + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + } + pa1 := 0xffff - uint32(p.A) + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R)) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G)) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B)) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A)) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } + } +} + +func (ablInterpolator) scale_RGBA64Image_RGBA64Image_Src(dst RGBA64Image, dr, adr image.Rectangle, src image.RGBA64Image, sr image.Rectangle, opts *Options) { + sw := int32(sr.Dx()) + sh := int32(sr.Dy()) + yscale := float64(sh) / float64(dr.Dy()) + xscale := float64(sw) / float64(dr.Dx()) + swMinus1, shMinus1 := sw-1, sh-1 + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + sy := (float64(dy)+0.5)*yscale - 0.5 + // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if + // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for + // sx, below. + sy0 := int32(sy) + yFrac0 := sy - float64(sy0) + yFrac1 := 1 - yFrac0 + sy1 := sy0 + 1 + if sy < 0 { + sy0, sy1 = 0, 0 + yFrac0, yFrac1 = 0, 1 + } else if sy1 > shMinus1 { + sy0, sy1 = shMinus1, shMinus1 + yFrac0, yFrac1 = 1, 0 + } + + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + sx := (float64(dx)+0.5)*xscale - 0.5 + sx0 := int32(sx) + xFrac0 := sx - float64(sx0) + xFrac1 := 1 - xFrac0 + sx1 := sx0 + 1 + if sx < 0 { + sx0, sx1 = 0, 0 + xFrac0, xFrac1 = 0, 1 + } else if sx1 > swMinus1 { + sx0, sx1 = swMinus1, swMinus1 + xFrac0, xFrac1 = 1, 0 + } + + s00u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy0)).RGBA() + s00u.R = uint16(uint32(s00u.R) * ma / 0xffff) + s00u.G = uint16(uint32(s00u.G) * ma / 0xffff) + s00u.B = uint16(uint32(s00u.B) * ma / 0xffff) + s00u.A = uint16(uint32(s00u.A) * ma / 0xffff) + } + s00r := float64(s00u.R) + s00g := float64(s00u.G) + s00b := float64(s00u.B) + s00a := float64(s00u.A) + s10u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy0)).RGBA() + s10u.R = uint16(uint32(s10u.R) * ma / 0xffff) + s10u.G = uint16(uint32(s10u.G) * ma / 0xffff) + s10u.B = uint16(uint32(s10u.B) * ma / 0xffff) + s10u.A = uint16(uint32(s10u.A) * ma / 0xffff) + } + s10r := float64(s10u.R) + s10g := float64(s10u.G) + s10b := float64(s10u.B) + s10a := float64(s10u.A) + s10r = xFrac1*s00r + xFrac0*s10r + s10g = xFrac1*s00g + xFrac0*s10g + s10b = xFrac1*s00b + xFrac0*s10b + s10a = xFrac1*s00a + xFrac0*s10a + s01u := src.RGBA64At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy1)).RGBA() + s01u.R = uint16(uint32(s01u.R) * ma / 0xffff) + s01u.G = uint16(uint32(s01u.G) * ma / 0xffff) + s01u.B = uint16(uint32(s01u.B) * ma / 0xffff) + s01u.A = uint16(uint32(s01u.A) * ma / 0xffff) + } + s01r := float64(s01u.R) + s01g := float64(s01u.G) + s01b := float64(s01u.B) + s01a := float64(s01u.A) + s11u := src.RGBA64At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy1)).RGBA() + s11u.R = uint16(uint32(s11u.R) * ma / 0xffff) + s11u.G = uint16(uint32(s11u.G) * ma / 0xffff) + s11u.B = uint16(uint32(s11u.B) * ma / 0xffff) + s11u.A = uint16(uint32(s11u.A) * ma / 0xffff) + } + s11r := float64(s11u.R) + s11g := float64(s11u.G) + s11b := float64(s11u.B) + s11a := float64(s11u.A) + s11r = xFrac1*s01r + xFrac0*s11r + s11g = xFrac1*s01g + xFrac0*s11g + s11b = xFrac1*s01b + xFrac0*s11b + s11a = xFrac1*s01a + xFrac0*s11a + s11r = yFrac1*s10r + yFrac0*s11r + s11g = yFrac1*s10g + yFrac0*s11g + s11b = yFrac1*s10b + yFrac0*s11b + s11a = yFrac1*s10a + yFrac0*s11a + p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)} + if dstMask != nil { + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy)) + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + pa1 := 0xffff - ma + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R)) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G)) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B)) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A)) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } else { + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), p) } - pa1 := 0xffff - pa - dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr) - dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg) - dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb) - dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa) - dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor) } } } -func (ablInterpolator) scale_Image_Image_Src(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) { +func (ablInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) { sw := int32(sr.Dx()) sh := int32(sr.Dy()) yscale := float64(sh) / float64(dr.Dy()) @@ -2812,35 +3389,159 @@ func (ablInterpolator) scale_Image_Image_Src(dst Image, dr, adr image.Rectangle, pg := uint32(s11g) pb := uint32(s11b) pa := uint32(s11a) + qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA() if dstMask != nil { - qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA() _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() pr = pr * ma / 0xffff pg = pg * ma / 0xffff pb = pb * ma / 0xffff pa = pa * ma / 0xffff - pa1 := 0xffff - ma - dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr) - dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg) - dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb) - dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa) - dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor) - } else { - dstColorRGBA64.R = uint16(pr) - dstColorRGBA64.G = uint16(pg) - dstColorRGBA64.B = uint16(pb) - dstColorRGBA64.A = uint16(pa) - dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor) } + pa1 := 0xffff - pa + dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr) + dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg) + dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb) + dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor) } } } -func (ablInterpolator) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point, opts *Options) { - for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { - dyf := float64(dr.Min.Y+int(dy)) + 0.5 - d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 - for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { +func (ablInterpolator) scale_Image_Image_Src(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) { + sw := int32(sr.Dx()) + sh := int32(sr.Dy()) + yscale := float64(sh) / float64(dr.Dy()) + xscale := float64(sw) / float64(dr.Dx()) + swMinus1, shMinus1 := sw-1, sh-1 + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := &color.RGBA64{} + dstColor := color.Color(dstColorRGBA64) + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + sy := (float64(dy)+0.5)*yscale - 0.5 + // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if + // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for + // sx, below. + sy0 := int32(sy) + yFrac0 := sy - float64(sy0) + yFrac1 := 1 - yFrac0 + sy1 := sy0 + 1 + if sy < 0 { + sy0, sy1 = 0, 0 + yFrac0, yFrac1 = 0, 1 + } else if sy1 > shMinus1 { + sy0, sy1 = shMinus1, shMinus1 + yFrac0, yFrac1 = 1, 0 + } + + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + sx := (float64(dx)+0.5)*xscale - 0.5 + sx0 := int32(sx) + xFrac0 := sx - float64(sx0) + xFrac1 := 1 - xFrac0 + sx1 := sx0 + 1 + if sx < 0 { + sx0, sx1 = 0, 0 + xFrac0, xFrac1 = 0, 1 + } else if sx1 > swMinus1 { + sx0, sx1 = swMinus1, swMinus1 + xFrac0, xFrac1 = 1, 0 + } + + s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA() + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy0)).RGBA() + s00ru = s00ru * ma / 0xffff + s00gu = s00gu * ma / 0xffff + s00bu = s00bu * ma / 0xffff + s00au = s00au * ma / 0xffff + } + s00r := float64(s00ru) + s00g := float64(s00gu) + s00b := float64(s00bu) + s00a := float64(s00au) + s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA() + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy0)).RGBA() + s10ru = s10ru * ma / 0xffff + s10gu = s10gu * ma / 0xffff + s10bu = s10bu * ma / 0xffff + s10au = s10au * ma / 0xffff + } + s10r := float64(s10ru) + s10g := float64(s10gu) + s10b := float64(s10bu) + s10a := float64(s10au) + s10r = xFrac1*s00r + xFrac0*s10r + s10g = xFrac1*s00g + xFrac0*s10g + s10b = xFrac1*s00b + xFrac0*s10b + s10a = xFrac1*s00a + xFrac0*s10a + s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA() + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy1)).RGBA() + s01ru = s01ru * ma / 0xffff + s01gu = s01gu * ma / 0xffff + s01bu = s01bu * ma / 0xffff + s01au = s01au * ma / 0xffff + } + s01r := float64(s01ru) + s01g := float64(s01gu) + s01b := float64(s01bu) + s01a := float64(s01au) + s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA() + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy1)).RGBA() + s11ru = s11ru * ma / 0xffff + s11gu = s11gu * ma / 0xffff + s11bu = s11bu * ma / 0xffff + s11au = s11au * ma / 0xffff + } + s11r := float64(s11ru) + s11g := float64(s11gu) + s11b := float64(s11bu) + s11a := float64(s11au) + s11r = xFrac1*s01r + xFrac0*s11r + s11g = xFrac1*s01g + xFrac0*s11g + s11b = xFrac1*s01b + xFrac0*s11b + s11a = xFrac1*s01a + xFrac0*s11a + s11r = yFrac1*s10r + yFrac0*s11r + s11g = yFrac1*s10g + yFrac0*s11g + s11b = yFrac1*s10b + yFrac0*s11b + s11a = yFrac1*s10a + yFrac0*s11a + pr := uint32(s11r) + pg := uint32(s11g) + pb := uint32(s11b) + pa := uint32(s11a) + if dstMask != nil { + qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA() + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() + pr = pr * ma / 0xffff + pg = pg * ma / 0xffff + pb = pb * ma / 0xffff + pa = pa * ma / 0xffff + pa1 := 0xffff - ma + dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr) + dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg) + dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb) + dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor) + } else { + dstColorRGBA64.R = uint16(pr) + dstColorRGBA64.G = uint16(pg) + dstColorRGBA64.B = uint16(pb) + dstColorRGBA64.A = uint16(pa) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor) + } + } + } +} + +func (ablInterpolator) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point, opts *Options) { + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { dxf := float64(dr.Min.X+int(dx)) + 0.5 sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] @@ -4007,6 +4708,169 @@ func (ablInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr imag } } +func (ablInterpolator) transform_RGBA_RGBA64Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) { + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] + sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { + continue + } + + sx -= 0.5 + sx0 := int(sx) + xFrac0 := sx - float64(sx0) + xFrac1 := 1 - xFrac0 + sx0 += bias.X + sx1 := sx0 + 1 + if sx0 < sr.Min.X { + sx0, sx1 = sr.Min.X, sr.Min.X + xFrac0, xFrac1 = 0, 1 + } else if sx1 >= sr.Max.X { + sx0, sx1 = sr.Max.X-1, sr.Max.X-1 + xFrac0, xFrac1 = 1, 0 + } + + sy -= 0.5 + sy0 := int(sy) + yFrac0 := sy - float64(sy0) + yFrac1 := 1 - yFrac0 + sy0 += bias.Y + sy1 := sy0 + 1 + if sy0 < sr.Min.Y { + sy0, sy1 = sr.Min.Y, sr.Min.Y + yFrac0, yFrac1 = 0, 1 + } else if sy1 >= sr.Max.Y { + sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1 + yFrac0, yFrac1 = 1, 0 + } + + s00u := src.RGBA64At(sx0, sy0) + s00r := float64(s00u.R) + s00g := float64(s00u.G) + s00b := float64(s00u.B) + s00a := float64(s00u.A) + s10u := src.RGBA64At(sx1, sy0) + s10r := float64(s10u.R) + s10g := float64(s10u.G) + s10b := float64(s10u.B) + s10a := float64(s10u.A) + s10r = xFrac1*s00r + xFrac0*s10r + s10g = xFrac1*s00g + xFrac0*s10g + s10b = xFrac1*s00b + xFrac0*s10b + s10a = xFrac1*s00a + xFrac0*s10a + s01u := src.RGBA64At(sx0, sy1) + s01r := float64(s01u.R) + s01g := float64(s01u.G) + s01b := float64(s01u.B) + s01a := float64(s01u.A) + s11u := src.RGBA64At(sx1, sy1) + s11r := float64(s11u.R) + s11g := float64(s11u.G) + s11b := float64(s11u.B) + s11a := float64(s11u.A) + s11r = xFrac1*s01r + xFrac0*s11r + s11g = xFrac1*s01g + xFrac0*s11g + s11b = xFrac1*s01b + xFrac0*s11b + s11a = xFrac1*s01a + xFrac0*s11a + s11r = yFrac1*s10r + yFrac0*s11r + s11g = yFrac1*s10g + yFrac0*s11g + s11b = yFrac1*s10b + yFrac0*s11b + s11a = yFrac1*s10a + yFrac0*s11a + p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)} + pa1 := (0xffff - uint32(p.A)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + uint32(p.R)) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + uint32(p.G)) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + uint32(p.B)) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + uint32(p.A)) >> 8) + } + } +} + +func (ablInterpolator) transform_RGBA_RGBA64Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) { + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] + sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { + continue + } + + sx -= 0.5 + sx0 := int(sx) + xFrac0 := sx - float64(sx0) + xFrac1 := 1 - xFrac0 + sx0 += bias.X + sx1 := sx0 + 1 + if sx0 < sr.Min.X { + sx0, sx1 = sr.Min.X, sr.Min.X + xFrac0, xFrac1 = 0, 1 + } else if sx1 >= sr.Max.X { + sx0, sx1 = sr.Max.X-1, sr.Max.X-1 + xFrac0, xFrac1 = 1, 0 + } + + sy -= 0.5 + sy0 := int(sy) + yFrac0 := sy - float64(sy0) + yFrac1 := 1 - yFrac0 + sy0 += bias.Y + sy1 := sy0 + 1 + if sy0 < sr.Min.Y { + sy0, sy1 = sr.Min.Y, sr.Min.Y + yFrac0, yFrac1 = 0, 1 + } else if sy1 >= sr.Max.Y { + sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1 + yFrac0, yFrac1 = 1, 0 + } + + s00u := src.RGBA64At(sx0, sy0) + s00r := float64(s00u.R) + s00g := float64(s00u.G) + s00b := float64(s00u.B) + s00a := float64(s00u.A) + s10u := src.RGBA64At(sx1, sy0) + s10r := float64(s10u.R) + s10g := float64(s10u.G) + s10b := float64(s10u.B) + s10a := float64(s10u.A) + s10r = xFrac1*s00r + xFrac0*s10r + s10g = xFrac1*s00g + xFrac0*s10g + s10b = xFrac1*s00b + xFrac0*s10b + s10a = xFrac1*s00a + xFrac0*s10a + s01u := src.RGBA64At(sx0, sy1) + s01r := float64(s01u.R) + s01g := float64(s01u.G) + s01b := float64(s01u.B) + s01a := float64(s01u.A) + s11u := src.RGBA64At(sx1, sy1) + s11r := float64(s11u.R) + s11g := float64(s11u.G) + s11b := float64(s11u.B) + s11a := float64(s11u.A) + s11r = xFrac1*s01r + xFrac0*s11r + s11g = xFrac1*s01g + xFrac0*s11g + s11b = xFrac1*s01b + xFrac0*s11b + s11a = xFrac1*s01a + xFrac0*s11a + s11r = yFrac1*s10r + yFrac0*s11r + s11g = yFrac1*s10g + yFrac0*s11g + s11b = yFrac1*s10b + yFrac0*s11b + s11a = yFrac1*s10a + yFrac0*s11a + p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)} + dst.Pix[d+0] = uint8(p.R >> 8) + dst.Pix[d+1] = uint8(p.G >> 8) + dst.Pix[d+2] = uint8(p.B >> 8) + dst.Pix[d+3] = uint8(p.A >> 8) + } + } +} + func (ablInterpolator) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { dyf := float64(dr.Min.Y+int(dy)) + 0.5 @@ -4176,11 +5040,11 @@ func (ablInterpolator) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.R } } -func (ablInterpolator) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) { +func (ablInterpolator) transform_RGBA64Image_RGBA64Image_Over(dst RGBA64Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) { srcMask, smp := opts.SrcMask, opts.SrcMaskP dstMask, dmp := opts.DstMask, opts.DstMaskP - dstColorRGBA64 := &color.RGBA64{} - dstColor := color.Color(dstColorRGBA64) + dstColorRGBA64 := color.RGBA64{} + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { dyf := float64(dr.Min.Y+int(dy)) + 0.5 for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { @@ -4219,15 +5083,261 @@ func (ablInterpolator) transform_Image_Image_Over(dst Image, dr, adr image.Recta yFrac0, yFrac1 = 1, 0 } - s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA() + s00u := src.RGBA64At(sx0, sy0) if srcMask != nil { _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA() - s00ru = s00ru * ma / 0xffff - s00gu = s00gu * ma / 0xffff - s00bu = s00bu * ma / 0xffff - s00au = s00au * ma / 0xffff - } - s00r := float64(s00ru) + s00u.R = uint16(uint32(s00u.R) * ma / 0xffff) + s00u.G = uint16(uint32(s00u.G) * ma / 0xffff) + s00u.B = uint16(uint32(s00u.B) * ma / 0xffff) + s00u.A = uint16(uint32(s00u.A) * ma / 0xffff) + } + s00r := float64(s00u.R) + s00g := float64(s00u.G) + s00b := float64(s00u.B) + s00a := float64(s00u.A) + s10u := src.RGBA64At(sx1, sy0) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy0).RGBA() + s10u.R = uint16(uint32(s10u.R) * ma / 0xffff) + s10u.G = uint16(uint32(s10u.G) * ma / 0xffff) + s10u.B = uint16(uint32(s10u.B) * ma / 0xffff) + s10u.A = uint16(uint32(s10u.A) * ma / 0xffff) + } + s10r := float64(s10u.R) + s10g := float64(s10u.G) + s10b := float64(s10u.B) + s10a := float64(s10u.A) + s10r = xFrac1*s00r + xFrac0*s10r + s10g = xFrac1*s00g + xFrac0*s10g + s10b = xFrac1*s00b + xFrac0*s10b + s10a = xFrac1*s00a + xFrac0*s10a + s01u := src.RGBA64At(sx0, sy1) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy1).RGBA() + s01u.R = uint16(uint32(s01u.R) * ma / 0xffff) + s01u.G = uint16(uint32(s01u.G) * ma / 0xffff) + s01u.B = uint16(uint32(s01u.B) * ma / 0xffff) + s01u.A = uint16(uint32(s01u.A) * ma / 0xffff) + } + s01r := float64(s01u.R) + s01g := float64(s01u.G) + s01b := float64(s01u.B) + s01a := float64(s01u.A) + s11u := src.RGBA64At(sx1, sy1) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy1).RGBA() + s11u.R = uint16(uint32(s11u.R) * ma / 0xffff) + s11u.G = uint16(uint32(s11u.G) * ma / 0xffff) + s11u.B = uint16(uint32(s11u.B) * ma / 0xffff) + s11u.A = uint16(uint32(s11u.A) * ma / 0xffff) + } + s11r := float64(s11u.R) + s11g := float64(s11u.G) + s11b := float64(s11u.B) + s11a := float64(s11u.A) + s11r = xFrac1*s01r + xFrac0*s11r + s11g = xFrac1*s01g + xFrac0*s11g + s11b = xFrac1*s01b + xFrac0*s11b + s11a = xFrac1*s01a + xFrac0*s11a + s11r = yFrac1*s10r + yFrac0*s11r + s11g = yFrac1*s10g + yFrac0*s11g + s11b = yFrac1*s10b + yFrac0*s11b + s11a = yFrac1*s10a + yFrac0*s11a + p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)} + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy)) + if dstMask != nil { + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + } + pa1 := 0xffff - uint32(p.A) + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R)) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G)) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B)) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A)) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } + } +} + +func (ablInterpolator) transform_RGBA64Image_RGBA64Image_Src(dst RGBA64Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, opts *Options) { + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] + sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { + continue + } + + sx -= 0.5 + sx0 := int(sx) + xFrac0 := sx - float64(sx0) + xFrac1 := 1 - xFrac0 + sx0 += bias.X + sx1 := sx0 + 1 + if sx0 < sr.Min.X { + sx0, sx1 = sr.Min.X, sr.Min.X + xFrac0, xFrac1 = 0, 1 + } else if sx1 >= sr.Max.X { + sx0, sx1 = sr.Max.X-1, sr.Max.X-1 + xFrac0, xFrac1 = 1, 0 + } + + sy -= 0.5 + sy0 := int(sy) + yFrac0 := sy - float64(sy0) + yFrac1 := 1 - yFrac0 + sy0 += bias.Y + sy1 := sy0 + 1 + if sy0 < sr.Min.Y { + sy0, sy1 = sr.Min.Y, sr.Min.Y + yFrac0, yFrac1 = 0, 1 + } else if sy1 >= sr.Max.Y { + sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1 + yFrac0, yFrac1 = 1, 0 + } + + s00u := src.RGBA64At(sx0, sy0) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA() + s00u.R = uint16(uint32(s00u.R) * ma / 0xffff) + s00u.G = uint16(uint32(s00u.G) * ma / 0xffff) + s00u.B = uint16(uint32(s00u.B) * ma / 0xffff) + s00u.A = uint16(uint32(s00u.A) * ma / 0xffff) + } + s00r := float64(s00u.R) + s00g := float64(s00u.G) + s00b := float64(s00u.B) + s00a := float64(s00u.A) + s10u := src.RGBA64At(sx1, sy0) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy0).RGBA() + s10u.R = uint16(uint32(s10u.R) * ma / 0xffff) + s10u.G = uint16(uint32(s10u.G) * ma / 0xffff) + s10u.B = uint16(uint32(s10u.B) * ma / 0xffff) + s10u.A = uint16(uint32(s10u.A) * ma / 0xffff) + } + s10r := float64(s10u.R) + s10g := float64(s10u.G) + s10b := float64(s10u.B) + s10a := float64(s10u.A) + s10r = xFrac1*s00r + xFrac0*s10r + s10g = xFrac1*s00g + xFrac0*s10g + s10b = xFrac1*s00b + xFrac0*s10b + s10a = xFrac1*s00a + xFrac0*s10a + s01u := src.RGBA64At(sx0, sy1) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy1).RGBA() + s01u.R = uint16(uint32(s01u.R) * ma / 0xffff) + s01u.G = uint16(uint32(s01u.G) * ma / 0xffff) + s01u.B = uint16(uint32(s01u.B) * ma / 0xffff) + s01u.A = uint16(uint32(s01u.A) * ma / 0xffff) + } + s01r := float64(s01u.R) + s01g := float64(s01u.G) + s01b := float64(s01u.B) + s01a := float64(s01u.A) + s11u := src.RGBA64At(sx1, sy1) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy1).RGBA() + s11u.R = uint16(uint32(s11u.R) * ma / 0xffff) + s11u.G = uint16(uint32(s11u.G) * ma / 0xffff) + s11u.B = uint16(uint32(s11u.B) * ma / 0xffff) + s11u.A = uint16(uint32(s11u.A) * ma / 0xffff) + } + s11r := float64(s11u.R) + s11g := float64(s11u.G) + s11b := float64(s11u.B) + s11a := float64(s11u.A) + s11r = xFrac1*s01r + xFrac0*s11r + s11g = xFrac1*s01g + xFrac0*s11g + s11b = xFrac1*s01b + xFrac0*s11b + s11a = xFrac1*s01a + xFrac0*s11a + s11r = yFrac1*s10r + yFrac0*s11r + s11g = yFrac1*s10g + yFrac0*s11g + s11b = yFrac1*s10b + yFrac0*s11b + s11a = yFrac1*s10a + yFrac0*s11a + p := color.RGBA64{uint16(s11r), uint16(s11g), uint16(s11b), uint16(s11a)} + if dstMask != nil { + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy)) + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() + p.R = uint16(uint32(p.R) * ma / 0xffff) + p.G = uint16(uint32(p.G) * ma / 0xffff) + p.B = uint16(uint32(p.B) * ma / 0xffff) + p.A = uint16(uint32(p.A) * ma / 0xffff) + pa1 := 0xffff - ma + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + uint32(p.R)) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + uint32(p.G)) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + uint32(p.B)) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + uint32(p.A)) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } else { + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), p) + } + } + } +} + +func (ablInterpolator) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) { + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := &color.RGBA64{} + dstColor := color.Color(dstColorRGBA64) + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] + sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { + continue + } + + sx -= 0.5 + sx0 := int(sx) + xFrac0 := sx - float64(sx0) + xFrac1 := 1 - xFrac0 + sx0 += bias.X + sx1 := sx0 + 1 + if sx0 < sr.Min.X { + sx0, sx1 = sr.Min.X, sr.Min.X + xFrac0, xFrac1 = 0, 1 + } else if sx1 >= sr.Max.X { + sx0, sx1 = sr.Max.X-1, sr.Max.X-1 + xFrac0, xFrac1 = 1, 0 + } + + sy -= 0.5 + sy0 := int(sy) + yFrac0 := sy - float64(sy0) + yFrac1 := 1 - yFrac0 + sy0 += bias.Y + sy1 := sy0 + 1 + if sy0 < sr.Min.Y { + sy0, sy1 = sr.Min.Y, sr.Min.Y + yFrac0, yFrac1 = 0, 1 + } else if sy1 >= sr.Max.Y { + sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1 + yFrac0, yFrac1 = 1, 0 + } + + s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA() + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA() + s00ru = s00ru * ma / 0xffff + s00gu = s00gu * ma / 0xffff + s00bu = s00bu * ma / 0xffff + s00au = s00au * ma / 0xffff + } + s00r := float64(s00ru) s00g := float64(s00gu) s00b := float64(s00bu) s00a := float64(s00au) @@ -4500,6 +5610,8 @@ func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr case image.YCbCrSubsampleRatio440: z.scaleX_YCbCr440(tmp, src, sr, &o) } + case image.RGBA64Image: + z.scaleX_RGBA64Image(tmp, src, sr, &o) default: z.scaleX_Image(tmp, src, sr, &o) } @@ -4518,6 +5630,8 @@ func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr switch dst := dst.(type) { case *image.RGBA: z.scaleY_RGBA_Over(dst, dr, adr, tmp, &o) + case RGBA64Image: + z.scaleY_RGBA64Image_Over(dst, dr, adr, tmp, &o) default: z.scaleY_Image_Over(dst, dr, adr, tmp, &o) } @@ -4525,6 +5639,8 @@ func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr switch dst := dst.(type) { case *image.RGBA: z.scaleY_RGBA_Src(dst, dr, adr, tmp, &o) + case RGBA64Image: + z.scaleY_RGBA64Image_Src(dst, dr, adr, tmp, &o) default: z.scaleY_Image_Src(dst, dr, adr, tmp, &o) } @@ -4600,9 +5716,16 @@ func (q *Kernel) Transform(dst Image, s2d f64.Aff3, src image.Image, sr image.Re q.transform_RGBA_NRGBA_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o) case *image.RGBA: q.transform_RGBA_RGBA_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o) + case image.RGBA64Image: + q.transform_RGBA_RGBA64Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o) default: q.transform_RGBA_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o) } + case RGBA64Image: + switch src := src.(type) { + case image.RGBA64Image: + q.transform_RGBA64Image_RGBA64Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o) + } default: switch src := src.(type) { default: @@ -4632,9 +5755,16 @@ func (q *Kernel) Transform(dst Image, s2d f64.Aff3, src image.Image, sr image.Re case image.YCbCrSubsampleRatio440: q.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o) } + case image.RGBA64Image: + q.transform_RGBA_RGBA64Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o) default: q.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o) } + case RGBA64Image: + switch src := src.(type) { + case image.RGBA64Image: + q.transform_RGBA64Image_RGBA64Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o) + } default: switch src := src.(type) { default: @@ -4909,6 +6039,37 @@ func (z *kernelScaler) scaleX_YCbCr440(tmp [][4]float64, src *image.YCbCr, sr im } } +func (z *kernelScaler) scaleX_RGBA64Image(tmp [][4]float64, src image.RGBA64Image, sr image.Rectangle, opts *Options) { + t := 0 + srcMask, smp := opts.SrcMask, opts.SrcMaskP + for y := int32(0); y < z.sh; y++ { + for _, s := range z.horizontal.sources { + var pr, pg, pb, pa float64 + for _, c := range z.horizontal.contribs[s.i:s.j] { + pu := src.RGBA64At(sr.Min.X+int(c.coord), sr.Min.Y+int(y)) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(c.coord), smp.Y+sr.Min.Y+int(y)).RGBA() + pu.R = uint16(uint32(pu.R) * ma / 0xffff) + pu.G = uint16(uint32(pu.G) * ma / 0xffff) + pu.B = uint16(uint32(pu.B) * ma / 0xffff) + pu.A = uint16(uint32(pu.A) * ma / 0xffff) + } + pr += float64(pu.R) * c.weight + pg += float64(pu.G) * c.weight + pb += float64(pu.B) * c.weight + pa += float64(pu.A) * c.weight + } + tmp[t] = [4]float64{ + pr * s.invTotalWeightFFFF, + pg * s.invTotalWeightFFFF, + pb * s.invTotalWeightFFFF, + pa * s.invTotalWeightFFFF, + } + t++ + } + } +} + func (z *kernelScaler) scaleX_Image(tmp [][4]float64, src image.Image, sr image.Rectangle, opts *Options) { t := 0 srcMask, smp := opts.SrcMask, opts.SrcMaskP @@ -4945,12 +6106,456 @@ func (z *kernelScaler) scaleY_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle d := (dr.Min.Y+adr.Min.Y-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+int(dx)-dst.Rect.Min.X)*4 for _, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] { var pr, pg, pb, pa float64 - for _, c := range z.vertical.contribs[s.i:s.j] { - p := &tmp[c.coord*z.dw+dx] - pr += p[0] * c.weight - pg += p[1] * c.weight - pb += p[2] * c.weight - pa += p[3] * c.weight + for _, c := range z.vertical.contribs[s.i:s.j] { + p := &tmp[c.coord*z.dw+dx] + pr += p[0] * c.weight + pg += p[1] * c.weight + pb += p[2] * c.weight + pa += p[3] * c.weight + } + + if pr > pa { + pr = pa + } + if pg > pa { + pg = pa + } + if pb > pa { + pb = pa + } + + pr0 := uint32(ftou(pr * s.invTotalWeight)) + pg0 := uint32(ftou(pg * s.invTotalWeight)) + pb0 := uint32(ftou(pb * s.invTotalWeight)) + pa0 := uint32(ftou(pa * s.invTotalWeight)) + pa1 := (0xffff - uint32(pa0)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8) + d += dst.Stride + } + } +} + +func (z *kernelScaler) scaleY_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) { + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + d := (dr.Min.Y+adr.Min.Y-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+int(dx)-dst.Rect.Min.X)*4 + for _, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] { + var pr, pg, pb, pa float64 + for _, c := range z.vertical.contribs[s.i:s.j] { + p := &tmp[c.coord*z.dw+dx] + pr += p[0] * c.weight + pg += p[1] * c.weight + pb += p[2] * c.weight + pa += p[3] * c.weight + } + + if pr > pa { + pr = pa + } + if pg > pa { + pg = pa + } + if pb > pa { + pb = pa + } + + dst.Pix[d+0] = uint8(ftou(pr*s.invTotalWeight) >> 8) + dst.Pix[d+1] = uint8(ftou(pg*s.invTotalWeight) >> 8) + dst.Pix[d+2] = uint8(ftou(pb*s.invTotalWeight) >> 8) + dst.Pix[d+3] = uint8(ftou(pa*s.invTotalWeight) >> 8) + d += dst.Stride + } + } +} + +func (z *kernelScaler) scaleY_RGBA64Image_Over(dst RGBA64Image, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) { + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + for dy, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] { + var pr, pg, pb, pa float64 + for _, c := range z.vertical.contribs[s.i:s.j] { + p := &tmp[c.coord*z.dw+dx] + pr += p[0] * c.weight + pg += p[1] * c.weight + pb += p[2] * c.weight + pa += p[3] * c.weight + } + + if pr > pa { + pr = pa + } + if pg > pa { + pg = pa + } + if pb > pa { + pb = pa + } + + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy)) + pr0 := uint32(ftou(pr * s.invTotalWeight)) + pg0 := uint32(ftou(pg * s.invTotalWeight)) + pb0 := uint32(ftou(pb * s.invTotalWeight)) + pa0 := uint32(ftou(pa * s.invTotalWeight)) + if dstMask != nil { + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(adr.Min.Y+dy)).RGBA() + pr0 = pr0 * ma / 0xffff + pg0 = pg0 * ma / 0xffff + pb0 = pb0 * ma / 0xffff + pa0 = pa0 * ma / 0xffff + } + pa1 := 0xffff - pa0 + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + pr0) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + pg0) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + pb0) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + pa0) + dst.SetRGBA64(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColorRGBA64) + } + } +} + +func (z *kernelScaler) scaleY_RGBA64Image_Src(dst RGBA64Image, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) { + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + for dy, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] { + var pr, pg, pb, pa float64 + for _, c := range z.vertical.contribs[s.i:s.j] { + p := &tmp[c.coord*z.dw+dx] + pr += p[0] * c.weight + pg += p[1] * c.weight + pb += p[2] * c.weight + pa += p[3] * c.weight + } + + if pr > pa { + pr = pa + } + if pg > pa { + pg = pa + } + if pb > pa { + pb = pa + } + + if dstMask != nil { + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy)) + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(adr.Min.Y+dy)).RGBA() + pr := uint32(ftou(pr*s.invTotalWeight)) * ma / 0xffff + pg := uint32(ftou(pg*s.invTotalWeight)) * ma / 0xffff + pb := uint32(ftou(pb*s.invTotalWeight)) * ma / 0xffff + pa := uint32(ftou(pa*s.invTotalWeight)) * ma / 0xffff + pa1 := 0xffff - ma + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + pr) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + pg) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + pb) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + pa) + dst.SetRGBA64(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColorRGBA64) + } else { + dstColorRGBA64.R = ftou(pr * s.invTotalWeight) + dstColorRGBA64.G = ftou(pg * s.invTotalWeight) + dstColorRGBA64.B = ftou(pb * s.invTotalWeight) + dstColorRGBA64.A = ftou(pa * s.invTotalWeight) + dst.SetRGBA64(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColorRGBA64) + } + } + } +} + +func (z *kernelScaler) scaleY_Image_Over(dst Image, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) { + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := &color.RGBA64{} + dstColor := color.Color(dstColorRGBA64) + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + for dy, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] { + var pr, pg, pb, pa float64 + for _, c := range z.vertical.contribs[s.i:s.j] { + p := &tmp[c.coord*z.dw+dx] + pr += p[0] * c.weight + pg += p[1] * c.weight + pb += p[2] * c.weight + pa += p[3] * c.weight + } + + if pr > pa { + pr = pa + } + if pg > pa { + pg = pa + } + if pb > pa { + pb = pa + } + + qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy)).RGBA() + pr0 := uint32(ftou(pr * s.invTotalWeight)) + pg0 := uint32(ftou(pg * s.invTotalWeight)) + pb0 := uint32(ftou(pb * s.invTotalWeight)) + pa0 := uint32(ftou(pa * s.invTotalWeight)) + if dstMask != nil { + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(adr.Min.Y+dy)).RGBA() + pr0 = pr0 * ma / 0xffff + pg0 = pg0 * ma / 0xffff + pb0 = pb0 * ma / 0xffff + pa0 = pa0 * ma / 0xffff + } + pa1 := 0xffff - pa0 + dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr0) + dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg0) + dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb0) + dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa0) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColor) + } + } +} + +func (z *kernelScaler) scaleY_Image_Src(dst Image, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) { + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := &color.RGBA64{} + dstColor := color.Color(dstColorRGBA64) + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { + for dy, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] { + var pr, pg, pb, pa float64 + for _, c := range z.vertical.contribs[s.i:s.j] { + p := &tmp[c.coord*z.dw+dx] + pr += p[0] * c.weight + pg += p[1] * c.weight + pb += p[2] * c.weight + pa += p[3] * c.weight + } + + if pr > pa { + pr = pa + } + if pg > pa { + pg = pa + } + if pb > pa { + pb = pa + } + + if dstMask != nil { + qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy)).RGBA() + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(adr.Min.Y+dy)).RGBA() + pr := uint32(ftou(pr*s.invTotalWeight)) * ma / 0xffff + pg := uint32(ftou(pg*s.invTotalWeight)) * ma / 0xffff + pb := uint32(ftou(pb*s.invTotalWeight)) * ma / 0xffff + pa := uint32(ftou(pa*s.invTotalWeight)) * ma / 0xffff + pa1 := 0xffff - ma + dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr) + dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg) + dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb) + dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColor) + } else { + dstColorRGBA64.R = ftou(pr * s.invTotalWeight) + dstColorRGBA64.G = ftou(pg * s.invTotalWeight) + dstColorRGBA64.B = ftou(pb * s.invTotalWeight) + dstColorRGBA64.A = ftou(pa * s.invTotalWeight) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColor) + } + } + } +} + +func (q *Kernel) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { + // When shrinking, broaden the effective kernel support so that we still + // visit every source pixel. + xHalfWidth, xKernelArgScale := q.Support, 1.0 + if xscale > 1 { + xHalfWidth *= xscale + xKernelArgScale = 1 / xscale + } + yHalfWidth, yKernelArgScale := q.Support, 1.0 + if yscale > 1 { + yHalfWidth *= yscale + yKernelArgScale = 1 / yscale + } + + xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth))) + yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth))) + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] + sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { + continue + } + + // TODO: adjust the bias so that we can use int(f) instead + // of math.Floor(f) and math.Ceil(f). + sx += float64(bias.X) + sx -= 0.5 + ix := int(math.Floor(sx - xHalfWidth)) + if ix < sr.Min.X { + ix = sr.Min.X + } + jx := int(math.Ceil(sx + xHalfWidth)) + if jx > sr.Max.X { + jx = sr.Max.X + } + + totalXWeight := 0.0 + for kx := ix; kx < jx; kx++ { + xWeight := 0.0 + if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support { + xWeight = q.At(t) + } + xWeights[kx-ix] = xWeight + totalXWeight += xWeight + } + for x := range xWeights[:jx-ix] { + xWeights[x] /= totalXWeight + } + + sy += float64(bias.Y) + sy -= 0.5 + iy := int(math.Floor(sy - yHalfWidth)) + if iy < sr.Min.Y { + iy = sr.Min.Y + } + jy := int(math.Ceil(sy + yHalfWidth)) + if jy > sr.Max.Y { + jy = sr.Max.Y + } + + totalYWeight := 0.0 + for ky := iy; ky < jy; ky++ { + yWeight := 0.0 + if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support { + yWeight = q.At(t) + } + yWeights[ky-iy] = yWeight + totalYWeight += yWeight + } + for y := range yWeights[:jy-iy] { + yWeights[y] /= totalYWeight + } + + var pr float64 + for ky := iy; ky < jy; ky++ { + if yWeight := yWeights[ky-iy]; yWeight != 0 { + for kx := ix; kx < jx; kx++ { + if w := xWeights[kx-ix] * yWeight; w != 0 { + pi := (ky-src.Rect.Min.Y)*src.Stride + (kx - src.Rect.Min.X) + pru := uint32(src.Pix[pi]) * 0x101 + pr += float64(pru) * w + } + } + } + } + out := uint8(fffftou(pr) >> 8) + dst.Pix[d+0] = out + dst.Pix[d+1] = out + dst.Pix[d+2] = out + dst.Pix[d+3] = 0xff + } + } +} + +func (q *Kernel) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { + // When shrinking, broaden the effective kernel support so that we still + // visit every source pixel. + xHalfWidth, xKernelArgScale := q.Support, 1.0 + if xscale > 1 { + xHalfWidth *= xscale + xKernelArgScale = 1 / xscale + } + yHalfWidth, yKernelArgScale := q.Support, 1.0 + if yscale > 1 { + yHalfWidth *= yscale + yKernelArgScale = 1 / yscale + } + + xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth))) + yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth))) + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] + sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { + continue + } + + // TODO: adjust the bias so that we can use int(f) instead + // of math.Floor(f) and math.Ceil(f). + sx += float64(bias.X) + sx -= 0.5 + ix := int(math.Floor(sx - xHalfWidth)) + if ix < sr.Min.X { + ix = sr.Min.X + } + jx := int(math.Ceil(sx + xHalfWidth)) + if jx > sr.Max.X { + jx = sr.Max.X + } + + totalXWeight := 0.0 + for kx := ix; kx < jx; kx++ { + xWeight := 0.0 + if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support { + xWeight = q.At(t) + } + xWeights[kx-ix] = xWeight + totalXWeight += xWeight + } + for x := range xWeights[:jx-ix] { + xWeights[x] /= totalXWeight + } + + sy += float64(bias.Y) + sy -= 0.5 + iy := int(math.Floor(sy - yHalfWidth)) + if iy < sr.Min.Y { + iy = sr.Min.Y + } + jy := int(math.Ceil(sy + yHalfWidth)) + if jy > sr.Max.Y { + jy = sr.Max.Y + } + + totalYWeight := 0.0 + for ky := iy; ky < jy; ky++ { + yWeight := 0.0 + if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support { + yWeight = q.At(t) + } + yWeights[ky-iy] = yWeight + totalYWeight += yWeight + } + for y := range yWeights[:jy-iy] { + yWeights[y] /= totalYWeight + } + + var pr, pg, pb, pa float64 + for ky := iy; ky < jy; ky++ { + if yWeight := yWeights[ky-iy]; yWeight != 0 { + for kx := ix; kx < jx; kx++ { + if w := xWeights[kx-ix] * yWeight; w != 0 { + pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4 + pau := uint32(src.Pix[pi+3]) * 0x101 + pru := uint32(src.Pix[pi+0]) * pau / 0xff + pgu := uint32(src.Pix[pi+1]) * pau / 0xff + pbu := uint32(src.Pix[pi+2]) * pau / 0xff + pr += float64(pru) * w + pg += float64(pgu) * w + pb += float64(pbu) * w + pa += float64(pau) * w + } + } + } } if pr > pa { @@ -4963,112 +6568,114 @@ func (z *kernelScaler) scaleY_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle pb = pa } - pr0 := uint32(ftou(pr * s.invTotalWeight)) - pg0 := uint32(ftou(pg * s.invTotalWeight)) - pb0 := uint32(ftou(pb * s.invTotalWeight)) - pa0 := uint32(ftou(pa * s.invTotalWeight)) + pr0 := uint32(fffftou(pr)) + pg0 := uint32(fffftou(pg)) + pb0 := uint32(fffftou(pb)) + pa0 := uint32(fffftou(pa)) pa1 := (0xffff - uint32(pa0)) * 0x101 dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8) dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8) dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8) dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8) - d += dst.Stride } } } -func (z *kernelScaler) scaleY_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) { - for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { - d := (dr.Min.Y+adr.Min.Y-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+int(dx)-dst.Rect.Min.X)*4 - for _, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] { - var pr, pg, pb, pa float64 - for _, c := range z.vertical.contribs[s.i:s.j] { - p := &tmp[c.coord*z.dw+dx] - pr += p[0] * c.weight - pg += p[1] * c.weight - pb += p[2] * c.weight - pa += p[3] * c.weight - } +func (q *Kernel) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { + // When shrinking, broaden the effective kernel support so that we still + // visit every source pixel. + xHalfWidth, xKernelArgScale := q.Support, 1.0 + if xscale > 1 { + xHalfWidth *= xscale + xKernelArgScale = 1 / xscale + } + yHalfWidth, yKernelArgScale := q.Support, 1.0 + if yscale > 1 { + yHalfWidth *= yscale + yKernelArgScale = 1 / yscale + } - if pr > pa { - pr = pa + xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth))) + yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth))) + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] + sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { + continue } - if pg > pa { - pg = pa + + // TODO: adjust the bias so that we can use int(f) instead + // of math.Floor(f) and math.Ceil(f). + sx += float64(bias.X) + sx -= 0.5 + ix := int(math.Floor(sx - xHalfWidth)) + if ix < sr.Min.X { + ix = sr.Min.X } - if pb > pa { - pb = pa + jx := int(math.Ceil(sx + xHalfWidth)) + if jx > sr.Max.X { + jx = sr.Max.X } - dst.Pix[d+0] = uint8(ftou(pr*s.invTotalWeight) >> 8) - dst.Pix[d+1] = uint8(ftou(pg*s.invTotalWeight) >> 8) - dst.Pix[d+2] = uint8(ftou(pb*s.invTotalWeight) >> 8) - dst.Pix[d+3] = uint8(ftou(pa*s.invTotalWeight) >> 8) - d += dst.Stride - } - } -} - -func (z *kernelScaler) scaleY_Image_Over(dst Image, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) { - dstMask, dmp := opts.DstMask, opts.DstMaskP - dstColorRGBA64 := &color.RGBA64{} - dstColor := color.Color(dstColorRGBA64) - for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { - for dy, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] { - var pr, pg, pb, pa float64 - for _, c := range z.vertical.contribs[s.i:s.j] { - p := &tmp[c.coord*z.dw+dx] - pr += p[0] * c.weight - pg += p[1] * c.weight - pb += p[2] * c.weight - pa += p[3] * c.weight + totalXWeight := 0.0 + for kx := ix; kx < jx; kx++ { + xWeight := 0.0 + if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support { + xWeight = q.At(t) + } + xWeights[kx-ix] = xWeight + totalXWeight += xWeight } - - if pr > pa { - pr = pa + for x := range xWeights[:jx-ix] { + xWeights[x] /= totalXWeight } - if pg > pa { - pg = pa + + sy += float64(bias.Y) + sy -= 0.5 + iy := int(math.Floor(sy - yHalfWidth)) + if iy < sr.Min.Y { + iy = sr.Min.Y } - if pb > pa { - pb = pa + jy := int(math.Ceil(sy + yHalfWidth)) + if jy > sr.Max.Y { + jy = sr.Max.Y } - qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy)).RGBA() - pr0 := uint32(ftou(pr * s.invTotalWeight)) - pg0 := uint32(ftou(pg * s.invTotalWeight)) - pb0 := uint32(ftou(pb * s.invTotalWeight)) - pa0 := uint32(ftou(pa * s.invTotalWeight)) - if dstMask != nil { - _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(adr.Min.Y+dy)).RGBA() - pr0 = pr0 * ma / 0xffff - pg0 = pg0 * ma / 0xffff - pb0 = pb0 * ma / 0xffff - pa0 = pa0 * ma / 0xffff + totalYWeight := 0.0 + for ky := iy; ky < jy; ky++ { + yWeight := 0.0 + if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support { + yWeight = q.At(t) + } + yWeights[ky-iy] = yWeight + totalYWeight += yWeight + } + for y := range yWeights[:jy-iy] { + yWeights[y] /= totalYWeight } - pa1 := 0xffff - pa0 - dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr0) - dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg0) - dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb0) - dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa0) - dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColor) - } - } -} -func (z *kernelScaler) scaleY_Image_Src(dst Image, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) { - dstMask, dmp := opts.DstMask, opts.DstMaskP - dstColorRGBA64 := &color.RGBA64{} - dstColor := color.Color(dstColorRGBA64) - for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { - for dy, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] { var pr, pg, pb, pa float64 - for _, c := range z.vertical.contribs[s.i:s.j] { - p := &tmp[c.coord*z.dw+dx] - pr += p[0] * c.weight - pg += p[1] * c.weight - pb += p[2] * c.weight - pa += p[3] * c.weight + for ky := iy; ky < jy; ky++ { + if yWeight := yWeights[ky-iy]; yWeight != 0 { + for kx := ix; kx < jx; kx++ { + if w := xWeights[kx-ix] * yWeight; w != 0 { + pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4 + pau := uint32(src.Pix[pi+3]) * 0x101 + pru := uint32(src.Pix[pi+0]) * pau / 0xff + pgu := uint32(src.Pix[pi+1]) * pau / 0xff + pbu := uint32(src.Pix[pi+2]) * pau / 0xff + pr += float64(pru) * w + pg += float64(pgu) * w + pb += float64(pbu) * w + pa += float64(pau) * w + } + } + } } if pr > pa { @@ -5081,31 +6688,15 @@ func (z *kernelScaler) scaleY_Image_Src(dst Image, dr, adr image.Rectangle, tmp pb = pa } - if dstMask != nil { - qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy)).RGBA() - _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(adr.Min.Y+dy)).RGBA() - pr := uint32(ftou(pr*s.invTotalWeight)) * ma / 0xffff - pg := uint32(ftou(pg*s.invTotalWeight)) * ma / 0xffff - pb := uint32(ftou(pb*s.invTotalWeight)) * ma / 0xffff - pa := uint32(ftou(pa*s.invTotalWeight)) * ma / 0xffff - pa1 := 0xffff - ma - dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr) - dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg) - dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb) - dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa) - dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColor) - } else { - dstColorRGBA64.R = ftou(pr * s.invTotalWeight) - dstColorRGBA64.G = ftou(pg * s.invTotalWeight) - dstColorRGBA64.B = ftou(pb * s.invTotalWeight) - dstColorRGBA64.A = ftou(pa * s.invTotalWeight) - dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColor) - } + dst.Pix[d+0] = uint8(fffftou(pr) >> 8) + dst.Pix[d+1] = uint8(fffftou(pg) >> 8) + dst.Pix[d+2] = uint8(fffftou(pb) >> 8) + dst.Pix[d+3] = uint8(fffftou(pa) >> 8) } } } -func (q *Kernel) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { +func (q *Kernel) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { // When shrinking, broaden the effective kernel support so that we still // visit every source pixel. xHalfWidth, xKernelArgScale := q.Support, 1.0 @@ -5183,28 +6774,49 @@ func (q *Kernel) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangl yWeights[y] /= totalYWeight } - var pr float64 + var pr, pg, pb, pa float64 for ky := iy; ky < jy; ky++ { if yWeight := yWeights[ky-iy]; yWeight != 0 { for kx := ix; kx < jx; kx++ { if w := xWeights[kx-ix] * yWeight; w != 0 { - pi := (ky-src.Rect.Min.Y)*src.Stride + (kx - src.Rect.Min.X) - pru := uint32(src.Pix[pi]) * 0x101 + pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4 + pru := uint32(src.Pix[pi+0]) * 0x101 + pgu := uint32(src.Pix[pi+1]) * 0x101 + pbu := uint32(src.Pix[pi+2]) * 0x101 + pau := uint32(src.Pix[pi+3]) * 0x101 pr += float64(pru) * w + pg += float64(pgu) * w + pb += float64(pbu) * w + pa += float64(pau) * w } } } } - out := uint8(fffftou(pr) >> 8) - dst.Pix[d+0] = out - dst.Pix[d+1] = out - dst.Pix[d+2] = out - dst.Pix[d+3] = 0xff + + if pr > pa { + pr = pa + } + if pg > pa { + pg = pa + } + if pb > pa { + pb = pa + } + + pr0 := uint32(fffftou(pr)) + pg0 := uint32(fffftou(pg)) + pb0 := uint32(fffftou(pb)) + pa0 := uint32(fffftou(pa)) + pa1 := (0xffff - uint32(pa0)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8) } } } -func (q *Kernel) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { +func (q *Kernel) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { // When shrinking, broaden the effective kernel support so that we still // visit every source pixel. xHalfWidth, xKernelArgScale := q.Support, 1.0 @@ -5288,10 +6900,10 @@ func (q *Kernel) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectan for kx := ix; kx < jx; kx++ { if w := xWeights[kx-ix] * yWeight; w != 0 { pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4 + pru := uint32(src.Pix[pi+0]) * 0x101 + pgu := uint32(src.Pix[pi+1]) * 0x101 + pbu := uint32(src.Pix[pi+2]) * 0x101 pau := uint32(src.Pix[pi+3]) * 0x101 - pru := uint32(src.Pix[pi+0]) * pau / 0xff - pgu := uint32(src.Pix[pi+1]) * pau / 0xff - pbu := uint32(src.Pix[pi+2]) * pau / 0xff pr += float64(pru) * w pg += float64(pgu) * w pb += float64(pbu) * w @@ -5311,20 +6923,15 @@ func (q *Kernel) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectan pb = pa } - pr0 := uint32(fffftou(pr)) - pg0 := uint32(fffftou(pg)) - pb0 := uint32(fffftou(pb)) - pa0 := uint32(fffftou(pa)) - pa1 := (0xffff - uint32(pa0)) * 0x101 - dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8) - dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8) - dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8) - dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8) + dst.Pix[d+0] = uint8(fffftou(pr) >> 8) + dst.Pix[d+1] = uint8(fffftou(pg) >> 8) + dst.Pix[d+2] = uint8(fffftou(pb) >> 8) + dst.Pix[d+3] = uint8(fffftou(pa) >> 8) } } } -func (q *Kernel) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { +func (q *Kernel) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { // When shrinking, broaden the effective kernel support so that we still // visit every source pixel. xHalfWidth, xKernelArgScale := q.Support, 1.0 @@ -5402,44 +7009,53 @@ func (q *Kernel) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectang yWeights[y] /= totalYWeight } - var pr, pg, pb, pa float64 + var pr, pg, pb float64 for ky := iy; ky < jy; ky++ { if yWeight := yWeights[ky-iy]; yWeight != 0 { for kx := ix; kx < jx; kx++ { if w := xWeights[kx-ix] * yWeight; w != 0 { - pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4 - pau := uint32(src.Pix[pi+3]) * 0x101 - pru := uint32(src.Pix[pi+0]) * pau / 0xff - pgu := uint32(src.Pix[pi+1]) * pau / 0xff - pbu := uint32(src.Pix[pi+2]) * pau / 0xff + pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X) + pj := (ky-src.Rect.Min.Y)*src.CStride + (kx - src.Rect.Min.X) + + // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method. + pyy1 := int(src.Y[pi]) * 0x10101 + pcb1 := int(src.Cb[pj]) - 128 + pcr1 := int(src.Cr[pj]) - 128 + pru := (pyy1 + 91881*pcr1) >> 8 + pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8 + pbu := (pyy1 + 116130*pcb1) >> 8 + if pru < 0 { + pru = 0 + } else if pru > 0xffff { + pru = 0xffff + } + if pgu < 0 { + pgu = 0 + } else if pgu > 0xffff { + pgu = 0xffff + } + if pbu < 0 { + pbu = 0 + } else if pbu > 0xffff { + pbu = 0xffff + } + pr += float64(pru) * w pg += float64(pgu) * w pb += float64(pbu) * w - pa += float64(pau) * w } } } } - - if pr > pa { - pr = pa - } - if pg > pa { - pg = pa - } - if pb > pa { - pb = pa - } - dst.Pix[d+0] = uint8(fffftou(pr) >> 8) dst.Pix[d+1] = uint8(fffftou(pg) >> 8) dst.Pix[d+2] = uint8(fffftou(pb) >> 8) - dst.Pix[d+3] = uint8(fffftou(pa) >> 8) + dst.Pix[d+3] = 0xff } } } -func (q *Kernel) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { +func (q *Kernel) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { // When shrinking, broaden the effective kernel support so that we still // visit every source pixel. xHalfWidth, xKernelArgScale := q.Support, 1.0 @@ -5517,49 +7133,53 @@ func (q *Kernel) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectang yWeights[y] /= totalYWeight } - var pr, pg, pb, pa float64 + var pr, pg, pb float64 for ky := iy; ky < jy; ky++ { if yWeight := yWeights[ky-iy]; yWeight != 0 { for kx := ix; kx < jx; kx++ { if w := xWeights[kx-ix] * yWeight; w != 0 { - pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4 - pru := uint32(src.Pix[pi+0]) * 0x101 - pgu := uint32(src.Pix[pi+1]) * 0x101 - pbu := uint32(src.Pix[pi+2]) * 0x101 - pau := uint32(src.Pix[pi+3]) * 0x101 + pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X) + pj := (ky-src.Rect.Min.Y)*src.CStride + ((kx)/2 - src.Rect.Min.X/2) + + // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method. + pyy1 := int(src.Y[pi]) * 0x10101 + pcb1 := int(src.Cb[pj]) - 128 + pcr1 := int(src.Cr[pj]) - 128 + pru := (pyy1 + 91881*pcr1) >> 8 + pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8 + pbu := (pyy1 + 116130*pcb1) >> 8 + if pru < 0 { + pru = 0 + } else if pru > 0xffff { + pru = 0xffff + } + if pgu < 0 { + pgu = 0 + } else if pgu > 0xffff { + pgu = 0xffff + } + if pbu < 0 { + pbu = 0 + } else if pbu > 0xffff { + pbu = 0xffff + } + pr += float64(pru) * w pg += float64(pgu) * w pb += float64(pbu) * w - pa += float64(pau) * w } } } } - - if pr > pa { - pr = pa - } - if pg > pa { - pg = pa - } - if pb > pa { - pb = pa - } - - pr0 := uint32(fffftou(pr)) - pg0 := uint32(fffftou(pg)) - pb0 := uint32(fffftou(pb)) - pa0 := uint32(fffftou(pa)) - pa1 := (0xffff - uint32(pa0)) * 0x101 - dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8) - dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8) - dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8) - dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8) + dst.Pix[d+0] = uint8(fffftou(pr) >> 8) + dst.Pix[d+1] = uint8(fffftou(pg) >> 8) + dst.Pix[d+2] = uint8(fffftou(pb) >> 8) + dst.Pix[d+3] = 0xff } } } -func (q *Kernel) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { +func (q *Kernel) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { // When shrinking, broaden the effective kernel support so that we still // visit every source pixel. xHalfWidth, xKernelArgScale := q.Support, 1.0 @@ -5637,44 +7257,53 @@ func (q *Kernel) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangl yWeights[y] /= totalYWeight } - var pr, pg, pb, pa float64 + var pr, pg, pb float64 for ky := iy; ky < jy; ky++ { if yWeight := yWeights[ky-iy]; yWeight != 0 { for kx := ix; kx < jx; kx++ { if w := xWeights[kx-ix] * yWeight; w != 0 { - pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4 - pru := uint32(src.Pix[pi+0]) * 0x101 - pgu := uint32(src.Pix[pi+1]) * 0x101 - pbu := uint32(src.Pix[pi+2]) * 0x101 - pau := uint32(src.Pix[pi+3]) * 0x101 + pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X) + pj := ((ky)/2-src.Rect.Min.Y/2)*src.CStride + ((kx)/2 - src.Rect.Min.X/2) + + // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method. + pyy1 := int(src.Y[pi]) * 0x10101 + pcb1 := int(src.Cb[pj]) - 128 + pcr1 := int(src.Cr[pj]) - 128 + pru := (pyy1 + 91881*pcr1) >> 8 + pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8 + pbu := (pyy1 + 116130*pcb1) >> 8 + if pru < 0 { + pru = 0 + } else if pru > 0xffff { + pru = 0xffff + } + if pgu < 0 { + pgu = 0 + } else if pgu > 0xffff { + pgu = 0xffff + } + if pbu < 0 { + pbu = 0 + } else if pbu > 0xffff { + pbu = 0xffff + } + pr += float64(pru) * w pg += float64(pgu) * w pb += float64(pbu) * w - pa += float64(pau) * w } } } } - - if pr > pa { - pr = pa - } - if pg > pa { - pg = pa - } - if pb > pa { - pb = pa - } - dst.Pix[d+0] = uint8(fffftou(pr) >> 8) dst.Pix[d+1] = uint8(fffftou(pg) >> 8) dst.Pix[d+2] = uint8(fffftou(pb) >> 8) - dst.Pix[d+3] = uint8(fffftou(pa) >> 8) + dst.Pix[d+3] = 0xff } } } -func (q *Kernel) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { +func (q *Kernel) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { // When shrinking, broaden the effective kernel support so that we still // visit every source pixel. xHalfWidth, xKernelArgScale := q.Support, 1.0 @@ -5758,7 +7387,7 @@ func (q *Kernel) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rect for kx := ix; kx < jx; kx++ { if w := xWeights[kx-ix] * yWeight; w != 0 { pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X) - pj := (ky-src.Rect.Min.Y)*src.CStride + (kx - src.Rect.Min.X) + pj := ((ky)/2-src.Rect.Min.Y/2)*src.CStride + (kx - src.Rect.Min.X) // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method. pyy1 := int(src.Y[pi]) * 0x10101 @@ -5783,22 +7412,138 @@ func (q *Kernel) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rect pbu = 0xffff } - pr += float64(pru) * w - pg += float64(pgu) * w - pb += float64(pbu) * w + pr += float64(pru) * w + pg += float64(pgu) * w + pb += float64(pbu) * w + } + } + } + } + dst.Pix[d+0] = uint8(fffftou(pr) >> 8) + dst.Pix[d+1] = uint8(fffftou(pg) >> 8) + dst.Pix[d+2] = uint8(fffftou(pb) >> 8) + dst.Pix[d+3] = 0xff + } + } +} + +func (q *Kernel) transform_RGBA_RGBA64Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { + // When shrinking, broaden the effective kernel support so that we still + // visit every source pixel. + xHalfWidth, xKernelArgScale := q.Support, 1.0 + if xscale > 1 { + xHalfWidth *= xscale + xKernelArgScale = 1 / xscale + } + yHalfWidth, yKernelArgScale := q.Support, 1.0 + if yscale > 1 { + yHalfWidth *= yscale + yKernelArgScale = 1 / yscale + } + + xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth))) + yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth))) + + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] + sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] + if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) { + continue + } + + // TODO: adjust the bias so that we can use int(f) instead + // of math.Floor(f) and math.Ceil(f). + sx += float64(bias.X) + sx -= 0.5 + ix := int(math.Floor(sx - xHalfWidth)) + if ix < sr.Min.X { + ix = sr.Min.X + } + jx := int(math.Ceil(sx + xHalfWidth)) + if jx > sr.Max.X { + jx = sr.Max.X + } + + totalXWeight := 0.0 + for kx := ix; kx < jx; kx++ { + xWeight := 0.0 + if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support { + xWeight = q.At(t) + } + xWeights[kx-ix] = xWeight + totalXWeight += xWeight + } + for x := range xWeights[:jx-ix] { + xWeights[x] /= totalXWeight + } + + sy += float64(bias.Y) + sy -= 0.5 + iy := int(math.Floor(sy - yHalfWidth)) + if iy < sr.Min.Y { + iy = sr.Min.Y + } + jy := int(math.Ceil(sy + yHalfWidth)) + if jy > sr.Max.Y { + jy = sr.Max.Y + } + + totalYWeight := 0.0 + for ky := iy; ky < jy; ky++ { + yWeight := 0.0 + if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support { + yWeight = q.At(t) + } + yWeights[ky-iy] = yWeight + totalYWeight += yWeight + } + for y := range yWeights[:jy-iy] { + yWeights[y] /= totalYWeight + } + + var pr, pg, pb, pa float64 + for ky := iy; ky < jy; ky++ { + if yWeight := yWeights[ky-iy]; yWeight != 0 { + for kx := ix; kx < jx; kx++ { + if w := xWeights[kx-ix] * yWeight; w != 0 { + pu := src.RGBA64At(kx, ky) + pr += float64(pu.R) * w + pg += float64(pu.G) * w + pb += float64(pu.B) * w + pa += float64(pu.A) * w } } } } - dst.Pix[d+0] = uint8(fffftou(pr) >> 8) - dst.Pix[d+1] = uint8(fffftou(pg) >> 8) - dst.Pix[d+2] = uint8(fffftou(pb) >> 8) - dst.Pix[d+3] = 0xff + + if pr > pa { + pr = pa + } + if pg > pa { + pg = pa + } + if pb > pa { + pb = pa + } + + pr0 := uint32(fffftou(pr)) + pg0 := uint32(fffftou(pg)) + pb0 := uint32(fffftou(pb)) + pa0 := uint32(fffftou(pa)) + pa1 := (0xffff - uint32(pa0)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8) } } } -func (q *Kernel) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { +func (q *Kernel) transform_RGBA_RGBA64Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { // When shrinking, broaden the effective kernel support so that we still // visit every source pixel. xHalfWidth, xKernelArgScale := q.Support, 1.0 @@ -5876,53 +7621,40 @@ func (q *Kernel) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rect yWeights[y] /= totalYWeight } - var pr, pg, pb float64 + var pr, pg, pb, pa float64 for ky := iy; ky < jy; ky++ { if yWeight := yWeights[ky-iy]; yWeight != 0 { for kx := ix; kx < jx; kx++ { if w := xWeights[kx-ix] * yWeight; w != 0 { - pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X) - pj := (ky-src.Rect.Min.Y)*src.CStride + ((kx)/2 - src.Rect.Min.X/2) - - // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method. - pyy1 := int(src.Y[pi]) * 0x10101 - pcb1 := int(src.Cb[pj]) - 128 - pcr1 := int(src.Cr[pj]) - 128 - pru := (pyy1 + 91881*pcr1) >> 8 - pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8 - pbu := (pyy1 + 116130*pcb1) >> 8 - if pru < 0 { - pru = 0 - } else if pru > 0xffff { - pru = 0xffff - } - if pgu < 0 { - pgu = 0 - } else if pgu > 0xffff { - pgu = 0xffff - } - if pbu < 0 { - pbu = 0 - } else if pbu > 0xffff { - pbu = 0xffff - } - - pr += float64(pru) * w - pg += float64(pgu) * w - pb += float64(pbu) * w + pu := src.RGBA64At(kx, ky) + pr += float64(pu.R) * w + pg += float64(pu.G) * w + pb += float64(pu.B) * w + pa += float64(pu.A) * w } } } } + + if pr > pa { + pr = pa + } + if pg > pa { + pg = pa + } + if pb > pa { + pb = pa + } + dst.Pix[d+0] = uint8(fffftou(pr) >> 8) dst.Pix[d+1] = uint8(fffftou(pg) >> 8) dst.Pix[d+2] = uint8(fffftou(pb) >> 8) - dst.Pix[d+3] = 0xff + dst.Pix[d+3] = uint8(fffftou(pa) >> 8) } } } -func (q *Kernel) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { +func (q *Kernel) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { // When shrinking, broaden the effective kernel support so that we still // visit every source pixel. xHalfWidth, xKernelArgScale := q.Support, 1.0 @@ -6000,53 +7732,45 @@ func (q *Kernel) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rect yWeights[y] /= totalYWeight } - var pr, pg, pb float64 + var pr, pg, pb, pa float64 for ky := iy; ky < jy; ky++ { if yWeight := yWeights[ky-iy]; yWeight != 0 { for kx := ix; kx < jx; kx++ { if w := xWeights[kx-ix] * yWeight; w != 0 { - pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X) - pj := ((ky)/2-src.Rect.Min.Y/2)*src.CStride + ((kx)/2 - src.Rect.Min.X/2) - - // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method. - pyy1 := int(src.Y[pi]) * 0x10101 - pcb1 := int(src.Cb[pj]) - 128 - pcr1 := int(src.Cr[pj]) - 128 - pru := (pyy1 + 91881*pcr1) >> 8 - pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8 - pbu := (pyy1 + 116130*pcb1) >> 8 - if pru < 0 { - pru = 0 - } else if pru > 0xffff { - pru = 0xffff - } - if pgu < 0 { - pgu = 0 - } else if pgu > 0xffff { - pgu = 0xffff - } - if pbu < 0 { - pbu = 0 - } else if pbu > 0xffff { - pbu = 0xffff - } - + pru, pgu, pbu, pau := src.At(kx, ky).RGBA() pr += float64(pru) * w pg += float64(pgu) * w pb += float64(pbu) * w + pa += float64(pau) * w } } } } - dst.Pix[d+0] = uint8(fffftou(pr) >> 8) - dst.Pix[d+1] = uint8(fffftou(pg) >> 8) - dst.Pix[d+2] = uint8(fffftou(pb) >> 8) - dst.Pix[d+3] = 0xff + + if pr > pa { + pr = pa + } + if pg > pa { + pg = pa + } + if pb > pa { + pb = pa + } + + pr0 := uint32(fffftou(pr)) + pg0 := uint32(fffftou(pg)) + pb0 := uint32(fffftou(pb)) + pa0 := uint32(fffftou(pa)) + pa1 := (0xffff - uint32(pa0)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8) } } } -func (q *Kernel) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { +func (q *Kernel) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { // When shrinking, broaden the effective kernel support so that we still // visit every source pixel. xHalfWidth, xKernelArgScale := q.Support, 1.0 @@ -6124,53 +7848,40 @@ func (q *Kernel) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rect yWeights[y] /= totalYWeight } - var pr, pg, pb float64 + var pr, pg, pb, pa float64 for ky := iy; ky < jy; ky++ { if yWeight := yWeights[ky-iy]; yWeight != 0 { for kx := ix; kx < jx; kx++ { if w := xWeights[kx-ix] * yWeight; w != 0 { - pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X) - pj := ((ky)/2-src.Rect.Min.Y/2)*src.CStride + (kx - src.Rect.Min.X) - - // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method. - pyy1 := int(src.Y[pi]) * 0x10101 - pcb1 := int(src.Cb[pj]) - 128 - pcr1 := int(src.Cr[pj]) - 128 - pru := (pyy1 + 91881*pcr1) >> 8 - pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8 - pbu := (pyy1 + 116130*pcb1) >> 8 - if pru < 0 { - pru = 0 - } else if pru > 0xffff { - pru = 0xffff - } - if pgu < 0 { - pgu = 0 - } else if pgu > 0xffff { - pgu = 0xffff - } - if pbu < 0 { - pbu = 0 - } else if pbu > 0xffff { - pbu = 0xffff - } - + pru, pgu, pbu, pau := src.At(kx, ky).RGBA() pr += float64(pru) * w pg += float64(pgu) * w pb += float64(pbu) * w + pa += float64(pau) * w } } } } + + if pr > pa { + pr = pa + } + if pg > pa { + pg = pa + } + if pb > pa { + pb = pa + } + dst.Pix[d+0] = uint8(fffftou(pr) >> 8) dst.Pix[d+1] = uint8(fffftou(pg) >> 8) dst.Pix[d+2] = uint8(fffftou(pb) >> 8) - dst.Pix[d+3] = 0xff + dst.Pix[d+3] = uint8(fffftou(pa) >> 8) } } } -func (q *Kernel) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { +func (q *Kernel) transform_RGBA64Image_RGBA64Image_Over(dst RGBA64Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { // When shrinking, broaden the effective kernel support so that we still // visit every source pixel. xHalfWidth, xKernelArgScale := q.Support, 1.0 @@ -6187,10 +7898,13 @@ func (q *Kernel) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectan xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth))) yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth))) + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { dyf := float64(dr.Min.Y+int(dy)) + 0.5 - d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 - for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { dxf := float64(dr.Min.X+int(dx)) + 0.5 sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] @@ -6253,11 +7967,18 @@ func (q *Kernel) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectan if yWeight := yWeights[ky-iy]; yWeight != 0 { for kx := ix; kx < jx; kx++ { if w := xWeights[kx-ix] * yWeight; w != 0 { - pru, pgu, pbu, pau := src.At(kx, ky).RGBA() - pr += float64(pru) * w - pg += float64(pgu) * w - pb += float64(pbu) * w - pa += float64(pau) * w + pu := src.RGBA64At(kx, ky) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+kx, smp.Y+ky).RGBA() + pu.R = uint16(uint32(pu.R) * ma / 0xffff) + pu.G = uint16(uint32(pu.G) * ma / 0xffff) + pu.B = uint16(uint32(pu.B) * ma / 0xffff) + pu.A = uint16(uint32(pu.A) * ma / 0xffff) + } + pr += float64(pu.R) * w + pg += float64(pu.G) * w + pb += float64(pu.B) * w + pa += float64(pu.A) * w } } } @@ -6273,20 +7994,29 @@ func (q *Kernel) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectan pb = pa } + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy)) pr0 := uint32(fffftou(pr)) pg0 := uint32(fffftou(pg)) pb0 := uint32(fffftou(pb)) pa0 := uint32(fffftou(pa)) - pa1 := (0xffff - uint32(pa0)) * 0x101 - dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8) - dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8) - dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8) - dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8) + if dstMask != nil { + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() + pr0 = pr0 * ma / 0xffff + pg0 = pg0 * ma / 0xffff + pb0 = pb0 * ma / 0xffff + pa0 = pa0 * ma / 0xffff + } + pa1 := 0xffff - pa0 + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + pr0) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + pg0) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + pb0) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + pa0) + dst.SetRGBA64(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) } } } -func (q *Kernel) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { +func (q *Kernel) transform_RGBA64Image_RGBA64Image_Src(dst RGBA64Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.RGBA64Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) { // When shrinking, broaden the effective kernel support so that we still // visit every source pixel. xHalfWidth, xKernelArgScale := q.Support, 1.0 @@ -6303,10 +8033,13 @@ func (q *Kernel) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectang xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth))) yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth))) + srcMask, smp := opts.SrcMask, opts.SrcMaskP + dstMask, dmp := opts.DstMask, opts.DstMaskP + dstColorRGBA64 := color.RGBA64{} + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { dyf := float64(dr.Min.Y+int(dy)) + 0.5 - d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4 - for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { dxf := float64(dr.Min.X+int(dx)) + 0.5 sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2] sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5] @@ -6369,11 +8102,18 @@ func (q *Kernel) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectang if yWeight := yWeights[ky-iy]; yWeight != 0 { for kx := ix; kx < jx; kx++ { if w := xWeights[kx-ix] * yWeight; w != 0 { - pru, pgu, pbu, pau := src.At(kx, ky).RGBA() - pr += float64(pru) * w - pg += float64(pgu) * w - pb += float64(pbu) * w - pa += float64(pau) * w + pu := src.RGBA64At(kx, ky) + if srcMask != nil { + _, _, _, ma := srcMask.At(smp.X+kx, smp.Y+ky).RGBA() + pu.R = uint16(uint32(pu.R) * ma / 0xffff) + pu.G = uint16(uint32(pu.G) * ma / 0xffff) + pu.B = uint16(uint32(pu.B) * ma / 0xffff) + pu.A = uint16(uint32(pu.A) * ma / 0xffff) + } + pr += float64(pu.R) * w + pg += float64(pu.G) * w + pb += float64(pu.B) * w + pa += float64(pu.A) * w } } } @@ -6389,10 +8129,26 @@ func (q *Kernel) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectang pb = pa } - dst.Pix[d+0] = uint8(fffftou(pr) >> 8) - dst.Pix[d+1] = uint8(fffftou(pg) >> 8) - dst.Pix[d+2] = uint8(fffftou(pb) >> 8) - dst.Pix[d+3] = uint8(fffftou(pa) >> 8) + if dstMask != nil { + q := dst.RGBA64At(dr.Min.X+int(dx), dr.Min.Y+int(dy)) + _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA() + pr := uint32(fffftou(pr)) * ma / 0xffff + pg := uint32(fffftou(pg)) * ma / 0xffff + pb := uint32(fffftou(pb)) * ma / 0xffff + pa := uint32(fffftou(pa)) * ma / 0xffff + pa1 := 0xffff - ma + dstColorRGBA64.R = uint16(uint32(q.R)*pa1/0xffff + pr) + dstColorRGBA64.G = uint16(uint32(q.G)*pa1/0xffff + pg) + dstColorRGBA64.B = uint16(uint32(q.B)*pa1/0xffff + pb) + dstColorRGBA64.A = uint16(uint32(q.A)*pa1/0xffff + pa) + dst.SetRGBA64(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } else { + dstColorRGBA64.R = fffftou(pr) + dstColorRGBA64.G = fffftou(pg) + dstColorRGBA64.B = fffftou(pb) + dstColorRGBA64.A = fffftou(pa) + dst.SetRGBA64(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColorRGBA64) + } } } } diff --git a/vendor/golang.org/x/image/font/basicfont/basicfont.go b/vendor/golang.org/x/image/font/basicfont/basicfont.go index 15503818..173c0610 100644 --- a/vendor/golang.org/x/image/font/basicfont/basicfont.go +++ b/vendor/golang.org/x/image/font/basicfont/basicfont.go @@ -89,41 +89,50 @@ func (f *Face) Metrics() font.Metrics { func (f *Face) Glyph(dot fixed.Point26_6, r rune) ( dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) { -loop: - for _, rr := range [2]rune{r, '\ufffd'} { - for _, rng := range f.Ranges { - if rr < rng.Low || rng.High <= rr { - continue - } - maskp.Y = (int(rr-rng.Low) + rng.Offset) * (f.Ascent + f.Descent) - ok = true - break loop + if found, rng := f.find(r); rng != nil { + maskp.Y = (int(found-rng.Low) + rng.Offset) * (f.Ascent + f.Descent) + x := int(dot.X+32)>>6 + f.Left + y := int(dot.Y+32) >> 6 + dr = image.Rectangle{ + Min: image.Point{ + X: x, + Y: y - f.Ascent, + }, + Max: image.Point{ + X: x + f.Width, + Y: y + f.Descent, + }, } - } - if !ok { - return image.Rectangle{}, nil, image.Point{}, 0, false - } - x := int(dot.X+32)>>6 + f.Left - y := int(dot.Y+32) >> 6 - dr = image.Rectangle{ - Min: image.Point{ - X: x, - Y: y - f.Ascent, - }, - Max: image.Point{ - X: x + f.Width, - Y: y + f.Descent, - }, + return dr, f.Mask, maskp, fixed.I(f.Advance), r == found } - - return dr, f.Mask, maskp, fixed.I(f.Advance), true + return image.Rectangle{}, nil, image.Point{}, 0, false } func (f *Face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) { - return fixed.R(0, -f.Ascent, f.Width, +f.Descent), fixed.I(f.Advance), true + if found, rng := f.find(r); rng != nil { + return fixed.R(0, -f.Ascent, f.Width, +f.Descent), fixed.I(f.Advance), r == found + } + return fixed.Rectangle26_6{}, 0, false } func (f *Face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) { - return fixed.I(f.Advance), true + if found, rng := f.find(r); rng != nil { + return fixed.I(f.Advance), r == found + } + return 0, false +} + +func (f *Face) find(r rune) (rune, *Range) { + for { + for i, rng := range f.Ranges { + if (rng.Low <= r) && (r < rng.High) { + return r, &f.Ranges[i] + } + } + if r == '\ufffd' { + return 0, nil + } + r = '\ufffd' + } } diff --git a/vendor/golang.org/x/image/font/font.go b/vendor/golang.org/x/image/font/font.go index d1a75350..6b9b9bc8 100644 --- a/vendor/golang.org/x/image/font/font.go +++ b/vendor/golang.org/x/image/font/font.go @@ -38,7 +38,10 @@ type Face interface { // glyph at the sub-pixel destination location dot, and that glyph's // advance width. // - // It returns !ok if the face does not contain a glyph for r. + // It returns !ok if the face does not contain a glyph for r. This includes + // returning !ok for a fallback glyph (such as substituting a U+FFFD glyph + // or OpenType's .notdef glyph), in which case the other return values may + // still be non-zero. // // The contents of the mask image returned by one Glyph call may change // after the next Glyph call. Callers that want to cache the mask must make @@ -49,7 +52,10 @@ type Face interface { // GlyphBounds returns the bounding box of r's glyph, drawn at a dot equal // to the origin, and that glyph's advance width. // - // It returns !ok if the face does not contain a glyph for r. + // It returns !ok if the face does not contain a glyph for r. This includes + // returning !ok for a fallback glyph (such as substituting a U+FFFD glyph + // or OpenType's .notdef glyph), in which case the other return values may + // still be non-zero. // // The glyph's ascent and descent are equal to -bounds.Min.Y and // +bounds.Max.Y. The glyph's left-side and right-side bearings are equal @@ -60,7 +66,10 @@ type Face interface { // GlyphAdvance returns the advance width of r's glyph. // - // It returns !ok if the face does not contain a glyph for r. + // It returns !ok if the face does not contain a glyph for r. This includes + // returning !ok for a fallback glyph (such as substituting a U+FFFD glyph + // or OpenType's .notdef glyph), in which case the other return values may + // still be non-zero. GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) // Kern returns the horizontal adjustment for the kerning pair (r0, r1). A @@ -150,14 +159,10 @@ func (d *Drawer) DrawBytes(s []byte) { if prevC >= 0 { d.Dot.X += d.Face.Kern(prevC, c) } - dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c) - if !ok { - // TODO: is falling back on the U+FFFD glyph the responsibility of - // the Drawer or the Face? - // TODO: set prevC = '\ufffd'? - continue + dr, mask, maskp, advance, _ := d.Face.Glyph(d.Dot, c) + if !dr.Empty() { + draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over) } - draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over) d.Dot.X += advance prevC = c } @@ -170,14 +175,10 @@ func (d *Drawer) DrawString(s string) { if prevC >= 0 { d.Dot.X += d.Face.Kern(prevC, c) } - dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c) - if !ok { - // TODO: is falling back on the U+FFFD glyph the responsibility of - // the Drawer or the Face? - // TODO: set prevC = '\ufffd'? - continue + dr, mask, maskp, advance, _ := d.Face.Glyph(d.Dot, c) + if !dr.Empty() { + draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over) } - draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over) d.Dot.X += advance prevC = c } @@ -227,16 +228,12 @@ func BoundBytes(f Face, s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int if prevC >= 0 { advance += f.Kern(prevC, c) } - b, a, ok := f.GlyphBounds(c) - if !ok { - // TODO: is falling back on the U+FFFD glyph the responsibility of - // the Drawer or the Face? - // TODO: set prevC = '\ufffd'? - continue + b, a, _ := f.GlyphBounds(c) + if !b.Empty() { + b.Min.X += advance + b.Max.X += advance + bounds = bounds.Union(b) } - b.Min.X += advance - b.Max.X += advance - bounds = bounds.Union(b) advance += a prevC = c } @@ -251,16 +248,12 @@ func BoundString(f Face, s string) (bounds fixed.Rectangle26_6, advance fixed.In if prevC >= 0 { advance += f.Kern(prevC, c) } - b, a, ok := f.GlyphBounds(c) - if !ok { - // TODO: is falling back on the U+FFFD glyph the responsibility of - // the Drawer or the Face? - // TODO: set prevC = '\ufffd'? - continue + b, a, _ := f.GlyphBounds(c) + if !b.Empty() { + b.Min.X += advance + b.Max.X += advance + bounds = bounds.Union(b) } - b.Min.X += advance - b.Max.X += advance - bounds = bounds.Union(b) advance += a prevC = c } @@ -278,13 +271,7 @@ func MeasureBytes(f Face, s []byte) (advance fixed.Int26_6) { if prevC >= 0 { advance += f.Kern(prevC, c) } - a, ok := f.GlyphAdvance(c) - if !ok { - // TODO: is falling back on the U+FFFD glyph the responsibility of - // the Drawer or the Face? - // TODO: set prevC = '\ufffd'? - continue - } + a, _ := f.GlyphAdvance(c) advance += a prevC = c } @@ -298,13 +285,7 @@ func MeasureString(f Face, s string) (advance fixed.Int26_6) { if prevC >= 0 { advance += f.Kern(prevC, c) } - a, ok := f.GlyphAdvance(c) - if !ok { - // TODO: is falling back on the U+FFFD glyph the responsibility of - // the Drawer or the Face? - // TODO: set prevC = '\ufffd'? - continue - } + a, _ := f.GlyphAdvance(c) advance += a prevC = c } diff --git a/vendor/golang.org/x/image/font/opentype/opentype.go b/vendor/golang.org/x/image/font/opentype/opentype.go index 231fdbea..694ac47b 100644 --- a/vendor/golang.org/x/image/font/opentype/opentype.go +++ b/vendor/golang.org/x/image/font/opentype/opentype.go @@ -133,8 +133,8 @@ func (f *Face) Metrics() font.Metrics { // Kern satisfies the font.Face interface. func (f *Face) Kern(r0, r1 rune) fixed.Int26_6 { - x0 := f.index(r0) - x1 := f.index(r1) + x0, _ := f.f.GlyphIndex(&f.buf, r0) + x1, _ := f.f.GlyphIndex(&f.buf, r1) k, err := f.f.Kern(&f.buf, x0, x1, fixed.Int26_6(f.f.UnitsPerEm()), f.hinting) if err != nil { return 0 @@ -251,22 +251,19 @@ func (f *Face) Glyph(dot fixed.Point26_6, r rune) (dr image.Rectangle, mask imag } f.rast.Draw(&f.mask, f.mask.Bounds(), image.Opaque, image.Point{}) - return dr, &f.mask, f.mask.Rect.Min, advance, true + return dr, &f.mask, f.mask.Rect.Min, advance, x != 0 } // GlyphBounds satisfies the font.Face interface. func (f *Face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) { - bounds, advance, err := f.f.GlyphBounds(&f.buf, f.index(r), f.scale, f.hinting) - return bounds, advance, err == nil + x, _ := f.f.GlyphIndex(&f.buf, r) + bounds, advance, err := f.f.GlyphBounds(&f.buf, x, f.scale, f.hinting) + return bounds, advance, (err == nil) && (x != 0) } // GlyphAdvance satisfies the font.Face interface. func (f *Face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) { - advance, err := f.f.GlyphAdvance(&f.buf, f.index(r), f.scale, f.hinting) - return advance, err == nil -} - -func (f *Face) index(r rune) sfnt.GlyphIndex { x, _ := f.f.GlyphIndex(&f.buf, r) - return x + advance, err := f.f.GlyphAdvance(&f.buf, x, f.scale, f.hinting) + return advance, (err == nil) && (x != 0) } diff --git a/vendor/golang.org/x/image/font/sfnt/sfnt.go b/vendor/golang.org/x/image/font/sfnt/sfnt.go index 8d0dba77..8ed19e21 100644 --- a/vendor/golang.org/x/image/font/sfnt/sfnt.go +++ b/vendor/golang.org/x/image/font/sfnt/sfnt.go @@ -745,7 +745,7 @@ func (f *Font) initialize(offset int, isDfont bool) error { f.cached.xHeight = xHeight if !hasXHeightCapHeight { - xh, ch, err := f.initOS2Version1() + xh, ch, err := f.initOS2VersionBelow2() if err != nil { return err } @@ -1201,7 +1201,7 @@ func (f *Font) glyphTopOS2(b *Buffer, ppem fixed.Int26_6, r rune) (int32, error) return int32(min), nil } -func (f *Font) initOS2Version1() (xHeight, capHeight int32, err error) { +func (f *Font) initOS2VersionBelow2() (xHeight, capHeight int32, err error) { ppem := fixed.Int26_6(f.UnitsPerEm()) var b Buffer @@ -1235,12 +1235,14 @@ func (f *Font) parseOS2(buf []byte) (buf1 []byte, hasXHeightCapHeight bool, xHei if err != nil { return nil, false, 0, 0, err } - if vers <= 1 { - const headerSize = 86 + if vers < 2 { + // "The original TrueType specification had this table at 68 bytes long." + // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6OS2.html + const headerSize = 68 if f.os2.length < headerSize { return nil, false, 0, 0, errInvalidOS2Table } - // Will resolve xHeight and capHeight later, see initOS2Version1. + // Will resolve xHeight and capHeight later, see initOS2VersionBelow2. return buf, false, 0, 0, nil } const headerSize = 96 diff --git a/vendor/golang.org/x/image/tiff/fuzz.go b/vendor/golang.org/x/image/tiff/fuzz.go index b27c5400..b388b6f4 100644 --- a/vendor/golang.org/x/image/tiff/fuzz.go +++ b/vendor/golang.org/x/image/tiff/fuzz.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build gofuzz -// +build gofuzz package tiff diff --git a/vendor/golang.org/x/image/tiff/reader.go b/vendor/golang.org/x/image/tiff/reader.go index 45cc056f..1b8fcb85 100644 --- a/vendor/golang.org/x/image/tiff/reader.go +++ b/vendor/golang.org/x/image/tiff/reader.go @@ -8,13 +8,13 @@ package tiff // import "golang.org/x/image/tiff" import ( + "bytes" "compress/zlib" "encoding/binary" "fmt" "image" "image/color" "io" - "io/ioutil" "math" "golang.org/x/image/ccitt" @@ -36,11 +36,14 @@ func (e UnsupportedError) Error() string { return "tiff: unsupported feature: " + string(e) } -var errNoPixels = FormatError("not enough pixel data") +var ( + errNoPixels = FormatError("not enough pixel data") + errInvalidColorIndex = FormatError("invalid color index") +) const maxChunkSize = 10 << 20 // 10M -// safeReadtAt is a verbatim copy of internal/saferio.ReadDataAt from the +// safeReadAt is a verbatim copy of internal/saferio.ReadDataAt from the // standard library, which is used to read data from a reader using a length // provided by untrusted data, without allocating the entire slice ahead of time // if it is large (>maxChunkSize). This allows us to avoid allocating giant @@ -337,13 +340,18 @@ func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error { } case mPaletted: img := dst.(*image.Paletted) + pLen := len(d.palette) for y := ymin; y < rMaxY; y++ { for x := xmin; x < rMaxX; x++ { v, ok := d.readBits(d.bpp) if !ok { return errNoPixels } - img.SetColorIndex(x, y, uint8(v)) + idx := uint8(v) + if int(idx) >= pLen { + return errInvalidColorIndex + } + img.SetColorIndex(x, y, idx) } d.flushBits() } @@ -579,6 +587,11 @@ func newDecoder(r io.Reader) (*decoder, error) { default: return nil, UnsupportedError("color model") } + if d.firstVal(tPhotometricInterpretation) != pRGB { + if len(d.features[tBitsPerSample]) != 1 { + return nil, UnsupportedError("extra samples") + } + } return d, nil } @@ -629,6 +642,13 @@ func Decode(r io.Reader) (img image.Image, err error) { blockWidth = int(d.firstVal(tTileWidth)) blockHeight = int(d.firstVal(tTileLength)) + // The specification says that tile widths and lengths must be a multiple of 16. + // We currently permit invalid sizes, but reject anything too small to limit the + // amount of work a malicious input can force us to perform. + if blockWidth < 8 || blockHeight < 8 { + return nil, FormatError("tile size is too small") + } + if blockWidth != 0 { blocksAcross = (d.config.Width + blockWidth - 1) / blockWidth } @@ -681,6 +701,11 @@ func Decode(r io.Reader) (img image.Image, err error) { } } + if blocksAcross == 0 || blocksDown == 0 { + return + } + // Maximum data per pixel is 8 bytes (RGBA64). + blockMaxDataSize := int64(blockWidth) * int64(blockHeight) * 8 for i := 0; i < blocksAcross; i++ { blkW := blockWidth if !blockPadding && i == blocksAcross-1 && d.config.Width%blockWidth != 0 { @@ -708,15 +733,15 @@ func Decode(r io.Reader) (img image.Image, err error) { inv := d.firstVal(tPhotometricInterpretation) == pWhiteIsZero order := ccittFillOrder(d.firstVal(tFillOrder)) r := ccitt.NewReader(io.NewSectionReader(d.r, offset, n), order, ccitt.Group3, blkW, blkH, &ccitt.Options{Invert: inv, Align: false}) - d.buf, err = ioutil.ReadAll(r) + d.buf, err = readBuf(r, d.buf, blockMaxDataSize) case cG4: inv := d.firstVal(tPhotometricInterpretation) == pWhiteIsZero order := ccittFillOrder(d.firstVal(tFillOrder)) r := ccitt.NewReader(io.NewSectionReader(d.r, offset, n), order, ccitt.Group4, blkW, blkH, &ccitt.Options{Invert: inv, Align: false}) - d.buf, err = ioutil.ReadAll(r) + d.buf, err = readBuf(r, d.buf, blockMaxDataSize) case cLZW: r := lzw.NewReader(io.NewSectionReader(d.r, offset, n), lzw.MSB, 8) - d.buf, err = ioutil.ReadAll(r) + d.buf, err = readBuf(r, d.buf, blockMaxDataSize) r.Close() case cDeflate, cDeflateOld: var r io.ReadCloser @@ -724,7 +749,7 @@ func Decode(r io.Reader) (img image.Image, err error) { if err != nil { return nil, err } - d.buf, err = ioutil.ReadAll(r) + d.buf, err = readBuf(r, d.buf, blockMaxDataSize) r.Close() case cPackBits: d.buf, err = unpackBits(io.NewSectionReader(d.r, offset, n)) @@ -748,6 +773,12 @@ func Decode(r io.Reader) (img image.Image, err error) { return } +func readBuf(r io.Reader, buf []byte, lim int64) ([]byte, error) { + b := bytes.NewBuffer(buf[:0]) + _, err := b.ReadFrom(io.LimitReader(r, lim)) + return b.Bytes(), err +} + func init() { image.RegisterFormat("tiff", leHeader, Decode, DecodeConfig) image.RegisterFormat("tiff", beHeader, Decode, DecodeConfig) diff --git a/vendor/golang.org/x/image/vector/acc_amd64.go b/vendor/golang.org/x/image/vector/acc_amd64.go index a6fa0ca2..5b148c58 100644 --- a/vendor/golang.org/x/image/vector/acc_amd64.go +++ b/vendor/golang.org/x/image/vector/acc_amd64.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build !appengine && gc && !noasm -// +build !appengine,gc,!noasm package vector diff --git a/vendor/golang.org/x/image/vector/acc_other.go b/vendor/golang.org/x/image/vector/acc_other.go index 39022691..e383d52c 100644 --- a/vendor/golang.org/x/image/vector/acc_other.go +++ b/vendor/golang.org/x/image/vector/acc_other.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build !amd64 || appengine || !gc || noasm -// +build !amd64 appengine !gc noasm package vector diff --git a/vendor/modules.txt b/vendor/modules.txt index a1d52278..8edf1647 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -54,8 +54,6 @@ github.com/inconshreveable/mousetrap github.com/jpillora/go-ogle-analytics # github.com/kr/pretty v0.3.1 ## explicit; go 1.12 -# github.com/kr/text v0.2.0 -## explicit # github.com/mattn/go-colorable v0.1.13 ## explicit; go 1.15 github.com/mattn/go-colorable @@ -74,14 +72,10 @@ github.com/pierrre/archivefile/zip # github.com/pkg/errors v0.9.1 ## explicit github.com/pkg/errors -# github.com/pmezard/go-difflib v1.0.0 -## explicit # github.com/rogpeppe/go-charset v0.0.0-20190617161244-0dc95cdf6f31 ## explicit github.com/rogpeppe/go-charset/charset github.com/rogpeppe/go-charset/data -# github.com/rogpeppe/go-internal v1.9.0 -## explicit; go 1.17 # github.com/ryanskidmore/parallel v0.0.1 ## explicit; go 1.13 github.com/ryanskidmore/parallel @@ -97,8 +91,6 @@ github.com/spf13/cobra # github.com/spf13/pflag v1.0.5 ## explicit; go 1.12 github.com/spf13/pflag -# github.com/stretchr/objx v0.5.0 -## explicit; go 1.12 # github.com/stretchr/testify v1.8.2 ## explicit; go 1.13 # github.com/vmihailenco/msgpack/v5 v5.3.5 @@ -112,8 +104,8 @@ github.com/vmihailenco/tagparser/v2/internal github.com/vmihailenco/tagparser/v2/internal/parser # golang.org/x/exp v0.0.0-20230321023759-10a507213a29 ## explicit; go 1.18 -# golang.org/x/image v0.6.0 -## explicit; go 1.12 +# golang.org/x/image v0.18.0 +## explicit; go 1.18 golang.org/x/image/ccitt golang.org/x/image/draw golang.org/x/image/font @@ -137,8 +129,8 @@ golang.org/x/net/publicsuffix golang.org/x/sys/internal/unsafeheader golang.org/x/sys/unix golang.org/x/sys/windows -# golang.org/x/text v0.8.0 -## explicit; go 1.17 +# golang.org/x/text v0.16.0 +## explicit; go 1.18 golang.org/x/text/encoding golang.org/x/text/encoding/charmap golang.org/x/text/encoding/internal @@ -165,5 +157,3 @@ gonum.org/v1/plot/vg/vgtex # gopkg.in/yaml.v2 v2.4.0 ## explicit; go 1.15 gopkg.in/yaml.v2 -# gopkg.in/yaml.v3 v3.0.1 -## explicit