scan

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 14, 2024 License: BSD-3-Clause Imports: 6 Imported by: 0

README

scanx

Warning: Scanx is beta software. There are known bugs being worked on. Please use scanFT or scanGV unless you want to test each svg file your application may use.

Scanx is a fast antialiaser supporting the draw.Image interface and image.RGBA and xgraphics.Image types in particular. It is intended for use with the rasterx package.

Scanx replaces the Painter interface with the Spanner interface that allows for more direct writing to an underlying image type. Scanx has two types that satisfy the Spanner interface; ImgSpanner and LinkListSpanner.

ImgSpanner draw into any image that supports the draw.Image interface. It is optimized for image.RGBA and xgraphics.Image types.

LinkListSpanner supports the same Image types as ImgSpanner, but stores the spans in y linked lists, where y is the height of the image. It is faster than ImgSpanner for svg icons where the paths overlap significantly, since it only writes to the image after all the spans are collected. The increase in speed is particually significant when drawing to a large image, like a high resolution monitor. However, LinkListSpanner does not support gradients, so if you are using them, you should use ImgSpanner instead.

Example using ImgSpanner:

bounds     = image.Rect(0, 0, w, h)
img        = image.NewRGBA(bounds)
spanner     = scanx.NewImgSpanner(img)
scanner    = scanx.NewScanner(spanner, w, h)
raster = rasterx.NewDasher(w, h, scanner)
//Use the raster to draw and the results go to the img

Example using LinkListSpanner:

bounds     = image.Rect(0, 0, w, h)
img        = image.NewRGBA(bounds)
spanner    = &scanx.LinkListSpanner{}
spanner.SetBounds(bounds)
scanner    = scanx.NewScanner(spanner, w, h)
raster = rasterx.NewDasher(w, h, scanner)
//Use the raster to draw ..
//This draws the accumulated spans onto the image
spanner.DrawToImage(img)
//Get the spanner ready for another image
spanner.Clear()

Test results in comparison to scanFT and scanGV

Images for the svg files in the test folder have all been generated and compared pixel for pixel using ScanFT, ImgSpanner and LinkListSpanner. ImgSpanner and LinkListSpanner generated images are all identical except in the case of gradients, which LinkListSpanner does not at this time support. ScanFT will differ from ImgScanner and LinkList spanner in some pixel values, usually by one digit, but in cases with multiple semitransparent overlays the effect can be cummulative. The highest difference in the data set is found in the randspot.svg file, where for some pixels the total difference is 4, although it is hard to see any difference visually.

Below are benchmark results using files in test/lanscapeIcons and the indicated spanner or scanner. They are draw at 0.5, 1, 5, and 15 times native resolution.

goos: linux
goarch: amd64
pkg: github.com/srwiley/scanx

Resolution: 0.5x 
BenchmarkLinkListSpanner5-16      	     100	  15692425 ns/op	   37215 B/op	     634 allocs/op
BenchmarkImgSpanner5-16           	     100	  14352161 ns/op	    8708 B/op	     634 allocs/op
BenchmarkFTScanner5-16            	      50	  24019383 ns/op	    3699 B/op	     321 allocs/op
BenchmarkGVScanner5-16            	       3	 362814157 ns/op	    3045 B/op	     321 allocs/op

Resolution: 1x
BenchmarkLinkListSpanner10-16     	      50	  31774480 ns/op	  128512 B/op	     634 allocs/op
BenchmarkImgSpanner10-16          	      50	  35224671 ns/op	   12805 B/op	     634 allocs/op
BenchmarkFTScanner10-16           	      20	  75619298 ns/op	   11241 B/op	     321 allocs/op
BenchmarkGVScanner10-16           	       1	1431206955 ns/op	    3056 B/op	     321 allocs/op

Resolution: 5x
BenchmarkLinkListSpanner50-16     	       5	 227859937 ns/op	 6047212 B/op	     642 allocs/op
BenchmarkImgSpanner50-16          	       2	 513577800 ns/op	  888680 B/op	     644 allocs/op
BenchmarkFTScanner50-16           	       1	1644670841 ns/op	  691184 B/op	     324 allocs/op
BenchmarkGVScanner50-16           	       1	38052841313 ns/op	26217456 B/op	     322 allocs/op

Resolution: 15x
BenchmarkLinkListSpanner150-16    	       1	1344679006 ns/op	93257568 B/op	     679 allocs/op
BenchmarkImgSpanner150-16         	       1	4173881468 ns/op	 5826384 B/op	     665 allocs/op
BenchmarkFTScanner150-16          	       1	10811718931 ns/op	 2788336 B/op	     325 allocs/op
BenchmarkGVScanner150-16          	       1	250690083743 ns/op	235934720 B/op	     327 allocs/op

The results indicate the ImgScanner is consistently faster than scanFT or scanGV. Also LinkListSpanner usually does better with this data set as size of the graphic increases. Also note that some svg files can perform quite badly using the LinkListSpanner, such as rl.svg in the testdata/svg folder. This file consists of lots of random lines that slow the list generation.

