code: func flip(im image.Image, dir FlipDirection) image.Image {
  	if dir == 0 {
  		return im
  	}
  	ycbcr := false
  	var nrgba image.Image
  	dx, dy := im.Bounds().Dx(), im.Bounds().Dy()
  	di, ok := im.(draw.Image)
  	if !ok {
  		if _, ok := im.(*image.YCbCr); !ok {
  			log.Printf("failed to flip image: input does not satisfy draw.Image")
  			return im
  		}
  		// because YCbCr does not implement Set, we replace it with a new NRGBA
  		ycbcr = true
  		nrgba = image.NewNRGBA(image.Rect(0, 0, dx, dy))
  		di, ok = nrgba.(draw.Image)
  		if !ok {
  			log.Print("failed to flip image: could not cast an NRGBA to a draw.Image")
  			return im
  		}
  	}
  	if dir&FlipHorizontal != 0 {
  		for y := 0; y < dy; y++ {
  			for x := 0; x < dx/2; x++ {
  				old := im.At(x, y)
  				di.Set(x, y, im.At(dx-1-x, y))
  				di.Set(dx-1-x, y, old)
  			}
  		}
  	}
  	if dir&FlipVertical != 0 {
  		for y := 0; y < dy/2; y++ {
  			for x := 0; x < dx; x++ {
  				old := im.At(x, y)
  				di.Set(x, y, im.At(x, dy-1-y))
  				di.Set(x, dy-1-y, old)
  			}
  		}
  	}
  	if ycbcr {
  		return nrgba
  	}
  	return im
  }
docs: // flip returns a flipped version of the image im, according to
  // the direction(s) in dir.
  // It may flip the input im in place and return it, or it may allocate a
  // new NRGBA (if im is an *image.YCbCr).