Go image upload - image

I am currently uploading an image to my server doing the following:
func (base *GuildController) GuildLogo(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
...
logo, _, err := req.FormFile("logo")
defer logo.Close()
logoGif, format, err := image.Decode(logo)
if err != nil {
base.Error = "Error while decoding your guild logo"
return
}
logoImage, err := os.Create(pigo.Config.String("template")+"/public/guilds/"+ps.ByName("name")+".gif")
if err != nil {
base.Error = "Error while trying to open guild logo image"
return
}
defer logoImage.Close()
//resizedLogo := resize.Resize(64, 64, logoGif, resize.Lanczos3)
err = gif.Encode(logoImage, logoGif, &gif.Options{
256,
nil,
nil,
})
if err != nil {
base.Error = "Error while encoding your guild logo"
return
}
...
}
So everything is working good. But gifs lose the animation.
For example here is a gif I want to upload
And here is the saved one
Not sure what I am doing wrong

As hinted in the comments, you are just working with one frame:
func Decode(r io.Reader) (image.Image, error) Decode reads a GIF image
from r and returns the first embedded image as an image.Image.
But you need
func DecodeAll(r io.Reader) (*GIF, error) DecodeAll reads a GIF image
from r and returns the sequential frames and timing information.
and
func EncodeAll(w io.Writer, g *GIF) error EncodeAll writes the images
in g to w in GIF format with the given loop count and delay between
frames.
Look at this post for details.
Here's an example that slows down the image to 0.5s each frame:
package main
import (
"image/gif"
"os"
)
func main() {
logo, err := os.Open("yay.gif")
if err != nil {
panic(err)
}
defer logo.Close()
inGif, err := gif.DecodeAll(logo)
if err != nil {
panic(err)
}
outGif, err := os.Create("done.gif")
if err != nil {
panic(err)
}
defer outGif.Close()
for i := range inGif.Delay {
inGif.Delay[i] = 50
}
if err := gif.EncodeAll(outGif, inGif); err != nil {
panic(err)
}
}
Results:
Side note
Even if in my browser (Firefox) I see the output image animated, and I can see the the frames in The GIMP, I cannot see it animated on my desktop viewers (gifview, comix). I do not know (yet) what is the cause of this.

Related

how generating transparent GIF with golang using png images?

I have a function that reads a lists of files and create a gif using each file on the list as a frame. But I have a problem. If my frames are png images with transparent background the output GIF have a black background.
I've read on the Internet that image.Paletted is related to the problem but I don't quite understand the issue.
func createAnimation(files []string, directory, filename string) {
outGif := &gif.GIF{}
for _, name := range files {
input := fmt.Sprintf("%s/%s", directory, name)
f, err := os.Open(input)
if err != nil {
log.Fatal(err)
}
imageData, _, err := image.Decode(f)
if err != nil {
log.Fatal(err)
}
buf := bytes.Buffer{}
if err = gif.Encode(&buf, imageData, nil); err != nil {
log.Fatal(err)
}
inGif, err := gif.Decode(&buf)
if err != nil {
log.Fatal(err)
}
f.Close()
outGif.Image = append(outGif.Image, inGif.(*image.Paletted))
outGif.Delay = append(outGif.Delay, 0)
}
output := fmt.Sprintf("FINAL_%s.gif", filename)
f, err := os.Create(output)
if err != nil {
log.Fatal(err)
}
gif.EncodeAll(f, outGif)
err = os.Rename(output, fmt.Sprintf("%s/%s", directory, output))
if err != nil {
log.Fatal(err)
}
}
Files is a slice of filenames e.g. {"base1.png", "base2.png"} and so on.
What should I check or modify in order to generate a transparent gif?
instead of encoding and decoding image you can use draw.Draw nethod. Just create a image.Paleted of size of the loaded image, specify palette you need (include transparent color) and perform draw call.
func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point, op Op)
// so
draw.Draw(newEmptyPalettedInage, loadedImage.Bounds(), loadedImage, loadedImage.Bounds().Min, 0)

How to covert a []byte object to an image and store it as a jpeg image on disk

