Exemple #1
0
func (ths *ImageTagServer) go_get_image(w http.ResponseWriter, r *http.Request) {
	path := r.URL.Query().Get("path")
	path = ths.imgRoot + path
	path = strings.Replace(path, "..", "", -1)

	info, infoErr := os.Stat(path)
	if infoErr != nil {
		http.Error(w, infoErr.Error(), http.StatusInternalServerError)
		return
	}

	if info.IsDir() == true {
		http.Error(w, "No an image", http.StatusBadRequest)
		return
	}

	img, err := imaging.Open(path)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Add("Content-Type", "image/jpeg")
	err = imaging.Encode(w, img, imaging.JPEG)
	if err != nil {
		http.Error(w, "Failed to thumbNail image", http.StatusInternalServerError)
		return
	}

}
Exemple #2
0
func (imageHandler) Handle(media MediaLibrary, file multipart.File, option *Option) error {
	if err := media.Store(media.URL("original"), option, file); err == nil {
		file.Seek(0, 0)

		if img, err := imaging.Decode(file); err == nil {
			if format, err := getImageFormat(media.URL()); err == nil {
				if cropOption := media.GetCropOption("original"); cropOption != nil {
					img = imaging.Crop(img, *cropOption)
				}

				// Save default image
				var buffer bytes.Buffer
				imaging.Encode(&buffer, img, *format)
				media.Store(media.URL(), option, &buffer)

				for key, size := range media.GetSizes() {
					newImage := img
					if cropOption := media.GetCropOption(key); cropOption != nil {
						newImage = imaging.Crop(newImage, *cropOption)
					}

					dst := imaging.Thumbnail(newImage, size.Width, size.Height, imaging.Lanczos)
					var buffer bytes.Buffer
					imaging.Encode(&buffer, dst, *format)
					media.Store(media.URL(key), option, &buffer)
				}
				return nil
			} else {
				return err
			}
		} else {
			return err
		}
	} else {
		return err
	}
}
Exemple #3
0
func Resize(src io.Reader, c *CacheContext) (io.Reader, error) {
	raw, err := ioutil.ReadAll(src)
	if err != nil {
		return nil, err
	}

	width := c.Width
	data := bytes.NewReader(raw)
	img, format, err := image.Decode(data)
	if err != nil {
		return nil, err
	}
	var resizedImage image.NRGBA
	if c.Crop {

		minDimension := int(math.Min(float64(img.Bounds().Size().X), float64(img.Bounds().Size().Y)))

		if minDimension < c.Width || c.Width == 0 {
			width = minDimension
		}

		resizedImage = *imaging.Fill(img, width, width, imaging.Center, imaging.Lanczos)
	} else {
		resizedImage = *imaging.Resize(img, width, 0, imaging.Lanczos)
	}

	buf := new(bytes.Buffer)
	var imgFormat imaging.Format
	switch format {
	case "png":
		imgFormat = imaging.PNG
	case "jpeg":
		imgFormat = imaging.JPEG
	case "tiff":
		imgFormat = imaging.TIFF
	case "bmp":
		imgFormat = imaging.BMP
	default:
		return nil, errors.New("unsupported image format")
	}

	err = imaging.Encode(buf, resizedImage.SubImage(resizedImage.Rect), imgFormat)
	if err != nil {
		return nil, err
	}

	return buf, err

}
Exemple #4
0
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
}
Exemple #5
0
func thumbnailHandler(w http.ResponseWriter, r *http.Request) {
	query := r.URL.Query()
	height, err := strconv.Atoi(query.Get("height"))
	if err != nil {
		height = 50
	}
	path := filepath.Join(storage, r.URL.Path)
	photo, err := imaging.Open(path)
	if err != nil {
		fmt.Fprint(w, err)
		return
	}
	switch readRotation(path) {
	case 8:
		photo = imaging.Rotate90(photo)
	case 2:
		photo = imaging.Rotate180(photo)
	case 6:
		photo = imaging.Rotate270(photo)
	}
	thumb := imaging.Resize(photo, 0, height, imaging.Box)
	imaging.Encode(w, thumb, imaging.JPEG)
}
Exemple #6
0
// Do performs the resize
func Do(r io.Reader, w io.Writer, crop *image.Rectangle, width, height int) error {
	// read it
	img, err := imaging.Decode(r)
	if err != nil {
		return err
	}

	// if crop isn't nil
	if crop != nil {
		// then crop it
		img = imaging.Crop(img, *crop)
	}

	// resize it
	img = imaging.Resize(img, width, height, imaging.MitchellNetravali)

	// write it
	if err := imaging.Encode(w, img, imaging.PNG); err != nil {
		return err
	}

	return nil
}
Exemple #7
0
/*
	blurImage: blur the image and save it
*/
func blurImage(inFilename string, outFilename string, factor float64, format imaging.Format) {
	//
	// print a message about what we are converting
	//
	fmt.Println("\t\t", inFilename, "=>", outFilename, "using factor", factor)

	//
	// Open the file and read in the image
	//
	infile, err := os.Open(inFilename)
	errorCheck(err)
	defer infile.Close()

	//
	// load in the actual image data (decode image) and work out the new dimensions
	//
	srcImage, _, err := image.Decode(infile)
	errorCheck(err)

	//
	// blue the image...
	//

	blurredImage := imaging.Blur(srcImage, factor)

	//
	// save the new image
	//
	outfile, err := os.Create(outFilename)
	errorCheck(err)
	defer outfile.Close()

	imaging.Encode(outfile, blurredImage, format)

	// png.Encode(outfile, blurredImage)

}
Exemple #8
0
func (ths *ImageTagServer) go_thumb_image(w http.ResponseWriter, r *http.Request) {
	imgPath := r.URL.Query().Get("path")
	path := imgPath
	path = ths.imgRoot + path
	path = strings.Replace(path, "..", "", -1)

	info, infoErr := os.Stat(path)
	if infoErr != nil {
		http.Error(w, infoErr.Error(), http.StatusInternalServerError)
		return
	}

	db := ths.get_db()
	if db == nil {
		return
	}
	defer db.Close()

	row, rerr := db.Query("SELECT Thumb FROM Image WHERE Path LIKE '" + imgPath + "';")
	if rerr != nil {
		log.Println(rerr.Error())
		http.Error(w, rerr.Error(), http.StatusInternalServerError)
		return
	}

	if row.Next() {
		var result string
		e := row.Scan(&result)
		if e != nil {
			log.Println(e.Error())
			http.Error(w, e.Error(), http.StatusInternalServerError)
			return
		}
		b, _ := base64.StdEncoding.DecodeString(result)

		w.Header().Add("Content-Type", "image/jpeg")
		w.Write(b)
		return
	}

	if info.IsDir() == true {
		http.Error(w, "No an image", http.StatusBadRequest)
		return
	}

	img, err := imaging.Open(path)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	thumb := imaging.Thumbnail(img, 300, 300, imaging.CatmullRom)

	buffer := bytes.NewBuffer(nil)
	imaging.Encode(buffer, thumb, imaging.JPEG)
	b64 := base64.StdEncoding.EncodeToString(buffer.Bytes())

	insertRes, insertResErr := db.Exec("INSERT INTO Image(Path,Thumb) VALUES('" + imgPath + "','" + b64 + "');")
	if insertResErr != nil {
		log.Println(insertResErr.Error())
		http.Error(w, insertResErr.Error(), http.StatusInternalServerError)
		return
	}
	iid, _ := insertRes.LastInsertId()
	log.Println("Added image \"" + imgPath + "\" with id " + strconv.FormatInt(iid, 10))

	w.Header().Add("Content-Type", "image/jpeg")
	w.Write(buffer.Bytes())
	if err != nil {
		http.Error(w, "Failed to thumbNail image", http.StatusInternalServerError)
		return
	}

}
Exemple #9
0
func storeImage(rw http.ResponseWriter, req *http.Request) {
	// Appengine
	var c appengine.Context
	// Google Cloud Storage authentication
	var cc gcscontext.Context
	// Google Cloud Storage bucket name
	var bucketName string = ""
	// Google Cloud Storage client
	var client *storage.Client
	// Google Cloud Storage bucket
	var bucketHandle *storage.BucketHandle
	// User uploaded image file name
	var fileName string = uuid.New()
	// Transform user uploaded image to a thumbnail file name
	var fileNameThumbnail string = uuid.New()
	// User uploaded image file type
	var contentType string = ""
	// User uploaded image file raw data
	var b []byte
	// Google Cloud Storage file writer
	var wc *storage.Writer = nil
	// Error
	var err error = nil
	// Result, 0: success, 1: failed
	var r int = http.StatusCreated

	// Set response in the end
	defer func() {
		// Return status. WriteHeader() must be called before call to Write
		if r == http.StatusCreated {
			// Changing the header after a call to WriteHeader (or Write) has no effect.
			// rw.Header().Set("Location", req.URL.String()+"/"+cKey.Encode())
			rw.Header().Set("Location", "http://"+bucketName+".storage.googleapis.com/"+fileName)
			rw.Header().Set("X-Thumbnail", "http://"+bucketName+".storage.googleapis.com/"+fileNameThumbnail)
			rw.WriteHeader(r)
		} else {
			http.Error(rw, http.StatusText(r), r)
		}
	}()

	// To log information in Google APP Engine console
	c = appengine.NewContext(req)

	// Get data from body
	b, err = ioutil.ReadAll(req.Body)
	if err != nil {
		c.Errorf("%s in reading body", err)
		r = http.StatusInternalServerError
		return
	}
	c.Infof("Body length %d bytes, read %d bytes", req.ContentLength, len(b))

	// Determine filename extension from content type
	contentType = req.Header["Content-Type"][0]
	switch contentType {
	case "image/jpeg":
		fileName += ".jpg"
		fileNameThumbnail += ".jpg"
	default:
		c.Errorf("Unknown or unsupported content type '%s'. Valid: image/jpeg", contentType)
		r = http.StatusBadRequest
		return
	}
	c.Infof("Content type %s is received, %s is detected.", contentType, http.DetectContentType(b))

	// Prepare Google Cloud Storage authentication
	cc = gcsappengine.NewContext(req)
	if client, err = storage.NewClient(cc); err != nil {
		c.Errorf("%s in initializing a GCS client", err)
		r = http.StatusInternalServerError
		return
	}
	defer client.Close()

	// Get default bucket
	if bucketName, err = gcsfile.DefaultBucketName(cc); err != nil {
		c.Errorf("%s in getting default GCS bucket name", err)
		r = http.StatusInternalServerError
		return
	}
	bucketHandle = client.Bucket(bucketName)
	c.Infof("APP Engine Version: %s", gcsappengine.VersionID(cc))
	c.Infof("Using bucket name: %s", bucketName)

	// Change default object ACLs
	if err = bucketHandle.DefaultObjectACL().Set(cc, storage.AllUsers, storage.RoleReader); err != nil {
		c.Errorf("%v in saving default object ACL rule for bucket %q", err, bucketName)
		r = http.StatusInternalServerError
		return
	}

	// Store rotated image in Google Cloud Storage
	var in *bytes.Reader = bytes.NewReader(b)
	var x *exif.Exif = nil
	var orientation *tiff.Tag = nil
	var beforeImage image.Image
	var afterImage *image.NRGBA = nil

	// Read EXIF
	if _, err = in.Seek(0, 0); err != nil {
		c.Errorf("%s in moving the reader offset to the beginning in order to read EXIF", err)
		return
	}
	if x, err = exif.Decode(in); err != nil {
		c.Errorf("%s in decoding JPEG image", err)
		return
	}

	// Get Orientation
	if orientation, err = x.Get(exif.Orientation); err != nil {
		c.Warningf("%s in getting orientation from EXIF", err)
		return
	}
	c.Debugf("Orientation %s", orientation.String())

	// Open image
	if _, err = in.Seek(0, 0); err != nil {
		c.Errorf("%s in moving the reader offset to the beginning in order to read EXIF", err)
		return
	}
	if beforeImage, err = imaging.Decode(in); err != nil {
		c.Errorf("%s in opening image %s", err)
		return
	}

	switch orientation.String() {
	case "1":
		afterImage = beforeImage.(*image.NRGBA)
	case "2":
		afterImage = imaging.FlipH(beforeImage)
	case "3":
		afterImage = imaging.Rotate180(beforeImage)
	case "4":
		afterImage = imaging.FlipV(beforeImage)
	case "5":
		afterImage = imaging.Transverse(beforeImage)
	case "6":
		afterImage = imaging.Rotate270(beforeImage)
	case "7":
		afterImage = imaging.Transpose(beforeImage)
	case "8":
		afterImage = imaging.Rotate90(beforeImage)
	}

	// Save rotated image
	wc = bucketHandle.Object(fileName).NewWriter(cc)
	wc.ContentType = contentType
	if err = imaging.Encode(wc, afterImage, imaging.JPEG); err != nil {
		c.Errorf("%s in saving rotated image", err)
		return
	}
	if err = wc.Close(); err != nil {
		c.Errorf("CreateFile: unable to close bucket %q, file %q: %v", bucketName, fileName, err)
		r = 1
		return
	}
	wc = nil

	// Make thumbnail
	if afterImage.Rect.Dx() > afterImage.Rect.Dy() {
		afterImage = imaging.Resize(afterImage, 1920, 0, imaging.Lanczos)
	} else {
		afterImage = imaging.Resize(afterImage, 0, 1920, imaging.Lanczos)
	}

	// Save thumbnail
	wc = bucketHandle.Object(fileNameThumbnail).NewWriter(cc)
	wc.ContentType = contentType
	if imaging.Encode(wc, afterImage, imaging.JPEG); err != nil {
		c.Errorf("%s in saving image thumbnail", err)
		return
	}
	if err = wc.Close(); err != nil {
		c.Errorf("CreateFileThumbnail: unable to close bucket %q, file %q: %v", bucketName, fileNameThumbnail, err)
		r = 1
		return
	}

	c.Infof("/%v/%v, /%v/%v created", bucketName, fileName, bucketName, fileNameThumbnail)
}
Exemple #10
0
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()
}
Exemple #11
0
func SaveAndCropImage(isCreate bool) func(scope *gorm.Scope) {
	return func(scope *gorm.Scope) {
		for _, field := range scope.Fields() {
			if media, ok := field.Field.Addr().Interface().(MediaLibrary); ok {
				option := parseTagOption(field.Tag.Get("media_library"))
				if media.GetFileHeader() != nil || media.NeedCrop() {
					var file multipart.File
					var err error
					if fileHeader := media.GetFileHeader(); fileHeader != nil {
						file, err = media.GetFileHeader().Open()
					} else {
						file, err = media.Retrieve(media.URL("original"))
					}

					if scope.Err(err) != nil {
						return
					}

					if url := media.GetURL(option, scope, field, media); url == "" {
						scope.Err(errors.New("invalid URL"))
					} else {
						result, _ := json.Marshal(map[string]string{"Url": url})
						media.Scan(string(result))
					}

					if isCreate && !scope.HasError() {
						if value, err := media.Value(); err == nil {
							gorm.Update(scope.New(scope.Value).InstanceSet("gorm:update_attrs", map[string]interface{}{field.DBName: value}))
						}
					}

					if file != nil {
						defer file.Close()

						if media.IsImage() {
							// Save Original Image
							if scope.Err(media.Store(media.URL("original"), option, file)) == nil {
								file.Seek(0, 0)

								// Crop & Resize
								if img, err := imaging.Decode(file); scope.Err(err) == nil {
									if format, err := getImageFormat(media.URL()); scope.Err(err) == nil {
										if cropOption := media.GetCropOption("original"); cropOption != nil {
											img = imaging.Crop(img, *cropOption)
										}

										// Save default image
										var buffer bytes.Buffer
										imaging.Encode(&buffer, img, *format)
										media.Store(media.URL(), option, &buffer)

										for key, size := range media.GetSizes() {
											newImage := img
											if cropOption := media.GetCropOption(key); cropOption != nil {
												newImage = imaging.Crop(newImage, *cropOption)
											}

											dst := imaging.Thumbnail(newImage, size.Width, size.Height, imaging.Lanczos)
											var buffer bytes.Buffer
											imaging.Encode(&buffer, dst, *format)
											media.Store(media.URL(key), option, &buffer)
										}
									}
								}
							}
						} else {
							// Save File
							scope.Err(media.Store(media.URL(), option, file))
						}
					}
				}
			}
		}
	}
}
Exemple #12
0
func handleServeImage(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	img, err := ImageByID(sq.DB(ctx), web.Args(ctx).ByIndex(0))
	switch err {
	case nil:
		// all good
	case sq.ErrNotFound:
		web.StdJSONResp(w, http.StatusNotFound)
		return
	default:
		log.Error("cannot get object",
			"object", web.Args(ctx).ByIndex(0),
			"error", err.Error())
		web.StdJSONResp(w, http.StatusInternalServerError)
		return
	}

	if web.CheckLastModified(w, r, img.Created) {
		return
	}

	fs := FileStore(ctx)
	fd, err := fs.Read(img.Created.Year(), img.ImageID)
	if err != nil {
		log.Error("cannot read image file",
			"image", img.ImageID,
			"error", err.Error())
		web.StdJSONResp(w, http.StatusInternalServerError)
		return
	}
	defer fd.Close()

	w.Header().Set("X-Image-ID", img.ImageID)
	w.Header().Set("X-Image-Width", fmt.Sprint(img.Width))
	w.Header().Set("X-Image-Height", fmt.Sprint(img.Height))
	w.Header().Set("X-Image-Created", img.Created.Format(time.RFC3339))
	w.Header().Set("Content-Type", "image/jpeg")

	if r.URL.Query().Get("resize") == "" {
		io.Copy(w, fd)
		return
	}

	image, err := jpeg.Decode(fd)
	if err != nil {
		log.Error("cannot read image file",
			"image", img.ImageID,
			"error", err.Error())
		web.StdJSONResp(w, http.StatusInternalServerError)
		return
	}
	var width, height int
	if _, err := fmt.Sscanf(r.URL.Query().Get("resize"), "%dx%d", &width, &height); err != nil {
		log.Error("cannot resize image",
			"image", img.ImageID,
			"error", err.Error())
	} else {
		switch img.Orientation {
		case 1:
			// all good
		case 3:
			image = imaging.Rotate180(image)
		case 8:
			image = imaging.Rotate90(image)
		case 6:
			image = imaging.Rotate270(image)
		default:
			log.Debug("unknown image orientation",
				"decoder", "EXIF",
				"image", img.ImageID,
				"value", fmt.Sprint(img.Orientation))
		}
		image = imaging.Fill(image, width, height, imaging.Center, imaging.Linear)
	}
	imaging.Encode(w, image, imaging.JPEG)
}
Exemple #13
0
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
}
func thumbImage(r io.Reader, width int, height int) (buf *bytes.Buffer, err error) {
	buf = new(bytes.Buffer)

	imageData, err := ioutil.ReadAll(r)

	if err != nil {
		log.Println("cannot read response", err)
		return nil, err
	}

	imageBuffer := bytes.NewBuffer(imageData)
	img, formatString, err := image.Decode(imageBuffer)
	if err != nil {
		log.Println("cannot decode image", err)
		return
	}

	switch formatString {
	case "jpg":
		fallthrough
	case "jpeg":
		croppedImg := imaging.Thumbnail(img, width, height, imaging.Lanczos)
		imaging.Encode(buf, croppedImg, imaging.JPEG)
		return
	case "png":
		croppedImg := imaging.Thumbnail(img, width, height, imaging.Lanczos)
		imaging.Encode(buf, croppedImg, imaging.PNG)
	case "bmp":
		croppedImg := imaging.Thumbnail(img, width, height, imaging.Lanczos)
		imaging.Encode(buf, croppedImg, imaging.BMP)
		return
	case "gif":
		imageBuffer = bytes.NewBuffer(imageData)
		g, err := gif.DecodeAll(imageBuffer)
		if err != nil {
			log.Println("cannot decode gif", err)
			return nil, err
		}

		// over-protected version, still slow
		// c := thumbGif(g, width, height)
		// for r := range c {
		// 	g.Image[r.Index] = r.Img
		// }

		// multiple reader, no wirter to golang map is ok
		// it's fastest
		var wg sync.WaitGroup
		wg.Add(len(g.Image))
		imageArray := make([]*image.Paletted, len(g.Image))
		for i := range g.Image {
			imageArray[i] = g.Image[i]
			go func(index int) {
				thumb := imaging.Thumbnail(imageArray[index], width, height, imaging.Lanczos)
				imageArray[index] = image.NewPaletted(image.Rect(0, 0, width, height), imageArray[index].Palette)
				draw.Draw(imageArray[index], image.Rect(0, 0, width, height), thumb, image.Pt(0, 0), draw.Over)
				wg.Done()
			}(i)
		}
		wg.Wait()
		for i := range g.Image {
			g.Image[i] = imageArray[i]
		}

		// plain single thread version, too slow
		// for i := range g.Image {
		// 	thumb := imaging.Thumbnail(g.Image[i], width, height, imaging.Lanczos)
		// 	g.Image[i] = image.NewPaletted(image.Rect(0, 0, width, height), g.Image[i].Palette)
		// 	draw.Draw(g.Image[i], image.Rect(0, 0, width, height), thumb, image.Pt(0, 0), draw.Over)
		// }
		g.Config.Width, g.Config.Height = width, height
		err = gif.EncodeAll(buf, g)
		if err != nil {
			log.Println("cannot encode gif", err)
			return nil, err
		}
	}
	return
}
Exemple #15
0
// CreateThumnail builds a JPG thumbnail and can rotate if an exif bit is set.
func CreateThumbnail(deps dependencies.Dependencies, r io.ReadSeeker) (string, int, error) {
	raw, format, err := image.Decode(r)

	if format == "" {
		return "", 0, nil
	}

	if format == "jpeg" || format == "jpg" {
		deps.Debug("Received JPG")
		orientation, err := readOrientation(r)

		if err == nil {
			deps.Debug("Rotating JPG", "orientation", orientation)
			raw = rotate(raw, orientation)
		}
	}

	deps.Debug("Thumbnail format", "fmt", format)

	if err != nil {
		deps.Error("Failed to decode image")
		return "", 0, err
	}

	fs := deps.Fs
	tmpFilePath := lib.TempFilePath("thumbnail")
	tmpFile, err := fs.Create(tmpFilePath)
	if err != nil {
		deps.Error("Failed to create temp file", "path", tmpFilePath)
		return "", 0, err
	}

	// Make sure we close.
	closeTmpFile := func() {
		if tmpFile != nil {
			tmpFile.Close()
			tmpFile = nil
		}
	}

	defer closeTmpFile()

	h := sha1.New()
	var wc writeCounter
	mw := io.MultiWriter(tmpFile, h, wc)

	// Generate Thumbnail image data
	dst := imaging.Fill(raw, 200, 200, imaging.Center, imaging.Lanczos)
	// Write it
	err = imaging.Encode(mw, dst, imaging.JPEG)
	if err != nil {
		deps.Error("Failed to encode data")
		return "", 0, err
	}

	hash := fmt.Sprintf("%x", h.Sum(nil))
	deps.Debug("Thumbnail hash", "hash:", hash)
	newPath := lib.LocalPath(hash)

	// Move temp thumbnail to final destination.
	err = os.Rename(tmpFilePath, newPath)
	if err != nil {
		deps.Error("Failed to rename file")

		// Todo delete file
		return hash, int(wc), err
	}

	// Set permissons
	err = fs.Chmod(newPath, 0644)
	if err != nil {
		deps.Error("Failed to set permissions", "path", newPath)
		// Todo delete file
		return hash, int(wc), err
	}

	return hash, int(wc), nil
}