M ascii/ascii.go => ascii/ascii.go +28 -3
@@ 10,6 10,14 @@ import (
"reflect"
)
+type PixelASCII struct {
+ Char byte
+ R uint8
+ G uint8
+ B uint8
+ A uint8
+}
+
// Options convert pixel to raw char
type Options struct {
Pixels []byte
@@ 46,14 54,15 @@ func NewPixelConverter() PixelConverter {
// PixelConverter define the convert pixel operation
type PixelConverter interface {
ConvertPixelToASCII(pixel color.Color, options *Options) string
+ ConvertPixelToPixelASCII(pixel color.Color, options *Options) PixelASCII
}
// PixelASCIIConverter responsible for pixel ascii conversion
type PixelASCIIConverter struct {
}
-// ConvertPixelToASCII converts a pixel to a ASCII char string
-func (converter PixelASCIIConverter) ConvertPixelToASCII(pixel color.Color, options *Options) string {
+// ConvertPixelToPixelASCII convert a image pixel to PixelASCII
+func (converter PixelASCIIConverter) ConvertPixelToPixelASCII(pixel color.Color, options *Options) PixelASCII {
convertOptions := NewOptions()
convertOptions.mergeOptions(options)
@@ 70,6 79,22 @@ func (converter PixelASCIIConverter) ConvertPixelToASCII(pixel color.Color, opti
// Choose the char
precision := float64(255 * 3 / (len(convertOptions.Pixels) - 1))
rawChar := convertOptions.Pixels[converter.roundValue(float64(value)/precision)]
+ return PixelASCII{
+ Char: rawChar,
+ R: uint8(r),
+ G: uint8(g),
+ B: uint8(b),
+ A: uint8(a),
+ }
+}
+
+// ConvertPixelToASCII converts a pixel to a ASCII char string
+func (converter PixelASCIIConverter) ConvertPixelToASCII(pixel color.Color, options *Options) string {
+ convertOptions := NewOptions()
+ convertOptions.mergeOptions(options)
+
+ pixelASCII := converter.ConvertPixelToPixelASCII(pixel, options)
+ rawChar, r, g, b := pixelASCII.Char, pixelASCII.R, pixelASCII.G, pixelASCII.B
if convertOptions.Colored {
return converter.decorateWithColor(r, g, b, rawChar)
}
@@ 93,7 118,7 @@ func (converter PixelASCIIConverter) intensity(r, g, b, a uint64) uint64 {
}
// decorateWithColor decorate the raw char with the color base on r,g,b value
-func (converter PixelASCIIConverter) decorateWithColor(r, g, b uint64, rawChar byte) string {
+func (converter PixelASCIIConverter) decorateWithColor(r, g, b uint8, rawChar byte) string {
coloredChar := rgbterm.FgString(string([]byte{rawChar}), uint8(r), uint8(g), uint8(b))
return coloredChar
}
M convert/convert.go => convert/convert.go +34 -0
@@ 50,6 50,8 @@ type Converter interface {
Image2ASCIIString(image image.Image, options *Options) string
ImageFile2ASCIIMatrix(imageFilename string, option *Options) []string
ImageFile2ASCIIString(imageFilename string, option *Options) string
+ Image2PixelASCIIMatrix(image image.Image, imageConvertOptions *Options) [][]ascii.PixelASCII
+ ImageFile2PixelASCIIMatrix(image image.Image, imageConvertOptions *Options) [][]ascii.PixelASCII
}
// ImageConverter implement the Convert interface, and responsible
@@ 59,6 61,38 @@ type ImageConverter struct {
pixelConverter ascii.PixelConverter
}
+// Image2PixelASCIIMatrix convert a image to a pixel ascii matrix
+func (converter *ImageConverter) Image2PixelASCIIMatrix(image image.Image, imageConvertOptions *Options) [][]ascii.PixelASCII {
+ newImage := converter.resizeHandler.ScaleImage(image, imageConvertOptions)
+ sz := newImage.Bounds()
+ newWidth := sz.Max.X
+ newHeight := sz.Max.Y
+ pixelASCIIs := make([][]ascii.PixelASCII, 0, newHeight)
+ for i := 0; i < int(newHeight); i++ {
+ line := make([]ascii.PixelASCII, 0, newWidth)
+ for j := 0; j < int(newWidth); j++ {
+ pixel := color.NRGBAModel.Convert(newImage.At(j, i))
+ // Convert the pixel to ascii char
+ pixelConvertOptions := ascii.NewOptions()
+ pixelConvertOptions.Colored = imageConvertOptions.Colored
+ pixelConvertOptions.Reversed = imageConvertOptions.Reversed
+ pixelASCII := converter.pixelConverter.ConvertPixelToPixelASCII(pixel, &pixelConvertOptions)
+ line = append(line, pixelASCII)
+ }
+ pixelASCIIs = append(pixelASCIIs, line)
+ }
+ return pixelASCIIs
+}
+
+// Image2PixelASCIIMatrix convert a image to a pixel ascii matrix
+func (converter *ImageConverter) ImageFile2PixelASCIIMatrix(imageFilename string, imageConvertOptions *Options) [][]ascii.PixelASCII {
+ img, err := OpenImageFile(imageFilename)
+ if err != nil {
+ log.Fatal("open image failed : " + err.Error())
+ }
+ return converter.Image2PixelASCIIMatrix(img, imageConvertOptions)
+}
+
// Image2ASCIIMatrix converts a image to ASCII matrix
func (converter *ImageConverter) Image2ASCIIMatrix(image image.Image, imageConvertOptions *Options) []string {
// Resize the convert first
M convert/convert_test.go => convert/convert_test.go +27 -0
@@ 96,6 96,33 @@ func TestImageFile2ASCIIString(t *testing.T) {
}
}
+func TestImageFile2PixelASCIIMatrix(t *testing.T) {
+ converter := NewImageConverter()
+ imageTests := []struct {
+ imageFilename string
+ width int
+ height int
+ }{
+ {"testdata/3x3_black.png", 3, 3},
+ {"testdata/3x3_white.png", 3,3},
+ {"testdata/8x3_multi_colors.png", 8, 3},
+ }
+
+ for _, tt := range imageTests {
+ t.Run(tt.imageFilename, func(t *testing.T) {
+ convertOptions := DefaultOptions
+ convertOptions.FitScreen = false
+ convertOptions.Colored = false
+
+ matrix := converter.ImageFile2PixelASCIIMatrix(tt.imageFilename, &convertOptions)
+ if len(matrix) != tt.height|| len(matrix[0]) != tt.width{
+ t.Errorf("image %s convert expected to %+v, %+v, but get %+v",
+ tt.imageFilename, tt.width, tt.height, matrix)
+ }
+ })
+ }
+}
+
func TestImage2ReversedASCIIString(t *testing.T) {
converter := NewImageConverter()
imageTests := []struct {