Rendering .gif in Go - go

I am trying to get a code example to work. It is from 'The GO Programming Language' (https://github.com/adonovan/gopl.io/blob/1ae3ec64947b7a5331b186f1b1138fc98c0f1c06/ch1/lissajous/main.go). When trying to view the animation, the gif doesn't get rendered. The gif rendering software reports the error:
Has the .gif standards changed since 2016 or is there something I'm doing wrong?
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
// Lissajous generates GIF animations of random Lissajous figures.
package main
import (
"image"
"image/color"
"image/gif"
"io"
"math"
"math/rand"
"os"
)
var palette = []color.Color{color.White, color.Black}
const (
whiteIndex = 0 // first color in palette
blackIndex = 1 // next color in palette
)
func main() {
lissajous(os.Stdout)
}
func lissajous(out io.Writer) {
const (
cycles = 5 // number of complete x oscillator revolutions
res = 0.001 // angular resolution
size = 100 // image canvas covers [-size..+size]
nframes = 64 // number of animation frames
delay = 8 // delay between frames in 10ms units
)
freq := rand.Float64() * 3.0 // relative frequency of y oscillator
anim := gif.GIF{LoopCount: nframes}
phase := 0.0 // phase difference
for i := 0; i < nframes; i++ {
rect := image.Rect(0, 0, 2*size+1, 2*size+1)
img := image.NewPaletted(rect, palette)
for t := 0.0; t < cycles*2*math.Pi; t += res {
x := math.Sin(t)
y := math.Sin(t*freq + phase)
img.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5),
blackIndex)
}
phase += 0.1
anim.Delay = append(anim.Delay, delay)
anim.Image = append(anim.Image, img)
}
gif.EncodeAll(out, &anim) // NOTE: ignoring encoding errors
}
The build and run commands are:
go build .\main.go
.\main.exe > out.gif

Use bufio.NewWriter
func main() {
fileName := "1.gif"
f, err3 := os.Create(fileName)
if err3 != nil {
fmt.Println("create file fail")
}
w := bufio.NewWriter(f)
lissajous(w)
w.Flush()
f.Close()
}
or
func main() {
w := bufio.NewWriter(os.Stdout)
lissajous(w)
w.Flush()
os.Stdout.Close()
}

Related

Repeating patterns in OpenSimplex noise?

I'm trying to generate a random field of stars using OpenSimplex noise, but I'm noticing repeating patterns appearing and now that I've noticed it, I can't stop noticing it. I think I've found a workaround but I still like to know why this is happening.
At the moment my code generates a 2D greyscale image using OpenSimplex noise, then sets every pixel below a threshold value to 0, so only a small, supposedly random set of "stars" are left.
Here is the generated image with a repeated pattern circled.
I'm currently using this package for the noise implementation: https://github.com/ojrac/opensimplex-go
package main
import (
"flag"
"fmt"
"image"
"image/color"
"image/png"
"math/rand"
"os"
"time"
"github.com/ojrac/opensimplex-go"
)
const (
startupMessage = "starfieldtest"
)
var (
flgSize int
flgSeed int64
flgCullThreshold float64
)
func init() {
rand.Seed(time.Now().UnixNano())
seed := rand.Int63()
flag.IntVar(&flgSize, "size", 2048, "size of the starfield")
flag.Int64Var(&flgSeed, "seed", seed, "random noise seed value")
flag.Float64Var(&flgCullThreshold, "cull", 0.998, "normalised threshold to cull values below")
}
func main() {
fmt.Println(startupMessage)
flag.Parse()
img := generate(flgSize, flgSeed, float32(flgCullThreshold))
outName := fmt.Sprintf("generated_%s.png", time.Now().Format("20060102150405"))
pngFile, err := os.OpenFile(outName, os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
panic(err)
}
defer pngFile.Close()
if err = png.Encode(pngFile, img); err != nil {
panic(err)
}
fmt.Printf("Done!\n")
}
func generate(size int, seed int64, threshold float32) *image.Gray {
noise := opensimplex.NewNormalized32(seed)
pix := image.NewGray(image.Rect(0, 0, size, size))
for y := 0; y < size; y++ {
for x := 0; x < size; x++ {
v := noise.Eval2(float32(x), float32(y))
if v < threshold {
v = 0
}
pix.SetGray(x, y, color.Gray{Y: uint8(v * 255.0)})
}
}
return pix
}
I think I can get around it by using the Eval3 function and changing depth after a certain number of pixels, but is this expected behaviour because it's only really pseudo-random, or is OpenSimplex noise not supposed to do this? I can't really find any statement by anyone knowledgeable one way or the other as to whether this is just a limitation of pseudo-random noise or a problem with the implementation.
EDIT: this still happens when I vary the depth, it seems like repeating patterns exist across all dimensions of the noise. This line however, does work (when I get rid of the dimensionality and treat it as a one long wrapped line of pixels):
v := noise.Eval2((float32(size)*float32(y))+float32(x), 0)

