1

I would probably prefer to use pressly/chi, but I guess it makes no difference. I imagine given an input URL like this example.com/Jd8saD.jpg?resize=420x320&fit=crop&rotate=90, then it would go to the following GET function because of r.Get("/:image", ImageGET):

function ImageGET(w http.ResponseWriter, r *http.Request) {
  if r.URL.Query().Get("resize") != "" {
    // do something
  }
  if r.URL.Query().Get("crop") != "" {
    // do something
  }
  if r.URL.Query().Get("watermark") != "" {
    // do something
  }
  etc
}

Now, my question is, how should I design whatever function does the image processing so that it will process everything properly and efficiently? I don't expect you to write code that will handle the resizing, but how would these functions look like? Perhaps:

function Resize(size string) (imgfile?, error) {
  // the resize stuff
}

What would that returned imgfile even be? A struct containing some relevant img info?

fisker
  • 979
  • 4
  • 18
  • 28

2 Answers2

1

Likely,

imgfile

will satisfy the image.Image interface and not the data saved on disk (ie. the actual jpg file)

Image is a finite rectangular grid of color.Color values taken from a color model.

Lots of 3rd party golang image libraries use image.Image to manipulate images.


I would use a standard image.Image interface retrieved (read to memory) by a filename in the imageGET function and modified according to the queries. You can see also the jpeg golang library from the standard lib.

function ImageGET(w http.ResponseWriter, r *http.Request) {
  // GetJPEGImageFromFileSystem must decode os.File content and 
  // return a golang image.Image interface
  img, _ := GetJPEGImageFromFileSystem(r.URL.Query().Get("filename"))
  if r.URL.Query().Get("resize") != "" {
      // If resizing, write over the image.Image in Memory, 
      // but not the image File on disk
      img, _ = Resize(img, r.URL.Query().GET("resize"))
  }
  // etc...
}

function Resize(img image.Image, size string) (image.Image, error) {
  // the resize stuff -- or, alternatively just call a dependency in the original handler to resize
  return resizedImage, nil
}
Nevermore
  • 7,141
  • 5
  • 42
  • 64
  • This is really great, I do wonder.. with this approach I will likely end up calling the image manipulation library (e.g. libvips) over and over again with each parameter. Would you also do it this way, or maybe it would be smarter to store the parameters and then do the image manipulation in some Process function, or maybe something else? – fisker May 01 '17 at 18:00
  • Mmh, I'm not sure how libvips works, but I bet it would be all around simpler to have one process function in which the queries could be passed – Nevermore May 01 '17 at 18:02
  • You can use libvips both ways. You can call the basic functions separately, or you can call a single high-level thumbnail function with a set of parameters. If you gather up your params and call vips_thumbnail() at the end, you can be sure the basic functions will be called for you in the best order. API here: http://jcupitt.github.io/libvips/API/current/libvips-resample.html#vips-thumbnail intro to resizing here: https://github.com/jcupitt/libvips/wiki/HOWTO----Image-shrinking intro to vipsthumbnail here: http://jcupitt.github.io/libvips/API/current/Using-vipsthumbnail.md.html – jcupitt May 02 '17 at 08:41
  • then I would call it once, and "gather up" the params to call `vips_thumbnail()` – Nevermore May 02 '17 at 16:37
1

Now, my question is, how should I design whatever function does the image processing so that it will process everything properly and efficiently?

Depends on the package you are using for your stuff and what you want to do with it. If you look for example to the imaging package you see that they return always: *image.NRGBA

That type implements the image.Image interface.

At the next step you can use the Encode function.

func Encode(w io.Writer, img image.Image, format Format) error

As you see that function uses a io.Writer.

function ImageGET(w http.ResponseWriter, r *http.Request) {
  // ...
  imaging.Encode(w,img,imaging.PNG)
  // ...

So you just need to use the writer from the your handler there and ready.

So to keep your function correct just return the image.Image interface.

apxp
  • 5,240
  • 4
  • 23
  • 43