コード例 #1
0
ファイル: processing.go プロジェクト: postfix/quiet-1
func ProcessPhoto(photo *Photo) error {
	origImg, err := imaging.Open(GetPhotoPath(photo, "o"))
	if err != nil {
		return err
	}

	src := imaging.Clone(origImg)

	for _, sz := range PhotoSizes {
		var dst image.Image

		switch sz.Type {
		case "thumbnail":
			dst = imaging.Thumbnail(src, sz.Width, sz.Height, imaging.Lanczos)
		case "fit":
			dst = imaging.Fit(src, sz.Width, sz.Height, imaging.Lanczos)
		}

		err := imaging.Save(dst, GetPhotoPath(photo, sz.Suffix))
		if err != nil {
			return err
		}
	}

	return nil
}
コード例 #2
0
ファイル: processing.go プロジェクト: postfix/quiet-1
func ProcessAvatar(user *User) error {
	origImg, err := imaging.Open(GetAvatarPath(user, "o"))
	if err != nil {
		return err
	}

	src := imaging.Clone(origImg)

	for _, sz := range AvatarSizes {
		var dst image.Image

		switch sz.Type {
		case "thumbnail":
			dst = imaging.Thumbnail(src, sz.Width, sz.Height, imaging.Lanczos)
		case "fit":
			dst = imaging.Fit(src, sz.Width, sz.Height, imaging.Lanczos)
		}

		err := imaging.Save(dst, GetAvatarPath(user, sz.Suffix))
		if err != nil {
			return err
		}
	}

	return nil
}
コード例 #3
0
ファイル: api.go プロジェクト: sisteamnik/guseful
func (api *Api) Resize(imgloc string, xsize, ysize int, resizeType string) bool {
	dest := setSize(imgloc, xsize, ysize)
	if _, err := os.Stat(dest); err == nil {
		return true
	}
	bts, err := ioutil.ReadFile(imgloc)
	if err != nil {
		fmt.Println(err)
		return false
	}
	rdr := bytes.NewReader(bts)
	i, _, err := image.Decode(rdr)
	if err != nil {
		fmt.Println(err)
		return false
	}
	var fsimg *image.NRGBA
	switch resizeType {
	case "fit":
		fsimg = imaging.Fit(i, xsize, ysize, imaging.Lanczos)
	case "thumb":
		fsimg = imaging.Thumbnail(i, xsize, ysize, imaging.Lanczos)
	default:
		fsimg = imaging.Resize(i, xsize, ysize, imaging.Lanczos)
	}
	out, err := os.Create(dest)
	if err != nil {
		return false
	}
	defer out.Close()
	jpeg.Encode(out, fsimg, nil)
	return true
}
コード例 #4
0
ファイル: handler.go プロジェクト: arkxu/caaas
func (h *ImgHandler) processImage(in io.Reader, out io.Writer, mode string, width int, height int) error {
	if Config.Image.UseGoRoutine {
		ImageChannel <- 1
		defer func() {
			<-ImageChannel
		}()
	}

	img, _, err := image.Decode(in)
	if err != nil {
		glog.Fatal(err)
		return err
	}

	var m *image.NRGBA
	switch mode {
	case "z":
		m = imaging.Fit(img, width, height, imaging.Lanczos)
	case "x":
		m = imaging.Fill(img, width, height, imaging.Center, imaging.Lanczos)
	}

	jpeg.Encode(out, m, &jpeg.Options{Config.Image.ReadQuality})
	return nil
}
コード例 #5
0
ファイル: cbconvert.go プロジェクト: gen2brain/cbconvert
// Extracts cover
func (c *Convertor) ExtractCover(file string, info os.FileInfo) {
	c.CurrFile += 1

	cover, err := c.GetCoverImage(file, info)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error GetCoverImage: %v\n", err.Error())
		return
	}

	if c.Opts.Width > 0 || c.Opts.Height > 0 {
		if c.Opts.Fit {
			cover = imaging.Fit(cover, c.Opts.Width, c.Opts.Height, filters[c.Opts.Filter])
		} else {
			cover = imaging.Resize(cover, c.Opts.Width, c.Opts.Height, filters[c.Opts.Filter])
		}
	}

	filename := filepath.Join(c.Opts.Outdir, fmt.Sprintf("%s.jpg", c.getBasename(file)))
	f, err := os.Create(filename)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error Create: %v\n", err.Error())
		return
	}
	defer f.Close()

	jpeg.Encode(f, cover, &jpeg.Options{c.Opts.Quality})
}
コード例 #6
0
ファイル: transform.go プロジェクト: LimiQS/imageproxy
// transformImage modifies the image m based on the transformations specified
// in opt.
func transformImage(m image.Image, opt Options) image.Image {
	// resize if needed
	if w, h, resize := resizeParams(m, opt); resize {
		if opt.Fit {
			m = imaging.Fit(m, w, h, resampleFilter)
		} else {
			if w == 0 || h == 0 {
				m = imaging.Resize(m, w, h, resampleFilter)
			} else {
				m = imaging.Thumbnail(m, w, h, resampleFilter)
			}
		}
	}

	// flip
	if opt.FlipVertical {
		m = imaging.FlipV(m)
	}
	if opt.FlipHorizontal {
		m = imaging.FlipH(m)
	}

	// rotate
	switch opt.Rotate {
	case 90:
		m = imaging.Rotate90(m)
	case 180:
		m = imaging.Rotate180(m)
	case 270:
		m = imaging.Rotate270(m)
	}

	return m
}
コード例 #7
0
ファイル: cbconvert.go プロジェクト: gen2brain/cbconvert
// Extracts thumbnail
func (c *Convertor) ExtractThumbnail(file string, info os.FileInfo) {
	c.CurrFile += 1

	cover, err := c.GetCoverImage(file, info)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error GetCoverImage: %v\n", err.Error())
		return
	}

	if err != nil {
		fmt.Fprintf(os.Stderr, "Error Thumbnail: %v\n", err.Error())
		return
	}

	if c.Opts.Width > 0 || c.Opts.Height > 0 {
		if c.Opts.Fit {
			cover = imaging.Fit(cover, c.Opts.Width, c.Opts.Height, filters[c.Opts.Filter])
		} else {
			cover = imaging.Resize(cover, c.Opts.Width, c.Opts.Height, filters[c.Opts.Filter])
		}
	} else {
		cover = imaging.Resize(cover, 256, 0, filters[c.Opts.Filter])
	}

	imagick.Initialize()

	mw := imagick.NewMagickWand()
	defer mw.Destroy()

	b := new(bytes.Buffer)
	png.Encode(b, cover)

	err = mw.ReadImageBlob(b.Bytes())
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error ReadImageBlob: %v\n", err.Error())
	}

	var fileuri string
	var filename string

	if c.Opts.Outfile == "" {
		fileuri = "file://" + file
		filename = filepath.Join(c.Opts.Outdir, fmt.Sprintf("%x.png", md5.Sum([]byte(fileuri))))
	} else {
		abs, _ := filepath.Abs(c.Opts.Outfile)
		fileuri = "file://" + abs
		filename = abs
	}

	mw.SetImageFormat("PNG")
	mw.SetImageProperty("Software", "CBconvert")
	mw.SetImageProperty("Description", "Thumbnail of "+fileuri)
	mw.SetImageProperty("Thumb::URI", fileuri)
	mw.SetImageProperty("Thumb::MTime", strconv.FormatInt(info.ModTime().Unix(), 10))
	mw.SetImageProperty("Thumb::Size", strconv.FormatInt(info.Size(), 10))
	mw.SetImageProperty("Thumb::Mimetype", mime.TypeByExtension(filepath.Ext(file)))

	mw.WriteImage(filename)
}
コード例 #8
0
ファイル: emoji.go プロジェクト: ZJvandeWeg/platform
func resizeEmoji(img image.Image, width int, height int) image.Image {
	emojiWidth := float64(width)
	emojiHeight := float64(height)

	var emoji image.Image
	if emojiHeight <= MaxEmojiHeight && emojiWidth <= MaxEmojiWidth {
		emoji = img
	} else {
		emoji = imaging.Fit(img, MaxEmojiWidth, MaxEmojiHeight, imaging.Lanczos)
	}
	return emoji
}
コード例 #9
0
ファイル: utils.go プロジェクト: netw0rm/reweb
func MakeFromImage(srcImage image.Image, t string, w, h int) (image *image.NRGBA, err error) {
	switch t {
	case "thumbnail":
		image = imaging.Thumbnail(srcImage, w, h, imaging.Lanczos)
	case "resize":
		image = imaging.Resize(srcImage, w, h, imaging.Lanczos)
	case "fit":
		image = imaging.Fit(srcImage, w, h, imaging.Lanczos)
	default:
		image = imaging.Thumbnail(srcImage, w, h, imaging.Lanczos)
	}

	return image, nil
}
コード例 #10
0
ファイル: download.go プロジェクト: rdterner/photoview
func getImage(filename string, small bool) (io.ReadCloser, error) {
	if !small {
		return os.Open(filename)
	}

	fullImage, err := imaging.Open(filename)
	if err != nil {
		return nil, err
	}
	resized := imaging.Fit(fullImage, config.SmallRes, config.SmallRes, imaging.Linear)

	r, w := io.Pipe()
	go imaging.Encode(w, resized, imaging.JPEG)
	return r, nil
}
コード例 #11
0
ファイル: utils.go プロジェクト: netw0rm/reweb
func MakeFromReader(reader io.Reader, t string, w, h int) (image *image.NRGBA, err error) {
	srcImage, err := Open(reader)
	if err != nil {
		return nil, err
	}

	switch t {
	case "thumbnail":
		image = imaging.Thumbnail(srcImage, w, h, imaging.Lanczos)
	case "resize":
		image = imaging.Resize(srcImage, w, h, imaging.Lanczos)
	case "fit":
		image = imaging.Fit(srcImage, w, h, imaging.Lanczos)
	default:
		image = imaging.Thumbnail(srcImage, w, h, imaging.Lanczos)
	}

	return
}
コード例 #12
0
ファイル: cbconvert.go プロジェクト: gen2brain/cbconvert
// Transforms image (resize, rotate, flip, brightness, contrast)
func (c *Convertor) TransformImage(img image.Image) image.Image {
	var i image.Image = img

	if c.Opts.Width > 0 || c.Opts.Height > 0 {
		if c.Opts.Fit {
			i = imaging.Fit(i, c.Opts.Width, c.Opts.Height, filters[c.Opts.Filter])
		} else {
			i = imaging.Resize(i, c.Opts.Width, c.Opts.Height, filters[c.Opts.Filter])
		}
	}

	if c.Opts.Rotate > 0 {
		switch c.Opts.Rotate {
		case 90:
			i = imaging.Rotate90(i)
		case 180:
			i = imaging.Rotate180(i)
		case 270:
			i = imaging.Rotate270(i)
		}
	}

	if c.Opts.Flip != "none" {
		switch c.Opts.Flip {
		case "horizontal":
			i = imaging.FlipH(i)
		case "vertical":
			i = imaging.FlipV(i)
		}
	}

	if c.Opts.Brightness != 0 {
		i = imaging.AdjustBrightness(i, c.Opts.Brightness)
	}

	if c.Opts.Contrast != 0 {
		i = imaging.AdjustContrast(i, c.Opts.Contrast)
	}

	return i
}
コード例 #13
0
ファイル: sync.go プロジェクト: rubyfox/eazyphotod
// Create HD and Thumbs Photos
func CreatePhotos(a *model.Album, p *model.Photo) (err error) {
	src, err := imaging.Open(a.PathSource() + p.OriginalName)
	if err != nil {
		return err
	}

	var dst *image.NRGBA
	filename := a.PathHD() + p.Filename
	log.Printf("Saving HD: %s\n", filename)
	dst = imaging.Fit(src, cfg.Image.MaxWidth, cfg.Image.MaxHeight, imaging.Lanczos)
	size, err := rewriteImage(dst, filename)
	if err != nil {
		return err
	}

	p.FileSizeHD = size
	filename = a.PathThumbs() + p.Filename
	log.Printf("Saving Thumb: %s\n", filename)
	dst = imaging.Thumbnail(dst, cfg.Image.ThumbWidth, cfg.Image.ThumbHeight, imaging.CatmullRom) // resize and crop the image to make a 200x200 thumbnail
	_, err = rewriteImage(dst, filename)

	return err
}
コード例 #14
0
ファイル: params.go プロジェクト: h2object/h2object
func do_params(ctx *context, ctrl *ext.Controller) bool {
	qr := ctrl.Request.Param("qrcode")
	if qr != "" {
		if size, err := strconv.ParseInt(qr, 10, 64); err == nil {
			return do_qrcode(ctx, ctrl, int(size))
		}
	}

	resize := ctrl.Request.Param("resize")
	if resize != "" {
		fn := path.Join(ctx.app.Options.StaticRoot, "resize", util.ResizeKey(ctrl.Request.URI(), resize))
		if util.Exist(fn) {
			ctrl.File(fn)
			return true
		}
		if rect, err := util.ParseRect(resize, "x"); err == nil {
			f1 := path.Join(ctx.app.Options.StaticRoot, ctrl.Request.URI())
			ctx.Info("f1 :%s", f1)
			if src, err := imaging.Open(f1); err == nil {
				dst := imaging.Resize(src, rect.Width, rect.Height, imaging.Lanczos)
				if err := imaging.Save(dst, fn); err == nil {
					ctrl.File(fn)
					return true
				}
			}
		}
	}

	fit := ctrl.Request.Param("fit")
	if fit != "" {
		fn := path.Join(ctx.app.Options.StaticRoot, "fit", util.ResizeKey(ctrl.Request.URI(), resize))
		if util.Exist(fn) {
			ctrl.File(fn)
			return true
		}
		if rect, err := util.ParseRect(resize, "x"); err == nil {
			f1 := path.Join(ctx.app.Options.StaticRoot, ctrl.Request.URI())
			if src, err := imaging.Open(f1); err == nil {
				dst := imaging.Fit(src, rect.Width, rect.Height, imaging.Lanczos)
				if err := imaging.Save(dst, fn); err == nil {
					ctrl.File(fn)
					return true
				}
			}
		}
	}

	thumbnail := ctrl.Request.Param("thumbnail")
	if thumbnail != "" {
		fn := path.Join(ctx.app.Options.StaticRoot, "thumbnail", util.ResizeKey(ctrl.Request.URI(), resize))
		if util.Exist(fn) {
			ctrl.File(fn)
			return true
		}
		if rect, err := util.ParseRect(thumbnail, "x"); err == nil {
			f1 := path.Join(ctx.app.Options.StaticRoot, ctrl.Request.URI())
			if src, err := imaging.Open(f1); err == nil {
				dst := imaging.Thumbnail(src, rect.Width, rect.Height, imaging.Lanczos)
				if err := imaging.Save(dst, fn); err == nil {
					ctrl.File(fn)
					return true
				}
			}
		}
	}

	return false
}
コード例 #15
0
ファイル: download.go プロジェクト: rdterner/photoview
func (p *program) downloadWriteKey(key string, w http.ResponseWriter) error {
	bl, found := downloadMapper[key]
	if !found {
		http.Error(w, "Not found", 404)
		return nil
	}

	w.Header().Set("Content-Disposition", `attachment; filename="photos.tar"`)

	tw := tar.NewWriter(w)

	result := &bytes.Buffer{}

	for _, item := range bl.list {
		filename := filepath.Join(config.FileRoot, bl.folder, item)
		fi, err := os.Stat(filename)
		if err != nil {
			return err
		}
		if !bl.small {
			header, err := tar.FileInfoHeader(fi, "")
			if err != nil {
				return err
			}
			err = tw.WriteHeader(header)
			if err != nil {
				return err
			}
			f, err := os.Open(filename)
			if err != nil {
				return err
			}
			_, err = io.Copy(tw, f)
			f.Close()
			if err != nil {
				return err
			}
		} else {
			fullImage, err := imaging.Open(filename)
			if err != nil {
				return err
			}
			resized := imaging.Fit(fullImage, config.SmallRes, config.SmallRes, imaging.Linear)

			err = imaging.Encode(result, resized, imaging.JPEG)
			if err != nil {
				return err
			}

			header := &tar.Header{
				Name:    item,
				Size:    int64(result.Len()),
				Mode:    0666,
				ModTime: fi.ModTime(),
			}
			err = tw.WriteHeader(header)
			if err != nil {
				return err
			}
			_, err = io.Copy(tw, result)
			if err != nil {
				return err
			}
			result.Reset()
		}
	}

	return tw.Close()
}
コード例 #16
0
ファイル: transform.go プロジェクト: victortrac/imageproxy
// transformImage modifies the image m based on the transformations specified
// in opt.
func transformImage(m image.Image, opt Options) image.Image {
	// convert percentage width and height values to absolute values
	imgW := m.Bounds().Max.X - m.Bounds().Min.X
	imgH := m.Bounds().Max.Y - m.Bounds().Min.Y
	var w, h int
	if 0 < opt.Width && opt.Width < 1 {
		w = int(float64(imgW) * opt.Width)
	} else if opt.Width < 0 {
		w = 0
	} else {
		w = int(opt.Width)
	}
	if 0 < opt.Height && opt.Height < 1 {
		h = int(float64(imgH) * opt.Height)
	} else if opt.Height < 0 {
		h = 0
	} else {
		h = int(opt.Height)
	}

	// never resize larger than the original image
	if !opt.ScaleUp {
		if w > imgW {
			w = imgW
		}
		if h > imgH {
			h = imgH
		}
	}

	// resize
	if w != 0 || h != 0 {
		if opt.Fit {
			m = imaging.Fit(m, w, h, resampleFilter)
		} else {
			if w == 0 || h == 0 {
				m = imaging.Resize(m, w, h, resampleFilter)
			} else {
				m = imaging.Thumbnail(m, w, h, resampleFilter)
			}
		}
	}

	// flip
	if opt.FlipVertical {
		m = imaging.FlipV(m)
	}
	if opt.FlipHorizontal {
		m = imaging.FlipH(m)
	}

	// rotate
	switch opt.Rotate {
	case 90:
		m = imaging.Rotate90(m)
	case 180:
		m = imaging.Rotate180(m)
	case 270:
		m = imaging.Rotate270(m)
	}

	return m
}
コード例 #17
0
ファイル: thumbnails.go プロジェクト: thechriswalker/opfs
func getItemThumbnail(s *Service, i *Item, size int) (io.ReadSeeker, string, error) {
	key := fmt.Sprintf("thumb-%s-%d", i.Hash, size)
	fn := func() (interface{}, error) {

		//first check cache.
		if cached, err := s.cache.Get(key); err == nil {
			return &readSeekerMimeType{read: cached}, nil
		}

		//massive short cut here. if we have a "large" thumb then just resize that...
		if size < THUMBNAIL_LARGE {
			//check cache for LARGE
			key := fmt.Sprintf("thumb-%s-%d", i.Hash, THUMBNAIL_LARGE)
			if cached, err := s.cache.Get(key); err == nil {
				//resize this.
				if img, _, err := image.Decode(cached); err != nil {
					img = imaging.Fit(img, size, size, imaging.Box)
					var wr bytes.Buffer
					if err := jpeg.Encode(&wr, img, nil); err != nil {
						r := bytes.NewReader(wr.Bytes())
						s.cache.SetReader(key, r)
						return &readSeekerMimeType{read: r, mime: "image/jpeg"}, nil
					}
				}
			}
		}

		//no cache, create file.
		rsc, err := s.store.Get(i.Hash)
		if err != nil {
			return nil, err
		}
		defer rsc.Close()
		var r io.ReadSeeker
		var m string

		//to get the type factory that may be capable of creating a thumbnail we use
		//the typeMap
		f := InspecterFor(i)
		var ok bool
		var tmb Thumbnailer
		if f != nil {
			tmb, ok = f.(Thumbnailer)
		}
		if ok {
			if err = f.EnsureMeta(i); err == nil {
				//ensure we don't try to make too many at once...
				//before we block on putting a token into the bucket. if the bucket is full this will block.
				//after we take a token out of the bucket, so another can process.
				thumbLimit <- struct{}{}
				r, m, err = tmb.Thumbnail(rsc, size)
				<-thumbLimit
				s.cache.SetReader(key, r)
			}
		} else {
			//fake it
			return &readSeekerMimeType{
				read: bytes.NewReader(createGif(uint16(size), uint16(size))),
				mime: "image/gif",
			}, nil
		}
		if err != nil {
			return nil, err
		}
		return &readSeekerMimeType{read: r, mime: m}, nil
	}
	r, err := thumbGroup.Do(key, fn)
	if err != nil {
		return nil, "", err
	}
	rsmt := r.(*readSeekerMimeType)
	return rsmt.read, rsmt.mime, nil
}
コード例 #18
0
ファイル: db.go プロジェクト: sisteamnik/guseful
func (a *Api) Create(data []byte, name string, descr string) (Img, error) {
	named := true
	bts := bytes.NewReader(data)
	img, _, err := image.Decode(bts)
	if err != nil {
		return Img{}, err
	}

	tm := time.Now()

	if name == "" || len(name) <= int(a.nesting) {
		name = randName()
		named = false
	}

	for {
		found, err := a.ExistName(name)
		if err != nil {
			return Img{}, err
		}
		if found {
			name = randName()
		}
		if !found {
			break
		}
	}

	path := a.path

	for i := uint8(0); i < a.nesting; i++ {
		path += "/" + name[i:i+1]
	}

	os.MkdirAll(path, 0777)
	for _, v := range a.sizes {
		save_path := path + "/" + name + "_" + strconv.Itoa(v.Width) + "x" +
			strconv.Itoa(v.Height)
		save_path_with_ex := save_path + ".jpg"
		if v.Crop == "thumb" {
			c := imaging.Thumbnail(img, v.Width, v.Height, imaging.Lanczos)
			imaging.Save(c, save_path_with_ex)
		} else if v.Crop == "fit" {
			c := imaging.Fit(img, v.Width, v.Height, imaging.Lanczos)
			imaging.Save(c, save_path_with_ex)
		}
		if a.WebpAddr != "" {
			cmd := exec.Command(a.WebpAddr, save_path_with_ex, "-o",
				save_path+".webp")
			err := cmd.Run()
			if err != nil {
				fmt.Println(err)
				return Img{}, errors.New("Webp Not Working")
			}
		}

	}
	out, err := os.Create(path + "/" + name + ".jpg")
	if err != nil {
		return Img{}, err
	}
	defer out.Close()
	jpeg.Encode(out, img, nil)

	if a.WebpAddr != "" {
		cmd := exec.Command(a.WebpAddr, path+"/"+name+".jpg", "-o",
			path+"/"+name+".webp")
		err := cmd.Run()
		if err != nil {
			fmt.Println(err)
			return Img{}, errors.New("Webp Not Working")
		}
	}

	im := Img{
		Name:        name,
		Description: descr,
		Named:       named,
		Created:     tm.UnixNano(),
		Updated:     tm.UnixNano(),
	}

	err = a.Db.Insert(&im)
	if err != nil {
		return Img{}, err
	}
	return im, nil
}
コード例 #19
0
ファイル: file.go プロジェクト: rdterner/photoview
func (p *program) serveFile(w http.ResponseWriter, r *http.Request, fullPath, urlPath, resolutionString string) error {
	if len(resolutionString) == 0 {
		http.ServeFile(w, r, fullPath)
		return nil
	}
	createThumbFrom := fullPath
	imgSize, err := strconv.Atoi(resolutionString)
	if err != nil {
		return err
	}
	isMovie := false
	cachePath := filepath.Join(p.cacheDir, r.URL.Path)
	if strings.HasSuffix(urlPath, ".mp4") {
		// Movie: avconv -i /data/store/Pictures/2015-Q1/VID_20150125_1928.mp4 -vframes 1 -ss 00:00:01 out.jpg
		createThumbFrom = cachePath + ".orig.jpg"
		cachePath = cachePath + ".jpg"
		isMovie = true
	}
	_, err = os.Stat(cachePath)
	if os.IsNotExist(err) {
		if isMovie {
			var output []byte
			for _, time := range movieTimes {
				cmd := exec.Command("avconv", "-i", fullPath, "-vframes", "1", "-ss", time, createThumbFrom)
				output, err = cmd.CombinedOutput()
				if err == nil {
					_, err = os.Stat(createThumbFrom)
					// Make sure avconv wrote file.
					if os.IsNotExist(err) {
						continue
					}
					break
				}
			}
			if err != nil {
				logger.Errorf("Problem converting thumbnail for movie: %v\n%s\n", err, output)
				createThumbFrom = filepath.Join(p.execDir, "template", badThumb)
			}
		}
		// Resize image, open cache image.
		cacheDir, _ := filepath.Split(cachePath)
		err := os.MkdirAll(cacheDir, 0777)
		if err != nil {
			return err
		}
		fullImage, err := imaging.Open(createThumbFrom)
		if err != nil {
			return err
		}
		resized := imaging.Fit(fullImage, imgSize, imgSize, imaging.Linear)
		// Um, assume JPG for now.
		cf, err := os.Create(cachePath)
		if err != nil {
			return err
		}
		err = imaging.Encode(cf, resized, imaging.JPEG)
		cf.Close()
		if err != nil {
			return err
		}
	}
	http.ServeFile(w, r, cachePath)
	return nil
}