Beispiel #1
0
func (processor *Processor) Execute(src *Image, dst io.Writer, query *Query) {
	processor.gift.Empty()
	quality := 100

	if query.Count() > 0 {
		// resize
		if query.Has("w") || query.Has("h") {
			width := query.GetInt("w")
			height := query.GetInt("h")

			if width > 0 || height > 0 {
				processor.gift.Add(gift.Resize(width, height, gift.LanczosResampling))
			}
		}

		// crop
		if query.Has("c") {
			c := query.GetIntArray("c")
			if len(c) == 4 {
				processor.gift.Add(gift.Crop(image.Rect(c[0], c[1], c[2], c[3])))
			}
		}

		// grayscale
		if query.Has("grayscale") {
			processor.gift.Add(gift.Grayscale())
		}

		// sepia
		if query.Has("sepia") {
			sepia := query.GetInt("sepia")
			if sepia <= 100 {
				processor.gift.Add(gift.Sepia(float32(sepia)))
			}
		}

		// contrast
		if query.Has("contrast") {
			contrast := query.GetInt("contrast")
			processor.gift.Add(gift.Contrast(float32(contrast)))
		}

		// brightness
		if query.Has("brightness") {
			brightness := query.GetInt("brightness")
			processor.gift.Add(gift.Brightness(float32(brightness)))
		}

		// saturation
		if query.Has("saturation") {
			saturation := query.GetInt("saturation")
			processor.gift.Add(gift.Saturation(float32(saturation)))
		}

		// colorize
		if query.Has("colorize") {
			colorize := query.GetIntArray("colorize")
			if len(colorize) == 3 {
				processor.gift.Add(gift.Colorize(float32(colorize[0]), float32(colorize[1]), float32(colorize[2])))
			}
		}

		// colorbalance
		if query.Has("colorbalance") {
			colorbalance := query.GetIntArray("colorbalance")
			if len(colorbalance) == 3 {
				processor.gift.Add(gift.ColorBalance(float32(colorbalance[0]), float32(colorbalance[1]), float32(colorbalance[2])))
			}
		}

		// quality
		if query.Has("q") {
			q := query.GetInt("q")
			if q > 0 && q < 100 {
				quality = q
			}
		}

		// Draw
		if len(processor.gift.Filters) > 0 {
			rgba := image.NewRGBA(processor.gift.Bounds(src.Object.Bounds()))
			processor.gift.Draw(rgba, src.Object)

			jpeg.Encode(dst, rgba, &jpeg.Options{Quality: quality})

			return
		}
	}

	// default
	jpeg.Encode(dst, src.Object, &jpeg.Options{Quality: quality})
}
Beispiel #2
0
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
}