8

Is there a way for me to crop an image with Go by giving dimensions and offsets?

I'm thinking of something flexible like this php function: http://php.net/manual/en/function.imagecopyresampled.php

I found this: https://github.com/nfnt/resize But that library does not seem to have an offset option.

I need to be able to crop any area of the original image. Not just scaling down, but also a different positioning of the cropped image.

Any suggestions on how I can achieve this?

Aiden
  • 1,147
  • 2
  • 10
  • 25

4 Answers4

11

I'll answer my own question so that it can be of help to other newcomers of Go.

Reading these two articles helped me greatly to understand how to crop images in Go. No need for third libraries. You decide how to crop an image with points and rectangles which is a very neat way of doing it.

http://blog.golang.org/go-image-package

http://blog.golang.org/go-imagedraw-package

Aiden
  • 1,147
  • 2
  • 10
  • 25
7

Here's a simple program that crops an image. If chops off the image outside of a given rectangle.

package main

import (
    "fmt"
    "image"
    "log"
    "os"

    "image/png"
)

func main() {
    if err := run(); err != nil {
        log.Fatalln(err)
    }
}

func run() error {
    img, err := readImage("pic.png")
    if err != nil {
        return err
    }

    // I've hard-coded a crop rectangle, start (0,0), end (100, 100).
    img, err = cropImage(img, image.Rect(0, 0, 100, 100))
    if err != nil {
        return err
    }

    return writeImage(img, "pic-cropped.png")
}

// readImage reads a image file from disk. We're assuming the file will be png
// format.
func readImage(name string) (image.Image, error) {
    fd, err := os.Open("pic.png")
    if err != nil {
        return nil, err
    }
    defer fd.Close()

    // image.Decode requires that you import the right image package. We've
    // imported "image/png", so Decode will work for png files. If we needed to
    // decode jpeg files then we would need to import "image/jpeg".
    //
    // Ignored return value is image format name.
    img, _, err := image.Decode(fd)
    if err != nil {
        return nil, err
    }

    return img, nil
}

// cropImage takes an image and crops it to the specified rectangle.
func cropImage(img image.Image, crop image.Rectangle) (image.Image, error) {
    type subImager interface {
        SubImage(r image.Rectangle) image.Image
    }

    // img is an Image interface. This checks if the underlying value has a
    // method called SubImage. If it does, then we can use SubImage to crop the
    // image.
    simg, ok := img.(subImager)
    if !ok {
        return nil, fmt.Errorf("image does not support cropping")
    }

    return simg.SubImage(crop), nil
}

// writeImage writes an Image back to the disk.
func writeImage(img image.Image, name string) error {
    fd, err := os.Create(name)
    if err != nil {
        return err
    }
    defer fd.Close()

    return png.Encode(fd, img)
}
425nesp
  • 6,936
  • 9
  • 50
  • 61
2

It is explained better in this answer. The SubImage method is implemented for most of the image formats (seems to be all but Uniform). Since it does not belong to the main interface you need to assert it in order to use it.

package main

import (
    "fmt"
    "image"
    "image/jpeg"
    "log"
    "os"
)

func main() {
    image_file, err := os.Open("somefile.jpeg")
    if err != nil {
        log.Fatal(err)
    }
    my_image, err := jpeg.Decode(image_file)
    if err != nil {
        log.Fatal(err)
    }

    my_sub_image := my_image.(interface {
        SubImage(r image.Rectangle) image.Image
    }).SubImage(image.Rect(0, 0, 10, 10))

    output_file, outputErr := os.Create("output.jpeg")
    if outputErr != nil {
        log.Fatal(outputErr)
    }
    jpeg.Encode(output_file, my_sub_image, nil)

}
Gabriel Furstenheim
  • 2,969
  • 30
  • 27
1

https://github.com/gographics/imagick seems to have what you need : https://godoc.org/github.com/gographics/imagick/imagick#MagickWand.CropImage

HectorJ
  • 5,814
  • 3
  • 34
  • 52
  • Thanks for the suggestion. But I found out that I can crop with offsets with the image/draw package from the standard library. Thanks for the suggestion tho! – Aiden Sep 14 '15 at 09:00