How to implement Custom cropping using golang

Am looking to do custom cropping on a set of images, Instead of cropping normally, using height and width i want the flexibility of getting an output image that is cropped like a polygon or an hexagon for example, Am using the library github.com/fogleman/gg, and the built in module "image", and github.com/disintegration/imaging, but I didn't find a way to customize the cropping, i also looked for an online SaaS to do this, like imgix or imageresizer.io, but they don't seem to offer that, i know golang is the right language for this maybe i didn't look hard enough, please Help
my sample Code looks like:
var image image.Image
dc := NewContext(1000, 1000)
image = imaging.Fill(profile, 800, 750, imaging.Center, imaging.Lanczos)
// Cropping needs to happen here
dc.DrawImage(image, 123, 250)
A bit longer than expected but here you have PNG image cropping with transparent background to a rectangle. You can modify the code for different shapes by changing the getPixAlpha function.
Just add the package name and it should include the imports, then add an image test.png and it should create a test-output.png
Note: You may want to make some minor modifications for using it as a service.
type Pixel struct {
R int
G int
B int
A int
}
func LogPanic(err error, msg string) {
if err != nil {
log.Printf("ERROR: %v %s", err, msg)
panic(err)
}
}
func getPixAlpha(x, y, halfWidth int) int {
if x < halfWidth-y || x > halfWidth+y {
return 0
}
if y > halfWidth+x {
return 0
}
if x > halfWidth*3-y && y > halfWidth*3-x {
return 0
}
return int(255)
}
func getPixels(file io.Reader) ([][]Pixel, error) {
img, _, err := image.Decode(file)
LogPanic(err, "error reading image")
bounds := img.Bounds()
width, height := bounds.Max.X, bounds.Max.Y
var pixels [][]Pixel
for x := 0; x < width; x++ {
var row []Pixel
for y := 0; y < height; y++ {
row = append(row, rgbaToPixel(img.At(x, y).RGBA()))
}
pixels = append(pixels, row)
}
return pixels, nil
}
func rgbaToPixel(r uint32, g uint32, b uint32, a uint32) Pixel {
return Pixel{int(r / 257), int(g / 257), int(b / 257), int(a / 257)}
}
func getRgbaPic(pixels [][]Pixel) [][]Pixel {
dx := len(pixels)
dy := len(pixels[0])
for x := 0; x < dx; x++ {
for y := 0; y < dy; y++ {
pixels[x][y].A = getPixAlpha(x, y, len(pixels)/2)
}
}
return pixels
}
func main() {
file, err := os.Open("./test.png")
LogPanic(err, "Error opening file")
defer file.Close()
pixels, err := getPixels(file)
LogPanic(err, "Error reading image")
pixels = getRgbaPic(pixels)
img := image.NewRGBA(image.Rect(0, 0, len(pixels), len(pixels[0])))
for x := 0; x < len(pixels); x++ {
for y := 0; y < len(pixels[0]); y++ {
img.Set(x, y, color.RGBA{
uint8(pixels[x][y].R),
uint8(pixels[x][y].G),
uint8(pixels[x][y].B),
uint8(pixels[x][y].A),
})
}
}
buf := &bytes.Buffer{}
err = png.Encode(buf, img)
LogPanic(err, "Error encoding")
err = ioutil.WriteFile("test-output.png", buf.Bytes(), 0666)
LogPanic(err, "Error writing file")
}

Flatbuffer serialization performance is slow compared to protobuf