Documentation

Overview

Package scan provides an anti-aliasing 2-D rasterizer, which is based on the larger Freetype suite of font-related packages, but the raster package is not specific to font rasterization, and can be used standalone without any other Freetype package. Rasterization is done by the same area/coverage accumulation algorithm as the Freetype "smooth" module, and the Anti-Grain Geometry library. A description of the area/coverage algorithm is at http://projects.tuxee.net/cl-vectors/section-the-cl-aa-algorithm

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type BaseSpanner

type BaseSpanner struct {
	// drawing is done with Bounds.Min as the origin
	Bounds image.Rectangle

	// Op is how pixels are overlayed
	Op      draw.Op
	FgColor color.RGBA
}

BaseSpanner contains base spanner information extended by ImgSpanner and LinkListSpanner.

type Cell

type Cell struct {
	Xi    int
	Area  int
	Cover int
	Next  int
}

Cell is part of a linked list (for a given yi co-ordinate) of accumulated area/coverage for the pixel at (xi, yi).

type ImgSpanner

type ImgSpanner struct {
	BaseSpanner
	Pix        []uint8
	Stride     int
	ColorImage image.Image
}

ImgSpanner is a Spanner that draws Spans onto an *image.RGBA image. It uses either a color function as a the color source, or a fgColor if colFunc is nil.

func NewImgSpanner

func NewImgSpanner(img *image.RGBA) (x *ImgSpanner)

NewImgSpanner returns an ImgSpanner set to draw to the given *image.RGBA.

func (*ImgSpanner) GetSpanFunc

func (x *ImgSpanner) GetSpanFunc() SpanFunc

GetSpanFunc returns the function that consumes a span described by the parameters. The next four func declarations are all slightly different but in order to reduce code redundancy, this method is used to dispatch the function in the draw method.

func (*ImgSpanner) SetColor

func (x *ImgSpanner) SetColor(c image.Image)

SetColor sets the color of x to the given color image

func (*ImgSpanner) SetImage

func (x *ImgSpanner) SetImage(img *image.RGBA)

SetImage set the *image.RGBA that the ImgSpanner will draw onto.

func (*ImgSpanner) SpanColorFunc

func (x *ImgSpanner) SpanColorFunc(yi, xi0, xi1 int, ma uint32)

SpanColorFunc draws the span using a colorFunc and the Porter-Duff composition operator.

func (*ImgSpanner) SpanColorFuncR

func (x *ImgSpanner) SpanColorFuncR(yi, xi0, xi1 int, ma uint32)

SpanColorFuncR draw the span using a colorFunc and replaces the previous values.

func (*ImgSpanner) SpanFgColor

func (x *ImgSpanner) SpanFgColor(yi, xi0, xi1 int, ma uint32)

SpanFgColor draw the span using the fore ground color and the Porter-Duff composition operator.

func (*ImgSpanner) SpanFgColorR

func (x *ImgSpanner) SpanFgColorR(yi, xi0, xi1 int, ma uint32)

SpanFgColorR draws the span with the fore ground color and replaces the previous values.

type LinkListSpanner

type LinkListSpanner struct {
	BaseSpanner
	Spans   []SpanCell
	BgColor color.RGBA
	LastY   int
	LastP   int
}

LinkListSpanner is a Spanner that draws Spans onto a draw.Image interface satisfying struct but it is optimized for *image.RGBA. It uses a solid Color only for fg and bg and does not support a color function used by gradients. Spans are accumulated into a set of linked lists, one for every horizontal line in the image. After the spans for the image are accumulated, use the DrawToImage function to write the spans to an image.

func (x *LinkListSpanner) AddLink(x0, x1, next, pp int, underColor color.RGBA, alpha uint32) (p int)

func (*LinkListSpanner) BlendColor

func (x *LinkListSpanner) BlendColor(under color.RGBA, ma uint32) color.RGBA

func (*LinkListSpanner) Clear

func (x *LinkListSpanner) Clear()

Clear clears the current spans

func (*LinkListSpanner) DrawToImage

func (x *LinkListSpanner) DrawToImage(img image.Image)

DrawToImage draws the accumulated y spans onto the img

func (*LinkListSpanner) GetSpanFunc

func (x *LinkListSpanner) GetSpanFunc() SpanFunc

GetSpanFunc returns the function that consumes a span described by the parameters.

func (*LinkListSpanner) SetBgColor

func (x *LinkListSpanner) SetBgColor(c image.Image)

SetBgColor sets the background color for blending to the first pixel of the given color

func (*LinkListSpanner) SetBounds

func (x *LinkListSpanner) SetBounds(bounds image.Rectangle)

SetBounds sets the spanner boundaries

func (*LinkListSpanner) SetColor

func (x *LinkListSpanner) SetColor(c image.Image)

SetColor sets the color of x to the first pixel of the given color

func (*LinkListSpanner) SpanOver

