Added 8-bit color support (#9, #11)

This commit is contained in:
Zoraiz 2021-09-11 02:16:17 +05:00
parent dd8f65207e
commit df5eafe9a3
8 changed files with 77 additions and 45 deletions

View File

@ -29,7 +29,6 @@ builds:
# - mipsle
# - mips64
# - mips64le
archives:
-

View File

@ -162,9 +162,9 @@ ascii-image-converter myImage.jpeg
#### --color OR -C
> **Note:** Your terminal must support 24-bit colors for appropriate results
> **Note:** Your terminal must support 24-bit or 8-bit colors for appropriate results. If 24-bit colors aren't supported, 8-bit color escape codes will be used
Display ascii art with the colors from original image. Works with the --negative flag as well.
Display ascii art with the colors from original image.
```
ascii-image-converter [image paths/urls] -C

View File

@ -91,7 +91,7 @@ func pathIsGif(gifPath, urlImgName string, pathIsURl bool, urlImgBytes []byte, l
// If a frame is found that is smaller than the first frame, then this gif contains smaller subimages that are
// positioned inside the original gif. This behavior isn't supported by this app
if firstGifFrameWidth != frameImage.Bounds().Dx() || firstGifFrameHeight != frameImage.Bounds().Dy() {
fmt.Println("Error: GIF contains subimages smaller than default width and height\nProcess aborted because ascii-image-converter doesn't support subimage placement and transparency in GIFs\n")
fmt.Printf("Error: GIF contains subimages smaller than default width and height\nProcess aborted because ascii-image-converter doesn't support subimage placement and transparency in GIFs\n\n")
os.Exit(0)
}
@ -99,16 +99,21 @@ func pathIsGif(gifPath, urlImgName string, pathIsURl bool, urlImgBytes []byte, l
imgSet, err = imgManip.ConvertToAsciiPixels(frameImage, dimensions, width, height, flipX, flipY, full, braille, dither, noTermSizeComparison)
if err != nil {
fmt.Println("Error:", err)
fmt.Printf("Error: %v\n", err)
os.Exit(0)
}
var asciiCharSet [][]imgManip.AsciiChar
if braille {
asciiCharSet = imgManip.ConvertToBrailleChars(imgSet, negative, colored, colorBg, fontColor, threshold)
asciiCharSet, err = imgManip.ConvertToBrailleChars(imgSet, negative, colored, grayscale, colorBg, fontColor, threshold)
} else {
asciiCharSet = imgManip.ConvertToAsciiChars(imgSet, negative, colored, complex, colorBg, customMap, fontColor)
asciiCharSet, err = imgManip.ConvertToAsciiChars(imgSet, negative, colored, grayscale, complex, colorBg, customMap, fontColor)
}
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(0)
}
gifFramesSlice[i].asciiCharSet = asciiCharSet
gifFramesSlice[i].delay = originalGif.Delay[i]
@ -187,7 +192,7 @@ func pathIsGif(gifPath, urlImgName string, pathIsURl bool, urlImgBytes []byte, l
colored || grayscale,
)
if err != nil {
fmt.Println("Error:", err)
fmt.Printf("Error: %v\n", err)
os.Exit(0)
}

View File

@ -51,9 +51,12 @@ func pathIsImage(imagePath, urlImgName string, pathIsURl bool, urlImgBytes []byt
var asciiSet [][]imgManip.AsciiChar
if braille {
asciiSet = imgManip.ConvertToBrailleChars(imgSet, negative, colored, colorBg, fontColor, threshold)
asciiSet, err = imgManip.ConvertToBrailleChars(imgSet, negative, colored, grayscale, colorBg, fontColor, threshold)
} else {
asciiSet = imgManip.ConvertToAsciiChars(imgSet, negative, colored, complex, colorBg, customMap, fontColor)
asciiSet, err = imgManip.ConvertToAsciiChars(imgSet, negative, colored, grayscale, complex, colorBg, customMap, fontColor)
}
if err != nil {
return "", err
}
// Save ascii art as .png image before printing it, if --save-img flag is passed

View File

@ -57,7 +57,7 @@ var (
rootCmd = &cobra.Command{
Use: "ascii-image-converter [image paths/urls]",
Short: "Converts images and gifs into ascii art",
Version: "1.9.2",
Version: "1.10.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
@ -128,7 +128,7 @@ 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\nTerminal must support 24-bit colors\n(Inverts with --negative flag)\n(Overrides --grayscale and --font-color flags)\n")
rootCmd.PersistentFlags().BoolVarP(&colored, "color", "C", false, "Display ascii art with original colors\nIf 24-bit colors aren't supported, uses 8-bit\n(Inverts with --negative flag)\n(Overrides --grayscale and --font-color flags)\n")
rootCmd.PersistentFlags().BoolVar(&colorBg, "color-bg", false, "If some color flag is passed, use that color\non character background instead of foreground\n(Inverts with --negative flag)\n(Only applicable for terminal display)\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")

View File

@ -16,12 +16,6 @@ limitations under the License.
package image_conversions
import (
"strconv"
"github.com/gookit/color"
)
var (
// Reference taken from http://paulbourke.net/dataformats/asciiart/
asciiTableSimple = " .:-=+*#%@"
@ -55,7 +49,7 @@ to a 2D image_conversions.AsciiChar slice
If complex parameter is true, values are compared to 70 levels of color density in ASCII characters.
Otherwise, values are compared to 10 levels of color density in ASCII characters.
*/
func ConvertToAsciiChars(imgSet [][]AsciiPixel, negative, colored, complex, colorBg bool, customMap string, fontColor [3]int) [][]AsciiChar {
func ConvertToAsciiChars(imgSet [][]AsciiPixel, negative, colored, grayscale, complex, colorBg bool, customMap string, fontColor [3]int) ([][]AsciiChar, error) {
height := len(imgSet)
width := len(imgSet[0])
@ -128,29 +122,33 @@ func ConvertToAsciiChars(imgSet [][]AsciiPixel, negative, colored, complex, colo
tempInt = (len(chosenTable) - 1) - tempInt
}
rStr := strconv.Itoa(r)
gStr := strconv.Itoa(g)
bStr := strconv.Itoa(b)
var char AsciiChar
char.Simple = chosenTable[tempInt]
var err error
if colorBg {
char.OriginalColor = color.Sprintf("<bg="+rStr+","+gStr+","+bStr+">%v</>", chosenTable[tempInt])
char.OriginalColor, err = getColoredCharForTerm(uint8(r), uint8(g), uint8(b), chosenTable[tempInt], true)
} else {
char.OriginalColor = color.Sprintf("<fg="+rStr+","+gStr+","+bStr+">%v</>", chosenTable[tempInt])
char.OriginalColor, err = getColoredCharForTerm(uint8(r), uint8(g), uint8(b), chosenTable[tempInt], false)
}
if (colored || grayscale) && err != nil {
return nil, err
}
// 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])
fcR := fontColor[0]
fcG := fontColor[1]
fcB := fontColor[2]
if colorBg {
char.SetColor = color.Sprintf("<bg="+fcR+","+fcG+","+fcB+">%v</>", chosenTable[tempInt])
char.SetColor, err = getColoredCharForTerm(uint8(fcR), uint8(fcG), uint8(fcB), chosenTable[tempInt], true)
} else {
char.SetColor = color.Sprintf("<fg="+fcR+","+fcG+","+fcB+">%v</>", chosenTable[tempInt])
char.SetColor, err = getColoredCharForTerm(uint8(fcR), uint8(fcG), uint8(fcB), chosenTable[tempInt], false)
}
if err != nil {
return nil, err
}
}
@ -165,7 +163,7 @@ func ConvertToAsciiChars(imgSet [][]AsciiPixel, negative, colored, complex, colo
result = append(result, tempSlice)
}
return result
return result, nil
}
/*
@ -174,7 +172,7 @@ to a 2D image_conversions.AsciiChar slice
Unlike ConvertToAsciiChars(), this function calculates braille characters instead of ascii
*/
func ConvertToBrailleChars(imgSet [][]AsciiPixel, negative, colored, colorBg bool, fontColor [3]int, threshold int) [][]AsciiChar {
func ConvertToBrailleChars(imgSet [][]AsciiPixel, negative, colored, grayscale, colorBg bool, fontColor [3]int, threshold int) ([][]AsciiChar, error) {
BrailleThreshold = uint32(threshold)
@ -216,29 +214,33 @@ func ConvertToBrailleChars(imgSet [][]AsciiPixel, negative, colored, colorBg boo
}
}
rStr := strconv.Itoa(r)
gStr := strconv.Itoa(g)
bStr := strconv.Itoa(b)
var char AsciiChar
char.Simple = brailleChar
var err error
if colorBg {
char.OriginalColor = color.Sprintf("<bg="+rStr+","+gStr+","+bStr+">%v</>", brailleChar)
char.OriginalColor, err = getColoredCharForTerm(uint8(r), uint8(g), uint8(b), brailleChar, true)
} else {
char.OriginalColor = color.Sprintf("<fg="+rStr+","+gStr+","+bStr+">%v</>", brailleChar)
char.OriginalColor, err = getColoredCharForTerm(uint8(r), uint8(g), uint8(b), brailleChar, false)
}
if (colored || grayscale) && err != nil {
return nil, err
}
// 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])
fcR := fontColor[0]
fcG := fontColor[1]
fcB := fontColor[2]
if colorBg {
char.SetColor = color.Sprintf("<bg="+fcR+","+fcG+","+fcB+">%v</>", brailleChar)
char.SetColor, err = getColoredCharForTerm(uint8(fcR), uint8(fcG), uint8(fcB), brailleChar, true)
} else {
char.SetColor = color.Sprintf("<fg="+fcR+","+fcG+","+fcB+">%v</>", brailleChar)
char.SetColor, err = getColoredCharForTerm(uint8(fcR), uint8(fcG), uint8(fcB), brailleChar, false)
}
if err != nil {
return nil, err
}
}
@ -254,7 +256,7 @@ func ConvertToBrailleChars(imgSet [][]AsciiPixel, negative, colored, colorBg boo
result = append(result, tempSlice)
}
return result
return result, nil
}
// Iterate through the BrailleStruct table to see which dots need to be highlighted

View File

@ -23,6 +23,7 @@ import (
"github.com/TheZoraiz/ascii-image-converter/aic_package/winsize"
"github.com/disintegration/imaging"
gookitColor "github.com/gookit/color"
"github.com/makeworld-the-better-one/dither/v2"
)
@ -200,3 +201,25 @@ func reverse(imgSet [][]AsciiPixel, flipX, flipY bool) [][]AsciiPixel {
return imgSet
}
var termColorLevel string = gookitColor.TermColorLevel().String()
// This functions calculates terminal color level between rgb colors, 256-colors, 16-colors
// and returns the character with escape codes appropriately
func getColoredCharForTerm(r, g, b uint8, char string, background bool) (string, error) {
var coloredChar string
if termColorLevel == "millions" {
colorRenderer := gookitColor.RGB(uint8(r), uint8(g), uint8(b), background)
coloredChar = colorRenderer.Sprintf("%v", char)
} else if termColorLevel == "hundreds" {
colorRenderer := gookitColor.RGB(uint8(r), uint8(g), uint8(b), background).C256()
coloredChar = colorRenderer.Sprintf("%v", char)
} else {
return "", fmt.Errorf("your terminal supports neither 24-bit nor 8-bit colors. Other coloring options aren't available")
}
return coloredChar, nil
}

View File

@ -1,6 +1,6 @@
name: ascii-image-converter
base: core18
version: "1.9.2"
version: "1.10.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