With following IDL files my intention is to measure the serialization speed of Flatbuffer . I am using golang for my analysis
namespace MyFlat;
struct Vertices {
x : double;
y :double;
}
table Polygon {
polygons : [Vertices];
}
table Layer {
polygons : [Polygon];
}
root_type Layer;
Here is the code I have written for calculation
package main
import (
"MyFlat"
"fmt"
"io/ioutil"
"log"
"strconv"
"time"
flatbuffers "github.com/google/flatbuffers/go"
)
func calculation(size int, vertices int) {
b := flatbuffers.NewBuilder(0)
var polyoffset []flatbuffers.UOffsetT
rawSize := ((16 * vertices) * size) / 1024
var vec1 flatbuffers.UOffsetT
var StartedAtMarshal time.Time
var EndedAtMarshal time.Time
StartedAtMarshal = time.Now()
for k := 0; k < size; k++ {
MyFlat.PolygonStartPolygonsVector(b, vertices)
for i := 0; i < vertices; i++ {
MyFlat.CreateVertices(b, 2.0, 2.4)
}
vec1 = b.EndVector(vertices)
MyFlat.PolygonStart(b)
MyFlat.PolygonAddPolygons(b, vec1)
polyoffset = append(polyoffset, MyFlat.PolygonEnd(b))
}
MyFlat.LayerStartPolygonsVector(b, size)
for _, offset := range polyoffset {
b.PrependUOffsetT(offset)
}
vec := b.EndVector(size)
MyFlat.LayerStart(b)
MyFlat.LayerAddPolygons(b, vec)
finalOffset := MyFlat.LayerEnd(b)
b.Finish(finalOffset)
EndedAtMarshal = time.Now()
SeElaprseTime := EndedAtMarshal.Sub(StartedAtMarshal).String()
mybyte := b.FinishedBytes()
file := "/tmp/myflat_" + strconv.Itoa(size) + ".txt"
if err := ioutil.WriteFile(file, mybyte, 0644); err != nil {
log.Fatalln("Failed to write address book:", err)
}
StartedAt := time.Now()
layer := MyFlat.GetRootAsLayer(mybyte, 0)
size = layer.PolygonsLength()
obj := &MyFlat.Polygon{}
layer.Polygons(obj, 1)
for i := 0; i < obj.PolygonsLength(); i++ {
objVertices := &MyFlat.Vertices{}
obj.Polygons(objVertices, i)
fmt.Println(objVertices.X(), objVertices.Y())
}
EndedAt := time.Now()
DeElapseTime := EndedAt.Sub(StartedAt).String()
fmt.Println(size, ",", vertices, ", ", SeElaprseTime, ",", DeElapseTime, ",", (len(mybyte) / 1024), ",", rawSize)
}
func main() {
data := []int{500000, 1000000, 1500000, 3000000, 8000000}
for _, size := range data {
//calculation(size, 5)
//calculation(size, 10)
calculation(size, 20)
}
}
Problem is I find it serialization is quite slow compared to protobuff with similar idl.
For 3M polygons serialization its taking almost 4.1167037s. Where in protobuf its taking half. Deserilization time for flatbuf is very less (in micro sec). In protobuf its quite high. But still if I add both flatbuf performance is lower.
Do you see any optimized way to serialize it. Flatbuffer is having a method createBinaryVector for byte vector but there is no direct way to serialize vector of polygon from a existing a user defined type vector.
I am adding protobuf code also
syntax = 'proto3';
package myproto;
message Polygon {
repeated double v_x = 1 ;
repeated double v_y = 2 ;
}
message CADData {
repeated Polygon polygon = 1;
string layer_name = 2;
}
Go Code with protobuf
package main
import (
"fmt"
"io/ioutil"
"log"
"math/rand"
"myproto"
"strconv"
"time"
"github.com/golang/protobuf/proto"
)
func calculation(size int, vertices int) {
var comp []*myproto.Polygon
var vx []float64
var vy []float64
for i := 0; i < vertices; i++ {
r := 0 + rand.Float64()*(10-0)
vx = append(vx, r)
vy = append(vy, r/2)
}
rawSize := ((16 * vertices) * size) / 1024
StartedAtMarshal := time.Now()
for i := 0; i < size; i++ {
comp = append(comp, &myproto.Polygon{
VX: vx,
VY: vy,
})
}
pfs := &myproto.CADData{
LayerName: "Layer",
Polygon: comp,
}
data, err := proto.Marshal(pfs)
if err != nil {
log.Fatal("marshaling error: ", err)
}
EndedAtMarshal := time.Now()
SeElaprseTime := EndedAtMarshal.Sub(StartedAtMarshal).String()
file := "/tmp/myproto_" + strconv.Itoa(size) + ".txt"
if err := ioutil.WriteFile(file, data, 0644); err != nil {
log.Fatalln("Failed to write address book:", err)
}
StartedAt := time.Now()
serialized := &myproto.CADData{}
proto.Unmarshal(data, serialized)
EndedAt := time.Now()
DeElapseTime := EndedAt.Sub(StartedAt).String()
fmt.Println(size, ",", vertices, ", ", SeElaprseTime, ",", DeElapseTime, ",", (len(data) / 1024), ",", rawSize)
}
func main() {
data := []int{500000, 1000000, 1500000, 3000000, 8000000}
for _, size := range data {
// calculation(size, 5)
//calculation(size, 10)
calculation(size, 20)
}
}
The time you give, is that for serialization, de-serialization, or both?
Your de-serialization code is likely entirely dominated by fmt.Println. Why don't you instead do sum += objVertices.X() + objVertices.Y() and print sum after timing is done? Can you pull objVertices := &MyFlat.Vertices{} outside of the loop?
You didn't post your protobuf code. Are you including in the timing the time to create the tree of objects which is being serialized (which is required for use in Protobuf but not in FlatBuffers)? Similarly, are you doing the timed (de-)serialization at least a 1000x or so, so you can include the cost of GC (Protobuf allocates a LOT of objects, FlatBuffers allocates few/none) in your comparison?
If after you do the above, it is still slower, post on the FlatBuffers github issues, the authors of the Go port may be able to help further. Make sure you post full code for both systems, and full timings.
Note generally: the design of FlatBuffers is such that it will create the biggest performance gap with Protobuf in C/C++. That said, it should still be a lot faster in Go also. There are unfortunate things about Go however that prevent it from maximizing the performance potential.
b := flatbuffers.NewBuilder(0)
I'm not sure what the "grows automatically" behavior is in Go for flatbuffers, but I'm pretty sure requiring the buffer to grow automatically is not the preferred pattern. Could you try doing your same timing comparison after initializing the buffer with flatbuffers.NewBuilder(moreBytesThanTheMessageNeeds)?

