From f318be9c56ef22aaa64fa726c8f3bee93d5511ca Mon Sep 17 00:00:00 2001 From: Zoraiz Date: Fri, 3 Sep 2021 00:09:02 +0500 Subject: [PATCH] Added braille art support --- README.md | 67 ++++++++---- aic_package/convert_gif.go | 26 +++-- aic_package/convert_image.go | 13 ++- aic_package/convert_root.go | 6 +- aic_package/util.go | 14 +-- aic_package/vars.go | 15 ++- cmd/root.go | 14 ++- cmd/util.go | 11 +- image_manipulation/ascii_conversions.go | 130 ++++++++++++++++++++++-- image_manipulation/image_conversions.go | 45 ++++---- snapcraft.yaml | 2 +- 11 files changed, 272 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index 29ee263..a3db2ed 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,9 @@ ![Github All Releases](https://img.shields.io/github/downloads/TheZoraiz/ascii-image-converter/total?color=brightgreen&label=Release%20Downloads) [![ascii-image-converter](https://snapcraft.io/ascii-image-converter/badge.svg)](https://snapcraft.io/ascii-image-converter) -ascii-image-converter is a command-line tool that converts images into ascii art and prints them out onto the console. Available on Windows, Linux and macOS. GIFs are now experimentally supported as well. +ascii-image-converter is a command-line tool that converts images into ascii art and prints them out onto the console. Available on Windows, Linux and macOS. + +Now supports braille art! Input formats currently supported: * JPEG/JPG @@ -14,7 +16,28 @@ Input formats currently supported: * BMP * WEBP * TIFF/TIF -* GIF (Experimental) +* GIF + +
+Single image: + +

+ +

+ +Multiple images: + +

+ +

+ +GIF: + +

+ +

+ + ## Table of Contents @@ -130,24 +153,6 @@ Example: ``` ascii-image-converter myImage.jpeg ``` -
-Single image: - -

- -

- -Multiple images: - -

- -

- -GIF: - -

- -

### Flags @@ -165,6 +170,28 @@ ascii-image-converter [image paths/urls] --color

+#### --braille OR -b + +Use braille characters instead of ascii. For this flag, your terminal must support braille patters (UTF-8) properly. Otherwise, you may encounter problems with colored or even uncolored braille art. +``` +ascii-image-converter [image paths/urls] -b +# Or +ascii-image-converter [image paths/urls] --braille +``` + +

+ +

+ +#### --threshold + +Set threshold value to compare when converting each pixel into a dot. Value must be between 0 and 255. + +Example: +``` +ascii-image-converter [image paths/urls] -b --threshold 170 +``` + #### --dimensions OR -d > **Note:** Don't immediately append another flag with -d diff --git a/aic_package/convert_gif.go b/aic_package/convert_gif.go index b5e0111..324dd57 100644 --- a/aic_package/convert_gif.go +++ b/aic_package/convert_gif.go @@ -45,7 +45,7 @@ as an ascii art gif. Multi-threading has been implemented in multiple places due to long execution time */ -func pathIsGif(gifPath, urlImgName string, pathIsURl bool, urlImgBytes []byte, localGif *os.File) (string, error) { +func pathIsGif(gifPath, urlImgName string, pathIsURl bool, urlImgBytes []byte, localGif *os.File) error { var ( originalGif *gif.GIF @@ -58,7 +58,12 @@ func pathIsGif(gifPath, urlImgName string, pathIsURl bool, urlImgBytes []byte, l originalGif, err = gif.DecodeAll(localGif) } if err != nil { - return "", fmt.Errorf("can't decode %v: %v", gifPath, err) + return fmt.Errorf("can't decode %v: %v", gifPath, err) + } + + // Error handled earlier to save time in case of long gif processing + if braille && saveGifPath != "" { + return fmt.Errorf("saving braille art as a gif is not supported") } var ( @@ -97,13 +102,18 @@ func pathIsGif(gifPath, urlImgName string, pathIsURl bool, urlImgBytes []byte, l var imgSet [][]imgManip.AsciiPixel - imgSet, err = imgManip.ConvertToAsciiPixels(frameImage, dimensions, width, height, flipX, flipY, full) + imgSet, err = imgManip.ConvertToAsciiPixels(frameImage, dimensions, width, height, flipX, flipY, full, braille) if err != nil { fmt.Println("Error:", err) os.Exit(0) } - asciiCharSet := imgManip.ConvertToAsciiChars(imgSet, negative, colored, complex, customMap, fontColor) + var asciiCharSet [][]imgManip.AsciiChar + if braille { + asciiCharSet = imgManip.ConvertToBrailleChars(imgSet, negative, colored, fontColor, threshold) + } else { + asciiCharSet = imgManip.ConvertToAsciiChars(imgSet, negative, colored, complex, customMap, fontColor) + } gifFramesSlice[i].asciiCharSet = asciiCharSet gifFramesSlice[i].delay = originalGif.Delay[i] @@ -137,12 +147,12 @@ func pathIsGif(gifPath, urlImgName string, pathIsURl bool, urlImgBytes []byte, l saveFileName, err := createSaveFileName(gifPath, urlImgName, "-ascii-art.gif") if err != nil { - return "", err + return err } fullPathName, err := getFullSavePath(saveFileName, saveGifPath) if err != nil { - return "", fmt.Errorf("can't save file: %v", err) + return fmt.Errorf("can't save file: %v", err) } // Initializing some constants for gif. Done outside loop to save execution @@ -219,7 +229,7 @@ func pathIsGif(gifPath, urlImgName string, pathIsURl bool, urlImgBytes []byte, l gifFile, err := os.OpenFile(fullPathName, os.O_WRONLY|os.O_CREATE, 0666) if err != nil { - return "", fmt.Errorf("can't save file: %v", err) + return fmt.Errorf("can't save file: %v", err) } defer gifFile.Close() @@ -248,5 +258,5 @@ func pathIsGif(gifPath, urlImgName string, pathIsURl bool, urlImgBytes []byte, l } } - return "", nil + return nil } diff --git a/aic_package/convert_image.go b/aic_package/convert_image.go index 2331897..0576c7c 100644 --- a/aic_package/convert_image.go +++ b/aic_package/convert_image.go @@ -43,15 +43,24 @@ func pathIsImage(imagePath, urlImgName string, pathIsURl bool, urlImgBytes []byt return "", fmt.Errorf("can't decode %v: %v", imagePath, err) } - imgSet, err := imgManip.ConvertToAsciiPixels(imData, dimensions, width, height, flipX, flipY, full) + imgSet, err := imgManip.ConvertToAsciiPixels(imData, dimensions, width, height, flipX, flipY, full, braille) if err != nil { return "", err } - asciiSet := imgManip.ConvertToAsciiChars(imgSet, negative, colored, complex, customMap, fontColor) + var asciiSet [][]imgManip.AsciiChar + + if braille { + asciiSet = imgManip.ConvertToBrailleChars(imgSet, negative, colored, fontColor, threshold) + } else { + asciiSet = imgManip.ConvertToAsciiChars(imgSet, negative, colored, complex, customMap, fontColor) + } // Save ascii art as .png image before printing it, if --save-img flag is passed if saveImagePath != "" { + if braille { + return "", fmt.Errorf("saving braille art as an image is not supported") + } if err := createImageToSave( asciiSet, colored || grayscale, diff --git a/aic_package/convert_root.go b/aic_package/convert_root.go index 47a7cc5..50e4511 100644 --- a/aic_package/convert_root.go +++ b/aic_package/convert_root.go @@ -57,6 +57,8 @@ func DefaultFlags() Flags { FontFilePath: "", FontColor: [3]int{255, 255, 255}, SaveBackgroundColor: [3]int{0, 0, 0}, + Braille: false, + Threshold: 128, } } @@ -88,6 +90,8 @@ func Convert(filePath string, flags Flags) (string, error) { fontPath = flags.FontFilePath fontColor = flags.FontColor saveBgColor = flags.SaveBackgroundColor + braille = flags.Braille + threshold = flags.Threshold // Declared at the start since some variables are initially used in conditional blocks var ( @@ -141,7 +145,7 @@ func Convert(filePath string, flags Flags) (string, error) { } if path.Ext(filePath) == ".gif" { - return pathIsGif(filePath, urlImgName, pathIsURl, urlImgBytes, localFile) + return "", pathIsGif(filePath, urlImgName, pathIsURl, urlImgBytes, localFile) } else { return pathIsImage(filePath, urlImgName, pathIsURl, urlImgBytes, localFile) } diff --git a/aic_package/util.go b/aic_package/util.go index 9ceb79c..a71a712 100644 --- a/aic_package/util.go +++ b/aic_package/util.go @@ -79,24 +79,24 @@ func flattenAscii(asciiSet [][]imgManip.AsciiChar, colored, toSaveTxt bool) []st var ascii []string for _, line := range asciiSet { - var tempAscii []string + var tempAscii string - for i := 0; i < len(line); i++ { + for _, char := range line { if toSaveTxt { - tempAscii = append(tempAscii, line[i].Simple) + tempAscii += char.Simple continue } if colored { - tempAscii = append(tempAscii, line[i].OriginalColor) + tempAscii += char.OriginalColor } else if fontColor != [3]int{255, 255, 255} { - tempAscii = append(tempAscii, line[i].SetColor) + tempAscii += char.SetColor } else { - tempAscii = append(tempAscii, line[i].Simple) + tempAscii += char.Simple } } - ascii = append(ascii, strings.Join(tempAscii, "")) + ascii = append(ascii, tempAscii) } return ascii diff --git a/aic_package/vars.go b/aic_package/vars.go index 02f1147..dd23220 100644 --- a/aic_package/vars.go +++ b/aic_package/vars.go @@ -74,13 +74,22 @@ type Flags struct { // This will be ignored if Flags.SaveImagePath or Flags.SaveGifPath are not set FontFilePath string - // Font RGB color in saved png or gif files. - // This will be ignored if Flags.SaveImagePath or Flags.SaveGifPath are not set + // Font RGB color for terminal display and saved png or gif files. FontColor [3]int // Background RGB color in saved png or gif files. // This will be ignored if Flags.SaveImagePath or Flags.SaveGifPath are not set SaveBackgroundColor [3]int + + // Use braille characters instead of ascii. Terminal must support UTF-8 encoding. + // Otherwise, problems may be encountered with colored or even uncolored braille art. + // This overrides Flags.Complex and Flags.CustomMap + Braille bool + + // Threshold for braille art if Flags.Braille is set to true. Value provided must + // be between 0 and 255. Ideal value is 128. + // This will be ignored if Flags.Braille is not set + Threshold int } var ( @@ -101,4 +110,6 @@ var ( fontPath string fontColor [3]int saveBgColor [3]int + braille bool + threshold int ) diff --git a/cmd/root.go b/cmd/root.go index dbb045d..a1142a7 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -48,12 +48,14 @@ var ( fontFile string fontColor []int saveBgColor []int + braille bool + threshold int // Root commands rootCmd = &cobra.Command{ Use: "ascii-image-converter [image paths/urls]", Short: "Converts images and gifs into ascii art", - Version: "1.6.0", + Version: "1.7.0", Long: "This tool converts images into ascii art and prints them on the terminal.\nFurther configuration can be managed with flags.", // Not RunE since help text is getting larger and seeing it for every error impacts user experience @@ -81,6 +83,8 @@ var ( FontFilePath: fontFile, FontColor: [3]int{fontColor[0], fontColor[1], fontColor[2]}, SaveBackgroundColor: [3]int{saveBgColor[0], saveBgColor[1], saveBgColor[2]}, + Braille: braille, + Threshold: threshold, } for _, imagePath := range args { @@ -119,12 +123,14 @@ func init() { rootCmd.Flags().SortFlags = false // rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.ascii-image-converter.yaml)") - rootCmd.PersistentFlags().BoolVarP(&colored, "color", "C", false, "Display ascii art with original colors\n(Can work with the --negative flag)\n(Overrides --grayscale and --font-color flags)\n") + rootCmd.PersistentFlags().BoolVarP(&colored, "color", "C", false, "Display ascii art with original colors\n(Inverts with --negative flag)\n(Overrides --grayscale and --font-color flags)\n") rootCmd.PersistentFlags().IntSliceVarP(&dimensions, "dimensions", "d", nil, "Set width and height for ascii art in CHARACTER length\ne.g. -d 60,30 (defaults to terminal height)\n(Overrides --width and --height flags)\n") rootCmd.PersistentFlags().IntVarP(&width, "width", "W", 0, "Set width for ascii art in CHARACTER length\nHeight is kept to aspect ratio\ne.g. -W 60\n") rootCmd.PersistentFlags().IntVarP(&height, "height", "H", 0, "Set height for ascii art in CHARACTER length\nWidth is kept to aspect ratio\ne.g. -H 60\n") rootCmd.PersistentFlags().StringVarP(&customMap, "map", "m", "", "Give custom ascii characters to map against\nOrdered from darkest to lightest\ne.g. -m \" .-+#@\" (Quotation marks excluded from map)\n(Overrides --complex flag)\n") - rootCmd.PersistentFlags().BoolVarP(&grayscale, "grayscale", "g", false, "Display grayscale ascii art\n(Can work with --negative flag)\n(Overrides --font-color flag)\n") + rootCmd.PersistentFlags().BoolVarP(&braille, "braille", "b", false, "Use braille characters instead of ascii\nTerminal must support braille patterns properly\n(Overrides --complex and --map flags)\n") + rootCmd.PersistentFlags().IntVar(&threshold, "threshold", 0, "Threshold for braille art\nValue between 0-255 is accepted\ne.g. --threshold 170\n(Defaults to 128)\n") + rootCmd.PersistentFlags().BoolVarP(&grayscale, "grayscale", "g", false, "Display grayscale ascii art\n(Inverts with --negative flag)\n(Overrides --font-color flag)\n") rootCmd.PersistentFlags().BoolVarP(&complex, "complex", "c", false, "Display ascii characters in a larger range\nMay result in higher quality\n") rootCmd.PersistentFlags().BoolVarP(&full, "full", "f", false, "Use largest dimensions for ascii art\nthat fill the terminal width\n(Overrides --dimensions, --width and --height flags)\n") rootCmd.PersistentFlags().BoolVarP(&negative, "negative", "n", false, "Display ascii art in negative colors\n") @@ -141,6 +147,8 @@ func init() { rootCmd.PersistentFlags().BoolP("help", "h", false, "Help for "+rootCmd.Name()+"\n") rootCmd.PersistentFlags().BoolP("version", "v", false, "Version for "+rootCmd.Name()) + rootCmd.SetVersionTemplate("{{printf \"v%s\" .Version}}\n") + defaultUsageTemplate := rootCmd.UsageTemplate() rootCmd.SetUsageTemplate(defaultUsageTemplate + "\nCopyright © 2021 Zoraiz Hassan \n" + "Distributed under the Apache License Version 2.0 (Apache-2.0)\n" + diff --git a/cmd/util.go b/cmd/util.go index 99b7724..f532d29 100644 --- a/cmd/util.go +++ b/cmd/util.go @@ -57,7 +57,7 @@ func checkInputAndFlags(args []string) bool { "WEBP\n" + "BMP\n" + "TIFF/TIF\n" + - "GIF (Experimental)\n\n") + "GIF\n\n") return true } @@ -171,5 +171,14 @@ func checkInputAndFlags(args []string) bool { } } + if threshold == 0 { + threshold = 128 + } + + if threshold < 0 || threshold > 255 { + fmt.Printf("Error: threshold must be between 0 and 255\n\n") + return true + } + return false } diff --git a/image_manipulation/ascii_conversions.go b/image_manipulation/ascii_conversions.go index 9b66692..f8b2510 100644 --- a/image_manipulation/ascii_conversions.go +++ b/image_manipulation/ascii_conversions.go @@ -22,12 +22,24 @@ import ( "github.com/gookit/color" ) -// Reference taken from http://paulbourke.net/dataformats/asciiart/ -var asciiTableSimple = " .:-=+*#%@" -var asciiTableDetailed = " .'`^\",:;Il!i><~+_-?][}{1)(|\\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$" +var ( + // Reference taken from http://paulbourke.net/dataformats/asciiart/ + asciiTableSimple = " .:-=+*#%@" + asciiTableDetailed = " .'`^\",:;Il!i><~+_-?][}{1)(|\\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$" + + // Structure for braille dots + BrailleStruct = [4][2]int{ + {0x1, 0x8}, + {0x2, 0x10}, + {0x4, 0x20}, + {0x40, 0x80}, + } + + BrailleThreshold uint32 +) // For each individual element of imgSet in ConvertToASCIISlice() -const MAX_VAL float64 = 65535 +const MAX_VAL float64 = 255 type AsciiChar struct { OriginalColor string @@ -72,10 +84,7 @@ func ConvertToAsciiChars(imgSet [][]AsciiPixel, negative, colored, complex bool, } } - result := make([][]AsciiChar, height) - for i := range result { - result[i] = make([]AsciiChar, width) - } + var result [][]AsciiChar for i := 0; i < height; i++ { @@ -146,8 +155,111 @@ func ConvertToAsciiChars(imgSet [][]AsciiPixel, negative, colored, complex bool, tempSlice = append(tempSlice, char) } - result[i] = tempSlice + result = append(result, tempSlice) + } + + return result +} + +/* +Converts the 2D image_conversions.AsciiPixel slice of image data (each instance representing each compressed pixel of original image) +to a 2D image_conversions.AsciiChar slice + +Unlike ConvertToAsciiChars(), this function calculates braille characters instead of ascii +*/ +func ConvertToBrailleChars(imgSet [][]AsciiPixel, negative, colored bool, fontColor [3]int, threshold int) [][]AsciiChar { + + BrailleThreshold = uint32(threshold) + + height := len(imgSet) + width := len(imgSet[0]) + + var result [][]AsciiChar + + for i := 0; i < height; i += 4 { + + var tempSlice []AsciiChar + + for j := 0; j < width; j += 2 { + + brailleChar := getBrailleChar(i, j, negative, imgSet) + + var r, g, b int + + if colored { + r = int(imgSet[i][j].rgbValue[0]) + g = int(imgSet[i][j].rgbValue[1]) + b = int(imgSet[i][j].rgbValue[2]) + } else { + r = int(imgSet[i][j].grayscaleValue[0]) + g = int(imgSet[i][j].grayscaleValue[1]) + b = int(imgSet[i][j].grayscaleValue[2]) + } + + if negative { + // Select character from opposite side of table as well as turn pixels negative + r = 255 - r + g = 255 - g + b = 255 - b + + if colored { + imgSet[i][j].rgbValue = [3]uint32{uint32(r), uint32(g), uint32(b)} + } else { + imgSet[i][j].grayscaleValue = [3]uint32{uint32(r), uint32(g), uint32(b)} + } + } + + rStr := strconv.Itoa(r) + gStr := strconv.Itoa(g) + bStr := strconv.Itoa(b) + + var char AsciiChar + + char.Simple = brailleChar + char.OriginalColor = color.Sprintf("%v", brailleChar) + + // If font color is not set, use a simple string. Otherwise, use True color + if fontColor != [3]int{255, 255, 255} { + fcR := strconv.Itoa(fontColor[0]) + fcG := strconv.Itoa(fontColor[1]) + fcB := strconv.Itoa(fontColor[2]) + + char.SetColor = color.Sprintf("%v", brailleChar) + } + + if colored { + char.RgbValue = imgSet[i][j].rgbValue + } else { + char.RgbValue = imgSet[i][j].grayscaleValue + } + + tempSlice = append(tempSlice, char) + } + + result = append(result, tempSlice) } return result } + +// Iterate through the BrailleStruct table to see which dots need to be highlighted +func getBrailleChar(x, y int, negative bool, imgSet [][]AsciiPixel) string { + + brailleChar := 0x2800 + + for i := 0; i < 4; i++ { + for j := 0; j < 2; j++ { + if negative { + if imgSet[x+i][y+j].charDepth <= BrailleThreshold { + brailleChar += BrailleStruct[i][j] + } + } else { + if imgSet[x+i][y+j].charDepth >= BrailleThreshold { + brailleChar += BrailleStruct[i][j] + } + } + } + } + + return string(brailleChar) +} diff --git a/image_manipulation/image_conversions.go b/image_manipulation/image_conversions.go index 93bcb08..93ae277 100644 --- a/image_manipulation/image_conversions.go +++ b/image_manipulation/image_conversions.go @@ -31,6 +31,10 @@ type AsciiPixel struct { rgbValue [3]uint32 } +func resizeForBraille(asciiWidth, asciiHeight int) (int, int) { + return asciiWidth * 2, asciiHeight * 4 +} + /* This function shrinks the passed image according to passed dimensions or terminal size if none are passed. Stores each pixel's grayscale and RGB values in an AsciiPixel @@ -39,7 +43,7 @@ instance to simplify getting numeric data for ASCII character comparison. The returned 2D AsciiPixel slice contains each corresponding pixel's values. Grayscale value ranges from 0 to 65535, while RGB values are separate. */ -func ConvertToAsciiPixels(img image.Image, dimensions []int, width, height int, flipX, flipY, full bool) ([][]AsciiPixel, error) { +func ConvertToAsciiPixels(img image.Image, dimensions []int, width, height int, flipX, flipY, full, isBraille bool) ([][]AsciiPixel, error) { var asciiWidth, asciiHeight int var smallImg image.Image @@ -57,8 +61,11 @@ func ConvertToAsciiPixels(img image.Image, dimensions []int, width, height int, asciiHeight = smallImg.Bounds().Max.Y - smallImg.Bounds().Min.Y // To fix aspect ratio in eventual ascii art - asciiHeight = int(0.5 * float32(asciiHeight)) + asciiHeight = int(0.5 * float64(asciiHeight)) + if isBraille { + asciiWidth, asciiHeight = resizeForBraille(asciiWidth, asciiHeight) + } smallImg = imaging.Resize(img, asciiWidth, asciiHeight, imaging.Lanczos) } else if (width != 0 || height != 0) && len(dimensions) == 0 { @@ -76,13 +83,11 @@ func ConvertToAsciiPixels(img image.Image, dimensions []int, width, height int, smallImg = imaging.Resize(img, asciiWidth, 0, imaging.Lanczos) asciiHeight = smallImg.Bounds().Max.Y - smallImg.Bounds().Min.Y - asciiHeight = int(0.5 * float32(asciiHeight)) + asciiHeight = int(0.5 * float64(asciiHeight)) if asciiHeight == 0 { asciiHeight = 1 } - smallImg = imaging.Resize(img, asciiWidth, asciiHeight, imaging.Lanczos) - } else if height != 0 && width == 0 { // If height is set and width is not set, use height to calculate aspect ratio @@ -91,18 +96,21 @@ func ConvertToAsciiPixels(img image.Image, dimensions []int, width, height int, smallImg = imaging.Resize(img, 0, asciiHeight, imaging.Lanczos) asciiWidth = smallImg.Bounds().Max.X - smallImg.Bounds().Min.X - asciiWidth = int(2 * float32(asciiWidth)) + asciiWidth = int(2 * float64(asciiWidth)) if asciiWidth > terminalWidth-1 { return nil, fmt.Errorf("width calculated with aspect ratio exceeds terminal width") } - smallImg = imaging.Resize(img, asciiWidth, asciiHeight, imaging.Lanczos) - } else { return nil, fmt.Errorf("both width and height can't be set. Use dimensions instead") } + if isBraille { + asciiWidth, asciiHeight = resizeForBraille(asciiWidth, asciiHeight) + } + smallImg = imaging.Resize(img, asciiWidth, asciiHeight, imaging.Lanczos) + } else if len(dimensions) == 0 { // This condition calculates aspect ratio according to terminal height @@ -112,7 +120,7 @@ func ConvertToAsciiPixels(img image.Image, dimensions []int, width, height int, asciiWidth = smallImg.Bounds().Max.X - smallImg.Bounds().Min.X // To fix aspect ratio in eventual ascii art - asciiWidth = int(2 * float32(asciiWidth)) + asciiWidth = int(2 * float64(asciiWidth)) // If ascii width exceeds terminal width, change ratio with respect to terminal width if asciiWidth >= terminalWidth { @@ -123,14 +131,21 @@ func ConvertToAsciiPixels(img image.Image, dimensions []int, width, height int, asciiHeight = smallImg.Bounds().Max.Y - smallImg.Bounds().Min.Y // To fix aspect ratio in eventual ascii art - asciiHeight = int(0.5 * float32(asciiHeight)) + asciiHeight = int(0.5 * float64(asciiHeight)) } + if isBraille { + asciiWidth, asciiHeight = resizeForBraille(asciiWidth, asciiHeight) + } smallImg = imaging.Resize(img, asciiWidth, asciiHeight, imaging.Lanczos) } else { asciiWidth = dimensions[0] asciiHeight = dimensions[1] + + if isBraille { + asciiWidth, asciiHeight = resizeForBraille(asciiWidth, asciiHeight) + } smallImg = imaging.Resize(img, asciiWidth, asciiHeight, imaging.Lanczos) } @@ -143,11 +158,7 @@ func ConvertToAsciiPixels(img image.Image, dimensions []int, width, height int, } } - // Initialize imgSet 2D slice - imgSet := make([][]AsciiPixel, asciiHeight) - for i := range imgSet { - imgSet[i] = make([]AsciiPixel, asciiWidth) - } + var imgSet [][]AsciiPixel b := smallImg.Bounds() @@ -161,7 +172,7 @@ func ConvertToAsciiPixels(img image.Image, dimensions []int, width, height int, grayPixel := color.GrayModel.Convert(oldPixel) r1, g1, b1, _ := grayPixel.RGBA() - charDepth := r1 // Only Red is needed from RGB for charDepth in AsciiPixel since they have the same value for grayscale images + charDepth := r1 / 257 // Only Red is needed from RGB for charDepth in AsciiPixel since they have the same value for grayscale images r1 = uint32(r1 / 257) g1 = uint32(g1 / 257) b1 = uint32(b1 / 257) @@ -179,7 +190,7 @@ func ConvertToAsciiPixels(img image.Image, dimensions []int, width, height int, }) } - imgSet[y] = temp + imgSet = append(imgSet, temp) } // This rarely affects performance since the ascii art 2D slice size isn't that large diff --git a/snapcraft.yaml b/snapcraft.yaml index 72df5f9..3669361 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -1,6 +1,6 @@ name: ascii-image-converter base: core18 -version: "1.6.0" +version: "1.7.0" summary: Convert images and gifs into ascii art description: | ascii-image-converter is a command-line tool that converts images into ascii art and prints