英文:
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("/", 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
}
答案2
得分: 1
你要找的函数是http.ServeFile。在你的代码中使用它,而不是http.Handle。
英文:
The function you are looking for is http.ServeFile. Use that instead of http.Handle in your code.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论