draw2d

package module
v0.0.0-...-cea70a7 Latest Latest
Warning

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

Go to latest
Published: Mar 28, 2017 License: BSD-2-Clause Imports: 8 Imported by: 0

README

draw2d

Coverage GoDoc

Package draw2d is a pure go 2D vector graphics library with support for multiple output devices such as images (draw2d), pdf documents (draw2dpdf) and opengl (draw2dgl), which can also be used on the google app engine. It can be used as a pure go Cairo alternative. draw2d is released under the BSD license. See the documentation for more details.

geometrypostscript

Click on an image above to get the pdf, generated with exactly the same draw2d code. The first image is the output of samples/geometry. The second image is the result of samples/postcript, which demonstrates that draw2d can draw postscript files into images or pdf documents with the ps package.

Features

Operations in draw2d include stroking and filling polygons, arcs, Bézier curves, drawing images and text rendering with truetype fonts. All drawing operations can be transformed by affine transformations (scale, rotation, translation).

Package draw2d follows the conventions of the HTML Canvas 2D Context for coordinate system, angles, etc...

Installation

Install golang. To install or update the package draw2d on your system, run:

Stable release

go get -u gopkg.in/llgcode/draw2d.v1

or Current release

go get -u github.com/llgcode/draw2d

Quick Start

The following Go code generates a simple drawing and saves it to an image file with package draw2d:

package main

import (
	"github.com/llgcode/draw2d/draw2dimg"
	"image"
	"image/color"
)

func main() {
	// Initialize the graphic context on an RGBA image
	dest := image.NewRGBA(image.Rect(0, 0, 297, 210.0))
	gc := draw2dimg.NewGraphicContext(dest)

	// Set some properties
	gc.SetFillColor(color.RGBA{0x44, 0xff, 0x44, 0xff})
	gc.SetStrokeColor(color.RGBA{0x44, 0x44, 0x44, 0xff})
	gc.SetLineWidth(5)

	// Draw a closed shape
	gc.MoveTo(10, 10) // should always be called first for a new path
	gc.LineTo(100, 50)
	gc.QuadCurveTo(100, 10, 10, 10)
	gc.Close()
	gc.FillStroke()

	// Save to file
	draw2dimg.SaveToPngFile("hello.png", dest)
}

The same Go code can also generate a pdf document with package draw2dpdf:

package main

import (
	"github.com/llgcode/draw2d/draw2dpdf"
	"image/color"
)

func main() {
	// Initialize the graphic context on an RGBA image
	dest := draw2dpdf.NewPdf("L", "mm", "A4")
	gc := draw2dpdf.NewGraphicContext(dest)

	// Set some properties
	gc.SetFillColor(color.RGBA{0x44, 0xff, 0x44, 0xff})
	gc.SetStrokeColor(color.RGBA{0x44, 0x44, 0x44, 0xff})
	gc.SetLineWidth(5)

	// Draw a closed shape
	gc.MoveTo(10, 10) // should always be called first for a new path
	gc.LineTo(100, 50)
	gc.QuadCurveTo(100, 10, 10, 10)
	gc.Close()
	gc.FillStroke()

	// Save to file
	draw2dpdf.SaveToPdfFile("hello.pdf", dest)
}

There are more examples here: https://github.com/llgcode/draw2d/tree/master/samples

Drawing on opengl is provided by the draw2dgl package.

Testing

The samples are run as tests from the root package folder draw2d by:

go test ./...

Or if you want to run with test coverage:

go test -cover ./... | grep -v "no test"

This will generate output by the different backends in the output folder.

Acknowledgments

Laurent Le Goff wrote this library, inspired by Postscript and HTML5 canvas. He implemented the image and opengl backend with the freetype-go package. Also he created a pure go Postscript interpreter, which can read postscript images and draw to a draw2d graphic context. Stani Michiels implemented the pdf backend with the gofpdf package.

Packages using draw2d

  • ps: Postscript interpreter written in Go
  • gonum/plot: drawing plots in Go
  • go.uik: a concurrent UI kit written in pure go.
  • smartcrop: content aware image cropping
  • karta: drawing Voronoi diagrams
  • chart: basic charts in Go
  • hilbert: package for drawing Hilbert curves

References

Documentation

Overview