How to open a image in Go to get binary data of black and white pixels?

I've been trying for sometime to open an image in binary mode with Go. In Python I'd use the Pillow and image.open() (rb mode). Example.
img = Image.open("PNG.png")
pix = img.getdata() #where 0 is black and 1 is white pixel
That would open the image with very clean binary of white and black dots like the image below. In go I've tried os.Open(file.jpg) to open the file.. I've tried decoding it with image.Decode(), I've loaded the file into bytes.Buffer, I've tried fmt.Sprintf("%b", data), all of the solutions give a byte array. Converting that byte array to binary looks nothing like the image above. I've also tried encoding/binary and its the same story with just getting bytes and the binary generated isn't what i want...
Most recently I've tried this
package main
import (
"fmt"
"image"
"image/jpeg"
"io"
"log"
"os"
)
// Pixel struct example
type Pixel struct {
R int
G int
B int
A int
}
func main() {
// You can register another format here
image.RegisterFormat("jpg", "jpg", jpeg.Decode, jpeg.DecodeConfig)
file, err := os.Open("/Users/marcsantiago/Desktop/2033bb1b194adace86f99c7bb7d72e81.jpg")
if err != nil {
log.Fatalln("Error: File could not be opened")
}
defer file.Close()
pixels, err := getPixels(file)
if err != nil {
log.Fatalln("Error: Image could not be decoded")
}
black := Pixel{0, 0, 0, 255}
for i := range pixels {
if pixels[i] == black {
fmt.Print("0")
} else {
fmt.Print("1")
}
}
}
func getPixels(file io.Reader) ([]Pixel, error) {
img, _, err := image.Decode(file)
if err != nil {
return nil, err
}
bounds := img.Bounds()
width, height := bounds.Max.X, bounds.Max.Y
var pixels []Pixel
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
pixels = append(pixels, rgbaToPixel(img.At(x, y).RGBA()))
}
}
return pixels, nil
}
// img.At(x, y).RGBA() returns four uint32 values; we want a Pixel
func rgbaToPixel(r uint32, g uint32, b uint32, a uint32) Pixel {
return Pixel{int(r / 257), int(g / 257), int(b / 257), int(a / 257)}
}
So that I can compare the binary against what I expect I converted the rgba to 1 and 0s where 0 == black... it still doesn't match up not even close. Example
Help please. I'm out of ideas. PS. This site http://www.dcode.fr/binary-image, also opens the image and generates the data I'm expecting.
UPDATE:
This is the image i'm working with..
For example,
package main
import (
"bytes"
"fmt"
"image"
"os"
_ "image/jpeg"
)
func main() {
fName := "ggk3Z.jpg"
f, err := os.Open(fName)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
defer f.Close()
img, _, err := image.Decode(f)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
// http://www.dcode.fr/binary-image
var txt bytes.Buffer
bounds := img.Bounds()
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
r, g, b, _ := img.At(x, y).RGBA()
bin := "0"
if float64((r+g+b))/3 > 0.5 {
bin = "1"
}
txt.WriteString(bin)
}
txt.WriteString("\n")
}
fmt.Fprint(os.Stdout, txt.String())
}

