image/image.go
func ServingURL(c context.Context, key appengine.BlobKey, opts *ServingURLOptions) (*url.URL, error) {
	req := &pb.ImagesGetUrlBaseRequest{
		BlobKey: (*string)(&key),
	}
	if opts != nil && opts.Secure {
		req.CreateSecureUrl = &opts.Secure
	}
	res := &pb.ImagesGetUrlBaseResponse{}
	if err := internal.Call(c, "images", "GetUrlBase", req, res); err != nil {
		return nil, err
	}

	// The URL may have suffixes added to dynamically resize or crop:
	// - adding "=s32" will serve the image resized to 32 pixels, preserving the aspect ratio.
	// - adding "=s32-c" is the same as "=s32" except it will be cropped.
	u := *res.Url
	if opts != nil && opts.Size > 0 {
		u += fmt.Sprintf("=s%d", opts.Size)
		if opts.Crop {
			u += "-c"
		}
	}
	return url.Parse(u)
}
func ServingURL(c context.Context, key appengine.BlobKey, opts *ServingURLOptions) (*url.URL, error) {
	req := &pb.ImagesGetUrlBaseRequest{
		BlobKey: (*string)(&key),
	}
	if opts != nil && opts.Secure {
		req.CreateSecureUrl = &opts.Secure
	}
	res := &pb.ImagesGetUrlBaseResponse{}
	if err := internal.Call(c, "images", "GetUrlBase", req, res); err != nil {
		return nil, err
	}

	// The URL may have suffixes added to dynamically resize or crop:
	// - adding "=s32" will serve the image resized to 32 pixels, preserving the aspect ratio.
	// - adding "=s32-c" is the same as "=s32" except it will be cropped.
	u := *res.Url
	if opts != nil && opts.Size > 0 {
		u += fmt.Sprintf("=s%d", opts.Size)
		if opts.Crop {
			u += "-c"
		}
	}
	return url.Parse(u)
}
// ServingURL returns a URL that will serve an image from Blobstore.