diff --git a/README.md b/README.md
index 4e919e5..86fd617 100644
--- a/README.md
+++ b/README.md
@@ -333,31 +333,42 @@ Saves the passed GIF as an ascii art GIF with the name `-ascii-art.g
+#### --save-bg
+
+> **Note:** This flag will be ignored if `--save-img` or `--save-gif` flags are not set
+
+This flag takes an RGB value that sets the background color in saved png and gif files.
+
+```
+ascii-image-converter [image paths/urls] -s . --save-bg 255,255,255 # For white background
+```
+
#### --font
> **Note:** This flag will be ignored if `--save-img` or `--save-gif` flags are not set
-This flag takes path to a font .ttf file that will be used to set font in saved .png or .gif files if `--save-img` or `--save-gif` flags are set.
+This flag takes path to a font .ttf file that will be used to set font in saved png or gif files.
```
ascii-image-converter [image paths/urls] -s . --font /path/to/font-file.ttf
```
-#### --formats
+#### --font-color
-Display supported input formats.
+This flag takes an RGB value that sets the font color in saved png and gif files as well as displayed ascii art in terminal.
```
-ascii-image-converter --formats
+ascii-image-converter [image paths/urls] -s . --font-color 0,0,0 # For black font color
```
-
+#### --formats
-You can combine flags as well. Following command outputs colored and negative ascii art, flips ascii art horizontally and vertically, with fixed 60 by 30 character dimensions, custom defined ascii characters " .-=+#@" and saves a generated image and .txt file in current directory as well.
+Display supported input formats.
```
-ascii-image-converter [image paths/urls] -Cnxyd 60,30 -m " .-=+#@" -s . --save-txt .
+ascii-image-converter --formats
```
+
## Library Usage
@@ -389,20 +400,23 @@ func main() {
// This part is optional.
// You can directly pass default flags variable to Convert() if you wish.
// For clarity, all flags are covered in this example, but you can use specific ones.
- flags.Complex = true // Use complex character set
+ flags.Complex = false // Use complex character set
flags.Dimensions = []int{50, 25} // 50 by 25 ascii art size
flags.SaveTxtPath = "." // Save generated text in same directory
flags.SaveImagePath = "." // Save generated PNG image in same directory
- flags.SaveGifPath = "." // If gif was provided, save ascii art gif in same directory
- flags.Negative = true // Ascii art will have negative color-depth
- flags.Colored = true // Keep colors from original image. This overrides flags.Grayscale
- flags.Grayscale = true // Returns grayscale ascii art
+ flags.SaveGifPath = "." // If gif is provided, save ascii art gif in same directory
+ flags.Negative = false // Ascii art will have negative color-depth
+ flags.Colored = true // Keep colors from original image. This overrides flags.Grayscale and flags.FontColor
+ flags.Grayscale = false // Returns grayscale ascii art. This overrides flags.FontColor
flags.CustomMap = " .-=+#@" // Starting from darkest to brightest shades. This overrides flags.Complex
- flags.FlipX = true // Flips ascii art horizontally
- flags.FlipY = true // Flips ascii art vertically
- flags.Full = true // Display ascii art that fills the terminal width. This overrides flags.Dimensions
+ flags.FlipX = false // Flips ascii art horizontally
+ flags.FlipY = false // Flips ascii art vertically
+ flags.Full = false // Display ascii art that fills the terminal width. This overrides flags.Dimensions
+ flags.FontFilePath = "./RobotoMono-Regular.ttf" // File path to font .ttf file for saved png and gif files. Ignored if flags.SaveImagePath or flags.SaveGifPath are not set
+ flags.FontColor = [3]int{0, 0, 0} // Font color for terminal and saved png and gif files.
+ flags.SaveBackgroundColor = [3]int{255, 255, 255} // Font color for saved png and gif files. Ignored if flags.SaveImagePath or flags.SaveGifPath are not set.
- // For an image
+ // Conversion for an image
asciiArt, err := aic_package.Convert(filePath, flags)
if err != nil {
fmt.Println(err)
diff --git a/aic_package/convert_gif.go b/aic_package/convert_gif.go
index b5a6520..b5e0111 100644
--- a/aic_package/convert_gif.go
+++ b/aic_package/convert_gif.go
@@ -103,11 +103,11 @@ func pathIsGif(gifPath, urlImgName string, pathIsURl bool, urlImgBytes []byte, l
os.Exit(0)
}
- asciiCharSet := imgManip.ConvertToAsciiChars(imgSet, negative, colored, complex, customMap)
+ asciiCharSet := imgManip.ConvertToAsciiChars(imgSet, negative, colored, complex, customMap, fontColor)
gifFramesSlice[i].asciiCharSet = asciiCharSet
gifFramesSlice[i].delay = originalGif.Delay[i]
- ascii := flattenAscii(asciiCharSet, colored || grayscale)
+ ascii := flattenAscii(asciiCharSet, colored || grayscale, false)
asciiArtSet[i] = strings.Join(ascii, "\n")
diff --git a/aic_package/convert_image.go b/aic_package/convert_image.go
index f5cd1a9..2331897 100644
--- a/aic_package/convert_image.go
+++ b/aic_package/convert_image.go
@@ -48,7 +48,7 @@ func pathIsImage(imagePath, urlImgName string, pathIsURl bool, urlImgBytes []byt
return "", err
}
- asciiSet := imgManip.ConvertToAsciiChars(imgSet, negative, colored, complex, customMap)
+ 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 != "" {
@@ -77,7 +77,7 @@ func pathIsImage(imagePath, urlImgName string, pathIsURl bool, urlImgBytes []byt
}
}
- ascii := flattenAscii(asciiSet, colored || grayscale)
+ ascii := flattenAscii(asciiSet, colored || grayscale, false)
result := strings.Join(ascii, "\n")
return result, nil
diff --git a/aic_package/convert_root.go b/aic_package/convert_root.go
index 015b2a6..47a7cc5 100644
--- a/aic_package/convert_root.go
+++ b/aic_package/convert_root.go
@@ -36,100 +36,27 @@ import (
"github.com/golang/freetype/truetype"
)
-type Flags struct {
- // Set dimensions of ascii art. Accepts a slice of 2 integers
- // e.g. []int{60,30}.
- // This overrides Flags.Width and Flags.Height
- Dimensions []int
-
- // Set width of ascii art while calculating height from aspect ratio.
- // Setting this along with Flags.Height will throw an error
- Width int
-
- // Set height of ascii art while calculating width from aspect ratio.
- // Setting this along with Flags.Width will throw an error
- Height int
-
- // Use set of 69 characters instead of the default 10
- Complex bool
-
- // Path to save ascii art .txt file
- SaveTxtPath string
-
- // Path to save ascii art .png file
- SaveImagePath string
-
- // Path to save ascii art .gif file, if gif is passed
- SaveGifPath string
-
- // Invert ascii art character mapping as well as colors
- Negative bool
-
- // Keep colors from the original image. This uses the True color codes for
- // the terminal and will work on saved .png and .gif files as well.
- // This overrides Flags.Grayscale
- Colored bool
-
- // Keep grayscale colors from the original image. This uses the True color
- // codes for the terminal and will work on saved .png and .gif files as well
- Grayscale bool
-
- // Pass custom ascii art characters as a string.
- // This overrides Flags.Complex
- CustomMap string
-
- // Flip ascii art horizontally
- FlipX bool
-
- // Flip ascii art vertically
- FlipY bool
-
- // Use terminal width to calculate ascii art size while keeping aspect ratio.
- // This overrides Flags.Dimensions, Flags.Width and Flags.Height
- Full bool
-
- // File path to a font .ttf file to use when saving ascii art gif or png file.
- // This will be ignored if Flags.SaveImagePath or Flags.SaveImagePath are not set
- FontFilePath string
-}
-
-var (
- dimensions []int
- width int
- height int
- complex bool
- saveTxtPath string
- saveImagePath string
- saveGifPath string
- grayscale bool
- negative bool
- colored bool
- customMap string
- flipX bool
- flipY bool
- full bool
- fontPath string
-)
-
// Return default configuration for flags.
// Can be sent directly to ConvertImage() for default ascii art
func DefaultFlags() Flags {
return Flags{
- Complex: false,
- Dimensions: nil,
- Width: 0,
- Height: 0,
- SaveTxtPath: "",
- SaveImagePath: "",
- SaveGifPath: "",
- Negative: false,
- Colored: false,
- Grayscale: false,
- CustomMap: "",
- FlipX: false,
- FlipY: false,
- Full: false,
- FontFilePath: "",
+ Complex: false,
+ Dimensions: nil,
+ Width: 0,
+ Height: 0,
+ SaveTxtPath: "",
+ SaveImagePath: "",
+ SaveGifPath: "",
+ Negative: false,
+ Colored: false,
+ Grayscale: false,
+ CustomMap: "",
+ FlipX: false,
+ FlipY: false,
+ Full: false,
+ FontFilePath: "",
+ FontColor: [3]int{255, 255, 255},
+ SaveBackgroundColor: [3]int{0, 0, 0},
}
}
@@ -159,6 +86,8 @@ func Convert(filePath string, flags Flags) (string, error) {
flipY = flags.FlipY
full = flags.Full
fontPath = flags.FontFilePath
+ fontColor = flags.FontColor
+ saveBgColor = flags.SaveBackgroundColor
// Declared at the start since some variables are initially used in conditional blocks
var (
diff --git a/aic_package/create_ascii_gif.go b/aic_package/create_ascii_gif.go
index 7216729..23cc504 100644
--- a/aic_package/create_ascii_gif.go
+++ b/aic_package/create_ascii_gif.go
@@ -78,8 +78,12 @@ func createGifFrameToSave(asciiArt [][]imgManip.AsciiChar, img image.Image, colo
dc := gg.NewContext(x, y)
- // Set image background as black
- dc.SetRGB(0, 0, 0)
+ // Set image background
+ dc.SetRGB(
+ float64(saveBgColor[0])/255,
+ float64(saveBgColor[1])/255,
+ float64(saveBgColor[2])/255,
+ )
dc.Clear()
dc.DrawImage(tempImg, 0, 0)
@@ -109,12 +113,17 @@ func createGifFrameToSave(asciiArt [][]imgManip.AsciiChar, img image.Image, colo
for _, char := range line {
- r := uint8(char.RgbValue[0])
- g := uint8(char.RgbValue[1])
- b := uint8(char.RgbValue[2])
-
if colored {
- // Simple put, dc.SetColor() sets color for EACH character before printing it
+ // dc.SetColor() sets color for EACH character before printing it
+ r := uint8(char.RgbValue[0])
+ g := uint8(char.RgbValue[1])
+ b := uint8(char.RgbValue[2])
+ dc.SetColor(color.RGBA{r, g, b, 255})
+
+ } else {
+ r := uint8(fontColor[0])
+ g := uint8(fontColor[1])
+ b := uint8(fontColor[2])
dc.SetColor(color.RGBA{r, g, b, 255})
}
diff --git a/aic_package/create_ascii_image.go b/aic_package/create_ascii_image.go
index ddd27bd..8bd02a8 100644
--- a/aic_package/create_ascii_image.go
+++ b/aic_package/create_ascii_image.go
@@ -69,8 +69,12 @@ func createImageToSave(asciiArt [][]imgManip.AsciiChar, colored bool, saveImageP
dc := gg.NewContext(imgWidth, imgHeight)
- // Set image background as black
- dc.SetRGB(0, 0, 0)
+ // Set image background
+ dc.SetRGB(
+ float64(saveBgColor[0])/255,
+ float64(saveBgColor[1])/255,
+ float64(saveBgColor[2])/255,
+ )
dc.Clear()
dc.DrawImage(tempImg, 0, 0)
@@ -93,12 +97,17 @@ func createImageToSave(asciiArt [][]imgManip.AsciiChar, colored bool, saveImageP
for _, char := range line {
- r := uint8(char.RgbValue[0])
- g := uint8(char.RgbValue[1])
- b := uint8(char.RgbValue[2])
-
if colored {
- // Simply put, dc.SetColor() sets color for EACH character before printing it
+ // dc.SetColor() sets color for EACH character before printing it
+ r := uint8(char.RgbValue[0])
+ g := uint8(char.RgbValue[1])
+ b := uint8(char.RgbValue[2])
+ dc.SetColor(color.RGBA{r, g, b, 255})
+
+ } else {
+ r := uint8(fontColor[0])
+ g := uint8(fontColor[1])
+ b := uint8(fontColor[2])
dc.SetColor(color.RGBA{r, g, b, 255})
}
diff --git a/aic_package/util.go b/aic_package/util.go
index 2d6536a..9ceb79c 100644
--- a/aic_package/util.go
+++ b/aic_package/util.go
@@ -30,7 +30,7 @@ import (
func saveAsciiArt(asciiSet [][]imgManip.AsciiChar, imagePath, savePath, urlImgName string) error {
// To make sure uncolored ascii art is the one saved as .txt
- saveAscii := flattenAscii(asciiSet, false)
+ saveAscii := flattenAscii(asciiSet, false, true)
saveFileName, err := createSaveFileName(imagePath, urlImgName, "-ascii-art.txt")
if err != nil {
@@ -75,15 +75,22 @@ func createSaveFileName(imagePath, urlImgName, label string) (string, error) {
// flattenAscii flattens a two-dimensional grid of ascii characters into a one dimension
// of lines of ascii
-func flattenAscii(asciiSet [][]imgManip.AsciiChar, colored bool) []string {
+func flattenAscii(asciiSet [][]imgManip.AsciiChar, colored, toSaveTxt bool) []string {
var ascii []string
for _, line := range asciiSet {
var tempAscii []string
for i := 0; i < len(line); i++ {
+ if toSaveTxt {
+ tempAscii = append(tempAscii, line[i].Simple)
+ continue
+ }
+
if colored {
- tempAscii = append(tempAscii, line[i].Colored)
+ tempAscii = append(tempAscii, line[i].OriginalColor)
+ } else if fontColor != [3]int{255, 255, 255} {
+ tempAscii = append(tempAscii, line[i].SetColor)
} else {
tempAscii = append(tempAscii, line[i].Simple)
}
diff --git a/aic_package/vars.go b/aic_package/vars.go
new file mode 100644
index 0000000..4d232b0
--- /dev/null
+++ b/aic_package/vars.go
@@ -0,0 +1,103 @@
+/*
+Copyright © 2021 Zoraiz Hassan
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package aic_package
+
+type Flags struct {
+ // Set dimensions of ascii art. Accepts a slice of 2 integers
+ // e.g. []int{60,30}.
+ // This overrides Flags.Width and Flags.Height
+ Dimensions []int
+
+ // Set width of ascii art while calculating height from aspect ratio.
+ // Setting this along with Flags.Height will throw an error
+ Width int
+
+ // Set height of ascii art while calculating width from aspect ratio.
+ // Setting this along with Flags.Width will throw an error
+ Height int
+
+ // Use set of 69 characters instead of the default 10
+ Complex bool
+
+ // Path to save ascii art .txt file
+ SaveTxtPath string
+
+ // Path to save ascii art .png file
+ SaveImagePath string
+
+ // Path to save ascii art .gif file, if gif is passed
+ SaveGifPath string
+
+ // Invert ascii art character mapping as well as colors
+ Negative bool
+
+ // Keep colors from the original image. This uses the True color codes for
+ // the terminal and will work on saved .png and .gif files as well.
+ // This overrides Flags.Grayscale and Flags.FontColor
+ Colored bool
+
+ // Keep grayscale colors from the original image. This uses the True color
+ // codes for the terminal and will work on saved .png and .gif files as well
+ // This overrides Flags.FontColor
+ Grayscale bool
+
+ // Pass custom ascii art characters as a string.
+ // This overrides Flags.Complex
+ CustomMap string
+
+ // Flip ascii art horizontally
+ FlipX bool
+
+ // Flip ascii art vertically
+ FlipY bool
+
+ // Use terminal width to calculate ascii art size while keeping aspect ratio.
+ // This overrides Flags.Dimensions, Flags.Width and Flags.Height
+ Full bool
+
+ // File path to a font .ttf file to use when saving ascii art gif or png file.
+ // 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
+ 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
+}
+
+var (
+ dimensions []int
+ width int
+ height int
+ complex bool
+ saveTxtPath string
+ saveImagePath string
+ saveGifPath string
+ grayscale bool
+ negative bool
+ colored bool
+ customMap string
+ flipX bool
+ flipY bool
+ full bool
+ fontPath string
+ fontColor [3]int
+ saveBgColor [3]int
+)
diff --git a/cmd/root.go b/cmd/root.go
index f1806c0..dbb045d 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -13,15 +13,14 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
+
package cmd
import (
"fmt"
"os"
- "path"
"github.com/TheZoraiz/ascii-image-converter/aic_package"
- "github.com/TheZoraiz/ascii-image-converter/aic_package/winsize"
homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"
@@ -47,12 +46,14 @@ var (
flipY bool
full bool
fontFile string
+ fontColor []int
+ saveBgColor []int
// Root commands
rootCmd = &cobra.Command{
Use: "ascii-image-converter [image paths/urls]",
Short: "Converts images and gifs into ascii art",
- Version: "1.5.0",
+ Version: "1.6.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
@@ -63,21 +64,23 @@ var (
}
flags := aic_package.Flags{
- Complex: complex,
- Dimensions: dimensions,
- Width: width,
- Height: height,
- SaveTxtPath: saveTxtPath,
- SaveImagePath: saveImagePath,
- SaveGifPath: saveGifPath,
- Negative: negative,
- Colored: colored,
- Grayscale: grayscale,
- CustomMap: customMap,
- FlipX: flipX,
- FlipY: flipY,
- Full: full,
- FontFilePath: fontFile,
+ Complex: complex,
+ Dimensions: dimensions,
+ Width: width,
+ Height: height,
+ SaveTxtPath: saveTxtPath,
+ SaveImagePath: saveImagePath,
+ SaveGifPath: saveGifPath,
+ Negative: negative,
+ Colored: colored,
+ Grayscale: grayscale,
+ CustomMap: customMap,
+ FlipX: flipX,
+ FlipY: flipY,
+ Full: full,
+ FontFilePath: fontFile,
+ FontColor: [3]int{fontColor[0], fontColor[1], fontColor[2]},
+ SaveBackgroundColor: [3]int{saveBgColor[0], saveBgColor[1], saveBgColor[2]},
}
for _, imagePath := range args {
@@ -100,117 +103,6 @@ var (
}
)
-// Check input and flags for any errors or interruptons
-func checkInputAndFlags(args []string) bool {
-
- gifCount := 0
- gifPresent := false
- nonGifPresent := false
- for _, arg := range args {
- extension := path.Ext(arg)
-
- if extension == ".gif" {
- gifPresent = true
- gifCount++
- } else {
- nonGifPresent = true
- }
- }
-
- if gifPresent && nonGifPresent {
- fmt.Printf("Error: There are other inputs along with GIFs\nDue to the potential looping nature of GIFs, non-GIFs must not be supplied alongside\n\n")
- return true
- }
-
- if gifCount > 1 {
- fmt.Printf("Error: There are multiple GIFs supplied\nDue to the potential looping nature of GIFs, only one GIF per command is supported\n\n")
- return true
- }
-
- if formatsTrue {
- fmt.Printf("Supported input formats:\n\n" +
- "JPEG/JPG\n" +
- "PNG\n" +
- "WEBP\n" +
- "BMP\n" +
- "TIFF/TIF\n" +
- "GIF (Experimental)\n\n")
- return true
- }
-
- if len(args) < 1 {
- fmt.Printf("Error: Need at least 1 input path/url\nUse the -h flag for more info\n\n")
- return true
- }
-
- if customMap != "" && len(customMap) < 2 {
- fmt.Printf("Need at least 2 characters for --map flag\n\n")
- return true
- }
-
- if dimensions != nil {
-
- numberOfDimensions := len(dimensions)
- if numberOfDimensions != 2 {
- fmt.Printf("Error: requires 2 dimensions, got %v\n\n", numberOfDimensions)
- return true
- }
-
- if dimensions[0] < 1 || dimensions[1] < 1 {
- fmt.Printf("Error: invalid values for dimensions\n\n")
- return true
- }
-
- defaultTermWidth, _, err := winsize.GetTerminalSize()
- if err != nil {
- fmt.Printf("Error: %v\n\n", err)
- return true
- }
-
- defaultTermWidth -= 1
- if dimensions[0] > defaultTermWidth {
- fmt.Printf("Error: set width must be lower than terminal width\n\n")
- return true
- }
- }
-
- if width != 0 || height != 0 {
-
- if width != 0 && height != 0 {
- fmt.Printf("Error: both --width and --height can't be set. Use --dimensions instead\n\n")
- return true
- } else {
-
- defaultTermWidth, _, err := winsize.GetTerminalSize()
- if err != nil {
- fmt.Printf("Error: %v\n\n", err)
- return true
- }
-
- // Check if set width exceeds terminal
- defaultTermWidth -= 1
- if width > defaultTermWidth {
- fmt.Printf("Error: set width must be lower than terminal width\n\n")
- return true
- }
-
- if width < 0 {
- fmt.Printf("Error: invalid value for width\n\n")
- return true
- }
-
- if height < 0 {
- fmt.Printf("Error: invalid value for height\n\n")
- return true
- }
-
- }
-
- }
-
- return false
-}
-
// Cobra configuration from here on
func Execute() {
@@ -227,12 +119,12 @@ 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 flag)\n")
+ 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().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")
+ 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(&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")
@@ -240,8 +132,10 @@ func init() {
rootCmd.PersistentFlags().BoolVarP(&flipY, "flipY", "y", false, "Flip ascii art vertically\n")
rootCmd.PersistentFlags().StringVarP(&saveImagePath, "save-img", "s", "", "Save ascii art as a .png file\nFormat: -ascii-art.png\nImage will be saved in passed path\n(pass . for current directory)\n")
rootCmd.PersistentFlags().StringVar(&saveTxtPath, "save-txt", "", "Save ascii art as a .txt file\nFormat: -ascii-art.txt\nFile will be saved in passed path\n(pass . for current directory)\n")
- rootCmd.PersistentFlags().StringVar(&saveGifPath, "save-gif", "", "(Experimental)\nIf input is a gif, save it as a .gif file\nFormat: -ascii-art.gif\nGif will be saved in passed path\n(pass . for current directory)\n")
- rootCmd.PersistentFlags().StringVar(&fontFile, "font", "", "Set font for --save-img and --save-gif flags\nPass file path to font .ttf file\ne.g. --font ./RobotoMono-Regular.ttf\n(Defaults to embedded Hack-Regular)\n")
+ rootCmd.PersistentFlags().StringVar(&saveGifPath, "save-gif", "", "If input is a gif, save it as a .gif file\nFormat: -ascii-art.gif\nGif will be saved in passed path\n(pass . for current directory)\n")
+ rootCmd.PersistentFlags().IntSliceVar(&saveBgColor, "save-bg", nil, "Set background color for --save-img and --save-gif flags\nPass an RGB value\ne.g. --save-bg 255,255,255\n(Defaults to 0,0,0)\n")
+ rootCmd.PersistentFlags().StringVar(&fontFile, "font", "", "Set font for --save-img and --save-gif flags\nPass file path to font .ttf file\ne.g. --font ./RobotoMono-Regular.ttf\n(Defaults to Hack-Regular)\n")
+ rootCmd.PersistentFlags().IntSliceVar(&fontColor, "font-color", nil, "Set font color for terminal as well as\n--save-img and --save-gif flags\nPass an RGB value\ne.g. --font-color 0,0,0\n(Defaults to 255,255,255)\n")
rootCmd.PersistentFlags().BoolVar(&formatsTrue, "formats", false, "Display supported input formats\n")
rootCmd.PersistentFlags().BoolP("help", "h", false, "Help for "+rootCmd.Name()+"\n")
diff --git a/cmd/util.go b/cmd/util.go
new file mode 100644
index 0000000..99b7724
--- /dev/null
+++ b/cmd/util.go
@@ -0,0 +1,175 @@
+/*
+Copyright © 2021 Zoraiz Hassan
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package cmd
+
+import (
+ "fmt"
+ "path"
+
+ "github.com/TheZoraiz/ascii-image-converter/aic_package/winsize"
+)
+
+// Check input and flag values for detecting errors or invalid inputs
+func checkInputAndFlags(args []string) bool {
+
+ gifCount := 0
+ gifPresent := false
+ nonGifPresent := false
+ for _, arg := range args {
+ extension := path.Ext(arg)
+
+ if extension == ".gif" {
+ gifPresent = true
+ gifCount++
+ } else {
+ nonGifPresent = true
+ }
+ }
+
+ if gifPresent && nonGifPresent {
+ fmt.Printf("Error: There are other inputs along with GIFs\nDue to the potential looping nature of GIFs, non-GIFs must not be supplied alongside\n\n")
+ return true
+ }
+
+ if gifCount > 1 {
+ fmt.Printf("Error: There are multiple GIFs supplied\nDue to the potential looping nature of GIFs, only one GIF per command is supported\n\n")
+ return true
+ }
+
+ if formatsTrue {
+ fmt.Printf("Supported input formats:\n\n" +
+ "JPEG/JPG\n" +
+ "PNG\n" +
+ "WEBP\n" +
+ "BMP\n" +
+ "TIFF/TIF\n" +
+ "GIF (Experimental)\n\n")
+ return true
+ }
+
+ if len(args) < 1 {
+ fmt.Printf("Error: Need at least 1 input path/url\nUse the -h flag for more info\n\n")
+ return true
+ }
+
+ if customMap != "" && len(customMap) < 2 {
+ fmt.Printf("Need at least 2 characters for --map flag\n\n")
+ return true
+ }
+
+ if dimensions != nil {
+
+ numberOfDimensions := len(dimensions)
+ if numberOfDimensions != 2 {
+ fmt.Printf("Error: requires 2 dimensions, got %v\n\n", numberOfDimensions)
+ return true
+ }
+
+ if dimensions[0] < 1 || dimensions[1] < 1 {
+ fmt.Printf("Error: invalid values for dimensions\n\n")
+ return true
+ }
+
+ defaultTermWidth, _, err := winsize.GetTerminalSize()
+ if err != nil {
+ fmt.Printf("Error: %v\n\n", err)
+ return true
+ }
+
+ defaultTermWidth -= 1
+ if dimensions[0] > defaultTermWidth {
+ fmt.Printf("Error: set width must be lower than terminal width\n\n")
+ return true
+ }
+ }
+
+ if width != 0 || height != 0 {
+
+ if width != 0 && height != 0 {
+ fmt.Printf("Error: both --width and --height can't be set. Use --dimensions instead\n\n")
+ return true
+ } else {
+
+ defaultTermWidth, _, err := winsize.GetTerminalSize()
+ if err != nil {
+ fmt.Printf("Error: %v\n\n", err)
+ return true
+ }
+
+ // Check if set width exceeds terminal
+ defaultTermWidth -= 1
+ if width > defaultTermWidth {
+ fmt.Printf("Error: set width must be lower than terminal width\n\n")
+ return true
+ }
+
+ if width < 0 {
+ fmt.Printf("Error: invalid value for width\n\n")
+ return true
+ }
+
+ if height < 0 {
+ fmt.Printf("Error: invalid value for height\n\n")
+ return true
+ }
+
+ }
+
+ }
+
+ if saveBgColor == nil {
+ saveBgColor = []int{0, 0, 0}
+ } else {
+ bgValues := len(saveBgColor)
+ if bgValues != 3 {
+ fmt.Printf("Error: --save-bg requires 3 values for RGB, got %v\n\n", bgValues)
+ return true
+ }
+
+ if saveBgColor[0] < 0 || saveBgColor[1] < 0 || saveBgColor[2] < 0 {
+ fmt.Printf("Error: RBG values must be between 0 and 255\n\n")
+ return true
+ }
+
+ if saveBgColor[0] > 255 || saveBgColor[1] > 255 || saveBgColor[2] > 255 {
+ fmt.Printf("Error: RBG values must be between 0 and 255\n\n")
+ return true
+ }
+ }
+
+ if fontColor == nil {
+ fontColor = []int{255, 255, 255}
+ } else {
+ fontColorValues := len(fontColor)
+ if fontColorValues != 3 {
+ fmt.Printf("Error: --font-color requires 3 values for RGB, got %v\n\n", fontColorValues)
+ return true
+ }
+
+ if fontColor[0] < 0 || fontColor[1] < 0 || fontColor[2] < 0 {
+ fmt.Printf("Error: RBG values must be between 0 and 255\n\n")
+ return true
+ }
+
+ if fontColor[0] > 255 || fontColor[1] > 255 || fontColor[2] > 255 {
+ fmt.Printf("Error: RBG values 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 0c9e764..e7cce54 100644
--- a/image_manipulation/ascii_conversions.go
+++ b/image_manipulation/ascii_conversions.go
@@ -113,18 +113,18 @@ var asciiTableDetailed = map[int]string{
const MAX_VAL float64 = 65535
type AsciiChar struct {
- Colored string
- Simple string
- RgbValue [3]uint32
+ OriginalColor string
+ SetColor string
+ Simple string
+ RgbValue [3]uint32
}
-// Converts the 2D AsciiPixel slice of image data (each instance representing each pixel of original image)
-// to a 2D AsciiChar slice with each colored and simple string having an ASCII character corresponding to
-// the original grayscale and RGB values in AsciiPixel.
+// 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
//
// If complex parameter is true, values are compared to 69 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 bool, customMap string) [][]AsciiChar {
+func ConvertToAsciiChars(imgSet [][]AsciiPixel, negative, colored, complex bool, customMap string, fontColor [3]int) [][]AsciiChar {
height := len(imgSet)
width := len(imgSet[0])
@@ -157,7 +157,7 @@ func ConvertToAsciiChars(imgSet [][]AsciiPixel, negative, colored, complex bool,
for j := 0; j < width; j++ {
value := float64(imgSet[i][j].charDepth)
- // Gets appropriate string index from asciiTableSimple by percentage comparisons with its length
+ // Gets appropriate string index from chosenTable by percentage comparisons with its length
tempFloat := (value / MAX_VAL) * float64(len(chosenTable))
if value == MAX_VAL {
tempFloat = float64(len(chosenTable) - 1)
@@ -198,7 +198,17 @@ func ConvertToAsciiChars(imgSet [][]AsciiPixel, negative, colored, complex bool,
var char AsciiChar
- char.Colored = color.Sprintf("%v>", chosenTable[tempInt])
+ char.OriginalColor = color.Sprintf("%v>", chosenTable[tempInt])
+
+ // 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>", chosenTable[tempInt])
+ }
+
char.Simple = chosenTable[tempInt]
if colored {
diff --git a/image_manipulation/image_conversions.go b/image_manipulation/image_conversions.go
index 4d7679f..e07835a 100644
--- a/image_manipulation/image_conversions.go
+++ b/image_manipulation/image_conversions.go
@@ -159,8 +159,7 @@ func ConvertToAsciiPixels(img image.Image, dimensions []int, width, height int,
grayPixel := color.GrayModel.Convert(oldPixel)
r1, g1, b1, _ := grayPixel.RGBA()
- // We only need Red from Red, Green, Blue (RGB) for charDepth in AsciiPixel since they have the same value for grayscale images
- charDepth := r1
+ charDepth := r1 // 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)
diff --git a/snapcraft.yaml b/snapcraft.yaml
index 2a9846e..72df5f9 100644
--- a/snapcraft.yaml
+++ b/snapcraft.yaml
@@ -1,10 +1,10 @@
name: ascii-image-converter
base: core18
-version: "1.5.0"
+version: "1.6.0"
summary: Convert images and gifs into ascii art
description: |
- This tool converts images and gifs into ascii format and prints them onto the terminal window.
- Supported input formats are JPEG/JPG, PNG, WEBP, BMP TIFF/TIF and GIF. Further configuration can be managed by flags.
+ ascii-image-converter is a command-line tool that converts images into ascii art and prints
+ them out onto the console. Supported input formats are JPEG/JPG, PNG, WEBP, BMP, TIFF/TIF and GIF
grade: stable
confinement: strict