func (r *FilesResource) getImageReader(registry kit.Registry, tmpDir string, file kit.File, width, height int64, filters []string, ip string) (reader kit.ReadSeekerCloser, size int64, err apperror.Error) { if width == 0 && height == 0 && len(filters) == 0 { reader, err = file.Reader() return } // Dimensions specified. // Check if the thumbnail was already created. // If so, serve it. Otherwise, create it first. if (width == 0 || height == 0) && (file.GetWidth() == 0 || file.GetHeight() == 0) { err = &apperror.Err{ Code: "image_dimensions_not_determined", Message: fmt.Sprintf("The file with id %v does not have width/height", file.GetId()), } return } if width < 0 || height < 0 { err = apperror.New("invalid_dimensions") return } // If either height or width is 0, determine proper values to presserve aspect ratio. if width == 0 { ratio := float64(file.GetWidth()) / float64(file.GetHeight()) width = int64(float64(height) * ratio) } else if height == 0 { ratio := float64(file.GetHeight()) / float64(file.GetWidth()) height = int64(float64(width) * ratio) } maxWidth := registry.Config().UInt("files.thumbGenerator.maxWidth", 2000) maxHeight := registry.Config().UInt("files.thumbGenerator.maxHeight", 2000) if width > int64(maxWidth) || height > int64(maxHeight) { err = &apperror.Err{ Code: "dimensions_exceed_maximum_limits", Message: "The specified dimensions exceed the maximum limits", } return } thumbId := fmt.Sprintf("%v_%v_%v_%v_%v_%v.%v", file.GetId(), file.GetBucket(), file.GetName(), strconv.FormatInt(width, 10), strconv.FormatInt(height, 10), strings.Replace(strings.Join(filters, "_"), ":", "_", -1), "jpeg") if ok, _ := file.GetBackend().HasFileById("thumbs", thumbId); !ok { var channel chan bool channel, err = r.thumbnailRateLimiter.Start(ip) if err != nil { return } if channel != nil { <-channel } // Thumb does not exist yet, so create it. reader, err = file.Reader() if err != nil { return } defer reader.Close() img, _, err2 := image.Decode(reader) if err2 != nil { err = apperror.Wrap(err2, "image_decode_error") return } var giftFilters []gift.Filter if !(height == 0 && width == 0) { giftFilters = append(giftFilters, gift.ResizeToFill(int(width), int(height), gift.LanczosResampling, gift.CenterAnchor)) } for _, filter := range filters { if filter == "" { continue } parts := strings.Split(filter, ":") if len(parts) > 1 { filter = parts[0] } switch filter { case "sepia": n := float32(100) if len(parts) == 2 { x, err2 := strconv.ParseFloat(parts[1], 64) if err2 == nil { n = float32(x) } else { err = apperror.New("invalid_sepia_filter_value", true) return } } giftFilters = append(giftFilters, gift.Sepia(n)) case "grayscale": giftFilters = append(giftFilters, gift.Grayscale()) case "brightness": n := float32(0) if len(parts) == 2 { x, err2 := strconv.ParseFloat(parts[1], 64) if err2 == nil { n = float32(x) } else { err = apperror.New("invalid_brightness_filter_value", true) return } } giftFilters = append(giftFilters, gift.Brightness(n)) default: err = apperror.New("unknown_filter", fmt.Sprintf("Unknown filter: %v", filter), true) return } } gift := gift.New(giftFilters...) thumb := image.NewRGBA(gift.Bounds(img.Bounds())) gift.Draw(thumb, img) var writer io.WriteCloser _, writer, err = file.GetBackend().WriterById("thumbs", thumbId, true) if err != nil { return } defer writer.Close() jpeg.Encode(writer, thumb, &jpeg.Options{Quality: 90}) r.thumbnailRateLimiter.Finish() } backend := file.GetBackend() size, err = backend.FileSizeById("thumbs", thumbId) if err != nil { return } reader, err = file.GetBackend().ReaderById("thumbs", thumbId) return }