Exemplo n.º 1
0
func TestFreetypeRasterizerNonZeroWinding(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)

	err := draw2dimg.SaveToPngFile("output/TestFreetypeRasterizerNonZeroWinding.png", img)
	if err != nil {
		fmt.Println(err)
	}
}
Exemplo n.º 2
0
// MeasureString returns the width and height of the string in s, in terms of
// raster.Fix32 units.
//
// BUG(burntsushi): I don't think negative x-coordinates are handled at all, so
// that the bounding box could be smaller than what it actually is. (i.e., the
// first letter is an italic 'J'.)
func (c *Context) MeasureString(s string) (raster.Fix32, raster.Fix32, error) {
	if c.font == nil {
		return 0, 0, errors.New("freetype: DrawText called with a nil font")
	}

	var width, height, heightMax raster.Fix32
	oneLine := c.PointToFix32(c.fontSize) & 0xff
	height = c.PointToFix32(c.fontSize)
	prev, hasPrev := truetype.Index(0), false
	for _, rune := range s {
		index := c.font.Index(rune)
		if hasPrev {
			width += raster.Fix32(c.font.Kerning(c.scale, prev, index)) << 2
		}

		if err := c.glyphBuf.Load(c.font, c.scale, index, truetype.NoHinting); err != nil {
			return 0, 0, err
		}
		ymax := oneLine - raster.Fix32(c.glyphBuf.B.YMin<<2) + 0xff
		heightMax = max(heightMax, ymax)

		width += raster.Fix32(c.font.HMetric(c.scale, index).AdvanceWidth) << 2
		prev, hasPrev = index, true
	}

	if heightMax > 0 {
		height += heightMax
	}
	return width, height, nil
}
Exemplo n.º 3
0
Arquivo: arc.go Projeto: stanim/draw2d
func arcAdder(adder raster.Adder, x, y, rx, ry, start, angle, scale float64) raster.Point {
	end := start + angle
	clockWise := true
	if angle < 0 {
		clockWise = false
	}
	ra := (math.Abs(rx) + math.Abs(ry)) / 2
	da := math.Acos(ra/(ra+0.125/scale)) * 2
	//normalize
	if !clockWise {
		da = -da
	}
	angle = start + da
	var curX, curY float64
	for {
		if (angle < end-da/4) != clockWise {
			curX = x + math.Cos(end)*rx
			curY = y + math.Sin(end)*ry
			return raster.Point{
				X: raster.Fix32(curX * 256),
				Y: raster.Fix32(curY * 256)}
		}
		curX = x + math.Cos(angle)*rx
		curY = y + math.Sin(angle)*ry

		angle += da
		adder.Add1(raster.Point{
			X: raster.Fix32(curX * 256),
			Y: raster.Fix32(curY * 256)})
	}
}
Exemplo n.º 4
0
func TestFreetypeNonZeroWinding(t *testing.T) {
	var p Path
	p.LineTo(10, 190)
	c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
	c.Segment(&p, flatteningThreshold)
	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)

	savepng("../output/raster/TestFreetypeNonZeroWinding.png", img)
}
Exemplo n.º 5
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),
	}
}
Exemplo n.º 6
0
func BenchmarkFreetype(b *testing.B) {
	var p Path
	p.LineTo(10, 190)
	c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
	c.Segment(&p, flatteningThreshold)
	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 = false
		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)
	}
}
Exemplo n.º 7
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 {
			p.X += raster.Fix32(c.font.Kerning(c.scale, prev, index)) << 2
		}
		mask, offset, err := c.glyph(index, p)
		if err != nil {
			return raster.Point{}, err
		}
		p.X += raster.Fix32(c.font.HMetric(c.scale, index).AdvanceWidth) << 2
		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
}
Exemplo n.º 8
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)
	}
}
Exemplo n.º 9
0
func (tr MatrixTransform) TransformRasterPoint(points ...*raster.Point) {
	for _, point := range points {
		x := float64(point.X) / 256
		y := float64(point.Y) / 256
		point.X = raster.Fix32((x*tr[0] + y*tr[2] + tr[4]) * 256)
		point.Y = raster.Fix32((x*tr[1] + y*tr[3] + tr[5]) * 256)
	}
}
Exemplo n.º 10
0
func (vertexAdder *VertexAdder) Vertex(x, y float64) {
	switch vertexAdder.command {
	case VertexStartCommand:
		vertexAdder.adder.Start(raster.Point{raster.Fix32(x * 256), raster.Fix32(y * 256)})
	default:
		vertexAdder.adder.Add1(raster.Point{raster.Fix32(x * 256), raster.Fix32(y * 256)})
	}
	vertexAdder.command = VertexNoCommand
}
Exemplo n.º 11
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
	}

	if p.tex != nil {
		p.tex.Release()
		p.tex = nil
	}

	return true
}
Exemplo n.º 12
0
func (pathAdder *PathAdder) Convert(paths ...*PathStorage) {
	for _, path := range paths {
		j := 0
		for _, cmd := range path.commands {
			switch cmd {
			case MoveTo:
				pathAdder.firstPoint = raster.Point{raster.Fix32(path.vertices[j] * 256), raster.Fix32(path.vertices[j+1] * 256)}
				pathAdder.adder.Start(pathAdder.firstPoint)
				j += 2
			case LineTo:
				pathAdder.adder.Add1(raster.Point{raster.Fix32(path.vertices[j] * 256), raster.Fix32(path.vertices[j+1] * 256)})
				j += 2
			case QuadCurveTo:
				pathAdder.adder.Add2(raster.Point{raster.Fix32(path.vertices[j] * 256), raster.Fix32(path.vertices[j+1] * 256)}, raster.Point{raster.Fix32(path.vertices[j+2] * 256), raster.Fix32(path.vertices[j+3] * 256)})
				j += 4
			case CubicCurveTo:
				pathAdder.adder.Add3(raster.Point{raster.Fix32(path.vertices[j] * 256), raster.Fix32(path.vertices[j+1] * 256)}, raster.Point{raster.Fix32(path.vertices[j+2] * 256), raster.Fix32(path.vertices[j+3] * 256)}, raster.Point{raster.Fix32(path.vertices[j+4] * 256), raster.Fix32(path.vertices[j+5] * 256)})
				j += 6
			case ArcTo:
				lastPoint := arcAdder(pathAdder.adder, path.vertices[j], path.vertices[j+1], path.vertices[j+2], path.vertices[j+3], path.vertices[j+4], path.vertices[j+5], pathAdder.ApproximationScale)
				pathAdder.adder.Add1(lastPoint)
				j += 6
			case Close:
				pathAdder.adder.Add1(pathAdder.firstPoint)
			}
		}
	}
}
Exemplo n.º 13
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)
	}
}
Exemplo n.º 14
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
}
Exemplo n.º 15
0
func (ig *ImageGraphics) TextLen(s string, font chart.Font) int {
	c := freetype.NewContext()
	c.SetDPI(dpi)
	c.SetFont(ig.font)
	fontsize := ig.relFontsizeToPixel(font.Size)
	c.SetFontSize(fontsize)
	scale := int32(fontsize * dpi * (64.0 / 72.0))
	var p raster.Point
	prev, hasPrev := truetype.Index(0), false
	for _, rune := range s {
		index := ig.font.Index(rune)
		if hasPrev {
			p.X += raster.Fix32(ig.font.Kerning(scale, prev, index)) << 2
		}
		p.X += raster.Fix32(ig.font.HMetric(scale, index).AdvanceWidth) << 2
		prev, hasPrev = index, true
	}
	return int((p.X + 127) / 256)
}
Exemplo n.º 16
0
func TestFreetype(t *testing.T) {
	var p Path
	p.LineTo(10, 190)
	c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
	c.Segment(&p, flattening_threshold)
	poly := Polygon(p.points)
	rgba := color.RGBA{0, 0, 0, 0xff}

	bounds := image.Rect(0, 0, 200, 200)
	mask := image.NewAlpha(bounds)
	img := image.NewRGBA(bounds)
	rasterizer := raster.NewRasterizer(200, 200)
	rasterizer.UseNonZeroWinding = false
	rasterizer.Start(raster.Point{raster.Fix32(10 * 256), raster.Fix32(190 * 256)})
	for j := 0; j < len(poly); j = j + 2 {
		rasterizer.Add1(raster.Point{raster.Fix32(poly[j] * 256), raster.Fix32(poly[j+1] * 256)})
	}
	painter := raster.NewAlphaSrcPainter(mask)
	rasterizer.Rasterize(painter)
	DrawSolidRGBA(img, mask, rgba)
	savepng("_testFreetype.png", img)
}
Exemplo n.º 17
0
// moustache draws a moustache of the specified size and droop
// onto the image m and returns the result. It may overwrite the
// original.
func moustache(m image.Image, x, y, size, droopFactor int) image.Image {
	mrgba := rgba(m)

	p := raster.NewRGBAPainter(mrgba)
	p.SetColor(color.RGBA{0, 0, 0, 255})

	w, h := m.Bounds().Dx(), m.Bounds().Dy()
	r := raster.NewRasterizer(w, h)
	var (
		mag   = raster.Fix32((10 + size) << 8)
		width = pt(20, 0).Mul(mag)
		mid   = pt(x, y)
		droop = pt(0, droopFactor).Mul(mag)
		left  = mid.Sub(width).Add(droop)
		right = mid.Add(width).Add(droop)
		bow   = pt(0, 5).Mul(mag).Sub(droop)
		curlx = pt(10, 0).Mul(mag)
		curly = pt(0, 2).Mul(mag)
		risex = pt(2, 0).Mul(mag)
		risey = pt(0, 5).Mul(mag)
	)
	r.Start(left)
	r.Add3(
		mid.Sub(curlx).Add(curly),
		mid.Sub(risex).Sub(risey),
		mid,
	)
	r.Add3(
		mid.Add(risex).Sub(risey),
		mid.Add(curlx).Add(curly),
		right,
	)
	r.Add2(
		mid.Add(bow),
		left,
	)
	r.Rasterize(p)

	return mrgba
}
Exemplo n.º 18
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))
}
Exemplo n.º 19
0
// the returned zoneOfColor always has A == 256.
func worldImage(t *testing.T) (im *image.RGBA, zoneOfColor map[color.RGBA]string) {
	scale := *flagScale
	width := int(scale * 360)
	height := int(scale * 180)

	im = image.NewRGBA(image.Rect(0, 0, width, height))
	zoneOfColor = map[color.RGBA]string{}
	tab := crc32.MakeTable(crc32.IEEE + 1)

	drawPoly := func(col color.RGBA, xys ...int) {
		painter := raster.NewRGBAPainter(im)
		painter.SetColor(col)
		r := raster.NewRasterizer(width, height)
		r.Start(raster.Point{X: raster.Fix32(xys[0]) << 8, Y: raster.Fix32(xys[1]) << 8})
		for i := 2; i < len(xys); i += 2 {
			r.Add1(raster.Point{X: raster.Fix32(xys[i]) << 8, Y: raster.Fix32(xys[i+1]) << 8})
		}
		r.Add1(raster.Point{X: raster.Fix32(xys[0]) << 8, Y: raster.Fix32(xys[1]) << 8})
		r.Rasterize(raster.NewMonochromePainter(painter))
	}

	sr, err := shp.Open("world/tz_world.shp")
	if err != nil {
		t.Fatalf("Error opening world/tz_world.shp: %v; unzip it from http://efele.net/maps/tz/world/tz_world.zip", err)
	}
	defer sr.Close()

	for sr.Next() {
		i, s := sr.Shape()
		p, ok := s.(*shp.Polygon)
		if !ok {
			t.Fatalf("Unknown shape %T", p)
		}
		zoneName := sr.ReadAttribute(i, 0)
		if zoneName == "uninhabited" {
			continue
		}
		if _, err := time.LoadLocation(zoneName); err != nil {
			t.Fatalf("Failed to load: %v (%v)", zoneName, err)
		}
		hash := crc32.Checksum([]byte(zoneName), tab)
		col := color.RGBA{uint8(hash >> 24), uint8(hash >> 16), uint8(hash >> 8), 255}
		if name, ok := zoneOfColor[col]; ok {
			if name != zoneName {
				log.Fatalf("Color %+v dup: %s and %s", col, name, zoneName)
			}
		} else {
			zoneOfColor[col] = zoneName
		}

		var xys []int
		for _, pt := range p.Points {
			xys = append(xys, int((pt.X+180)*scale), int((90-pt.Y)*scale))
		}
		drawPoly(col, xys...)
	}

	// adjust point from scale 32 to whatever the user is using.
	ap := func(x int) int { return x * int(scale) / 32 }
	// Fix some rendering glitches:
	// {186 205 234 255} = Europe/Rome
	drawPoly(color.RGBA{186, 205, 234, 255},
		ap(6156), ap(1468),
		ap(6293), ap(1596),
		ap(6293), ap(1598),
		ap(6156), ap(1540))
	// {136 136 180 255} = America/Boise
	drawPoly(color.RGBA{136, 136, 180, 255},
		ap(2145), ap(1468),
		ap(2189), ap(1468),
		ap(2189), ap(1536),
		ap(2145), ap(1536))
	// {120 247 14 255} = America/Denver
	drawPoly(color.RGBA{120, 247, 14, 255},
		ap(2167), ap(1536),
		ap(2171), ap(1536),
		ap(2217), ap(1714),
		ap(2204), ap(1724),
		ap(2160), ap(1537))
	return
}
Exemplo n.º 20
0
func (liner FtLineBuilder) LineTo(x, y float64) {
	liner.Adder.Add1(raster.Point{X: raster.Fix32(x * 256), Y: raster.Fix32(y * 256)})
}
Exemplo n.º 21
0
// pt returns the raster.Point corresponding to the pixel position (x, y).
func pt(x, y int) raster.Point {
	return raster.Point{X: raster.Fix32(x << 8), Y: raster.Fix32(y << 8)}
}
Exemplo n.º 22
0
func p(x, y int) raster.Point {
	return raster.Point{
		X: raster.Fix32(x * 256),
		Y: raster.Fix32(y * 256),
	}
}
Exemplo n.º 23
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}
}
Exemplo n.º 24
0
func float2fixed(f float64) raster.Fix32 {
	if f < 0 {
		return raster.Fix32(f*256 + 0.5)
	}
	return raster.Fix32(f*256 - 0.5)
}
Exemplo n.º 25
0
func int2fix(i int) raster.Fix32 {
	return raster.Fix32(i << fixBits)
}
Exemplo n.º 26
0
func float2fix(f float64) raster.Fix32 {
	return raster.Fix32(f*fixScale + 0.5)
}
Exemplo n.º 27
0
func genGlyphs(font *truetype.Font, size int, text string) (glyphs []*glyph) {

	scale := int32(float64(size) * dpi * (64.0 / 72.0))
	clip := image.Rect(0, 0, width, height)

	// Calculate the rasterizer's bounds to handle the largest glyph.
	b := font.Bounds(scale)
	xmin := int(b.XMin) >> 6
	ymin := -int(b.YMax) >> 6
	xmax := int(b.XMax+63) >> 6
	ymax := -int(b.YMin-63) >> 6

	r := raster.NewRasterizer(xmax-xmin, ymax-ymin)
	buf := truetype.NewGlyphBuf()

	for _, variant := range []string{strings.ToUpper(text), strings.ToLower(text)} {

		pt := Pt(30, 10+int(pointToFix32(float64(size))>>8))

		for _, char := range variant {

			idx := font.Index(char)
			buf.Load(font, scale, idx, truetype.FullHinting)

			// Calculate the integer-pixel bounds for the glyph.
			xmin := int(raster.Fix32(buf.B.XMin<<2)) >> 8
			ymin := int(-raster.Fix32(buf.B.YMax<<2)) >> 8
			xmax := int(raster.Fix32(buf.B.XMax<<2)+0xff) >> 8
			ymax := int(-raster.Fix32(buf.B.YMin<<2)+0xff) >> 8
			fx := raster.Fix32(-xmin << 8)
			fy := raster.Fix32(-ymin << 8)

			ix := int(pt.X >> 8)
			iy := int(pt.Y >> 8)

			// Rasterize the glyph's vectors.
			r.Clear()
			e0 := 0
			for _, e1 := range buf.End {
				drawContour(r, buf.Point[e0:e1], fx, fy)
				e0 = e1
			}

			mask := image.NewAlpha(image.Rect(0, 0, xmax-xmin, ymax-ymin))
			r.Rasterize(raster.NewAlphaSrcPainter(mask))
			pt.X += raster.Fix32(buf.AdvanceWidth << 2)
			offset := image.Point{xmin + ix, ymin + iy}

			glyphRect := mask.Bounds().Add(offset)
			dr := clip.Intersect(glyphRect)
			mp := image.Point{0, dr.Min.Y - glyphRect.Min.Y}
			glyphs = append(glyphs, &glyph{
				mask: mask,
				mp:   mp,
				dr:   dr,
			})

		}
	}

	return

}
Exemplo n.º 28
0
func fix32(x int) raster.Fix32 {
	return raster.Fix32(x << 8)
}
Exemplo n.º 29
0
func pixel2fixPoint(p image.Point) raster.Point {
	return raster.Point{raster.Fix32(p.X << fixBits), raster.Fix32(p.Y << fixBits)}
}
Exemplo n.º 30
0
func pointToFix32(x float64) raster.Fix32 {
	return raster.Fix32(x * dpi * (256.0 / 72.0))
}