mirror of
https://github.com/unidoc/unipdf.git
synced 2025-05-05 19:30:30 +08:00

* Add render package * Add text state * Add more text operators * Remove unnecessary files * Add text font * Add custom text render method * Improve text rendering method * Rename text state methods * Refactor and document context interface * Refact text begin/end operators * Fix graphics state transformations * Keep original font when doing font substitution * Take page cropbox into account * Revert to substitution font if original font measurement is 0 * Add font substitution package * Implement addition transform.Point methods * Use transform.Point in the image context package * Remove unneeded functionality from the render image package * Fix golint notices in the image rendering package * Fix go vet notices in the render package * Fix golint notices in the top-level render package * Improve render context package documentation * Document context text state struct. * Document context text font struct. * Minor logging improvements * Add license disclaimer to the render package files * Avoid using package aliases where possible * Change style of section comments * Adapt render package import style to follow the developer guide * Improve documentation for the internal matrix implementation * Update render package dependency versions * Apply crop box post render * Account for offseted media boxes * Improve metrics of rendered characters * Fix text matrix translation * Change priority of fonts used for measuring rendered characters * Skip invalid m and l operators on image rendering * Small fix for v operator * Fix rendered characters spacing issues * Refactor naming of internal render packages
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}
|
|
}
|