在Go中提供刚刚创建的图像。

huangapple go评论82阅读模式
英文:

Serve image in Go that was just created

问题

我正在创建一个动态图像,当不存在时会创建一个。例如,当请求example_t500.jpg时,会从example.jpg创建。我遇到的问题是,在显示创建的图像之前,当请求一个不存在的图像时无法显示。

代码:

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)
}

这是我第一次尝试使用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.

答案1

得分: 26

有几件事情你需要做。

首先,你需要从WebHandler函数中删除这行代码:

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

这是设置默认的服务处理器来处理根路由的方式 - 但是你已经在main函数中做过了,就像这样:

http.HandleFunc("/", WebHandler)

所以每次你访问根路由时,实际上你只是告诉服务处理器再次处理它.. 但是以不同的方式。

你想要做的是.. 设置响应的Content-Type头,然后将文件的内容复制到响应流中。类似这样:

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) // 或许可以更好地处理这个错误
    }
    defer img.Close()
    w.Header().Set("Content-Type", "image/jpeg") // <-- 设置 content-type 头
    io.Copy(w, img)
}

这是手动的版本。还有一个方法叫做http.ServeFile

编辑:

根据你的评论 - 如果你根本不想写文件,只是动态地提供它,那么你只需要将http.ResponseWriter传递给Encode方法。jpeg.Encode接受一个io.Writer,就像我原来的例子中的io.Copy一样:

// 传递 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)

    // 不写文件..
    /*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) // 写入 ResponseWriter
}

在方法中接受一个io.Writer,然后对其进行编码。然后你可以这样调用你的方法:

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

There are a few things you need to do.

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

http.Handle(&quot;/&quot;, http.FileServer(http.Dir(&quot;example_t500.jpg&quot;)))

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(&quot;/&quot;, 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 = &quot;../../static/img/photos/2014/11/4/test.jpg&quot;
    ResizeImage(Path, 500)
    
    img, err := os.Open(&quot;example_t500.jpg&quot;)
    if err != nil {
        log.Fatal(err) // perhaps handle this nicer
    }
    defer img.Close()
    w.Header().Set(&quot;Content-Type&quot;, &quot;image/jpeg&quot;) // &lt;-- 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, &quot;.jpg&quot;)
    var ImageNum       = strings.Split(ImageExtension[0], &quot;/&quot;)
    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&#39;t write the file..
    /*out, err := os.Create(ImageName + &quot;_t&quot; + strconv.Itoa(int(Width)) + &quot;.jpg&quot;)
    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 = &quot;../../static/img/photos/2014/11/4/test.jpg&quot;
    ResizeImage(w, Path, 500) // pass the ResponseWriter in
}

答案2

得分: 1

你要找的函数是http.ServeFile。在你的代码中使用它,而不是http.Handle。

英文:

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

huangapple
  • 本文由 发表于 2014年11月5日 04:53:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/26744814.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定