Package draw2d is a pure go 2D vector graphics library with support for multiple output devices such as images (draw2d), pdf documents (draw2dpdf) and opengl (draw2dgl), which can also be used on the google app engine. It can be used as a pure go Cairo alternative. draw2d is released under the BSD license.

Features

Operations in draw2d include stroking and filling polygons, arcs, Bézier curves, drawing images and text rendering with truetype fonts. All drawing operations can be transformed by affine transformations (scale, rotation, translation).

Package draw2d follows the conventions of http://www.w3.org/TR/2dcontext for coordinate system, angles, etc...

Installation

To install or update the package draw2d on your system, run:

go get -u github.com/llgcode/draw2d

Quick Start

Package draw2d itself provides a graphic context that can draw vector graphics and text on an image canvas. The following Go code generates a simple drawing and saves it to an image file:

package main

import (
	"github.com/llgcode/draw2d/draw2dimg"
	"image"
	"image/color"
)

func main() {
	// Initialize the graphic context on an RGBA image
	dest := image.NewRGBA(image.Rect(0, 0, 297, 210.0))
	gc := draw2dimg.NewGraphicContext(dest)

	// Set some properties
	gc.SetFillColor(color.RGBA{0x44, 0xff, 0x44, 0xff})
	gc.SetStrokeColor(color.RGBA{0x44, 0x44, 0x44, 0xff})
	gc.SetLineWidth(5)

	// Draw a closed shape
	gc.MoveTo(10, 10) // should always be called first for a new path
	gc.LineTo(100, 50)
	gc.QuadCurveTo(100, 10, 10, 10)
	gc.Close()
	gc.FillStroke()

	// Save to file
	draw2dimg.SaveToPngFile("hello.png", dest)
}

There are more examples here: https://github.com/llgcode/draw2d/tree/master/samples

Drawing on pdf documents is provided by the draw2dpdf package. Drawing on opengl is provided by the draw2dgl package. See subdirectories at the bottom of this page.

Testing

The samples are run as tests from the root package folder `draw2d` by:

go test ./...

Or if you want to run with test coverage:

go test -cover ./... | grep -v "no test"

This will generate output by the different backends in the output folder.

Acknowledgments

