// initLayout constructs two masks for drawing the battery and the remaining // energy as well as sets the pixel bounds for drawing energy capacity. the // masks allow for simplified space-fills and reduced chance of pixel gaps. func (app *App) initLayout() { var zeropt image.Point rectOutTop := image.Rectangle{Min: app.Layout.battRect.Min, Max: app.Layout.battRect.Min.Add(image.Point{2, 2})} rectOutBottom := rectOutTop.Add(image.Point{Y: app.Layout.battRect.Size().Y - rectOutTop.Size().Y}) capRect := image.Rectangle{ Min: image.Point{X: rectOutTop.Min.X, Y: rectOutTop.Max.Y}, Max: image.Point{X: rectOutBottom.Max.X, Y: rectOutBottom.Min.Y}, } bodyRect := app.Layout.battRect bodyRect.Min.X = capRect.Max.X // energy will be drawn under the battery shell. The only place where it // is not safe to draw energy is outside the battery on the positive end. energyMask := image.NewAlpha(app.Layout.battRect) draw.Draw(energyMask, app.Layout.battRect, opaque, zeropt, draw.Over) draw.Draw(energyMask, rectOutTop, transparent, zeropt, draw.Src) draw.Draw(energyMask, rectOutBottom, transparent, zeropt, draw.Src) app.maskEnergy = energyMask // the body uses the same mask as the energy with additional transparency // inside the battery's shell. the mask construction is complex because // area inside the cap may be exposed. bodyMask := image.NewAlpha(app.Layout.battRect) draw.Draw(bodyMask, app.Layout.battRect, energyMask, app.Layout.battRect.Min, draw.Over) bodyMaskRect := shrinkRect(bodyRect, app.Layout.thickness) draw.Draw(bodyMask, bodyMaskRect, transparent, zeropt, draw.Src) capMaskRect := shrinkRect(capRect, app.Layout.thickness) capMaskRect.Max.X += 2 * app.Layout.thickness draw.Draw(bodyMask, capMaskRect, transparent, zeropt, draw.Src) app.maskBattery = bodyMask // create a freetype.Context to render text. each time the context is used // it must have its SetDst method called. app.tt = freetype.NewContext() app.tt.SetSrc(black) app.tt.SetClip(app.Layout.textRect) app.tt.SetDPI(app.Layout.DPI) app.tt.SetFont(app.Layout.font) app.tt.SetFontSize(app.Layout.fontSize) ttopt := &truetype.Options{ Size: app.Layout.fontSize, DPI: app.Layout.DPI, } ttface := truetype.NewFace(app.Layout.font, ttopt) app.font = &font.Drawer{ Src: black, Face: ttface, } // the rectangle in which energy is drawn needs to account for thickness to // make the visible percentage more accurate. after adjustment reduce the // energy rect to account for the account of energy drained. the energy // mask makes computing Y bounds largely irrelevant. app.minEnergy = capMaskRect.Min.X app.maxEnergy = bodyMaskRect.Max.X }
// NewDrawableSize returns a new draw.Image with the same type as p and the given bounds. // If p is not a draw.Image, another type is used. func NewDrawableSize(p image.Image, r image.Rectangle) draw.Image { switch p := p.(type) { case *image.RGBA: return image.NewRGBA(r) case *image.RGBA64: return image.NewRGBA64(r) case *image.NRGBA: return image.NewNRGBA(r) case *image.NRGBA64: return image.NewNRGBA64(r) case *image.Alpha: return image.NewAlpha(r) case *image.Alpha16: return image.NewAlpha16(r) case *image.Gray: return image.NewGray(r) case *image.Gray16: return image.NewGray16(r) case *image.Paletted: pl := make(color.Palette, len(p.Palette)) copy(pl, p.Palette) return image.NewPaletted(r, pl) case *image.CMYK: return image.NewCMYK(r) default: return image.NewRGBA(r) } }
// 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 }
// textBox renders t into a tight fitting image func (ig *ImageGraphics) textBox(t string, size int) image.Image { // Initialize the context. fg := image.NewUniform(color.Alpha{0xff}) bg := image.NewUniform(color.Alpha{0x00}) canvas := image.NewAlpha(image.Rect(0, 0, 400, 2*size)) draw.Draw(canvas, canvas.Bounds(), bg, image.ZP, draw.Src) c := freetype.NewContext() c.SetDPI(dpi) c.SetFont(ig.font) c.SetFontSize(float64(size)) c.SetClip(canvas.Bounds()) c.SetDst(canvas) c.SetSrc(fg) // Draw the text. h := c.FUnitToPixelRU(ig.font.UnitsPerEm()) pt := freetype.Pt(0, h) extent, err := c.DrawString(t, pt) if err != nil { log.Println(err) return nil } // log.Printf("text %q, extent: %v", t, extent) return canvas.SubImage(image.Rect(0, 0, int(extent.X/256), h*5/4)) }
func main() { var err error gophersImage, _, err = common.AssetImage("gophers.jpg", ebiten.FilterNearest) if err != nil { log.Fatal(err) } fiveyearsImage, _, err = common.AssetImage("fiveyears.jpg", ebiten.FilterNearest) if err != nil { log.Fatal(err) } maskImage, err = ebiten.NewImage(screenWidth, screenHeight, ebiten.FilterNearest) if err != nil { log.Fatal(err) } as := image.Point{128, 128} a := image.NewAlpha(image.Rectangle{image.ZP, as}) for j := 0; j < as.Y; j++ { for i := 0; i < as.X; i++ { r := as.X / 2 d := math.Sqrt(float64((i-r)*(i-r) + (j-r)*(j-r))) b := uint8(max(0, min(0xff, 3*0xff-int(d*3*0xff)/r))) a.SetAlpha(i, j, color.Alpha{b}) } } spotLightImage, err = ebiten.NewImageFromImage(a, ebiten.FilterNearest) if err != nil { log.Fatal(err) } if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Masking (Ebiten Demo)"); err != nil { log.Fatal(err) } }
// Save saves the texture as a PNG image. func (a *TextureAtlas) Save(file string) (err error) { fd, err := os.Create(file) if err != nil { return } defer fd.Close() rect := image.Rect(0, 0, a.width, a.height) switch a.depth { case 1: img := image.NewAlpha(rect) copy(img.Pix, a.data) err = png.Encode(fd, img) case 3: img := image.NewRGBA(rect) copy(img.Pix, a.data) err = png.Encode(fd, img) case 4: img := image.NewRGBA(rect) copy(img.Pix, a.data) err = png.Encode(fd, img) } return }
func NewImageOfTypeRect(src image.Image, bounds image.Rectangle) image.Image { switch i := src.(type) { case *image.Alpha: return image.NewAlpha(bounds) case *image.Alpha16: return image.NewAlpha16(bounds) case *image.Gray: return image.NewGray(bounds) case *image.Gray16: return image.NewGray16(bounds) case *image.NRGBA: return image.NewNRGBA(bounds) case *image.NRGBA64: return image.NewNRGBA64(bounds) case *image.Paletted: return image.NewPaletted(bounds, i.Palette) case *image.RGBA: return image.NewRGBA(bounds) case *image.RGBA64: return image.NewRGBA64(bounds) case *image.YCbCr: return image.NewYCbCr(bounds, i.SubsampleRatio) } panic("Unknown image type") }
func (c *Context) rasterize(glyph uint16, fx, fy Fix32) (*image.Alpha, image.Point, error) { if err := c.glyph.Load(c.font, c.scale, glyph, nil); err != nil { return nil, image.ZP, err } xmin := int(fx+Fix32(c.glyph.Rect.XMin<<2)) >> 8 ymin := int(fy-Fix32(c.glyph.Rect.YMax<<2)) >> 8 xmax := int(fx+Fix32(c.glyph.Rect.XMax<<2)+0xff) >> 8 ymax := int(fy-Fix32(c.glyph.Rect.YMin<<2)+0xff) >> 8 if xmin > xmax || ymin > ymax { return nil, image.ZP, errors.New("freetype negative sized glyph") } fx += Fix32(-xmin << 8) fy += Fix32(-ymin << 8) c.rast.Clear() e0 := 0 for _, e1 := range c.glyph.EndIndexArray { c.drawContour(c.glyph.AllPoints[e0:e1], fx, fy) e0 = e1 } a := image.NewAlpha(image.Rect(0, 0, xmax-xmin, ymax-ymin)) c.rast.Rast(NewAlphaSrcDrawer(a)) return a, image.Point{xmin, ymin}, nil }
// rasterize returns the advance width, glyph mask and integer-pixel offset // to render the given glyph at the given sub-pixel offsets. // The 26.6 fixed point arguments fx and fy must be in the range [0, 1). func (c *Context) rasterize(glyph truetype.Index, fx, fy fixed.Int26_6) ( fixed.Int26_6, *image.Alpha, image.Point, error) { if err := c.glyphBuf.Load(c.f, c.scale, glyph, c.hinting); err != nil { return 0, nil, image.Point{}, err } // Calculate the integer-pixel bounds for the glyph. xmin := int(fx+c.glyphBuf.Bounds.Min.X) >> 6 ymin := int(fy-c.glyphBuf.Bounds.Max.Y) >> 6 xmax := int(fx+c.glyphBuf.Bounds.Max.X+0x3f) >> 6 ymax := int(fy-c.glyphBuf.Bounds.Min.Y+0x3f) >> 6 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 -= fixed.Int26_6(xmin << 6) fy -= fixed.Int26_6(ymin << 6) // Rasterize the glyph's vectors. c.r.Clear() e0 := 0 for _, e1 := range c.glyphBuf.Ends { c.drawContour(c.glyphBuf.Points[e0:e1], fx, fy) e0 = e1 } a := image.NewAlpha(image.Rect(0, 0, xmax-xmin, ymax-ymin)) c.r.Rasterize(raster.NewAlphaSrcPainter(a)) return c.glyphBuf.AdvanceWidth, a, image.Point{xmin, ymin}, nil }
// NewFace returns a new font.Face for the given Font. func NewFace(f *Font, opts *Options) font.Face { a := &face{ f: f, hinting: opts.hinting(), scale: fixed.Int26_6(0.5 + (opts.size() * opts.dpi() * 64 / 72)), glyphCache: make([]glyphCacheEntry, opts.glyphCacheEntries()), } a.subPixelX, a.subPixelBiasX, a.subPixelMaskX = opts.subPixelsX() a.subPixelY, a.subPixelBiasY, a.subPixelMaskY = opts.subPixelsY() // Fill the cache with invalid entries. Valid glyph cache entries have fx // and fy in the range [0, 64). Valid index cache entries have rune >= 0. for i := range a.glyphCache { a.glyphCache[i].key.fy = 0xff } for i := range a.indexCache { a.indexCache[i].rune = -1 } // Set the rasterizer's bounds to be big enough to handle the largest glyph. b := f.Bounds(a.scale) xmin := +int(b.Min.X) >> 6 ymin := -int(b.Max.Y) >> 6 xmax := +int(b.Max.X+63) >> 6 ymax := -int(b.Min.Y-63) >> 6 a.maxw = xmax - xmin a.maxh = ymax - ymin a.masks = image.NewAlpha(image.Rect(0, 0, a.maxw, a.maxh*len(a.glyphCache))) a.r.SetBounds(a.maxw, a.maxh) a.p = facePainter{a} return a }
// textBox renders t into a tight fitting image func (ig *ImageGraphics) textBox(t string, font chart.Font) image.Image { // Initialize the context. fg := image.NewUniform(color.Alpha{0xff}) bg := image.NewUniform(color.Alpha{0x00}) width := ig.TextLen(t, font) size := ig.relFontsizeToPixel(font.Size) canvas := image.NewAlpha(image.Rect(0, 0, width, int(1.5*size+0.5))) draw.Draw(canvas, canvas.Bounds(), bg, image.ZP, draw.Src) c := freetype.NewContext() c.SetDPI(dpi) c.SetFont(ig.font) c.SetFontSize(size) c.SetClip(canvas.Bounds()) c.SetDst(canvas) c.SetSrc(fg) // Draw the text. h := c.FUnitToPixelRU(ig.font.UnitsPerEm()) pt := freetype.Pt(0, h) extent, err := c.DrawString(t, pt) if err != nil { log.Println(err) return nil } // log.Printf("text %q, extent: %v", t, extent) return canvas.SubImage(image.Rect(0, 0, int((extent.X+127)/256), h*5/4)) }
func createRandomImage(maxPaletteSize int) image.Image { r := image.Rectangle{Min: image.Point{0, 0}, Max: image.Point{gen.Rand(32) + 1, gen.Rand(32) + 1}} var img Image switch gen.Rand(10) { case 0: img = image.NewAlpha(r) case 1: img = image.NewAlpha16(r) case 2: img = image.NewCMYK(r) case 3: img = image.NewGray(r) case 4: img = image.NewGray16(r) case 5: img = image.NewNRGBA(r) case 6: img = image.NewNRGBA64(r) case 7: img = image.NewPaletted(r, randPalette(maxPaletteSize)) case 8: img = image.NewRGBA(r) case 9: img = image.NewRGBA64(r) default: panic("bad") } fill := gen.Rand(19) var palette []color.Color if fill == 17 { palette = randPalette(maxPaletteSize) } for y := 0; y < r.Max.Y; y++ { for x := 0; x < r.Max.X; x++ { switch { case fill <= 15: img.Set(x, y, color.RGBA64{ ^uint16(0) * uint16((fill>>0)&1), ^uint16(0) * uint16((fill>>1)&1), ^uint16(0) * uint16((fill>>2)&1), ^uint16(0) * uint16((fill>>3)&1), }) case fill == 16: img.Set(x, y, randColor()) case fill == 17: img.Set(x, y, palette[gen.Rand(len(palette))]) case fill == 18: if gen.Rand(3) != 0 { img.Set(x, y, color.RGBA64{}) } else { img.Set(x, y, randColor()) } default: panic("bad") } } } return img.(image.Image) }
func (d Draw) save() { r := raster.NewRasterizer() mask := image.NewAlpha(image.Rect(0, 0, d.Width, d.Height)) img := image.NewRGBA(image.Rect(0, 0, d.Width, d.Height)) r.Fill(mask, d.Polygons[0], false) raster.DrawSolidRGBA(img, mask, color.RGBAModel.Convert(d.Color).(color.RGBA)) savepng("_test"+d.Name+".png", img) }
// ConvertToAlpha returns an *image.Alpha instance by asserting the given // ImageReader has that type or, if it does not, using Copy to concurrently // set the color.Color values of a new *image.Alpha instance with the same // bounds. func ConvertToAlpha(src ImageReader) *image.Alpha { if dst, ok := src.(*image.Alpha); ok { return dst } dst := image.NewAlpha(src.Bounds()) Copy(dst, src) return dst }
func main() { fd, _ := os.OpenFile("log.txt", os.O_RDWR|os.O_CREATE, 0666) defer fd.Close() log.SetOutput(fd) // Draw a rounded corner that is one pixel wide. r := ft.NewRast(50, 50) r.Start(p(5, 5)) r.Add1(p(5, 25)) r.Add2(p(5, 45), p(25, 45)) r.Add1(p(45, 45)) r.Add1(p(45, 44)) r.Add1(p(26, 44)) r.Add2(p(6, 44), p(6, 24)) r.Add1(p(6, 5)) r.Add1(p(5, 5)) // Rasterize that curve multiple times at different gammas. const ( w = 600 h = 200 ) rgba := image.NewRGBA(image.Rect(0, 0, w, h)) draw.Draw(rgba, image.Rect(0, 0, w, h/2), image.Black, image.ZP, draw.Src) draw.Draw(rgba, image.Rect(0, h/2, w, h), image.White, image.ZP, draw.Src) mask := image.NewAlpha(image.Rect(0, 0, 50, 50)) drawer := ft.NewAlphaSrcDrawer(mask) gammas := []float64{1.0 / 10.0, 1.0 / 3.0, 1.0 / 2.0, 2.0 / 3.0, 4.0 / 5.0, 1.0, 5.0 / 4.0, 3.0 / 2.0, 2.0, 3.0, 10.0} for i, g := range gammas { draw.Draw(mask, mask.Bounds(), image.Transparent, image.ZP, draw.Src) r.Rast(ft.NewGammaCorrectionDrawer(drawer, g)) x, y := 50*i+25, 25 draw.DrawMask(rgba, image.Rect(x, y, x+50, y+50), image.White, image.ZP, mask, image.ZP, draw.Over) y += 100 draw.DrawMask(rgba, image.Rect(x, y, x+50, y+50), image.Black, image.ZP, mask, image.ZP, draw.Over) } // 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, rgba) 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.") }
func vgradAlpha(alpha int) image.Image { m := image.NewAlpha(16, 16) for y := 0; y < 16; y++ { for x := 0; x < 16; x++ { m.Set(x, y, image.AlphaColor{uint8(y * alpha / 15)}) } } return m }
func vgradAlpha(alpha int) image.Image { m := image.NewAlpha(image.Rect(0, 0, 16, 16)) for y := 0; y < 16; y++ { for x := 0; x < 16; x++ { m.Set(x, y, color.Alpha{uint8(y * alpha / 15)}) } } return m }
func (self *face) Glyph(dot fixed.Point26_6, char rune) (dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) { var bounds fixed.Rectangle26_6 var cached bool var cachedGlyph glyph if cachedGlyph, cached = self.cache.get(char); cached { bounds, advance, mask = cachedGlyph.bounds, cachedGlyph.advance, cachedGlyph.mask } if bounds == (fixed.Rectangle26_6{}) || advance == 0 { if bounds, advance, ok = self.GlyphBounds(char); !ok { return } } offset := fixed.Point26_6{ X: abs26_6(bounds.Min.X), Y: self.metrics.Ascent, } origin := C.CGPoint{ x: C.CGFloat(f64(offset.X)), y: C.CGFloat(f64(offset.Y)), } dx := (int(bounds.Max.X+offset.X) >> 6) + 1 dy := (int(self.metrics.Ascent+self.metrics.Descent) >> 6) + 1 dr.Min.X = (int(dot.X) >> 6) - int(origin.x) dr.Min.Y = (int(dot.Y) >> 6) - int(origin.y) dr.Max.X = dr.Min.X + dx dr.Max.Y = dr.Min.Y + dy if mask == nil { alpha := image.NewAlpha(image.Rect(0, 0, dx, dy)) if !C.CTFontGlyphDraw__( self.ref, C.UTF32Char(char), origin, (*C.UInt8)(unsafe.Pointer(&alpha.Pix[0])), C.size_t(alpha.Stride), C.size_t(dx), C.size_t(dy), ) { dr, advance = image.Rectangle{}, 0 return } mask = alpha self.cache.set(glyph{rune: char, bounds: bounds, advance: advance, mask: mask}) } ok = true return }
// MaskForCharacter returns an 4x6 black-and-white image mask for // the given character. Useful for image/draw.DrawMask(). func MaskForCharacter(c byte) image.Image { mask := image.NewAlpha(image.Rect(0, 0, 4, 6)) rows := font[int(c)] for y, row := range rows { for x := uint(0); x < 4; x++ { if (row>>x)&1 > 0 { mask.Set(4-(int(x)+1), y, color.Black) } } } return mask }
func avatarImageProvider(id string, width, height int) image.Image { var r io.Reader if c := getContactForTel(id); c != nil { r = strings.NewReader(c.Photo) } if g, ok := groups[id]; ok { r = bytes.NewReader(g.Avatar) } if r == nil { return image.NewAlpha(image.Rectangle{}) } img, _, err := image.Decode(r) if err != nil { return image.NewAlpha(image.Rectangle{}) } return img }
func (d *decoder) decode(r io.Reader) (err error) { if err = d.decodeHeader(r); err != nil { return err } if err = d.decodeEntries(r); err != nil { return err } d.images = make([]image.Image, d.head.Number) for i, _ := range d.entries { e := &(d.entries[i]) data := make([]byte, e.Size+14) n, err := io.ReadFull(r, data[14:]) if err != nil && err != io.ErrUnexpectedEOF { return err } data = data[:14+n] if n > 8 && bytes.Compare(data[14:22], pngHeader) == 0 { // decode as PNG if d.images[i], err = png.Decode(bytes.NewReader(data[14:])); err != nil { return err } } else { // decode as BMP maskData := d.forgeBMPHead(data, e) if maskData != nil { data = data[:n+14-len(maskData)] } if d.images[i], err = bmp.Decode(bytes.NewReader(data)); err != nil { return err } bounds := d.images[i].Bounds() mask := image.NewAlpha(image.Rect(0, 0, bounds.Dx(), bounds.Dy())) masked := image.NewNRGBA(image.Rect(0, 0, bounds.Dx(), bounds.Dy())) for row := 0; row < int(e.Height); row++ { for col := 0; col < int(e.Width); col++ { if maskData != nil { rowSize := (int(e.Width) + 31) / 32 * 4 if (maskData[row*rowSize+col/8]>>(7-uint(col)%8))&0x01 != 1 { mask.SetAlpha(col, int(e.Height)-row-1, color.Alpha{255}) } } else { // 32-Bit rowSize := (int(e.Width)*32 + 31) / 32 * 4 offset := int(binary.LittleEndian.Uint32(data[10:14])) mask.SetAlpha(col, int(e.Height)-row-1, color.Alpha{data[offset+row*rowSize+col*4+3]}) } } } draw.DrawMask(masked, masked.Bounds(), d.images[i], bounds.Min, mask, bounds.Min, draw.Src) d.images[i] = masked } } return nil }
// Decode decodes an image from the given data. func Decode(r io.Reader) (img image.Image, err error) { defer func() { if x := recover(); x != nil { err = fmt.Errorf("Decode: %v", x) } }() br := bufio.NewReader(r) format := readS(br) width := readU(br) height := readU(br) rect := image.Rect(0, 0, int(width), int(height)) switch format { case "P1": img = image.NewAlpha(rect) decodeP1(br, img.(draw.Image), width, height) case "P2": img = image.NewGray(rect) decodeP2(br, img.(draw.Image), width, height) case "P3": img = image.NewRGBA(rect) decodeP3(br, img.(draw.Image), width, height) case "P4": img = image.NewAlpha(rect) decodeP4(br, img.(draw.Image), width, height) case "P5": img = image.NewGray(rect) decodeP5(br, img.(draw.Image), width, height) case "P6": img = image.NewRGBA(rect) decodeP6(br, img.(draw.Image), width, height) default: panic("Unknown PPM format: " + format) } return }
func TestQuadCurve(t *testing.T) { for i, curve := range testsQuadFloat64 { var p Path p.LineTo(curve[0], curve[1]) curve.Segment(&p, flattening_threshold) img := image.NewAlpha(image.Rect(0, 0, 300, 300)) raster.DrawPolyline(img, curve[:]...) raster.DrawPolyline(img, p.points...) drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...) savepng(fmt.Sprintf("_testQuad%d.png", i), img) log.Printf("Num of points: %d\n", len(p.points)) } fmt.Println() }
func TestRasterize30Degrees(t *testing.T) { z := NewRasterizer(8, 8) z.MoveTo(4, 4) z.LineTo(8, 4) z.LineTo(4, 6) z.ClosePath() dst := image.NewAlpha(z.Bounds()) z.Draw(dst, dst.Bounds(), image.Opaque, image.Point{}) if err := checkCornersCenter(dst); err != nil { t.Error(err) } }
func TestCubicCurveAdaptive(t *testing.T) { for i, curve := range testsCubicFloat64 { var p Path p.LineTo(curve[0], curve[1]) curve.AdaptiveSegment(&p, 1, 0, 0) img := image.NewAlpha(image.Rect(0, 0, 300, 300)) raster.DrawPolyline(img, curve[:]...) raster.DrawPolyline(img, p.points...) drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...) savepng(fmt.Sprintf("_testAdaptive%d.png", i), img) log.Printf("Num of points: %d\n", len(p.points)) } fmt.Println() }
func TestNewPixelGetter(t *testing.T) { var img image.Image var pg *pixelGetter img = image.NewNRGBA(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itNRGBA || pg.imgNRGBA == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter NRGBA") } img = image.NewNRGBA64(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itNRGBA64 || pg.imgNRGBA64 == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter NRGBA64") } img = image.NewRGBA(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itRGBA || pg.imgRGBA == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter RGBA") } img = image.NewRGBA64(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itRGBA64 || pg.imgRGBA64 == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter RGBA64") } img = image.NewGray(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itGray || pg.imgGray == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter Gray") } img = image.NewGray16(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itGray16 || pg.imgGray16 == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter Gray16") } img = image.NewYCbCr(image.Rect(0, 0, 1, 1), image.YCbCrSubsampleRatio422) pg = newPixelGetter(img) if pg.imgType != itYCbCr || pg.imgYCbCr == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter YCbCr") } img = image.NewUniform(color.NRGBA64{0, 0, 0, 0}) pg = newPixelGetter(img) if pg.imgType != itGeneric || pg.imgGeneric == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter Generic(Uniform)") } img = image.NewAlpha(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itGeneric || pg.imgGeneric == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter Generic(Alpha)") } }
func TestSimpleRasterizer(t *testing.T) { bounds := image.Rect(0, 0, 200, 200) img := image.NewRGBA(bounds) mask := image.NewAlpha(bounds) 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} r := NewRasterizer() r.Fill(mask, poly, false) DrawSolidRGBA(img, mask, rgba) savepng("_testSimpleRasterizer.png", img) }
func TestRasterizeAlmostAxisAligned(t *testing.T) { z := NewRasterizer(8, 8) z.MoveTo(2, 2) z.LineTo(6, math.Nextafter32(2, 0)) z.LineTo(6, 6) z.LineTo(math.Nextafter32(2, 0), 6) z.ClosePath() dst := image.NewAlpha(z.Bounds()) z.Draw(dst, dst.Bounds(), image.Opaque, image.Point{}) if err := checkCornersCenter(dst); err != nil { t.Error(err) } }
func BenchmarkRasterizerNonZeroWinding(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) rgba := color.RGBA{0, 0, 0, 0xff} rasterizer := NewRasterizer() for i := 0; i < b.N; i++ { bounds := image.Rect(0, 0, 200, 200) img := image.NewRGBA(bounds) mask := image.NewAlpha(bounds) rasterizer.Fill(mask, poly, true) DrawSolidRGBA(img, mask, rgba) } }
func BenchmarkSimpleRasterizerNonZero(b *testing.B) { 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} rasterizer := NewRasterizer() for i := 0; i < b.N; i++ { bounds := image.Rect(0, 0, 200, 200) img := image.NewRGBA(bounds) mask := image.NewAlpha(bounds) rasterizer.Fill(mask, poly, true) DrawSolidRGBA(img, mask, rgba) } }