// Draw renders the given cpu cores on img. func (app *App) Draw(img draw.Image, cpus []CPU) { rect := img.Bounds() bg := app.Background if bg == nil { bg = image.Black } draw.Draw(img, rect, bg, bg.Bounds().Min, draw.Over) if len(cpus) == 0 { return } cpuDx := rect.Dx() / len(cpus) ptIncr := image.Point{X: cpuDx} ptDelta := image.Point{} rectDx := image.Rectangle{ Min: rect.Min, Max: rect.Max, } rectDx.Max.X = rect.Min.X + cpuDx for _, cpu := range cpus { irect := image.Rectangle{ Min: rectDx.Min.Add(ptDelta), Max: rectDx.Max.Add(ptDelta), } subimg := SubImage(img, irect) app.renderCPU(subimg, cpu) ptDelta = ptDelta.Add(ptIncr) } }
func gennoise(screen draw.Image) { for y := 0; y < 240; y++ { for x := 0; x < 320; x++ { screen.Set(x, y, <-randcol) } } }
func (p *Drawer) PasteAt(img draw.Image, pt P) { flr := pt.Floor() bounds := img.Bounds() dp := image.Point{flr[0], flr[1]} rec := bounds.Sub(bounds.Min).Add(dp) draw.Draw(p.Img, rec, img, bounds.Min, draw.Over) }
// Thumbnail scales and crops src so it fits in dst. func Thumbnail(dst draw.Image, src image.Image) error { // Scale down src in the dimension that is closer to dst. sb := src.Bounds() db := dst.Bounds() rx := float64(sb.Dx()) / float64(db.Dx()) ry := float64(sb.Dy()) / float64(db.Dy()) var b image.Rectangle if rx < ry { b = image.Rect(0, 0, db.Dx(), int(float64(sb.Dy())/rx)) } else { b = image.Rect(0, 0, int(float64(sb.Dx())/ry), db.Dy()) } buf := image.NewRGBA(b) if err := Scale(buf, src); err != nil { return err } // Crop. // TODO(crawshaw): improve on center-alignment. var pt image.Point if rx < ry { pt.Y = (b.Dy() - db.Dy()) / 2 } else { pt.X = (b.Dx() - db.Dx()) / 2 } draw.Draw(dst, db, buf, pt, draw.Src) return nil }
func line(img draw.Image, a, b image.Point, c color.Color) { minx, maxx := minmax(a.X, b.X) miny, maxy := minmax(a.Y, b.Y) Δx := float64(b.X - a.X) Δy := float64(b.Y - a.Y) if maxx-minx > maxy-miny { d := 1 if a.X > b.X { d = -1 } for x := 0; x != b.X-a.X+d; x += d { y := int(float64(x) * Δy / Δx) img.Set(a.X+x, a.Y+y, c) } } else { d := 1 if a.Y > b.Y { d = -1 } for y := 0; y != b.Y-a.Y+d; y += d { x := int(float64(y) * Δx / Δy) img.Set(a.X+x, a.Y+y, c) } } }
// http://en.wikipedia.org/wiki/Bresenham's_line_algorithm#Simplification func line(x0, y0, x1, y1 int, c color.Color, img draw.Image) { var dx = abs(x1 - x0) var dy = abs(y1 - y0) var err = dx - dy var sx, sy = 1, 1 if x0 > x1 { sx = -1 } if y0 > y1 { sy = -1 } img.Set(x0, y0, c) for x0 != x1 || y0 != y1 { var e2 = 2 * err if e2 > -dy { err -= dy x0 += sx } if e2 < dx { err += dx y0 += sy } img.Set(x0, y0, c) } }
func Bresenham(img draw.Image, color color.Color, x0, y0, x1, y1 int) { dx := abs(x1 - x0) dy := abs(y1 - y0) var sx, sy int if x0 < x1 { sx = 1 } else { sx = -1 } if y0 < y1 { sy = 1 } else { sy = -1 } err := dx - dy var e2 int for { img.Set(x0, y0, color) if x0 == x1 && y0 == y1 { return } e2 = 2 * err if e2 > -dy { err = err - dy x0 = x0 + sx } if e2 < dx { err = err + dx y0 = y0 + sy } } }
// NewImage returns a new image canvas // that draws to the given image. The // minimum point of the given image // should probably be 0,0. func NewImage(img draw.Image, name string) (*Canvas, error) { w := float64(img.Bounds().Max.X - img.Bounds().Min.X) h := float64(img.Bounds().Max.Y - img.Bounds().Min.Y) X, err := xgbutil.NewConn() if err != nil { return nil, err } keybind.Initialize(X) ximg := xgraphics.New(X, image.Rect(0, 0, int(w), int(h))) err = ximg.CreatePixmap() if err != nil { return nil, err } painter := NewPainter(ximg) gc := draw2d.NewGraphicContextWithPainter(ximg, painter) gc.SetDPI(dpi) gc.Scale(1, -1) gc.Translate(0, -h) wid := ximg.XShowExtra(name, true) go func() { xevent.Main(X) }() c := &Canvas{ Canvas: vgimg.NewWith(vgimg.UseImageWithContext(img, gc)), x: X, ximg: ximg, wid: wid, } vg.Initialize(c) return c, nil }
// decodeP6 reads a binary pixmap func decodeP6(r *bufio.Reader, img draw.Image, width, height uint) { var x, y, pix int mask := byte(readU(r)) mul := 255 / mask data := make([]byte, width*height*3) space(r) _, err := r.Read(data) check(err) for y = 0; y < int(height); y++ { for x = 0; x < int(width); x++ { img.Set(x, y, color.RGBA{ (data[pix] & mask) * mul, (data[pix+1] & mask) * mul, (data[pix+2] & mask) * mul, 0xff, }) pix += 3 } } }
func (ff *FontFace) GetImage(text string) (img draw.Image, err error) { var ( src image.Image bg image.Image dst draw.Image pt fixed.Point26_6 w int h int ) src = image.NewUniform(ff.fg) bg = image.NewUniform(ff.bg) w = int(float32(len(text)) * ff.charw) h = int(ff.charh) dst = image.NewRGBA(image.Rect(0, 0, w, h)) draw.Draw(dst, dst.Bounds(), bg, image.ZP, draw.Src) ff.context.SetSrc(src) ff.context.SetDst(dst) ff.context.SetClip(dst.Bounds()) pt = freetype.Pt(0, int(ff.charh+ff.offy)) if pt, err = ff.context.DrawString(text, pt); err != nil { return } img = image.NewRGBA(image.Rect(0, 0, int(pt.X/64), int(pt.Y/64))) draw.Draw(img, img.Bounds(), dst, image.Pt(0, -int(ff.offy)), draw.Src) return }
// decodeP4 reads a binary bitmap func decodeP4(r *bufio.Reader, img draw.Image, width, height uint) { var x, y, bit int bytes := int(math.Ceil((float64(width) / 8))) bits := newBitset(uint(bytes) * height * 8) pad := (bytes * 8) - int(width) space(r) _, err := r.Read(bits) check(err) for y = 0; y < int(height); y++ { for x = 0; x < int(width); x++ { if bits.Test(bit) { img.Set(x, y, color.Alpha{0xff}) } else { img.Set(x, y, color.Alpha{0x00}) } bit++ } bit += pad } }
// Convolve produces dst by applying the convolution kernel k to src. func Convolve(dst draw.Image, src image.Image, k Kernel) (err error) { if dst == nil || src == nil || k == nil { return nil } b := dst.Bounds() dstRgba, ok := dst.(*image.RGBA) if !ok { dstRgba = image.NewRGBA(b) } switch k := k.(type) { case *SeparableKernel: err = convolveRGBASep(dstRgba, src, k) default: err = convolveRGBA(dstRgba, src, k) } if err != nil { return err } if !ok { draw.Draw(dst, b, dstRgba, b.Min, draw.Src) } return nil }
// NewFromImage uses the given image as the destination for all calls to Add. // It is assumed to be empty at the beginning so all the available space will be // used for sub-images. func NewFromImage(atlas draw.Image) *Atlas { packer := binpacker.New(atlas.Bounds().Dx(), atlas.Bounds().Dy()) return &Atlas{ Image: atlas, packer: packer, } }
// 翻转函数,要求两个图像大小契合,act&1 == 0则左右翻转,否则垂直翻转。 func Overturn(dst draw.Image, src image.Image, act int) error { var to func(int, int) (int, int) sr := src.Bounds() dr := dst.Bounds() W := dr.Max.X - dr.Min.X H := dr.Max.Y - dr.Min.Y if H <= 0 || W <= 0 { return errors.New("target image is empty or noncanonical") } if sr.Min.X >= sr.Max.X || sr.Min.Y >= sr.Max.Y { return errors.New("source image is empty or noncanonical") } if sr.Max.X-sr.Min.X != W || sr.Max.Y-sr.Min.Y != H { return errors.New("target and source must be same size!") } if act&1 == 0 { to = func(x, y int) (int, int) { return W - 1 - x, y } } else { to = func(x, y int) (int, int) { return x, H - 1 - y } } for i := 0; i < W; i++ { for j := 0; j < H; j++ { x, y := to(i, j) dst.Set(dr.Min.X+x, dr.Min.Y+y, src.At(sr.Min.X+i, sr.Min.Y+j)) } } return nil }
// Transform applies the affine transform to src and produces dst. func (a Affine) Transform(dst draw.Image, src image.Image, i interp.Interp) error { if dst == nil { return errors.New("graphics: dst is nil") } if src == nil { return errors.New("graphics: src is nil") } // RGBA fast path. dstRGBA, dstOk := dst.(*image.RGBA) srcRGBA, srcOk := src.(*image.RGBA) interpRGBA, interpOk := i.(interp.RGBA) if dstOk && srcOk && interpOk { return a.transformRGBA(dstRGBA, srcRGBA, interpRGBA) } srcb := src.Bounds() b := dst.Bounds() for y := b.Min.Y; y < b.Max.Y; y++ { for x := b.Min.X; x < b.Max.X; x++ { sx, sy := a.pt(x, y) if inBounds(srcb, sx, sy) { dst.Set(x, y, i.Interp(src, sx, sy)) } } } return nil }
// RenderCPU implements the Renderer interface. func (b *Border) RenderCPU(img draw.Image, cpu CPU) { rect := img.Bounds() interior := geometry.Contract(rect, b.Size) mask := MaskInside(interior) draw.DrawMask(img, rect, image.NewUniform(b.Color), image.ZP, mask, rect.Min, draw.Over) sub := SubImage(img, interior) b.Renderer.RenderCPU(sub, cpu) }
func newImageDimentions(img draw.Image, angle float64) (int, int) { bounds := img.Bounds() width := float64(bounds.Max.X - bounds.Min.X) height := float64(bounds.Max.Y - bounds.Min.Y) w, h := newDimentions(width, height, angle) return int(w), int(h) }
func testDrawRandom(p draw.Image) { bd := p.Bounds() for y, yEnd := bd.Min.Y, bd.Max.Y; y < yEnd; y++ { for x, xEnd := bd.Min.X, bd.Max.X; x < xEnd; x++ { p.Set(x, y, testRandomColor()) } } }
// decodeP1 reads an ASCII bitmap func decodeP1(r *bufio.Reader, img draw.Image, width, height uint) { var x, y int for y = 0; y < int(height); y++ { for x = 0; x < int(width); x++ { img.Set(x, y, color.Alpha{uint8(readU(r)) * 0xff}) } } }
func imageConvert(src image.Image, dest draw.Image) draw.Image { w, h := src.Bounds().Dx(), src.Bounds().Dy() for y := 0; y < h; y += 1 { for x := 0; x < w; x += 1 { dest.Set(x, y, dest.ColorModel().Convert(src.At(x, y))) } } return dest }
// MapColorInRectangle is a helper function for working on part of an image. It // takes the original image, a function to use, a image to write to, and the // bounds of the original (and therefore the final image) to act upon. func MapColorInRectangle(img image.Image, bounds image.Rectangle, dest draw.Image, f Composable) { for y := bounds.Min.Y; y < bounds.Max.Y; y++ { for x := bounds.Min.X; x < bounds.Max.X; x++ { dest.Set(x, y, f(img.At(x, y))) } } }
// TransformCenter applies the affine transform to src and produces dst. // Equivalent to // a.CenterFit(dst, src).Transform(dst, src, i). func (a Affine) TransformCenter(dst draw.Image, src image.Image, i interp.Interp) error { if dst == nil { return errors.New("graphics: dst is nil") } if src == nil { return errors.New("graphics: src is nil") } return a.CenterFit(dst.Bounds(), src.Bounds()).Transform(dst, src, i) }
// Like PixelSizeChanger, but instead of the pixel size the new image // is given. func DimensionChanger(img draw.Image, w, h int) draw.Image { b := img.Bounds().Canon() return &dimensionChanger{ Image: img, paddingX: b.Dx() % w, paddingY: b.Dy() % h, pixel: image.Rect(0, 0, b.Dx()/w, b.Dy()/h), bounds: image.Rect(0, 0, w, h), } }
// NewBackground creates a new Background object that // draws to img, and draws the actual background with bg. // The flush function, if non-nil, will be called to // whenever changes are to be made visible externally // (for example when Flush() is called. // // Note that bg is drawn with the draw.Src operation, // so it is possible to create images with a transparent // background. // func NewBackground(img draw.Image, bg image.Image, flush func(r image.Rectangle)) *Background { r := img.Bounds() return &Background{ img: img, bg: bg, r: r, flushrect: r, imgflush: flush, } }
func newSetFuncDefault(p draw.Image) SetFunc { return func(x, y int, r, g, b, a uint32) { p.Set(x, y, color.RGBA64{ R: uint16(r), G: uint16(g), B: uint16(b), A: uint16(a), }) } }
// SliceImage returns an image which is a view onto a portion of img. // The returned image has the specified width and height, // but all draw operations are clipped to r. // The origin of img is aligned with p. Where img // overlaps with r, it will be used for drawing operations. // func SliceImage(width, height int, r image.Rectangle, img draw.Image, p image.Point) draw.Image { // TODO: detect when img is itself a SliceImage and // use the underlying image directly. i := new(imageSlice) i.img = img i.r = r.Intersect(image.Rectangle{p, p.Add(img.Bounds().Size())}) //debugp("actual sliced rectangle %v\n", i.r) i.p = p return i }
// DrawLinear draws a linear gradient to dst. If the gradient vector (as // defined by x0, y0, x1, and y1) is found to be purely horizontal or purely // vertical, the appropriate optimized functions will be called. func DrawLinear(dst draw.Image, x0, y0, x1, y1 float64, stops []Stop) { if y0 == y1 && x0 != x1 { drawHLinear(dst, x0, x1, stops) return } if x0 == x1 && y0 != y1 { drawVLinear(dst, y0, y1, stops) return } if len(stops) == 0 { return } if y0 > y1 { panic(fmt.Sprintf("invalid bounds y0(%f)>y1(%f)", y0, y1)) } if x0 > x1 { panic(fmt.Sprintf("invalid bounds x0(%f)>x1(%f)", x0, x1)) } bb := dst.Bounds() width, height := bb.Dx(), bb.Dy() x0, y0 = x0*float64(width), y0*float64(height) x1, y1 = x1*float64(width), y1*float64(height) dx, dy := x1-x0, y1-y0 px0, py0 := x0-dy, y0+dx mag := math.Hypot(dx, dy) var col color.Color for y := 0; y < width; y++ { fy := float64(y) for x := 0; x < width; x++ { fx := float64(x) // is the pixel before the start of the gradient? s0 := (px0-x0)*(fy-y0) - (py0-y0)*(fx-x0) if s0 > 0 { col = stops[0].Col } else { // calculate the distance of the pixel from the first stop line u := ((fx-x0)*(px0-x0) + (fy-y0)*(py0-y0)) / (mag * mag) x2, y2 := x0+u*(px0-x0), y0+u*(py0-y0) d := math.Hypot(fx-x2, fy-y2) / mag col = getColour(d, stops) } dst.Set(x+bb.Min.X, y+bb.Min.Y, col) } } }
func (l limits) translate(p DataPoint, i draw.Image, dotsize int) (rv image.Point) { // Normalize to 0-1 x := float64(p.X()-l.Min.X()) / float64(l.Dx()) y := float64(p.Y()-l.Min.Y()) / float64(l.Dy()) // And remap to the image rv.X = int(x * float64((i.Bounds().Max.X - dotsize))) rv.Y = int((1.0 - y) * float64((i.Bounds().Max.Y - dotsize))) return }
func (burkes) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) { quantError0 := make([][3]int32, r.Dx()+4) quantError1 := make([][3]int32, r.Dx()+4) out := color.RGBA64{A: 0xffff} for y := 0; y != r.Dy(); y++ { for x := 0; x != r.Dx(); x++ { sr, sg, sb, _ := src.At(sp.X+x, sp.Y+y).RGBA() er, eg, eb := int32(sr), int32(sg), int32(sb) er = clamp(er + quantError0[x+2][0]/32) eg = clamp(eg + quantError0[x+2][1]/32) eb = clamp(eb + quantError0[x+2][2]/32) out.R = uint16(er) out.G = uint16(eg) out.B = uint16(eb) dst.Set(r.Min.X+x, r.Min.Y+y, &out) sr, sg, sb, _ = dst.At(r.Min.X+x, r.Min.Y+y).RGBA() er -= int32(sr) eg -= int32(sg) eb -= int32(sb) quantError0[x+3][0] += er * 8 quantError0[x+3][1] += eg * 8 quantError0[x+3][2] += eb * 8 quantError0[x+4][0] += er * 4 quantError0[x+4][1] += eg * 4 quantError0[x+4][2] += eb * 4 quantError1[x+0][0] += er * 2 quantError1[x+0][1] += eg * 2 quantError1[x+0][2] += eb * 2 quantError1[x+1][0] += er * 4 quantError1[x+1][1] += eg * 4 quantError1[x+1][2] += eb * 4 quantError1[x+2][0] += er * 8 quantError1[x+2][1] += eg * 8 quantError1[x+2][2] += eb * 8 quantError1[x+3][0] += er * 4 quantError1[x+3][1] += eg * 4 quantError1[x+3][2] += eb * 4 quantError1[x+4][0] += er * 2 quantError1[x+4][1] += eg * 2 quantError1[x+4][2] += eb * 2 } // Recycle the quantization error buffers. quantError0, quantError1 = quantError1, quantError0 for i := range quantError1 { quantError1[i] = [3]int32{} } } }
// RenderCPU implements the Renderer interface. func (frac *FractionRenderer) RenderCPU(img draw.Image, cpu CPU) { rect := img.Bounds() utilized := cpu.FracUtil() utilizedHeight := int(float64(rect.Dy()) * utilized) yoffset := rect.Dy() - utilizedHeight rect.Min = rect.Min.Add(image.Pt(0, yoffset)) img = SubImage(img, rect) frac.Renderer.RenderCPU(img, cpu) }