Laurent Le Goff wrote this library, inspired by Postscript and HTML5 canvas. He implemented the image and opengl backend with the freetype-go package. Also he created a pure go Postscript interpreter, which can read postscript images and draw to a draw2d graphic context (https://github.com/llgcode/ps). Stani Michiels implemented the pdf backend with the gofpdf package.

Packages using draw2d

- https://github.com/llgcode/ps: Postscript interpreter written in Go

- https://github.com/gonum/plot: drawing plots in Go

- https://github.com/muesli/smartcrop: content aware image cropping

- https://github.com/peterhellberg/karta: drawing Voronoi diagrams

- https://github.com/vdobler/chart: basic charts in Go

Index

Constants

View Source
const (
	// HalignLeft Horizontally align to left
	HalignLeft = iota
	// HalignCenter Horizontally align to center
	HalignCenter
	// HalignRight Horizontally align to right
	HalignRight
)

Variables

This section is empty.

Functions

func FontFileName

func FontFileName(fontData FontData) string

func GetFont

func GetFont(fontData FontData) (font *truetype.Font)

func GetFontFolder

func GetFontFolder() string

func RegisterFont

func RegisterFont(fontData FontData, font *truetype.Font)

func SetFontCache

func SetFontCache(cache FontCache)

Changes the font cache backend used by the package. After calling this functionSetFontFolder and SetFontNamer will not affect anymore how fonts are loaded. To restore the default font cache, call this function passing nil as argument.

func SetFontFolder

func SetFontFolder(folder string)

func SetFontNamer

func SetFontNamer(fn FontFileNamer)

Types

type FillRule

type FillRule int

FillRule defines the type for fill rules

const (
	// FillRuleEvenOdd determines the "insideness" of a point in the shape
	// by drawing a ray from that point to infinity in any direction
	// and counting the number of path segments from the given shape that the ray crosses.
	// If this number is odd, the point is inside; if even, the point is outside.
	FillRuleEvenOdd FillRule = iota
	// FillRuleWinding determines the "insideness" of a point in the shape
	// by drawing a ray from that point to infinity in any direction
	// and then examining the places where a segment of the shape crosses the ray.
	// Starting with a count of zero, add one each time a path segment crosses
	// the ray from left to right and subtract one each time
	// a path segment crosses the ray from right to left. After counting the crossings,
	// if the result is zero then the point is outside the path. Otherwise, it is inside.
	FillRuleWinding
)

type FontCache

type FontCache interface {
	// Loads a truetype font represented by the FontData object passed as
	// argument.
	// The method returns an error if the font could not be loaded, either
	// because it didn't exist or the resource it was loaded from was corrupted.
	Load(FontData) (*truetype.Font, error)

	// Sets the truetype font that will be returned by Load when given the font
	// data passed as first argument.
	Store(FontData, *truetype.Font)
}

Types implementing this interface can be passed to SetFontCache to change the way fonts are being stored and retrieved.

type FontData

type FontData struct {
	Name   string
	Family FontFamily
	Style  FontStyle
}

type FontFamily

type FontFamily byte
const (
	FontFamilySans FontFamily = iota
	FontFamilySerif
	FontFamilyMono
)

type FontFileNamer

type FontFileNamer func(fontData FontData) string

type FontStyle

type FontStyle byte

FontStyle defines bold and italic styles for the font It is possible to combine values for mixed styles, eg.

FontData.Style = FontStyleBold | FontStyleItalic
const (
	FontStyleNormal FontStyle = iota
	FontStyleBold
	FontStyleItalic
)

type GraphicContext

type GraphicContext interface {
	// PathBuilder describes the interface for path drawing
	PathBuilder
	// BeginPath creates a new path
	BeginPath()
	// GetPath copies the current path, then returns it
	GetPath() Path
	// GetMatrixTransform returns the current transformation matrix
	GetMatrixTransform() Matrix
	// SetMatrixTransform sets the current transformation matrix
	SetMatrixTransform(tr Matrix)
	// ComposeMatrixTransform composes the current transformation matrix with tr
	ComposeMatrixTransform(tr Matrix)
	// Rotate applies a rotation to the current transformation matrix. angle is in radian.
	Rotate(angle float64)
	// Translate applies a translation to the current transformation matrix.
	Translate(tx, ty float64)
	// Scale applies a scale to the current transformation matrix.
	Scale(sx, sy float64)
	// SetStrokeColor sets the current stroke color
	SetStrokeColor(c color.Color)
	// SetFillColor sets the current fill color
	SetFillColor(c color.Color)
	// SetFillRule sets the current fill rule
	SetFillRule(f FillRule)
	// SetLineWidth sets the current line width
	SetLineWidth(lineWidth float64)
	// SetLineCap sets the current line cap
	SetLineCap(cap LineCap)
	// SetLineJoin sets the current line join
	SetLineJoin(join LineJoin)
	// SetLineDash sets the current dash
	SetLineDash(dash []float64, dashOffset float64)
	// SetFontSize sets the current font size
	SetFontSize(fontSize float64)
	// GetFontSize gets the current font size
	GetFontSize() float64
	// SetFontData sets the current FontData
	SetFontData(fontData FontData)
	// GetFontData gets the current FontData
	GetFontData() FontData
	// GetFontName gets the current FontData as a string
	GetFontName() string
	// DrawImage draws the raster image in the current canvas
	DrawImage(image image.Image)
	// Save the context and push it to the context stack
	Save()
	// Restore remove the current context and restore the last one
	Restore()
	// Clear fills the current canvas with a default transparent color
	Clear()
	// ClearRect fills the specified rectangle with a default transparent color
	ClearRect(x1, y1, x2, y2 int)
	// SetDPI sets the current DPI
	SetDPI(dpi int)
	// GetDPI gets the current DPI
	GetDPI() int
	// GetStringBounds gets pixel bounds(dimensions) of given string
	GetStringBounds(s string) (left, top, right, bottom float64)
	// CreateStringPath creates a path from the string s at x, y
	CreateStringPath(text string, x, y float64) (cursor float64)
	// FillString draws the text at point (0, 0)
	FillString(text string) (cursor float64)
	// FillStringAt draws the text at the specified point (x, y)
	FillStringAt(text string, x, y float64) (cursor float64)
	// StrokeString draws the contour of the text at point (0, 0)
	StrokeString(text string) (cursor float64)
	// StrokeStringAt draws the contour of the text at point (x, y)
	StrokeStringAt(text string, x, y float64) (cursor float64)
	// Stroke strokes the paths with the color specified by SetStrokeColor
	Stroke(paths ...*Path)
	// Fill fills the paths with the color specified by SetFillColor
	Fill(paths ...*Path)
	// FillStroke first fills the paths and than strokes them
	FillStroke(paths ...*Path)
}

GraphicContext describes the interface for the various backends (images, pdf, opengl, ...)

type Halign

type Halign int

Halign Horizontal Alignment of the text

type ImageScaling

type ImageScaling struct {
	// Horizontal Alignment of the image
	Halign Halign
	// Vertical Alignment of the image
	Valign Valign
	// Width Height used by scaling policy
	Width, Height float64
	// ScalingPolicy defines the scaling policy to applied to the image
	ScalingPolicy ScalingPolicy
}

ImageScaling style attributes used to display the image

type LineCap

type LineCap int

LineCap is the style of line extremities

const (
	// RoundCap defines a rounded shape at the end of the line
	RoundCap LineCap = iota
	// ButtCap defines a squared shape exactly at the end of the line
	ButtCap
	// SquareCap defines a squared shape at the end of the line
	SquareCap
)

type LineJoin

type LineJoin int

LineJoin is the style of segments joint

const (
	// BevelJoin represents cut segments joint
	BevelJoin LineJoin = iota
	// RoundJoin represents rounded segments joint
	RoundJoin
	// MiterJoin represents peaker segments joint
	MiterJoin
)

type Matrix

type Matrix [6]float64

Matrix represents an affine transformation

func NewIdentityMatrix

func NewIdentityMatrix() Matrix

NewIdentityMatrix creates an identity transformation matrix.

func NewMatrixFromRects

func NewMatrixFromRects(rectangle1, rectangle2 [4]float64) Matrix

NewMatrixFromRects creates a transformation matrix, combining a scale and a translation, that transform rectangle1 into rectangle2.

func NewRotationMatrix

func NewRotationMatrix(angle float64) Matrix

NewRotationMatrix creates a rotation transformation matrix. angle is in radian

func NewScaleMatrix

func NewScaleMatrix(sx, sy float64) Matrix

NewScaleMatrix creates a transformation matrix with a sx, sy scale factor

func NewTranslationMatrix

func NewTranslationMatrix(tx, ty float64) Matrix

NewTranslationMatrix creates a transformation matrix with a translation tx and ty translation parameter

func (*Matrix) Compose

func (tr *Matrix) Compose(trToCompose Matrix)

Compose multiplies trToConcat x tr

func (Matrix) Copy

func (tr Matrix) Copy() Matrix

func (Matrix) Determinant

func (tr Matrix) Determinant() float64

Determinant compute the determinant of the matrix

func (Matrix) Equals

func (tr1 Matrix) Equals(tr2 Matrix) bool

Equals tests if a two transformation are equal. A tolerance is applied when comparing matrix elements.

func (Matrix) GetScale

func (tr Matrix) GetScale() float64

GetScale computes a scale for the matrix

func (Matrix) GetScaling

func (tr Matrix) GetScaling() (x, y float64)

GetScaling

func (Matrix) GetTranslation

func (tr Matrix) GetTranslation() (x, y float64)

GetTranslation

func (*Matrix) Inverse

func (tr *Matrix) Inverse()

Inverse computes the inverse matrix

func (Matrix) InverseTransform

func (tr Matrix) InverseTransform(points []float64)

InverseTransform applies the transformation inverse matrix to the rectangle represented by the min and the max point of the rectangle

func (Matrix) InverseTransformPoint

func (tr Matrix) InverseTransformPoint(x, y float64) (xres, yres float64)

InverseTransformPoint applies the transformation inverse matrix to point. It returns the point the transformed point.

func (Matrix) IsIdentity

func (tr Matrix) IsIdentity() bool

IsIdentity tests if a transformation is the identity transformation. A tolerance is applied when comparing matrix elements.

func (Matrix) IsTranslation

func (tr Matrix) IsTranslation() bool

IsTranslation tests if a transformation is is a pure translation. A tolerance is applied when comparing matrix elements.

func (*Matrix) Rotate

func (tr *Matrix) Rotate(angle float64)

Rotate adds a rotation to the matrix. angle is in radian

func (*Matrix) Scale

func (tr *Matrix) Scale(sx, sy float64)

Scale adds a scale to the matrix

func (Matrix) Transform

func (tr Matrix) Transform(points []float64)

Transform applies the transformation matrix to points. It modify the points passed in parameter.

func (Matrix) TransformPoint

func (tr Matrix) TransformPoint(x, y float64) (xres, yres float64)

TransformPoint applies the transformation matrix to point. It returns the point the transformed point.

func (Matrix) TransformRectangle

func (tr Matrix) TransformRectangle(x0, y0, x2, y2 float64) (nx0, ny0, nx2, ny2 float64)

Transform applies the transformation matrix to the rectangle represented by the min and the max point of the rectangle

func (*Matrix) Translate

func (tr *Matrix) Translate(tx, ty float64)

Translate adds a translation to the matrix

func (Matrix) VectorTransform

func (tr Matrix) VectorTransform(points []float64)

VectorTransform applies the transformation matrix to points without using the translation parameter of the affine matrix. It modify the points passed in parameter.

type Path

type Path struct {
	// Components is a slice of PathCmp in a Path and mark the role of each points in the Path
	Components []PathCmp
	// Points are combined with Components to have a specific role in the path
	Points []float64
	// contains filtered or unexported fields
}

Path stores points

func (*Path) ArcTo

func (p *Path) ArcTo(cx, cy, rx, ry, startAngle, angle float64)

ArcTo adds an arc to the path

func (*Path) Clear

func (p *Path) Clear()

Clear reset the path

func (*Path) Close

func (p *Path) Close()

Close closes the current path

func (*Path) Copy

func (p *Path) Copy() (dest *Path)

Copy make a clone of the current path and return it

func (*Path) CubicCurveTo

func (p *Path) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64)

