169 lines
3.1 KiB
Go
169 lines
3.1 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"image"
|
|
"image/color"
|
|
"image/draw"
|
|
"math"
|
|
"os"
|
|
)
|
|
|
|
func ReadImage(name string) image.Image {
|
|
file, err := os.Open(name)
|
|
if err != nil {
|
|
fmt.Println("Error: File could not be opened")
|
|
os.Exit(1)
|
|
}
|
|
defer file.Close()
|
|
|
|
img, _, _ := image.Decode(file)
|
|
|
|
return img
|
|
}
|
|
|
|
func imageToRGBA(src image.Image) *image.RGBA {
|
|
// No conversion needed if image is an *image.RGBA.
|
|
if dst, ok := src.(*image.RGBA); ok {
|
|
return dst
|
|
}
|
|
|
|
// Use the image/draw package to convert to *image.RGBA.
|
|
b := src.Bounds()
|
|
dst := image.NewRGBA(image.Rect(0, 0, b.Dx(), b.Dy()))
|
|
draw.Draw(dst, dst.Bounds(), src, b.Min, draw.Src)
|
|
return dst
|
|
}
|
|
|
|
// Colorf represents a color with float64 RGB values. [R, G, B]
|
|
type Colorf [3]float64
|
|
|
|
// Convert an image to a 2D array of Colorf.
|
|
func ConvertImageToColors(src image.Image) [][]Colorf {
|
|
img := imageToRGBA(src)
|
|
|
|
bounds := img.Bounds()
|
|
width, height := bounds.Max.X, bounds.Max.Y
|
|
|
|
// Initialize the 2D slice.
|
|
colorfImg := make([][]Colorf, height)
|
|
for i := range colorfImg {
|
|
colorfImg[i] = make([]Colorf, width)
|
|
}
|
|
|
|
// Iterate over each pixel.
|
|
for y := 0; y < height; y++ {
|
|
for x := 0; x < width; x++ {
|
|
r, g, b, _ := img.At(x, y).RGBA()
|
|
|
|
// Convert the uint32 color values to float64, normalized to [0, 1].
|
|
colorf := Colorf{
|
|
float64(r) / 0xffff,
|
|
float64(g) / 0xffff,
|
|
float64(b) / 0xffff,
|
|
}
|
|
|
|
colorfImg[y][x] = colorf
|
|
}
|
|
}
|
|
|
|
return colorfImg
|
|
}
|
|
|
|
func CorrectGamma(in Colorf) Colorf {
|
|
gamma := func(in float64) float64 {
|
|
return math.Pow(in, 1.2)
|
|
|
|
// This is the correct algorithm but looks too dark
|
|
// if in > 0.04045 {
|
|
// return math.Pow((in+0.055)/(1.0+0.055), 2.4)
|
|
// } else {
|
|
// return in / 12.92
|
|
// }
|
|
}
|
|
|
|
return Colorf{
|
|
gamma(in[0]),
|
|
gamma(in[1]),
|
|
gamma(in[2]),
|
|
}
|
|
}
|
|
|
|
func convertToRGBA(colorf Colorf) color.RGBA {
|
|
// Convert the float64 color values to uint8, and ignore the alpha channel.
|
|
return color.RGBA{
|
|
R: uint8(colorf[0] * 255),
|
|
G: uint8(colorf[1] * 255),
|
|
B: uint8(colorf[2] * 255),
|
|
A: 255,
|
|
}
|
|
}
|
|
|
|
func subtractColorf(c1, c2 Colorf) Colorf {
|
|
return Colorf{
|
|
c1[0] - c2[0],
|
|
c1[1] - c2[1],
|
|
c1[2] - c2[2],
|
|
}
|
|
}
|
|
|
|
func addColorf(c1, c2 Colorf) Colorf {
|
|
return Colorf{
|
|
c1[0] + c2[0],
|
|
c1[1] + c2[1],
|
|
c1[2] + c2[2],
|
|
}
|
|
}
|
|
|
|
func multColor(c Colorf, m float64) Colorf {
|
|
return Colorf{
|
|
c[0] * m,
|
|
c[1] * m,
|
|
c[2] * m,
|
|
}
|
|
}
|
|
|
|
func clampColor(value Colorf, min, max float64) Colorf {
|
|
return Colorf{
|
|
clamp(value[0], min, max),
|
|
clamp(value[1], min, max),
|
|
clamp(value[2], min, max),
|
|
}
|
|
}
|
|
|
|
func clamp(value, min, max float64) float64 {
|
|
if value < min {
|
|
return min
|
|
}
|
|
if value > max {
|
|
return max
|
|
}
|
|
return value
|
|
}
|
|
|
|
func flipImage(img image.Image, vertical, horizontal bool) image.Image {
|
|
bounds := img.Bounds()
|
|
width, height := bounds.Max.X, bounds.Max.Y
|
|
|
|
newImg := image.NewRGBA(image.Rect(0, 0, width, height))
|
|
|
|
for y := 0; y < height; y++ {
|
|
for x := 0; x < width; x++ {
|
|
srcX, srcY := x, y
|
|
|
|
if horizontal {
|
|
srcX = width - x - 1
|
|
}
|
|
|
|
if vertical {
|
|
srcY = height - y - 1
|
|
}
|
|
|
|
c := img.At(srcX, srcY)
|
|
newImg.Set(x, y, c)
|
|
}
|
|
}
|
|
|
|
return newImg
|
|
}
|