105 lines
2.3 KiB
Go
105 lines
2.3 KiB
Go
|
package catprinter
|
||
|
|
||
|
import (
|
||
|
"github.com/disintegration/imaging"
|
||
|
"github.com/makeworld-the-better-one/dither/v2"
|
||
|
"image"
|
||
|
"image/color"
|
||
|
"image/draw"
|
||
|
"log"
|
||
|
)
|
||
|
|
||
|
const printWidth = 384
|
||
|
|
||
|
func convertImageToBytes(img image.Image) ([]byte, error) {
|
||
|
|
||
|
if img.Bounds().Dx() != printWidth {
|
||
|
return nil, ErrInvalidImageSize
|
||
|
}
|
||
|
|
||
|
var byteArray []byte
|
||
|
for y := 0; y < img.Bounds().Dy(); y++ {
|
||
|
for x := 0; x < img.Bounds().Dx(); x++ {
|
||
|
r, g, b, _ := img.At(x, y).RGBA()
|
||
|
if r != g || g != b || r != b || (r != 0 && r != 65535) {
|
||
|
return nil, ErrNotBlackWhite
|
||
|
}
|
||
|
if r == 0 {
|
||
|
byteArray = append(byteArray, 1) // black
|
||
|
} else {
|
||
|
byteArray = append(byteArray, 0) // white
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return byteArray, nil
|
||
|
|
||
|
}
|
||
|
|
||
|
func grayscaleToBlackWhite(img image.Image, blackPoint float32) *image.NRGBA {
|
||
|
|
||
|
bounds := img.Bounds()
|
||
|
nrgbaImg := image.NewNRGBA(bounds)
|
||
|
draw.Draw(nrgbaImg, bounds, img, bounds.Min, draw.Src)
|
||
|
|
||
|
for y := 0; y < img.Bounds().Dy(); y++ {
|
||
|
for x := 0; x < img.Bounds().Dx(); x++ {
|
||
|
r, g, b, _ := img.At(x, y).RGBA()
|
||
|
if r != g || g != b || r != b {
|
||
|
log.Panicln("logic error, image should have been grayscale")
|
||
|
}
|
||
|
if float32(r)/65535 < blackPoint {
|
||
|
nrgbaImg.Set(x, y, color.Black)
|
||
|
} else {
|
||
|
nrgbaImg.Set(x, y, color.White)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nrgbaImg
|
||
|
|
||
|
}
|
||
|
|
||
|
func ditherImage(img image.Image, algo dither.ErrorDiffusionMatrix) image.Image {
|
||
|
|
||
|
palette := []color.Color{
|
||
|
color.Black,
|
||
|
color.White,
|
||
|
}
|
||
|
|
||
|
d := dither.NewDitherer(palette)
|
||
|
d.Matrix = algo
|
||
|
|
||
|
return d.Dither(img)
|
||
|
|
||
|
}
|
||
|
|
||
|
// FormatImage formats the image for printing by resizing it and dithering or grayscaling it
|
||
|
func (c *Client) FormatImage(img image.Image, opts *PrinterOptions) image.Image {
|
||
|
|
||
|
if img.Bounds().Dx() > img.Bounds().Dy() && opts.autoRotate {
|
||
|
img = imaging.Rotate90(img)
|
||
|
}
|
||
|
|
||
|
var newImg image.Image = imaging.New(img.Bounds().Dx(), img.Bounds().Dy(), color.White)
|
||
|
newImg = imaging.OverlayCenter(newImg, img, 1)
|
||
|
newImg = imaging.Resize(newImg, printWidth, 0, imaging.NearestNeighbor)
|
||
|
|
||
|
if opts.dither {
|
||
|
newImg = ditherImage(newImg, opts.ditherAlgo)
|
||
|
} else {
|
||
|
newImg = imaging.Grayscale(newImg)
|
||
|
newImg = grayscaleToBlackWhite(newImg, opts.blackPoint)
|
||
|
}
|
||
|
|
||
|
if c.Debug.DumpImage {
|
||
|
err := imaging.Save(newImg, "./image.png")
|
||
|
if err != nil {
|
||
|
log.Println("failed to save debugging image dump", err.Error())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return newImg
|
||
|
|
||
|
}
|