CubicCurveTo adds a cubic bezier curve to the current path

func (*Path) IsEmpty

func (p *Path) IsEmpty() bool

IsEmpty returns true if the path is empty

func (*Path) LastPoint

func (p *Path) LastPoint() (x, y float64)

LastPoint returns the current point of the current path

func (*Path) LineTo

func (p *Path) LineTo(x, y float64)

LineTo adds a line to the current path

func (*Path) MoveTo

func (p *Path) MoveTo(x, y float64)

MoveTo starts a new path at (x, y) position

func (*Path) QuadCurveTo

func (p *Path) QuadCurveTo(cx, cy, x, y float64)

QuadCurveTo adds a quadratic bezier curve to the current path

func (*Path) String

func (p *Path) String() string

String returns a debug text view of the path

type PathBuilder

type PathBuilder interface {
	// LastPoint returns the current point of the current sub path
	LastPoint() (x, y float64)
	// MoveTo creates a new subpath that start at the specified point
	MoveTo(x, y float64)
	// LineTo adds a line to the current subpath
	LineTo(x, y float64)
	// QuadCurveTo adds a quadratic Bézier curve to the current subpath
	QuadCurveTo(cx, cy, x, y float64)
	// CubicCurveTo adds a cubic Bézier curve to the current subpath
	CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64)
	// ArcTo adds an arc to the current subpath
	ArcTo(cx, cy, rx, ry, startAngle, angle float64)
	// Close creates a line from the current point to the last MoveTo
	// point (if not the same) and mark the path as closed so the
	// first and last lines join nicely.
	Close()
}

