Reputation: 117
I'm trying to convert an image to grayscale using Go.
I've found the below code, however, I'm struggling to understand it.
It would be extremely helpful if you could explain what each function is doing and where to define the incoming and outgoing file.
package main
import (
"image"
_ "image/jpeg" // Register JPEG format
"image/png" // Register PNG format
"image/color"
"log"
"os"
)
// Converted implements image.Image, so you can
// pretend that it is the converted image.
type Converted struct {
Img image.Image
Mod color.Model
}
// We return the new color model...
func (c *Converted) ColorModel() color.Model{
return c.Mod
}
// ... but the original bounds
func (c *Converted) Bounds() image.Rectangle{
return c.Img.Bounds()
}
// At forwards the call to the original image and
// then asks the color model to convert it.
func (c *Converted) At(x, y int) color.Color{
return c.Mod.Convert(c.Img.At(x,y))
}
func main() {
if len(os.Args) != 3 { log.Fatalln("Needs two arguments")}
infile, err := os.Open(os.Args[1])
if err != nil {
log.Fatalln(err)
}
defer infile.Close()
img, _, err := image.Decode(infile)
if err != nil {
log.Fatalln(err)
}
// Since Converted implements image, this is now a grayscale image
gr := &Converted{img, color.GrayModel}
// Or do something like this to convert it into a black and
// white image.
// bw := []color.Color{color.Black,color.White}
// gr := &Converted{img, color.Palette(bw)}
outfile, err := os.Create(os.Args[2])
if err != nil {
log.Fatalln(err)
}
defer outfile.Close()
png.Encode(outfile,gr)
}
I'm quite new to Go so any suggestions or help would be appreciated.
Upvotes: 1
Views: 3602
Reputation: 7419
So as Atomic_alarm pointed out, https://maxhalford.github.io/blog/halftoning-1/ explains how to do this succinctly.
But you're question, if I understand correctly, is about the file opening and creation?
The first step is to use the image
package to Decode
the opened file
into an image.Image
struct:
infile, err := os.Open("fullcolor.png")
if err != nil {
return nil, err
}
defer infile.Close()
img, _, err := image.Decode(infile) // img -> image.Image
if err != nil {
return nil, err
}
With this Go image.Image
struct, you can convert it to a grayscaled image, image.Gray
and then, finally, write or encode the image onto an outgoing file on the disk:
outfile, _ := os.Create("grayscaled.png")
defer outfile.Close()
png.Encode(outfile, grayscaledImage) // grayscaledImage -> image.Gray
Inbetween the infile opening and outfile creating, you have to, of course, convert the image to grayscale. Again, try the link above, and you'll find this function, which takes an image.Image
and returns a pointer to a image.Gray
:
func rgbaToGray(img image.Image) *image.Gray {
var (
bounds = img.Bounds()
gray = image.NewGray(bounds)
)
for x := 0; x < bounds.Max.X; x++ {
for y := 0; y < bounds.Max.Y; y++ {
var rgba = img.At(x, y)
gray.Set(x, y, rgba)
}
}
return gray
}
Concerning the code you provided (and your comment), you were opening a file with os.Args[1]
, and creating the file os.Args[2]
. os.Args
is a slice of arguments passed when running the program, 0
will always be the program itself (main
), and whatever follows will with 1
, 2
, etc. The docs states:
Args hold the command-line arguments, starting with the program name.
var Args []string
so you would run your code above like this:
$ go run main.go infile.png outfile.png
infile.png must to be a file on disk (inside the directory you are running the code from, or the complete path to file).
What I have provide above doesn't use os.Args
but rather hard codes the file names into the program.
Upvotes: 2