英文:
Serve a decoded image via Martini
问题
我目前正在玩耍golang和Martini等,想要动态地提供一些处理/生成的图像。这是一个最简单的例子:
package main
import (
"github.com/codegangsta/martini"
"github.com/nfnt/resize"
"image"
"image/jpeg"
"log"
"os"
)
func thumb() image.Image {
file, err := os.Open("test.jpg")
if err != nil {
log.Fatal(err)
}
img, err := jpeg.Decode(file)
if err != nil {
log.Fatal(err)
}
file.Close()
m := resize.Resize(0, 200, img, resize.MitchellNetravali)
return m
}
func main() {
m := martini.Classic()
m.Get("/", func() image.Image {
return thumb()
})
m.Run()
}
这个代码可以正常编译,但是返回的不是一个图像,而是一些"Content-Type:text/plain; charset=utf-8"的内容,看起来像这样:
<*image.RGBA64 Value>
我相当确定我需要再次对图像进行编码,然后提供它。但是我不太确定如何在不将图像保存到磁盘的情况下做到这一点...
提前感谢!
英文:
I am currently playing around with golang and Martini and such and wanted to dynamically serve some manipulated/generated images. Here's a minimal example:
package main
import (
"github.com/codegangsta/martini"
"github.com/nfnt/resize"
"image"
"image/jpeg"
"log"
"os"
)
func thumb() image.Image {
file, err := os.Open("test.jpg")
if err != nil {
log.Fatal(err)
}
img, err := jpeg.Decode(file)
if err != nil {
log.Fatal(err)
}
file.Close()
m := resize.Resize(0, 200, img, resize.MitchellNetravali)
return m
}
func main() {
m := martini.Classic()
m.Get("/") image.Image {
return thumb()
})
m.Run()
}
That compiles fine, but instead of serving an image, I get some "Content-Type:text/plain; charset=utf-8" that looks like this:
<*image.RGBA64 Value>
I am pretty sure that I need to encode the image again and then serve it. But im not quite sure how to do this without saving the image to the disk...
Thanks in advance!
答案1
得分: 7
你可以直接向ResponseWriter写入内容,因为它实现了io.Writer接口,无需使用缓冲区或将图像复制到磁盘。
你已经接近成功了,只需要设置内容类型,并像你提到的那样将image.Image对象重新编码为jpeg格式。幸运的是,jpeg.Encode()方法需要一个写入器来写入,而且由于Martini具有将其注入到处理程序中的能力,你可以随时使用ResponseWriter来完成这个任务。
注意:你可能希望进行更健壮的错误处理,而不仅仅是我提供的这样简单的处理方式。这只是为了让事情开始进行而已。;)
package main
import (
"image"
"image/jpeg"
"log"
"net/http"
"os"
"github.com/codegangsta/martini"
"github.com/nfnt/resize"
)
func thumb() image.Image {
file, err := os.Open("test.jpg")
if err != nil {
log.Fatal(err)
}
img, err := jpeg.Decode(file)
if err != nil {
log.Fatal(err)
}
file.Close()
m := resize.Resize(0, 200, img, resize.MitchellNetravali)
return m
}
func main() {
m := martini.Classic()
m.Get("/", func(res http.ResponseWriter, req *http.Request) {
res.Header().Set("Content-Type", "image/jpeg")
err := jpeg.Encode(res, thumb(), &jpeg.Options{100})
if err != nil {
res.WriteHeader(500)
} else {
res.WriteHeader(200)
}
})
m.Run()
}
英文:
You can write to the ResponseWriter directly because it implements the io.Writer interface, no need to use a buffer or copy the image to disk.
You were almost there, just needed to set the content type and like you mentioned encode the image.Image object back into a jpeg. Luckily, the jpeg.Encode() method needed a writer to write to and you have the ResponseWriter available at your disposal to do just that thanks to Martini having the ability to inject it into your handler.
Note: you will probably want to do a more robust job of error handling than I have provided. This is just to get the ball rolling.
package main
import (
"image"
"image/jpeg"
"log"
"net/http"
"os"
"github.com/codegangsta/martini"
"github.com/nfnt/resize"
)
func thumb() image.Image {
file, err := os.Open("test.jpg")
if err != nil {
log.Fatal(err)
}
img, err := jpeg.Decode(file)
if err != nil {
log.Fatal(err)
}
file.Close()
m := resize.Resize(0, 200, img, resize.MitchellNetravali)
return m
}
func main() {
m := martini.Classic()
m.Get("/", func(res http.ResponseWriter, req *http.Request) {
res.Header().Set("Content-Type", "image/jpeg")
err := jpeg.Encode(res, thumb(), &jpeg.Options{100})
if err != nil {
res.WriteHeader(500)
} else {
res.WriteHeader(200)
}
})
m.Run()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论