I am trying to convert an []byte object to an image and save it as a jpeg in Golang. I tried to use Decode function of image but it always returns <nil>.
func saveFrames(imgByte []byte) {
img, _, _ := image.Decode(bytes.NewReader(imgByte))
out, err := os.Create("./img.jpeg")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
err = jpeg.Encode(out, img)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
You are not passing Options,to jpeg.Encode, you can also set it to nil.
func serveFrames(imgByte []byte) {
img, _, err := image.Decode(bytes.NewReader(imgByte))
if err != nil {
log.Fatalln(err)
}
out, _ := os.Create("./img.jpeg")
defer out.Close()
var opts jpeg.Options
opts.Quality = 1
err = jpeg.Encode(out, img, &opts)
//jpeg.Encode(out, img, nil)
if err != nil {
log.Println(err)
}
}
Don't forget to close any file, if opened.
You can use log.Fatalln(...), if you want to print error message and quit in-case of any error.

Reading Image in Go

func (sticky *Sticky) DrawImage(W, H int) (img *image, err error) {
myImage := image.NewRGBA(image.Rect(0, 0, 10, 25))
myImage.Pix[0] = 55 // 1st pixel red
myImage.Pix[1] = 155 // 1st pixel green
return myImage ,nil
}
I am creating an image. I want to read the existing Image and return in this Function. How I can I do that?
Something like this:
func getImageFromFilePath(filePath string) (image.Image, error) {
f, err := os.Open(filePath)
if err != nil {
return nil, err
}
defer f.Close()
image, _, err := image.Decode(f)
return image, err
}
references
https://golang.org/pkg/image/#Decode
https://golang.org/pkg/os/#Open
try this:
package main
import (
"fmt"
"image"
"image/png"
"os"
)
func main() {
// Read image from file that already exists
existingImageFile, err := os.Open("test.png")
if err != nil {
// Handle error
}
defer existingImageFile.Close()
// Calling the generic image.Decode() will tell give us the data
// and type of image it is as a string. We expect "png"
imageData, imageType, err := image.Decode(existingImageFile)
if err != nil {
// Handle error
}
fmt.Println(imageData)
fmt.Println(imageType)
// We only need this because we already read from the file
// We have to reset the file pointer back to beginning
existingImageFile.Seek(0, 0)
// Alternatively, since we know it is a png already
// we can call png.Decode() directly
loadedImage, err := png.Decode(existingImageFile)
if err != nil {
// Handle error
}
fmt.Println(loadedImage)
}
references
https://www.devdungeon.com/content/working-images-go

Encoding/Decoding a Gif

I will be working on a project connected with GIF images and I tried to do some basic operations on them in Go (such as retrieving frames or creating GIF from a bunch of images). But for now let's do a simple example in which I am only trying to decode a GIF and then to encode it again. I tried to use "image/gif" package, but I am unable to get it to do what I want.
Here is the code :
package main
import (
"os"
"image/gif"
)
func main() {
inputFile , err := os.Open("travolta.gif")
defer inputFile.Close()
if err != nil {
panic(err)
}
g, err := gif.DecodeAll(inputFile)
if err != nil {
panic(err)
}
outputFile, err := os.OpenFile("travolta2.gif", os.O_WRONLY|os.O_CREATE, 0777)
defer outputFile.Close()
if err != nil {
panic(err)
}
err = gif.EncodeAll(outputFile, g)
if err != nil {
panic(err)
}
}
When I run the code it does not panic and another gif is indeed created. Unfortunetely it is corrupted. Moreover the gif's size changes from 3,4MB to 4,4MB. Is it not a way to save/read a gif? What mistake do I make?
EDIT:
By corrupted I mean that when I try to open it an error occurs- screnshot here : http://www.filedropper.com/obrazekpociety.
GIF:
http://vader.joemonster.org/upload/rwu/1539970c1d48acceLw7m.gif
Go version 1.7.4
The problem is you are passing a File* to DecodeAll rather than something that supports the io.Reader interface.
I have adapted your code so that it creates a bufio.Reader from the file and then hands that to DecodeAll as below:
import (
"bufio"
"os"
"image/gif"
)
func main() {
inputFile , err := os.Open("travolta.gif")
defer inputFile.Close()
if err != nil {
panic(err)
}
r := bufio.NewReader(inputFile)
g, err := gif.DecodeAll(r)
if err != nil {
panic(err)
}
// ... remaining code
}

Looking for better way to save an in memory image to file

The goal of the code is to download an image, stick it to a larger parent image and save the result.
After quite a few failures I ended up with the following code that does work.
However, is there a better way than using bytes.Buffer and a writer to save the target image to a file / pass it to an httpResponse?
package main
import (
"image"
"image/draw"
"image/jpeg"
"os"
// "image/color"
// "io/ioutil"
// "fmt"
"bufio"
"bytes"
"log"
"net/http"
)
func main() {
// Fetch an image.
resp, err := http.Get("http://katiebrookekennels.com/wp-content/uploads/2014/10/dog-bone4.jpg")
if err != nil {
log.Panic(err)
}
defer resp.Body.Close()
// Keep an in memory copy.
myImage, err := jpeg.Decode(resp.Body)
if err != nil {
log.Panic(err)
}
// Prepare parent image where we want to position child image.
target := image.NewRGBA(image.Rect(0, 0, 800, 800))
// Draw white layer.
draw.Draw(target, target.Bounds(), image.White, image.ZP, draw.Src)
// Draw child image.
draw.Draw(target, myImage.Bounds(), myImage, image.Point{0, 0}, draw.Src)
// Encode to jpeg.
var imageBuf bytes.Buffer
err = jpeg.Encode(&imageBuf, target, nil)
if err != nil {
log.Panic(err)
}
// Write to file.
fo, err := os.Create("img.jpg")
if err != nil {
panic(err)
}
fw := bufio.NewWriter(fo)
fw.Write(imageBuf.Bytes())
}
jpeg.Encode() expects an io.Writer to write the encoded image to (in JPEG format). Both *os.File and http.ResponseWriter implement io.Writer too, so instead of a bytes.Buffer, you can directly pass a file or HTTP response writer too.
To save an image directly to a file:
f, err := os.Create("img.jpg")
if err != nil {
panic(err)
}
defer f.Close()
if err = jpeg.Encode(f, target, nil); err != nil {
log.Printf("failed to encode: %v", err)
}
To serve it as an image:
// w is of type http.ResponseWriter:
if err := jpeg.Encode(w, target, nil); err != nil {
log.Printf("failed to encode: %v", err)
}
You can see some examples in these questions (saving/loading JPEG and PNG images):
Draw a rectangle in Golang?
How to add a simple text label to an image in Go?
Change color of a single pixel - Golang image

Resources