Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serve image in Go that was just created

Tags:

image

go

I'm creating an image dynamically when one doesn't exist. IE example_t500.jpg when requested would be created from example.jpg. The problem I'm having is displaying the created image when it's requested before a missing image is shown.

Code:

package main

import (
        "image/jpeg"
        "net/http"
        "log"
        "os"
        "strings"
        "fmt"
        "strconv"
        resizer "github.com/nfnt/resize"
    )

func WebHandler (w http.ResponseWriter, r *http.Request) {
    var Path = "../../static/img/photos/2014/11/4/test.jpg"
    ResizeImage(Path, 500)
    http.Handle("/", http.FileServer(http.Dir("example_t500.jpg")))
}

func ResizeImage (Path string, Width uint) {
    var ImageExtension = strings.Split(Path, ".jpg")
    var ImageNum       = strings.Split(ImageExtension[0], "/")
    var ImageName      = ImageNum[len(ImageNum)-1]
    fmt.Println(ImageName)
    file, err := os.Open(Path)
    if err != nil {
        log.Fatal(err)
    }

    img, err := jpeg.Decode(file)
    if err != nil {
        log.Fatal(err)
    }
    file.Close()

    m := resizer.Resize(Width, 0, img, resizer.Lanczos3)

    out, err := os.Create(ImageName + "_t" + strconv.Itoa(int(Width)) + ".jpg")
    if err != nil {
        log.Fatal(err)
    }
    defer out.Close()

    jpeg.Encode(out, m, nil)
}

func main() {
    http.HandleFunc("/", WebHandler)
    http.ListenAndServe(":8080", nil)
}

This is my first time trying to use Go and am having trouble rendering the image. Any help is appreciated.

like image 779
Austin Munro Avatar asked Nov 04 '14 20:11

Austin Munro


2 Answers

There are a few things you need to do.

First, you need to remove this line from your WebHandler function:

http.Handle("/", http.FileServer(http.Dir("example_t500.jpg")))

That's setting up the default serve mux to handle the root route - but you've already done that in your main function here:

http.HandleFunc("/", WebHandler)

So every time you hit the root route, you're effectively just telling the servemux to handle it again .. but differently.

What you want to do.. is set the Content-Type header of the response.. then copy the contents of the file to the response stream. Something like this:

func WebHandler (w http.ResponseWriter, r *http.Request) {
    var Path = "../../static/img/photos/2014/11/4/test.jpg"
    ResizeImage(Path, 500)

    img, err := os.Open("example_t500.jpg")
    if err != nil {
        log.Fatal(err) // perhaps handle this nicer
    }
    defer img.Close()
    w.Header().Set("Content-Type", "image/jpeg") // <-- set the content-type header
    io.Copy(w, img)
}

Thats the manual version. There's also http.ServeFile.

EDIT:

In response to your comment - if you don't want to write the file at all and just serve it dynamically, then all you need to do is pass the http.ResponseWriter to the Encode method. jpeg.Encode takes an io.Writer .. just as io.Copy does in my original example:

// Pass in the ResponseWriter
func ResizeImage (w io.Writer, Path string, Width uint) {
    var ImageExtension = strings.Split(Path, ".jpg")
    var ImageNum       = strings.Split(ImageExtension[0], "/")
    var ImageName      = ImageNum[len(ImageNum)-1]
    fmt.Println(ImageName)
    file, err := os.Open(Path)
    if err != nil {
        log.Fatal(err)
    }

    img, err := jpeg.Decode(file)
    if err != nil {
        log.Fatal(err)
    }
    file.Close()

    m := resizer.Resize(Width, 0, img, resizer.Lanczos3)

    // Don't write the file..
    /*out, err := os.Create(ImageName + "_t" + strconv.Itoa(int(Width)) + ".jpg")
    if err != nil {
        log.Fatal(err)
    }
    defer out.Close()*/

    jpeg.Encode(w, m, nil) // Write to the ResponseWriter
}

Accept an io.Writer in the method .. then encode it to that. You can then call your method like this:

func WebHandler (w http.ResponseWriter, r *http.Request) {
    var Path = "../../static/img/photos/2014/11/4/test.jpg"
    ResizeImage(w, Path, 500) // pass the ResponseWriter in
}
like image 111
Simon Whitehead Avatar answered Oct 23 '22 14:10

Simon Whitehead


The function you are looking for is http.ServeFile. Use that instead of http.Handle in your code.

like image 39
Logiraptor Avatar answered Oct 23 '22 16:10

Logiraptor