PathBuilder describes the interface for path drawing.

type PathCmp

type PathCmp int

PathCmp represents component of a path

const (
	// MoveToCmp is a MoveTo component in a Path
	MoveToCmp PathCmp = iota
	// LineToCmp is a LineTo component in a Path
	LineToCmp
	// QuadCurveToCmp is a QuadCurveTo component in a Path
	QuadCurveToCmp
	// CubicCurveToCmp is a CubicCurveTo component in a Path
	CubicCurveToCmp
	// ArcToCmp is a ArcTo component in a Path
	ArcToCmp
	// CloseCmp is a ArcTo component in a Path
	CloseCmp
)

type ScalingPolicy

type ScalingPolicy int

ScalingPolicy is a constant to define how to scale an image

const (
	// ScalingNone no scaling applied
	ScalingNone ScalingPolicy = iota
	// ScalingStretch the image is stretched so that its width and height are exactly the given width and height
	ScalingStretch
	// ScalingWidth the image is scaled so that its width is exactly the given width
	ScalingWidth
	// ScalingHeight the image is scaled so that its height is exactly the given height
	ScalingHeight
	// ScalingFit the image is scaled to the largest scale that allow the image to fit within a rectangle width x height
	ScalingFit
	// ScalingSameArea the image is scaled so that its area is exactly the area of the given rectangle width x height
	ScalingSameArea
	// ScalingFill the image is scaled to the smallest scale that allow the image to fully cover a rectangle width x height
	ScalingFill
)