func (x *LinkListSpanner) SpanOver(yi, xi0, xi1 int, ma uint32)

SpanOver adds the span into an array of linked lists of spans using the fgColor and Porter-Duff composition ma is the accumulated alpha coverage. This function also assumes usage sorted x inputs for each y and so if inputs for x in y are not monotonically increasing, then lastY should be set to -1.

func (*LinkListSpanner) SpansToImage

func (x *LinkListSpanner) SpansToImage(img draw.Image)

func (*LinkListSpanner) SpansToPix

func (x *LinkListSpanner) SpansToPix(pix []uint8, stride int)

type Scanner

type Scanner struct {
	// If false, the behavior is to use the even-odd winding fill
	// rule during Rasterize.
	UseNonZeroWinding bool

	// The Width of the Rasterizer. The height is implicit in len(cellIndex).
	Width int

	// The current pen position.
	A fixed.Point26_6

	// The current cell and its area/coverage being accumulated.
	Xi, Yi int
	Area   int
	Cover  int

	// The clip bounds of the scanner
	Clip image.Rectangle

	// The saved cells.
	Cell []Cell

	// Linked list of cells, one per row.
	CellIndex []int

	// The spanner that we use.
	Spanner Spanner

	// The bounds.
	MinX, MinY, MaxX, MaxY fixed.Int26_6
}

Scanner is a refactored version of the freetype scanner

func NewScanner

func NewScanner(xs Spanner, width, height int) (sc *Scanner)

NewScanner creates a new Scanner with the given bounds.

func (*Scanner) AreaToAlpha

func (s *Scanner) AreaToAlpha(area int) uint32

AreaToAlpha converts an area value to a uint32 alpha value. A completely filled pixel corresponds to an area of 64*64*2, and an alpha of 0xffff. The conversion of area values greater than this depends on the winding rule: even-odd or non-zero.

func (*Scanner) Clear

func (s *Scanner) Clear()

Clear cancels any previous accumulated scans

func (*Scanner) Draw

func (s *Scanner) Draw()

Draw converts r's accumulated curves into Spans for p. The Spans passed to the spanner are non-overlapping, and sorted by Y and then X. They all have non-zero width (and 0 <= X0 < X1 <= r.width) and non-zero A, except for the final Span, which has Y, X0, X1 and A all equal to zero.

func (*Scanner) FindCell

func (s *Scanner) FindCell() int

FindCell returns the index in [Scanner.Cell] for the cell corresponding to (r.xi, r.yi). The cell is created if necessary.

func (*Scanner) GetPathExtent

func (s *Scanner) GetPathExtent() fixed.Rectangle26_6

GetPathExtent returns the bounds of the accumulated path extent

func (*Scanner) Line

func (s *Scanner) Line(b fixed.Point26_6)

Line adds a linear segment to the current curve.

func (*Scanner) SaveCell

func (s *Scanner) SaveCell()

SaveCell saves any accumulated [Scanner.Area] or [Scanner.Cover] for ([Scanner.Xi], [Scanner.Yi]).

func (*Scanner) Scan

func (s *Scanner) Scan(yi int, x0, y0f, x1, y1f fixed.Int26_6)

Scan accumulates area/coverage for the yi'th scanline, going from x0 to x1 in the horizontal direction (in 26.6 fixed point co-ordinates) and from y0f to y1f fractional vertical units within that scanline.

func (*Scanner) Set

func (s *Scanner) Set(a fixed.Point26_6)

func (*Scanner) SetBounds

func (s *Scanner) SetBounds(width, height int)

SetBounds sets the maximum width and height of the rasterized image and calls Clear. The width and height are in pixels, not fixed.Int26_6 units.

func (*Scanner) SetCell

func (s *Scanner) SetCell(xi, yi int)

SetCell sets the (xi, yi) cell that r is accumulating area/coverage for.

func (*Scanner) SetClip

func (s *Scanner) SetClip(r image.Rectangle)

SetClip will not affect accumulation of scans, but it will clip drawing of the spans int the Draw func by the clip rectangle.

func (*Scanner) SetColor

func (s *Scanner) SetColor(clr image.Image)

SetColor sets the color used for rendering.

func (*Scanner) SetWinding

func (s *Scanner) SetWinding(useNonZeroWinding bool)

SetWinding set the winding rule for the polygons

func (*Scanner) Start

func (s *Scanner) Start(a fixed.Point26_6)

Start starts a new path at the given point.

type SpanCell

type SpanCell struct {
	X0   int
	X1   int
	Next int
	Clr  color.RGBA
}

SpanCell represents a span cell.

type SpanFunc

type SpanFunc func(yi, xi0, xi1 int, alpha uint32)

SpanFunc is the type of a span function

type Spanner

type Spanner interface {
	// SetColor sets the color used for rendering.
	SetColor(color image.Image)

	// This returns a function that is efficient given the Spanner parameters.
	GetSpanFunc() SpanFunc
}

A Spanner consumes spans as they are created by the Scanner Draw function

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL