Пример #1
0
// 画一个带有text的图片
func (this *Signer) DrawStringImage(text string) (image.Image, error) {
	fg, bg := image.Black, image.Transparent
	rgba := image.NewRGBA(image.Rect(0, 0, this.signPoint.X, this.signPoint.Y))
	draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src)

	c := freetype.NewContext()
	c.SetDPI(this.Dpi)
	c.SetFont(this.font)
	c.SetFontSize(this.FontSize)
	c.SetClip(rgba.Bounds())
	c.SetDst(rgba)
	c.SetSrc(fg)

	// Draw the text.
	pt := freetype.Pt(10, 10+int(c.PointToFix32(12)>>8))
	limit := c.PointToFix32(100) - raster.Fix32(10<<8) - raster.Fix32(10<<8)
	for _, s := range strings.Split(text, "\r\n") {
		_, err := c.DrawString(s, pt, limit)
		if err != nil {
			fmt.Println("c.DrawString(%s) error(%v)", s, err)
			return nil, err
		}
		pt.Y += c.PointToFix32(12 * 1.5)
	}

	// fff, _ := os.Create("aaa.png")
	// defer fff.Close()
	// png.Encode(fff, rgba)

	return rgba, nil
}
Пример #2
0
func BenchmarkFreetypeNonZeroWinding(b *testing.B) {
	var p Path
	p.LineTo(10, 190)
	draw2dbase.TraceCubic(&p, []float64{10, 190, 10, 10, 190, 10, 190, 190}, 0.5)

	poly := Polygon(p.points)
	color := color.RGBA{0, 0, 0, 0xff}

	for i := 0; i < b.N; i++ {
		img := image.NewRGBA(image.Rect(0, 0, 200, 200))
		rasterizer := raster.NewRasterizer(200, 200)
		rasterizer.UseNonZeroWinding = true
		rasterizer.Start(raster.Point{
			X: raster.Fix32(10 * 256),
			Y: raster.Fix32(190 * 256)})
		for j := 0; j < len(poly); j = j + 2 {
			rasterizer.Add1(raster.Point{
				X: raster.Fix32(poly[j] * 256),
				Y: raster.Fix32(poly[j+1] * 256)})
		}
		painter := raster.NewRGBAPainter(img)
		painter.SetColor(color)
		rasterizer.Rasterize(painter)
	}
}
Пример #3
0
func p(n node) raster.Point {
	x, y := 20+n.x/4, 380-n.y/4
	return raster.Point{
		X: raster.Fix32(x * 256),
		Y: raster.Fix32(y * 256),
	}
}
Пример #4
0
// DrawString draws s at p and returns p advanced by the text extent. The text
// is placed so that the left edge of the em square of the first character of s
// and the baseline intersect at p. The majority of the affected pixels will be
// above and to the right of the point, but some may be below or to the left.
// For example, drawing a string that starts with a 'J' in an italic font may
// affect pixels below and left of the point.
// p is a raster.Point and can therefore represent sub-pixel positions.
func (c *Context) DrawString(s string, p raster.Point) (raster.Point, error) {
	if c.font == nil {
		return raster.Point{}, errors.New("freetype: DrawText called with a nil font")
	}
	prev, hasPrev := truetype.Index(0), false
	for _, rune := range s {
		index := c.font.Index(rune)
		if hasPrev {
			kern := raster.Fix32(c.font.Kerning(c.scale, prev, index)) << 2
			if c.hinting != NoHinting {
				kern = (kern + 128) &^ 255
			}
			p.X += kern
		}
		advanceWidth, mask, offset, err := c.glyph(index, p)
		if err != nil {
			return raster.Point{}, err
		}
		p.X += advanceWidth
		glyphRect := mask.Bounds().Add(offset)
		dr := c.clip.Intersect(glyphRect)
		if !dr.Empty() {
			mp := image.Point{0, dr.Min.Y - glyphRect.Min.Y}
			draw.DrawMask(c.dst, dr, c.src, image.ZP, mask, mp, draw.Over)
		}
		prev, hasPrev = index, true
	}
	return p, nil
}
Пример #5
0
// drawContour draws the given closed contour with the given offset.
func (p *glyphPage) drawContour(ps []truetype.Point, dx, dy raster.Fix32) {
	if len(ps) == 0 {
		return
	}
	rast := p.rast
	resolution := p.resolution
	// ps[0] is a truetype.Point measured in FUnits and positive Y going upwards.
	// start is the same thing measured in fixed point units and positive Y
	// going downwards, and offset by (dx, dy)
	start := raster.Point{
		X: dx + raster.Fix32(int64(ps[0].X)*int64(resolution)>>14),
		Y: dy - raster.Fix32(int64(ps[0].Y)*int64(resolution)>>14),
	}
	rast.Start(start)
	q0, on0 := start, true
	for _, p := range ps[1:] {
		q := raster.Point{
			X: dx + raster.Fix32(int64(p.X)*int64(resolution)>>14),
			Y: dy - raster.Fix32(int64(p.Y)*int64(resolution)>>14),
		}
		on := p.Flags&0x01 != 0
		if on {
			if on0 {
				rast.Add1(q)
			} else {
				rast.Add2(q0, q)
			}
		} else {
			if on0 {
				// No-op.
			} else {
				mid := raster.Point{
					X: (q0.X + q.X) / 2,
					Y: (q0.Y + q.Y) / 2,
				}
				rast.Add2(q0, mid)
			}
		}
		q0, on0 = q, on
	}
	// Close the curve.
	if on0 {
		rast.Add1(start)
	} else {
		rast.Add2(q0, start)
	}
}
Пример #6
0
func (p *glyphPage) add(rune rune, g *glyph) bool {
	if _, found := p.offsets[rune]; found {
		panic("Glyph already added to glyph page")
	}

	w, h := g.size(p.resolution).WH()
	x, y := p.nextPoint.X, p.nextPoint.Y

	if x+w > p.size.W {
		// Row full, start new line
		x = 0
		y += p.rowHeight + glyphPadding
		p.rowHeight = 0
	}

	if y+h > p.size.H {
		return false // Page full
	}

	// Build the raster contours
	p.rast.Clear()
	fx := -raster.Fix32((int64(g.B.XMin) * int64(p.resolution)) >> 14)
	fy := +raster.Fix32((int64(g.B.YMax) * int64(p.resolution)) >> 14)
	e0 := 0
	for _, e1 := range g.End {
		p.drawContour(g.Point[e0:e1], fx, fy)
		e0 = e1
	}

	// Perform the rasterization
	a := &image.Alpha{
		Pix:    p.image.Pix[x+y*p.image.Stride:],
		Stride: p.image.Stride,
		Rect:   image.Rect(0, 0, w, h),
	}
	p.rast.Rasterize(raster.NewAlphaSrcPainter(a))

	p.offsets[rune] = math.Point{X: x, Y: y}
	p.nextPoint = math.Point{X: x + w + glyphPadding, Y: y}
	if h > p.rowHeight {
		p.rowHeight = h
	}
	p.tex = nil

	return true
}
Пример #7
0
// rasterize returns the advance width, glyph mask and integer-pixel offset
// to render the given glyph at the given sub-pixel offsets.
// The 24.8 fixed point arguments fx and fy must be in the range [0, 1).
func (c *Context) rasterize(glyph truetype.Index, fx, fy raster.Fix32) (
	raster.Fix32, *image.Alpha, image.Point, error) {

	if err := c.glyphBuf.Load(c.font, c.scale, glyph, truetype.Hinting(c.hinting)); err != nil {
		return 0, nil, image.Point{}, err
	}
	// Calculate the integer-pixel bounds for the glyph.
	xmin := int(fx+raster.Fix32(c.glyphBuf.B.XMin<<2)) >> 8
	ymin := int(fy-raster.Fix32(c.glyphBuf.B.YMax<<2)) >> 8
	xmax := int(fx+raster.Fix32(c.glyphBuf.B.XMax<<2)+0xff) >> 8
	ymax := int(fy-raster.Fix32(c.glyphBuf.B.YMin<<2)+0xff) >> 8
	if xmin > xmax || ymin > ymax {
		return 0, nil, image.Point{}, errors.New("freetype: negative sized glyph")
	}
	// A TrueType's glyph's nodes can have negative co-ordinates, but the
	// rasterizer clips anything left of x=0 or above y=0. xmin and ymin
	// are the pixel offsets, based on the font's FUnit metrics, that let
	// a negative co-ordinate in TrueType space be non-negative in
	// rasterizer space. xmin and ymin are typically <= 0.
	fx += raster.Fix32(-xmin << 8)
	fy += raster.Fix32(-ymin << 8)
	// Rasterize the glyph's vectors.
	c.r.Clear()
	e0 := 0
	for _, e1 := range c.glyphBuf.End {
		c.drawContour(c.glyphBuf.Point[e0:e1], fx, fy)
		e0 = e1
	}
	a := image.NewAlpha(image.Rect(0, 0, xmax-xmin, ymax-ymin))
	c.r.Rasterize(raster.NewAlphaSrcPainter(a))
	return raster.Fix32(c.glyphBuf.AdvanceWidth << 2), a, image.Point{xmin, ymin}, nil
}
Пример #8
0
func TestFreetypeNonZeroWinding(t *testing.T) {
	var p Path
	p.LineTo(10, 190)
	draw2dbase.TraceCubic(&p, []float64{10, 190, 10, 10, 190, 10, 190, 190}, 0.5)
	poly := Polygon(p.points)
	color := color.RGBA{0, 0, 0, 0xff}

	img := image.NewRGBA(image.Rect(0, 0, 200, 200))
	rasterizer := raster.NewRasterizer(200, 200)
	rasterizer.UseNonZeroWinding = true
	rasterizer.Start(raster.Point{
		X: raster.Fix32(10 * 256),
		Y: raster.Fix32(190 * 256)})
	for j := 0; j < len(poly); j = j + 2 {
		rasterizer.Add1(raster.Point{
			X: raster.Fix32(poly[j] * 256),
			Y: raster.Fix32(poly[j+1] * 256)})
	}
	painter := raster.NewRGBAPainter(img)
	painter.SetColor(color)
	rasterizer.Rasterize(painter)

	draw2dimg.SaveToPngFile("../output/raster/TestFreetypeNonZeroWinding.png", img)
}
Пример #9
0
// PointToFix32 converts the given number of points (as in ``a 12 point font'')
// into fixed point units.
func (c *Context) PointToFix32(x float64) raster.Fix32 {
	return raster.Fix32(x * float64(c.dpi) * (256.0 / 72.0))
}
Пример #10
0
// Pt converts from a co-ordinate pair measured in pixels to a raster.Point
// co-ordinate pair measured in raster.Fix32 units.
func Pt(x, y int) raster.Point {
	return raster.Point{
		X: raster.Fix32(x << 8),
		Y: raster.Fix32(y << 8),
	}
}
Пример #11
0
// drawContour draws the given closed contour with the given offset.
func (c *Context) drawContour(ps []truetype.Point, dx, dy raster.Fix32) {
	if len(ps) == 0 {
		return
	}

	// The low bit of each point's Flags value is whether the point is on the
	// curve. Truetype fonts only have quadratic Bézier curves, not cubics.
	// Thus, two consecutive off-curve points imply an on-curve point in the
	// middle of those two.
	//
	// See http://chanae.walon.org/pub/ttf/ttf_glyphs.htm for more details.

	// ps[0] is a truetype.Point measured in FUnits and positive Y going
	// upwards. start is the same thing measured in fixed point units and
	// positive Y going downwards, and offset by (dx, dy).
	start := raster.Point{
		X: dx + raster.Fix32(ps[0].X<<2),
		Y: dy - raster.Fix32(ps[0].Y<<2),
	}
	others := []truetype.Point(nil)
	if ps[0].Flags&0x01 != 0 {
		others = ps[1:]
	} else {
		last := raster.Point{
			X: dx + raster.Fix32(ps[len(ps)-1].X<<2),
			Y: dy - raster.Fix32(ps[len(ps)-1].Y<<2),
		}
		if ps[len(ps)-1].Flags&0x01 != 0 {
			start = last
			others = ps[:len(ps)-1]
		} else {
			start = raster.Point{
				X: (start.X + last.X) / 2,
				Y: (start.Y + last.Y) / 2,
			}
			others = ps
		}
	}
	c.r.Start(start)
	q0, on0 := start, true
	for _, p := range others {
		q := raster.Point{
			X: dx + raster.Fix32(p.X<<2),
			Y: dy - raster.Fix32(p.Y<<2),
		}
		on := p.Flags&0x01 != 0
		if on {
			if on0 {
				c.r.Add1(q)
			} else {
				c.r.Add2(q0, q)
			}
		} else {
			if on0 {
				// No-op.
			} else {
				mid := raster.Point{
					X: (q0.X + q.X) / 2,
					Y: (q0.Y + q.Y) / 2,
				}
				c.r.Add2(q0, mid)
			}
		}
		q0, on0 = q, on
	}
	// Close the curve.
	if on0 {
		c.r.Add1(start)
	} else {
		c.r.Add2(q0, start)
	}
}
Пример #12
0
func int2fix(i int) raster.Fix32 {
	return raster.Fix32(i << fixBits)
}
Пример #13
0
func main() {
	const (
		n = 17
		r = 256 * 80
	)
	s := raster.Fix32(r * math.Sqrt(2) / 2)
	t := raster.Fix32(r * math.Tan(math.Pi/8))

	m := image.NewRGBA(image.Rect(0, 0, 800, 600))
	draw.Draw(m, m.Bounds(), image.NewUniform(color.RGBA{63, 63, 63, 255}), image.ZP, draw.Src)
	mp := raster.NewRGBAPainter(m)
	mp.SetColor(image.Black)
	z := raster.NewRasterizer(800, 600)

	for i := 0; i < n; i++ {
		cx := raster.Fix32(25600 + 51200*(i%4))
		cy := raster.Fix32(2560 + 32000*(i/4))
		c := raster.Point{X: cx, Y: cy}
		theta := math.Pi * (0.5 + 0.5*float64(i)/(n-1))
		dx := raster.Fix32(r * math.Cos(theta))
		dy := raster.Fix32(r * math.Sin(theta))
		d := raster.Point{X: dx, Y: dy}
		// Draw a quarter-circle approximated by two quadratic segments,
		// with each segment spanning 45 degrees.
		z.Start(c)
		z.Add1(c.Add(raster.Point{X: r, Y: 0}))
		z.Add2(c.Add(raster.Point{X: r, Y: t}), c.Add(raster.Point{X: s, Y: s}))
		z.Add2(c.Add(raster.Point{X: t, Y: r}), c.Add(raster.Point{X: 0, Y: r}))
		// Add another quadratic segment whose angle ranges between 0 and 90 degrees.
		// For an explanation of the magic constants 22, 150, 181 and 256, read the
		// comments in the freetype/raster package.
		dot := 256 * d.Dot(raster.Point{X: 0, Y: r}) / (r * r)
		multiple := raster.Fix32(150 - 22*(dot-181)/(256-181))
		z.Add2(c.Add(raster.Point{X: dx, Y: r + dy}.Mul(multiple)), c.Add(d))
		// Close the curve.
		z.Add1(c)
	}
	z.Rasterize(mp)

	for i := 0; i < n; i++ {
		cx := raster.Fix32(25600 + 51200*(i%4))
		cy := raster.Fix32(2560 + 32000*(i/4))
		for j := 0; j < n; j++ {
			theta := math.Pi * float64(j) / (n - 1)
			dx := raster.Fix32(r * math.Cos(theta))
			dy := raster.Fix32(r * math.Sin(theta))
			m.Set(int((cx+dx)/256), int((cy+dy)/256), color.RGBA{255, 255, 0, 255})
		}
	}

	// Save that RGBA image to disk.
	f, err := os.Create("out.png")
	if err != nil {
		log.Println(err)
		os.Exit(1)
	}
	defer f.Close()
	b := bufio.NewWriter(f)
	err = png.Encode(b, m)
	if err != nil {
		log.Println(err)
		os.Exit(1)
	}
	err = b.Flush()
	if err != nil {
		log.Println(err)
		os.Exit(1)
	}
	fmt.Println("Wrote out.png OK.")
}
Пример #14
0
func (obj *RasterItem) pt(p raster.Point) raster.Point {
	return raster.Point{p.X + raster.Fix32(obj.rasterizer.Dx)<<fixBits, p.Y + raster.Fix32(obj.rasterizer.Dy)<<fixBits}
}
Пример #15
0
func float2fixed(f float64) raster.Fix32 {
	if f < 0 {
		return raster.Fix32(f*256 + 0.5)
	}
	return raster.Fix32(f*256 - 0.5)
}
Пример #16
0
func pixel2fixPoint(p image.Point) raster.Point {
	return raster.Point{raster.Fix32(p.X << fixBits), raster.Fix32(p.Y << fixBits)}
}
Пример #17
0
func (c *Context) PixToFix32(p int) raster.Fix32 {
	return raster.Fix32(p * 256)
}
Пример #18
0
func p(x, y int) raster.Point {
	return raster.Point{
		X: raster.Fix32(x * 256),
		Y: raster.Fix32(y * 256),
	}
}
Пример #19
0
func (liner FtLineBuilder) LineTo(x, y float64) {
	liner.Adder.Add1(raster.Point{X: raster.Fix32(x * 256), Y: raster.Fix32(y * 256)})
}
Пример #20
0
func float2fix(f float64) raster.Fix32 {
	return raster.Fix32(f*fixScale + 0.5)
}