type SolidFillStyle

type SolidFillStyle struct {
	// Color defines the line color
	Color color.Color
	// FillRule defines the file rule to used
	FillRule FillRule
}

SolidFillStyle define style attributes for a solid fill style

type StrokeStyle

type StrokeStyle struct {
	// Color defines the color of stroke
	Color color.Color
	// Line width
	Width float64
	// Line cap style rounded, butt or square
	LineCap LineCap
	// Line join style bevel, round or miter
	LineJoin LineJoin
	// offset of the first dash
	DashOffset float64
	// array represented dash length pair values are plain dash and impair are space between dash
	// if empty display plain line
	Dash []float64
}

StrokeStyle keeps stroke style attributes that is used by the Stroke method of a Drawer

type TextStyle

type TextStyle struct {
	// Color defines the color of text
	Color color.Color
	// Size font size
	Size float64
	// The font to use
	Font FontData
	// Horizontal Alignment of the text
	Halign Halign
	// Vertical Alignment of the text
	Valign Valign
}

TextStyle describe text property

type Valign

type Valign int

Valign Vertical Alignment of the text

const (
	// ValignTop top align text
	ValignTop Valign = iota
	// ValignCenter centered text
	ValignCenter
	// ValignBottom bottom aligned text
	ValignBottom
	// ValignBaseline align text with the baseline of the font
	ValignBaseline
)

Directories

Path Synopsis
Package draw2dgl provides a graphic context that can draw vector graphics and text on OpenGL.
Package draw2dgl provides a graphic context that can draw vector graphics and text on OpenGL.
Package draw2dkit provides helpers to draw common figures using a Path
Package draw2dkit provides helpers to draw common figures using a Path
Package draw2dpdf provides a graphic context that can draw vector graphics and text on pdf file with the gofpdf package.
Package draw2dpdf provides a graphic context that can draw vector graphics and text on pdf file with the gofpdf package.
Package samples provides examples which can be used with different backends.
Package samples provides examples which can be used with different backends.
android
Package android draws an android avatar.
Package android draws an android avatar.
frameimage
Package frameimage centers a png image and rotates it.
Package frameimage centers a png image and rotates it.
geometry
Package geometry draws some geometric tests.
Package geometry draws some geometric tests.
gopher
Package gopher draws a gopher avatar based on a svg of: https://github.com/golang-samples/gopher-vector/
Package gopher draws a gopher avatar based on a svg of: https://github.com/golang-samples/gopher-vector/
gopher2
Package gopher2 draws a gopher avatar based on a svg of: https://github.com/golang-samples/gopher-vector/
Package gopher2 draws a gopher avatar based on a svg of: https://github.com/golang-samples/gopher-vector/
helloworld
Package helloworld displays multiple "Hello World" (one rotated) in a rounded rectangle.
Package helloworld displays multiple "Hello World" (one rotated) in a rounded rectangle.
helloworldgl
Open an OpenGl window and display a rectangle using a OpenGl GraphicContext
Open an OpenGl window and display a rectangle using a OpenGl GraphicContext
line
Package line draws vertically spaced lines.
Package line draws vertically spaced lines.
linecapjoin
Package linecapjoin demonstrates the different line caps and joins.
Package linecapjoin demonstrates the different line caps and joins.
postscript
Package postscript reads the tiger.ps file and draws it to a backend.
Package postscript reads the tiger.ps file and draws it to a backend.
postscriptgl
Open a OpenGL window and display a tiger interpreting a postscript file
Open a OpenGL window and display a tiger interpreting a postscript file

Jump to

Keyboard shortcuts

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