Aligning text in golang with Truetype

I am trying to render some text on a png in a Golang project using freetype/truetype. As you can see from the attachment, I am trying to render 4 letters in columns - each letter centered in the column. Have used the truetype api to get bounds and widths of the glyphs but have been unable to convert these to give me an accurate offset for each glyph. For example with the O glyph, given the font I using. I get the following dimensions:
Hmetric {AdvanceWidth:543 LeftSideBearing:36}
Bounds {XMin:0 YMin:-64 XMax:512 YMax:704}
Advance width: 512
With the last dimension being returned from GlyphBuf.
I rendered it using the following:
size := 125.00
tileOffset := (int(tileWidth) * i) + int(tileWidth/2)
pt := freetype.Pt(tileOffset, (imgH-newCharHeight)-int(size))
How can I use the glyph dimensions returned by truetype to offset the letters correctly? I have tried using the AdvanceWidth as detailed in this plotinum code (line 160) but that does not give me a consistent result across all glyphs.
As suggested by Simon the correct solution is to use AdvanceWidth:
Crude example:
package main
import (
"flag"
"fmt"
"io/ioutil"
"log"
"image"
"bufio"
"image/draw"
"image/png"
"image/color"
"github.com/golang/freetype/truetype"
"golang.org/x/image/font"
"github.com/golang/freetype"
"os"
)
var (
dpi = flag.Float64("dpi", 72, "screen resolution in Dots Per Inch")
fontfile = flag.String("fontfile", "/usr/share/fonts/liberation/LiberationSerif-Regular.ttf", "filename of the ttf font")
hinting = flag.String("hinting", "none", "none | full")
size = flag.Float64("size", 125, "font size in points")
spacing = flag.Float64("spacing", 1.5, "line spacing (e.g. 2 means double spaced)")
wonb = flag.Bool("whiteonblack", false, "white text on a black background")
text = string("JOJO")
)
func main() {
flag.Parse()
fmt.Printf("Loading fontfile %q\n", *fontfile)
b, err := ioutil.ReadFile(*fontfile)
if err != nil {
log.Println(err)
return
}
f, err := truetype.Parse(b)
if err != nil {
log.Println(err)
return
}
// Freetype context
fg, bg := image.Black, image.White
rgba := image.NewRGBA(image.Rect(0, 0, 1000, 200))
draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src)
c := freetype.NewContext()
c.SetDPI(*dpi)
c.SetFont(f)
c.SetFontSize(*size)
c.SetClip(rgba.Bounds())
c.SetDst(rgba)
c.SetSrc(fg)
switch *hinting {
default:
c.SetHinting(font.HintingNone)
case "full":
c.SetHinting(font.HintingFull)
}
// Make some background
// Draw the guidelines.
ruler := color.RGBA{0xdd, 0xdd, 0xdd, 0xff}
for rcount := 0; rcount < 4; rcount ++ {
for i := 0; i < 200; i++ {
rgba.Set(250*rcount, i, ruler)
}
}
// Truetype stuff
opts := truetype.Options{}
opts.Size = 125.0
face := truetype.NewFace(f, &opts)
// Calculate the widths and print to image
for i, x := range(text) {
awidth, ok := face.GlyphAdvance(rune(x))
if ok != true {
log.Println(err)
return
}
iwidthf := int(float64(awidth) / 64)
fmt.Printf("%+v\n", iwidthf)
pt := freetype.Pt(i*250+(125-iwidthf/2), 128)
c.DrawString(string(x), pt)
fmt.Printf("%+v\n", awidth)
}
// Save that RGBA image to disk.
outFile, err := os.Create("out.png")
if err != nil {
log.Println(err)
os.Exit(1)
}
defer outFile.Close()
bf := bufio.NewWriter(outFile)
err = png.Encode(bf, rgba)
if err != nil {
log.Println(err)
os.Exit(1)
}
err = bf.Flush()
if err != nil {
log.Println(err)
os.Exit(1)
}
fmt.Println("Wrote out.png OK.")
}

Resources