Example #1
0
func decodeFirstImage(local_path string) (firstImage image.Image, imageKind string, err error) {
	imf, err := os.Open(local_path)
	if err != nil {
		return nil, "", err
	}
	defer imf.Close()

	_, imageKind, err = image.DecodeConfig(imf)
	if err != nil {
		return nil, "", err
	}
	imf.Seek(0, 0)

	switch imageKind {
	case "gif":
		// Decode GIF frames until we reach the first fully opaque image:
		var g *gif.GIF
		g, err = gif.DecodeAll(imf)
		if err != nil {
			return nil, "", err
		}

		firstFrame := g.Image[0]
		g.Image = nil
		g.Delay = nil
		g = nil

		return firstFrame, imageKind, nil
	default:
		firstImage, imageKind, err = image.Decode(imf)
		if err != nil {
			return nil, "", err
		}
		return
	}
}
Example #2
0
// Crops an image and outputs a new image file:
func cropImage(image_path string, left, top, right, bottom int) (tmp_output string, err error) {
	cropBounds := image.Rect(left, top, right, bottom)

	// Open the image for reading:
	imf, err := os.Open(image_path)
	if err != nil {
		return "", err
	}
	defer imf.Close()

	// Figure out what kind of image it is:
	_, imageKind, err := image.DecodeConfig(imf)
	if err != nil {
		return "", err
	}
	imf.Seek(0, 0)

	// Crop images:
	switch imageKind {
	case "gif":
		// Decode all GIF frames and crop them:

		// FIXME(jsd): This approach clearly does not work. An integrated decoder-encoder needs to be written
		// for animated GIFs so as to preserve as much of the encoding details as possible and crop the
		// transparent animation subframes over the full image.

		var g *gif.GIF
		g, err = gif.DecodeAll(imf)
		if err != nil {
			return "", err
		}

		// Crop all the frames:
		for i, img := range g.Image {
			if !cropBounds.In(img.Bounds()) {
				return "", fmt.Errorf("Crop boundaries are not contained within image boundaries")
			}

			g.Image[i] = imaging.CloneKind(imaging.SubImageKind(img, cropBounds)).(*image.Paletted)
		}

		// Write the cropped images to a new GIF:
		tmpf, err := TempFile(tmp_folder(), "crop-", ".gif")
		if err != nil {
			return "", err
		}
		defer tmpf.Close()

		err = gif.EncodeAll(tmpf, g)
		if err != nil {
			return "", err
		}

		g.Image = nil
		g.Delay = nil
		g = nil

		return tmpf.Name(), nil
	case "jpeg":
		img, err := jpeg.Decode(imf)
		if err != nil {
			return "", err
		}

		if !cropBounds.In(img.Bounds()) {
			return "", fmt.Errorf("Crop boundaries are not contained within image boundaries")
		}

		tmpf, err := TempFile(tmp_folder(), "crop-", ".jpg")
		if err != nil {
			return "", err
		}
		defer tmpf.Close()

		img = imaging.CloneKind(imaging.SubImageKind(img, cropBounds))
		err = jpeg.Encode(tmpf, img, &jpeg.Options{Quality: 100})
		if err != nil {
			return "", err
		}

		return tmpf.Name(), nil
	case "png":
		img, err := png.Decode(imf)
		if err != nil {
			return "", err
		}

		if !cropBounds.In(img.Bounds()) {
			return "", fmt.Errorf("Crop boundaries are not contained within image boundaries")
		}

		tmpf, err := TempFile(tmp_folder(), "crop-", ".png")
		if err != nil {
			return "", err
		}
		defer tmpf.Close()

		img = imaging.SubImageKind(img, cropBounds)
		err = png.Encode(tmpf, img)
		if err != nil {
			return "", err
		}

		return tmpf.Name(), nil
	default:
		return "", fmt.Errorf("Unrecognized image kind '%s'", imageKind)
	}
}