mirror of
https://github.com/unidoc/unipdf.git
synced 2025-05-05 19:30:30 +08:00
127 lines
2.6 KiB
Go
127 lines
2.6 KiB
Go
![]() |
/*
|
||
|
* This file is subject to the terms and conditions defined in
|
||
|
* file 'LICENSE.md', which is part of this source code package.
|
||
|
*/
|
||
|
|
||
|
package imagerender
|
||
|
|
||
|
import (
|
||
|
"image"
|
||
|
"image/color"
|
||
|
|
||
|
"github.com/golang/freetype/raster"
|
||
|
|
||
|
"github.com/unidoc/unipdf/v3/render/internal/context"
|
||
|
)
|
||
|
|
||
|
type repeatOp int
|
||
|
|
||
|
const (
|
||
|
repeatBoth repeatOp = iota
|
||
|
repeatX
|
||
|
repeatY
|
||
|
repeatNone
|
||
|
)
|
||
|
|
||
|
// Solid Pattern
|
||
|
type solidPattern struct {
|
||
|
color color.Color
|
||
|
}
|
||
|
|
||
|
func (p *solidPattern) ColorAt(x, y int) color.Color {
|
||
|
return p.color
|
||
|
}
|
||
|
|
||
|
func newSolidPattern(color color.Color) context.Pattern {
|
||
|
return &solidPattern{color: color}
|
||
|
}
|
||
|
|
||
|
// Surface Pattern
|
||
|
type surfacePattern struct {
|
||
|
im image.Image
|
||
|
op repeatOp
|
||
|
}
|
||
|
|
||
|
func (p *surfacePattern) ColorAt(x, y int) color.Color {
|
||
|
b := p.im.Bounds()
|
||
|
switch p.op {
|
||
|
case repeatX:
|
||
|
if y >= b.Dy() {
|
||
|
return color.Transparent
|
||
|
}
|
||
|
case repeatY:
|
||
|
if x >= b.Dx() {
|
||
|
return color.Transparent
|
||
|
}
|
||
|
case repeatNone:
|
||
|
if x >= b.Dx() || y >= b.Dy() {
|
||
|
return color.Transparent
|
||
|
}
|
||
|
}
|
||
|
x = x%b.Dx() + b.Min.X
|
||
|
y = y%b.Dy() + b.Min.Y
|
||
|
return p.im.At(x, y)
|
||
|
}
|
||
|
|
||
|
func newSurfacePattern(im image.Image, op repeatOp) context.Pattern {
|
||
|
return &surfacePattern{im: im, op: op}
|
||
|
}
|
||
|
|
||
|
type patternPainter struct {
|
||
|
im *image.RGBA
|
||
|
mask *image.Alpha
|
||
|
p context.Pattern
|
||
|
}
|
||
|
|
||
|
// Paint satisfies the Painter interface.
|
||
|
func (r *patternPainter) Paint(ss []raster.Span, done bool) {
|
||
|
b := r.im.Bounds()
|
||
|
for _, s := range ss {
|
||
|
if s.Y < b.Min.Y {
|
||
|
continue
|
||
|
}
|
||
|
if s.Y >= b.Max.Y {
|
||
|
return
|
||
|
}
|
||
|
if s.X0 < b.Min.X {
|
||
|
s.X0 = b.Min.X
|
||
|
}
|
||
|
if s.X1 > b.Max.X {
|
||
|
s.X1 = b.Max.X
|
||
|
}
|
||
|
if s.X0 >= s.X1 {
|
||
|
continue
|
||
|
}
|
||
|
const m = 1<<16 - 1
|
||
|
y := s.Y - r.im.Rect.Min.Y
|
||
|
x0 := s.X0 - r.im.Rect.Min.X
|
||
|
// RGBAPainter.Paint() in $GOPATH/src/github.com/golang/freetype/raster/paint.go
|
||
|
i0 := (s.Y-r.im.Rect.Min.Y)*r.im.Stride + (s.X0-r.im.Rect.Min.X)*4
|
||
|
i1 := i0 + (s.X1-s.X0)*4
|
||
|
for i, x := i0, x0; i < i1; i, x = i+4, x+1 {
|
||
|
ma := s.Alpha
|
||
|
if r.mask != nil {
|
||
|
ma = ma * uint32(r.mask.AlphaAt(x, y).A) / 255
|
||
|
if ma == 0 {
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
c := r.p.ColorAt(x, y)
|
||
|
cr, cg, cb, ca := c.RGBA()
|
||
|
dr := uint32(r.im.Pix[i+0])
|
||
|
dg := uint32(r.im.Pix[i+1])
|
||
|
db := uint32(r.im.Pix[i+2])
|
||
|
da := uint32(r.im.Pix[i+3])
|
||
|
a := (m - (ca * ma / m)) * 0x101
|
||
|
r.im.Pix[i+0] = uint8((dr*a + cr*ma) / m >> 8)
|
||
|
r.im.Pix[i+1] = uint8((dg*a + cg*ma) / m >> 8)
|
||
|
r.im.Pix[i+2] = uint8((db*a + cb*ma) / m >> 8)
|
||
|
r.im.Pix[i+3] = uint8((da*a + ca*ma) / m >> 8)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func newPatternPainter(im *image.RGBA, mask *image.Alpha, p context.Pattern) *patternPainter {
|
||
|
return &patternPainter{im, mask, p}
|
||
|
}
|