Example #1
0
// Text takes an image and, using the freetype package, writes text in the
// position specified on to the image. A color.Color, a font size and a font
// must also be specified.
// Finally, the (x, y) coordinate advanced by the text extents is returned.
//
// Note that the ParseFont helper function can be used to get a *truetype.Font
// value without having to import freetype-go directly.
//
// If you need more control over the 'context' used to draw text (like the DPI),
// then you'll need to ignore this convenience method and use your own.
func (im *Image) Text(x, y int, clr color.Color, fontSize float64,
	font *truetype.Font, text string) (int, int, error) {

	// Create a solid color image
	textClr := image.NewUniform(clr)

	// Set up the freetype context... mostly boiler plate
	c := ftContext(font, fontSize)
	c.SetClip(im.Bounds())
	c.SetDst(im)
	c.SetSrc(textClr)

	// Now let's actually draw the text...
	pt := freetype.Pt(x, y+int(c.PointToFix32(fontSize)>>8))
	newpt, err := c.DrawString(text, pt)
	if err != nil {
		return 0, 0, err
	}

	return int(newpt.X / 256), int(newpt.Y / 256), nil
}
Example #2
0
func (s *diagram) png(w io.Writer) {
	aaLen, _ := s.g.Length.Int64()
	scale := (s.GraphicWidth - s.Padding*2) / float64(aaLen)
	aaSpace := int((20 * s.dpi / 72.0) / scale)

	img := image.NewRGBA(image.Rect(0, 0, int(s.GraphicWidth), int(s.GraphicHeight)))
	drawRectWH(img, 0, 0, s.GraphicWidth, s.GraphicHeight, color.White)

	fontContext.SetDst(img)
	fontContext.SetClip(img.Bounds())
	fontContext.SetFontSize(10.0)

	//////

	startY := s.startY
	poptop := startY + s.LollipopRadius
	popbot := poptop + s.LollipopHeight
	fontContext.SetSrc(&image.Uniform{color.Black})

	firstLollipop := true
	for _, pop := range s.ticks {
		if !pop.isLollipop {
			continue
		}
		if firstLollipop {
			firstLollipop = false
			startY = popbot - (s.DomainHeight-s.BackboneHeight)/2
		}

		c := color.RGBA{0xBA, 0xBD, 0xB6, 0xFF}
		thickvline(img, int(pop.x-s.dpi/144), int(pop.y), int(popbot), 2*s.dpi/72.0, c)
		drawCircle(img, int(pop.x+s.dpi/144), int(pop.y), int(pop.r), colorFromHex(pop.Col))

		if s.ShowLabels {
			chg := pop.label
			if pop.Cnt > 1 {
				chg = fmt.Sprintf("%s (%d)", chg, pop.Cnt)
			}

			// FIXME: rotate label to match SVG output
			w, _, _ := fontContext.MeasureString(chg)
			fontContext.DrawString(chg, freetype.Pt(
				int(pop.x-(float64(freetype.Pixel(w))/2.0)),
				int(pop.y-(pop.r*1.5)),
			))
		}
	}

	// draw the backbone
	drawRectWH(img, s.Padding, startY+(s.DomainHeight-s.BackboneHeight)/2, s.GraphicWidth-(s.Padding*2),
		s.BackboneHeight, color.RGBA{0xBA, 0xBD, 0xB6, 0xFF})

	if !s.HideMotifs {
		disFill := color.RGBA{0, 0, 0, 38} // 15% opacity

		// draw transmembrane, signal peptide, coiled-coil, etc motifs
		for _, r := range s.g.Motifs {
			if r.Type == "pfamb" {
				continue
			}
			if r.Type == "disorder" && s.HideDisordered {
				continue
			}
			sstart, _ := r.Start.Float64()
			swidth, _ := r.End.Float64()

			sstart *= scale
			swidth = (swidth * scale) - sstart

			if r.Type == "disorder" {
				// draw disordered regions with a understated diagonal hatch pattern
				drawRectWH(img, s.Padding+sstart, startY+(s.DomainHeight-s.BackboneHeight)/2,
					swidth, s.BackboneHeight, disFill)
			} else {
				drawRectWHShadow(img, s.Padding+sstart, startY+(s.DomainHeight-s.MotifHeight)/2,
					swidth, s.MotifHeight, colorFromHex(BlendColorStrings(r.Color, "#FFFFFF")),
					2*s.dpi/72.0)
			}
		}
	}

	fontContext.SetSrc(&image.Uniform{color.White})
	fontContext.SetFontSize(12.0)
	// get font height in px assuming ~2pt descender
	fontH := float64(freetype.Pixel(fontContext.PointToFix32(10.0)))

	// draw the curated domains
	for ri, r := range s.g.Regions {
		sstart, _ := r.Start.Float64()
		swidth, _ := r.End.Float64()

		sstart *= scale
		swidth = (swidth * scale) - sstart

		drawRectWHShadow(img, s.Padding+sstart, startY, swidth, s.DomainHeight, colorFromHex(r.Color), 2*s.dpi/72.0)

		if swidth > 10 && s.domainLabels[ri] != "" {
			// center text at x
			w, _, _ := fontContext.MeasureString(s.domainLabels[ri])
			fontContext.DrawString(s.domainLabels[ri], freetype.Pt(
				int(s.Padding+sstart+((swidth-float64(freetype.Pixel(w)))/2.0)),
				int(startY+s.DomainHeight/2+fontH/2),
			))
		}
	}

	if !s.HideAxis {
		startY += s.DomainHeight + s.AxisPadding
		thickhline(img, int(s.Padding), int(s.GraphicWidth-s.Padding+s.dpi/36.0), int(startY), s.dpi/72.0, color.Gray{0xAA})
		thickvline(img, int(s.Padding), int(startY), int(startY+(s.AxisHeight/3)), s.dpi/72.0, color.Gray{0xAA})

		// set black 10px font
		fontContext.SetFontSize(10.0)
		fontContext.SetSrc(&image.Uniform{color.Black})

		lastDrawn := 0
		for i, t := range s.ticks {
			if lastDrawn > 0 && (t.Pos-lastDrawn) < aaSpace {
				continue
			}
			j := s.ticks.NextBetter(i, aaSpace)
			if i != j {
				continue
			}
			lastDrawn = t.Pos
			x := s.Padding + (float64(t.Pos) * scale)
			thickvline(img, int(x), int(startY), int(startY+(s.AxisHeight/3)), s.dpi/72.0, color.Gray{0xAA})

			// center text at x
			spos := fmt.Sprint(t.Pos)
			w, _, _ := fontContext.MeasureString(spos)
			fontContext.DrawString(spos, freetype.Pt(int(x-float64(freetype.Pixel(w))/2.0), int(startY+s.AxisHeight)))
		}
	}

	png.Encode(w, img)
}