|  |  |  | @ -1,26 +1,27 @@ | 
			
		
	
		
			
				
					|  |  |  |  | package media | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | import ( | 
			
		
	
		
			
				
					|  |  |  |  | 	"fmt" | 
			
		
	
		
			
				
					|  |  |  |  | 	"image" | 
			
		
	
		
			
				
					|  |  |  |  | 	"image/jpeg" | 
			
		
	
		
			
				
					|  |  |  |  | 	"io" | 
			
		
	
		
			
				
					|  |  |  |  | 	"net/http" | 
			
		
	
		
			
				
					|  |  |  |  | 	"os" | 
			
		
	
		
			
				
					|  |  |  |  | 	"path" | 
			
		
	
		
			
				
					|  |  |  |  | 	"path/filepath" | 
			
		
	
		
			
				
					|  |  |  |  | 	"regexp" | 
			
		
	
		
			
				
					|  |  |  |  | 	"sort" | 
			
		
	
		
			
				
					|  |  |  |  | 	"strconv" | 
			
		
	
		
			
				
					|  |  |  |  | 	"time" | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	// for processing images
 | 
			
		
	
		
			
				
					|  |  |  |  | 	_ "image/gif" | 
			
		
	
		
			
				
					|  |  |  |  | 	_ "image/png" | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	"github.com/nfnt/resize" | 
			
		
	
		
			
				
					|  |  |  |  | 	"github.com/tajtiattila/metadata" | 
			
		
	
		
			
				
					|  |  |  |  | ) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | const ( | 
			
		
	
		
			
				
					|  |  |  |  | 	TypeImage = "image" | 
			
		
	
		
			
				
					|  |  |  |  | 	TypeVideo = "video" | 
			
		
	
		
			
				
					|  |  |  |  | ) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | type MediaSource struct { | 
			
		
	
		
			
				
					|  |  |  |  | 	StorageDir string | 
			
		
	
		
			
				
					|  |  |  |  | 	ThumbDir   string | 
			
		
	
	
		
			
				
					|  |  |  | @ -34,32 +35,39 @@ type Media struct { | 
			
		
	
		
			
				
					|  |  |  |  | 	Size     image.Rectangle | 
			
		
	
		
			
				
					|  |  |  |  | 	FullName string | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	ms       *MediaSource | 
			
		
	
		
			
				
					|  |  |  |  | 	metadata *metadata.Metadata | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | func (ms *MediaSource) LocationOrig(m Media) string { | 
			
		
	
		
			
				
					|  |  |  |  | 	return path.Join(ms.StorageDir, m.Name) | 
			
		
	
		
			
				
					|  |  |  |  | func (m Media) ThumbPath(size image.Rectangle) string { | 
			
		
	
		
			
				
					|  |  |  |  | 	return "/" + thumbPath(size, m.Name) | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | func (ms *MediaSource) ThumbPath(m Media, size image.Rectangle) string { | 
			
		
	
		
			
				
					|  |  |  |  | 	w := size.Dx() | 
			
		
	
		
			
				
					|  |  |  |  | 	h := size.Dy() | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	var ws, hs string | 
			
		
	
		
			
				
					|  |  |  |  | func (m Media) ThumbFilename(size image.Rectangle) string { | 
			
		
	
		
			
				
					|  |  |  |  | 	size = m.NormalizeSize(size) | 
			
		
	
		
			
				
					|  |  |  |  | 	return thumbFilename(m.ms.ThumbDir, size, m.Name) | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if w != 0 { | 
			
		
	
		
			
				
					|  |  |  |  | 		ws = fmt.Sprint(w) | 
			
		
	
		
			
				
					|  |  |  |  | func (ms *MediaSource) ServeHTTP(w http.ResponseWriter, r *http.Request) { | 
			
		
	
		
			
				
					|  |  |  |  | 	m, err := ms.ByName(path.Base(r.URL.Path)) | 
			
		
	
		
			
				
					|  |  |  |  | 	if err != nil { | 
			
		
	
		
			
				
					|  |  |  |  | 		http.Error(w, err.Error(), http.StatusInternalServerError) | 
			
		
	
		
			
				
					|  |  |  |  | 		return | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	if h != 0 { | 
			
		
	
		
			
				
					|  |  |  |  | 		hs = fmt.Sprint(h) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	sizeRequested, err := SizeRequested(r.URL.Path, m.Size) | 
			
		
	
		
			
				
					|  |  |  |  | 	if err != nil { | 
			
		
	
		
			
				
					|  |  |  |  | 		http.Error(w, err.Error(), http.StatusBadRequest) | 
			
		
	
		
			
				
					|  |  |  |  | 		return | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	thumbSlug := filepath.Join(fmt.Sprintf("%sx%s", ws, hs), m.Name) | 
			
		
	
		
			
				
					|  |  |  |  | 	return path.Join("/media", thumbSlug) | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 	size, err := ms.Thumb(*m, sizeRequested) | 
			
		
	
		
			
				
					|  |  |  |  | 	if err != nil { | 
			
		
	
		
			
				
					|  |  |  |  | 		http.Error(w, err.Error(), http.StatusBadRequest) | 
			
		
	
		
			
				
					|  |  |  |  | 		return | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | func (ms *MediaSource) ThumbFilename(m Media, size image.Rectangle) string { | 
			
		
	
		
			
				
					|  |  |  |  | 	return filepath.Join(ms.ThumbDir, ms.ThumbPath(m, size)) | 
			
		
	
		
			
				
					|  |  |  |  | 	http.ServeFile(w, r, m.ThumbFilename(size)) | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | func (ms *MediaSource) ReceiveNewMedia(name string, r io.Reader) error { | 
			
		
	
	
		
			
				
					|  |  |  | @ -118,123 +126,33 @@ func (m *Media) getMetadata() error { | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | func (ms *MediaSource) Size(name string) (image.Rectangle, error) { | 
			
		
	
		
			
				
					|  |  |  |  | 	f, err := os.Open(name) | 
			
		
	
		
			
				
					|  |  |  |  | 	if err != nil { | 
			
		
	
		
			
				
					|  |  |  |  | 		return image.ZR, err | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	defer f.Close() | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	cfg, _, err := image.DecodeConfig(f) | 
			
		
	
		
			
				
					|  |  |  |  | 	if err != nil { | 
			
		
	
		
			
				
					|  |  |  |  | 		return image.ZR, err | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	width := cfg.Width | 
			
		
	
		
			
				
					|  |  |  |  | 	height := cfg.Height | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	return image.Rect(0, 0, width, height), nil | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | func (ms *MediaSource) ThumbMax(m Media, maxDim int) (string, image.Rectangle, error) { | 
			
		
	
		
			
				
					|  |  |  |  | 	f, err := os.Open(ms.LocationOrig(m)) | 
			
		
	
		
			
				
					|  |  |  |  | 	if err != nil { | 
			
		
	
		
			
				
					|  |  |  |  | 		return "", image.ZR, err | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	defer f.Close() | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	cfg, _, err := image.DecodeConfig(f) | 
			
		
	
		
			
				
					|  |  |  |  | 	if err != nil { | 
			
		
	
		
			
				
					|  |  |  |  | 		return "", image.ZR, err | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	width := cfg.Width | 
			
		
	
		
			
				
					|  |  |  |  | 	height := cfg.Height | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if width > height { | 
			
		
	
		
			
				
					|  |  |  |  | 		height = height * maxDim / width | 
			
		
	
		
			
				
					|  |  |  |  | 		width = maxDim | 
			
		
	
		
			
				
					|  |  |  |  | 	} else { | 
			
		
	
		
			
				
					|  |  |  |  | 		width = width * maxDim / height | 
			
		
	
		
			
				
					|  |  |  |  | 		height = maxDim | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	size := image.Rect(0, 0, width, height) | 
			
		
	
		
			
				
					|  |  |  |  | 	if ms.HasThumb(m, size) { | 
			
		
	
		
			
				
					|  |  |  |  | 		return ms.ThumbPath(m, size), size, nil | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	_, err = f.Seek(0, io.SeekStart) | 
			
		
	
		
			
				
					|  |  |  |  | 	if err != nil { | 
			
		
	
		
			
				
					|  |  |  |  | 		return "", image.ZR, err | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	src, err := ms.thumbReader(f, m, size) | 
			
		
	
		
			
				
					|  |  |  |  | 	return src, size, err | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | func (ms *MediaSource) HasThumb(m Media, size image.Rectangle) bool { | 
			
		
	
		
			
				
					|  |  |  |  | 	fi, err := os.Stat(ms.ThumbFilename(m, size)) | 
			
		
	
		
			
				
					|  |  |  |  | 	if err != nil { | 
			
		
	
		
			
				
					|  |  |  |  | 		return false | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	return m.Date().Before(fi.ModTime()) | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | func (ms *MediaSource) ByName(name string) *Media { | 
			
		
	
		
			
				
					|  |  |  |  | 	size, _ := ms.Size(path.Join(ms.StorageDir, name)) | 
			
		
	
		
			
				
					|  |  |  |  | 	m := Media{ | 
			
		
	
		
			
				
					|  |  |  |  | 		Type: "image", | 
			
		
	
		
			
				
					|  |  |  |  | 		Name: name, | 
			
		
	
		
			
				
					|  |  |  |  | 		Size: size, | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	m.FullName = ms.LocationOrig(m) | 
			
		
	
		
			
				
					|  |  |  |  | 	return &m | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | func (ms *MediaSource) Thumb(m Media, size image.Rectangle) (string, error) { | 
			
		
	
		
			
				
					|  |  |  |  | 	if ms.HasThumb(m, size) { | 
			
		
	
		
			
				
					|  |  |  |  | 		return ms.ThumbPath(m, size), nil | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	f, err := os.Open(ms.LocationOrig(m)) | 
			
		
	
		
			
				
					|  |  |  |  | 	if err != nil { | 
			
		
	
		
			
				
					|  |  |  |  | 		return "", err | 
			
		
	
		
			
				
					|  |  |  |  | 	switch filepath.Ext(name) { | 
			
		
	
		
			
				
					|  |  |  |  | 	case ".mp4": | 
			
		
	
		
			
				
					|  |  |  |  | 		return VideoSize(name) | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	defer f.Close() | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	return ms.thumbReader(f, m, size) | 
			
		
	
		
			
				
					|  |  |  |  | 	return imageSize(name) | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | func (ms *MediaSource) thumbReader(r io.Reader, m Media, size image.Rectangle) (string, error) { | 
			
		
	
		
			
				
					|  |  |  |  | 	img, _, err := image.Decode(r) | 
			
		
	
		
			
				
					|  |  |  |  | 	if err != nil { | 
			
		
	
		
			
				
					|  |  |  |  | 		return "", err | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | func (ms *MediaSource) ByName(name string) (*Media, error) { | 
			
		
	
		
			
				
					|  |  |  |  | 	ext := filepath.Ext(name) | 
			
		
	
		
			
				
					|  |  |  |  | 	typ := TypeImage | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	return ms.ThumbImage(img, m, size) | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | func (ms *MediaSource) ThumbImage(img image.Image, m Media, size image.Rectangle) (string, error) { | 
			
		
	
		
			
				
					|  |  |  |  | 	thumbLoc := ms.ThumbFilename(m, size) | 
			
		
	
		
			
				
					|  |  |  |  | 	os.MkdirAll(path.Dir(thumbLoc), 0755) | 
			
		
	
		
			
				
					|  |  |  |  | 	fthumb, err := os.OpenFile(thumbLoc, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0655) | 
			
		
	
		
			
				
					|  |  |  |  | 	if err != nil { | 
			
		
	
		
			
				
					|  |  |  |  | 		return "", err | 
			
		
	
		
			
				
					|  |  |  |  | 	switch ext { | 
			
		
	
		
			
				
					|  |  |  |  | 	case ".mp4": | 
			
		
	
		
			
				
					|  |  |  |  | 		typ = TypeVideo | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	img = resize.Resize(uint(size.Dx()), uint(size.Dy()), img, resize.Bilinear) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	err = jpeg.Encode(fthumb, img, nil) | 
			
		
	
		
			
				
					|  |  |  |  | 	if err != nil { | 
			
		
	
		
			
				
					|  |  |  |  | 		return "", err | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	fullName := path.Join(ms.StorageDir, name) | 
			
		
	
		
			
				
					|  |  |  |  | 	size, _ := ms.Size(fullName) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	err = fthumb.Close() | 
			
		
	
		
			
				
					|  |  |  |  | 	if err != nil { | 
			
		
	
		
			
				
					|  |  |  |  | 		return "", err | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	return ms.ThumbPath(m, size), nil | 
			
		
	
		
			
				
					|  |  |  |  | 	return &Media{ | 
			
		
	
		
			
				
					|  |  |  |  | 		Type:     typ, | 
			
		
	
		
			
				
					|  |  |  |  | 		Name:     name, | 
			
		
	
		
			
				
					|  |  |  |  | 		Size:     size, | 
			
		
	
		
			
				
					|  |  |  |  | 		FullName: fullName, | 
			
		
	
		
			
				
					|  |  |  |  | 		ms:       ms, | 
			
		
	
		
			
				
					|  |  |  |  | 	}, nil | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | func (ms *MediaSource) Walk() ([]*Media, error) { | 
			
		
	
	
		
			
				
					|  |  |  | @ -248,7 +166,11 @@ func (ms *MediaSource) Walk() ([]*Media, error) { | 
			
		
	
		
			
				
					|  |  |  |  | 			if fi.IsDir() { | 
			
		
	
		
			
				
					|  |  |  |  | 				return nil | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 			media = append(media, ms.ByName(path.Base(name))) | 
			
		
	
		
			
				
					|  |  |  |  | 			m, err := ms.ByName(path.Base(name)) | 
			
		
	
		
			
				
					|  |  |  |  | 			if err != nil { | 
			
		
	
		
			
				
					|  |  |  |  | 				return nil | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 			media = append(media, m) | 
			
		
	
		
			
				
					|  |  |  |  | 			return nil | 
			
		
	
		
			
				
					|  |  |  |  | 		}) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -271,49 +193,6 @@ func (s Set) ByDate() Set { | 
			
		
	
		
			
				
					|  |  |  |  | 	return s | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | var ( | 
			
		
	
		
			
				
					|  |  |  |  | 	sizeString = regexp.MustCompile(`([0-9]*)(x)?([0-9]*)`) | 
			
		
	
		
			
				
					|  |  |  |  | ) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | func ParseSizeString(str string, actual image.Rectangle) (image.Rectangle, error) { | 
			
		
	
		
			
				
					|  |  |  |  | 	var err = fmt.Errorf("expected a size string {width}x{height}, saw %q", str) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	strs := sizeString.FindStringSubmatch(str) | 
			
		
	
		
			
				
					|  |  |  |  | 	if len(strs) < 4 { | 
			
		
	
		
			
				
					|  |  |  |  | 		return image.ZR, err | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	var w, h int | 
			
		
	
		
			
				
					|  |  |  |  | 	var strconvErr error | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if strs[1] != "" { | 
			
		
	
		
			
				
					|  |  |  |  | 		w, strconvErr = strconv.Atoi(strs[1]) | 
			
		
	
		
			
				
					|  |  |  |  | 		if strconvErr != nil { | 
			
		
	
		
			
				
					|  |  |  |  | 			return image.ZR, err | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if strs[3] != "" { | 
			
		
	
		
			
				
					|  |  |  |  | 		h, strconvErr = strconv.Atoi(strs[3]) | 
			
		
	
		
			
				
					|  |  |  |  | 		if strconvErr != nil { | 
			
		
	
		
			
				
					|  |  |  |  | 			return image.ZR, err | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if strs[2] != "x" { | 
			
		
	
		
			
				
					|  |  |  |  | 		// w was the only dimension given, so set it to the greater dimension
 | 
			
		
	
		
			
				
					|  |  |  |  | 		// of the actual image size
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if actual.Dx() > actual.Dy() { | 
			
		
	
		
			
				
					|  |  |  |  | 			h = 0 | 
			
		
	
		
			
				
					|  |  |  |  | 		} else { | 
			
		
	
		
			
				
					|  |  |  |  | 			h = w | 
			
		
	
		
			
				
					|  |  |  |  | 			w = 0 | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	return image.Rect(0, 0, w, h), nil | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | func removeExtension(name string) string { | 
			
		
	
		
			
				
					|  |  |  |  | 	ext := path.Ext(name) | 
			
		
	
		
			
				
					|  |  |  |  | 	return name[:len(name)-len(ext)] | 
			
		
	
	
		
			
				
					|  |  |  | 
 |