Added --save-bg and --font-color flag

This commit is contained in:
Zoraiz 2021-08-09 18:49:05 +05:00
parent d11ab9f718
commit 1c8b009dd1
13 changed files with 424 additions and 275 deletions

View File

@ -333,16 +333,34 @@ Saves the passed GIF as an ascii art GIF with the name `<image-name>-ascii-art.g
<img src="https://raw.githubusercontent.com/TheZoraiz/ascii-image-converter/master/example_gifs/save.gif"> <img src="https://raw.githubusercontent.com/TheZoraiz/ascii-image-converter/master/example_gifs/save.gif">
</p> </p>
#### --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 #### --font
> **Note:** This flag will be ignored if `--save-img` or `--save-gif` flags are not set > **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 ascii-image-converter [image paths/urls] -s . --font /path/to/font-file.ttf
``` ```
#### --font-color
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 [image paths/urls] -s . --font-color 0,0,0 # For black font color
```
#### --formats #### --formats
Display supported input formats. Display supported input formats.
@ -353,13 +371,6 @@ ascii-image-converter --formats
<br> <br>
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.
```
ascii-image-converter [image paths/urls] -Cnxyd 60,30 -m " .-=+#@" -s . --save-txt .
```
<br>
## Library Usage ## Library Usage
> **Note:** The library may throw errors during Go tests due to some unresolved bugs with the [consolesize-go](https://github.com/nathan-fiscaletti/consolesize-go) package (Only during tests, not main program execution). Furthermore, GIF conversion is not advised as it isn't fully library-compatible yet. > **Note:** The library may throw errors during Go tests due to some unresolved bugs with the [consolesize-go](https://github.com/nathan-fiscaletti/consolesize-go) package (Only during tests, not main program execution). Furthermore, GIF conversion is not advised as it isn't fully library-compatible yet.
@ -389,20 +400,23 @@ func main() {
// This part is optional. // This part is optional.
// You can directly pass default flags variable to Convert() if you wish. // 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. // 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.Dimensions = []int{50, 25} // 50 by 25 ascii art size
flags.SaveTxtPath = "." // Save generated text in same directory flags.SaveTxtPath = "." // Save generated text in same directory
flags.SaveImagePath = "." // Save generated PNG image 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.SaveGifPath = "." // If gif is provided, save ascii art gif in same directory
flags.Negative = true // Ascii art will have negative color-depth flags.Negative = false // Ascii art will have negative color-depth
flags.Colored = true // Keep colors from original image. This overrides flags.Grayscale flags.Colored = true // Keep colors from original image. This overrides flags.Grayscale and flags.FontColor
flags.Grayscale = true // Returns grayscale ascii art flags.Grayscale = false // Returns grayscale ascii art. This overrides flags.FontColor
flags.CustomMap = " .-=+#@" // Starting from darkest to brightest shades. This overrides flags.Complex flags.CustomMap = " .-=+#@" // Starting from darkest to brightest shades. This overrides flags.Complex
flags.FlipX = true // Flips ascii art horizontally flags.FlipX = false // Flips ascii art horizontally
flags.FlipY = true // Flips ascii art vertically flags.FlipY = false // Flips ascii art vertically
flags.Full = true // Display ascii art that fills the terminal width. This overrides flags.Dimensions 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) asciiArt, err := aic_package.Convert(filePath, flags)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)

View File

@ -103,11 +103,11 @@ func pathIsGif(gifPath, urlImgName string, pathIsURl bool, urlImgBytes []byte, l
os.Exit(0) 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].asciiCharSet = asciiCharSet
gifFramesSlice[i].delay = originalGif.Delay[i] gifFramesSlice[i].delay = originalGif.Delay[i]
ascii := flattenAscii(asciiCharSet, colored || grayscale) ascii := flattenAscii(asciiCharSet, colored || grayscale, false)
asciiArtSet[i] = strings.Join(ascii, "\n") asciiArtSet[i] = strings.Join(ascii, "\n")

View File

@ -48,7 +48,7 @@ func pathIsImage(imagePath, urlImgName string, pathIsURl bool, urlImgBytes []byt
return "", err 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 // Save ascii art as .png image before printing it, if --save-img flag is passed
if saveImagePath != "" { 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") result := strings.Join(ascii, "\n")
return result, nil return result, nil

View File

@ -36,81 +36,6 @@ import (
"github.com/golang/freetype/truetype" "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. // Return default configuration for flags.
// Can be sent directly to ConvertImage() for default ascii art // Can be sent directly to ConvertImage() for default ascii art
func DefaultFlags() Flags { func DefaultFlags() Flags {
@ -130,6 +55,8 @@ func DefaultFlags() Flags {
FlipY: false, FlipY: false,
Full: false, Full: false,
FontFilePath: "", 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 flipY = flags.FlipY
full = flags.Full full = flags.Full
fontPath = flags.FontFilePath fontPath = flags.FontFilePath
fontColor = flags.FontColor
saveBgColor = flags.SaveBackgroundColor
// Declared at the start since some variables are initially used in conditional blocks // Declared at the start since some variables are initially used in conditional blocks
var ( var (

View File

@ -78,8 +78,12 @@ func createGifFrameToSave(asciiArt [][]imgManip.AsciiChar, img image.Image, colo
dc := gg.NewContext(x, y) dc := gg.NewContext(x, y)
// Set image background as black // Set image background
dc.SetRGB(0, 0, 0) dc.SetRGB(
float64(saveBgColor[0])/255,
float64(saveBgColor[1])/255,
float64(saveBgColor[2])/255,
)
dc.Clear() dc.Clear()
dc.DrawImage(tempImg, 0, 0) dc.DrawImage(tempImg, 0, 0)
@ -109,12 +113,17 @@ func createGifFrameToSave(asciiArt [][]imgManip.AsciiChar, img image.Image, colo
for _, char := range line { for _, char := range line {
if colored {
// dc.SetColor() sets color for EACH character before printing it
r := uint8(char.RgbValue[0]) r := uint8(char.RgbValue[0])
g := uint8(char.RgbValue[1]) g := uint8(char.RgbValue[1])
b := uint8(char.RgbValue[2]) b := uint8(char.RgbValue[2])
dc.SetColor(color.RGBA{r, g, b, 255})
if colored { } else {
// Simple put, dc.SetColor() sets color for EACH character before printing it r := uint8(fontColor[0])
g := uint8(fontColor[1])
b := uint8(fontColor[2])
dc.SetColor(color.RGBA{r, g, b, 255}) dc.SetColor(color.RGBA{r, g, b, 255})
} }

View File

@ -69,8 +69,12 @@ func createImageToSave(asciiArt [][]imgManip.AsciiChar, colored bool, saveImageP
dc := gg.NewContext(imgWidth, imgHeight) dc := gg.NewContext(imgWidth, imgHeight)
// Set image background as black // Set image background
dc.SetRGB(0, 0, 0) dc.SetRGB(
float64(saveBgColor[0])/255,
float64(saveBgColor[1])/255,
float64(saveBgColor[2])/255,
)
dc.Clear() dc.Clear()
dc.DrawImage(tempImg, 0, 0) dc.DrawImage(tempImg, 0, 0)
@ -93,12 +97,17 @@ func createImageToSave(asciiArt [][]imgManip.AsciiChar, colored bool, saveImageP
for _, char := range line { for _, char := range line {
if colored {
// dc.SetColor() sets color for EACH character before printing it
r := uint8(char.RgbValue[0]) r := uint8(char.RgbValue[0])
g := uint8(char.RgbValue[1]) g := uint8(char.RgbValue[1])
b := uint8(char.RgbValue[2]) b := uint8(char.RgbValue[2])
dc.SetColor(color.RGBA{r, g, b, 255})
if colored { } else {
// Simply put, dc.SetColor() sets color for EACH character before printing it r := uint8(fontColor[0])
g := uint8(fontColor[1])
b := uint8(fontColor[2])
dc.SetColor(color.RGBA{r, g, b, 255}) dc.SetColor(color.RGBA{r, g, b, 255})
} }

View File

@ -30,7 +30,7 @@ import (
func saveAsciiArt(asciiSet [][]imgManip.AsciiChar, imagePath, savePath, urlImgName string) error { func saveAsciiArt(asciiSet [][]imgManip.AsciiChar, imagePath, savePath, urlImgName string) error {
// To make sure uncolored ascii art is the one saved as .txt // 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") saveFileName, err := createSaveFileName(imagePath, urlImgName, "-ascii-art.txt")
if err != nil { 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 // flattenAscii flattens a two-dimensional grid of ascii characters into a one dimension
// of lines of ascii // of lines of ascii
func flattenAscii(asciiSet [][]imgManip.AsciiChar, colored bool) []string { func flattenAscii(asciiSet [][]imgManip.AsciiChar, colored, toSaveTxt bool) []string {
var ascii []string var ascii []string
for _, line := range asciiSet { for _, line := range asciiSet {
var tempAscii []string var tempAscii []string
for i := 0; i < len(line); i++ { for i := 0; i < len(line); i++ {
if toSaveTxt {
tempAscii = append(tempAscii, line[i].Simple)
continue
}
if colored { 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 { } else {
tempAscii = append(tempAscii, line[i].Simple) tempAscii = append(tempAscii, line[i].Simple)
} }

103
aic_package/vars.go Normal file
View File

@ -0,0 +1,103 @@
/*
Copyright © 2021 Zoraiz Hassan <hzoraiz8@gmail.com>
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
)

View File

@ -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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package cmd package cmd
import ( import (
"fmt" "fmt"
"os" "os"
"path"
"github.com/TheZoraiz/ascii-image-converter/aic_package" "github.com/TheZoraiz/ascii-image-converter/aic_package"
"github.com/TheZoraiz/ascii-image-converter/aic_package/winsize"
homedir "github.com/mitchellh/go-homedir" homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -47,12 +46,14 @@ var (
flipY bool flipY bool
full bool full bool
fontFile string fontFile string
fontColor []int
saveBgColor []int
// Root commands // Root commands
rootCmd = &cobra.Command{ rootCmd = &cobra.Command{
Use: "ascii-image-converter [image paths/urls]", Use: "ascii-image-converter [image paths/urls]",
Short: "Converts images and gifs into ascii art", 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.", 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 // Not RunE since help text is getting larger and seeing it for every error impacts user experience
@ -78,6 +79,8 @@ var (
FlipY: flipY, FlipY: flipY,
Full: full, Full: full,
FontFilePath: fontFile, FontFilePath: fontFile,
FontColor: [3]int{fontColor[0], fontColor[1], fontColor[2]},
SaveBackgroundColor: [3]int{saveBgColor[0], saveBgColor[1], saveBgColor[2]},
} }
for _, imagePath := range args { 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 // Cobra configuration from here on
func Execute() { func Execute() {
@ -227,12 +119,12 @@ func init() {
rootCmd.Flags().SortFlags = false rootCmd.Flags().SortFlags = false
// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.ascii-image-converter.yaml)") // 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().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(&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().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().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(&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(&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") 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().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: <image-name>-ascii-art.png\nImage will be saved in passed path\n(pass . for current directory)\n") rootCmd.PersistentFlags().StringVarP(&saveImagePath, "save-img", "s", "", "Save ascii art as a .png file\nFormat: <image-name>-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: <image-name>-ascii-art.txt\nFile 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: <image-name>-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: <image-name>-ascii-art.gif\nGif will be saved in passed path\n(pass . for current directory)\n") rootCmd.PersistentFlags().StringVar(&saveGifPath, "save-gif", "", "If input is a gif, save it as a .gif file\nFormat: <gif-name>-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().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().BoolVar(&formatsTrue, "formats", false, "Display supported input formats\n")
rootCmd.PersistentFlags().BoolP("help", "h", false, "Help for "+rootCmd.Name()+"\n") rootCmd.PersistentFlags().BoolP("help", "h", false, "Help for "+rootCmd.Name()+"\n")

175
cmd/util.go Normal file
View File

@ -0,0 +1,175 @@
/*
Copyright © 2021 Zoraiz Hassan <hzoraiz8@gmail.com>
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
}

View File

@ -113,18 +113,18 @@ var asciiTableDetailed = map[int]string{
const MAX_VAL float64 = 65535 const MAX_VAL float64 = 65535
type AsciiChar struct { type AsciiChar struct {
Colored string OriginalColor string
SetColor string
Simple string Simple string
RgbValue [3]uint32 RgbValue [3]uint32
} }
// Converts the 2D AsciiPixel slice of image data (each instance representing each pixel of original image) // Converts the 2D image_conversions.AsciiPixel slice of image data (each instance representing each compressed pixel of original image)
// to a 2D AsciiChar slice with each colored and simple string having an ASCII character corresponding to // to a 2D image_conversions.AsciiChar slice
// the original grayscale and RGB values in AsciiPixel.
// //
// If complex parameter is true, values are compared to 69 levels of color density in ASCII characters. // 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. // 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) height := len(imgSet)
width := len(imgSet[0]) width := len(imgSet[0])
@ -157,7 +157,7 @@ func ConvertToAsciiChars(imgSet [][]AsciiPixel, negative, colored, complex bool,
for j := 0; j < width; j++ { for j := 0; j < width; j++ {
value := float64(imgSet[i][j].charDepth) 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)) tempFloat := (value / MAX_VAL) * float64(len(chosenTable))
if value == MAX_VAL { if value == MAX_VAL {
tempFloat = float64(len(chosenTable) - 1) tempFloat = float64(len(chosenTable) - 1)
@ -198,7 +198,17 @@ func ConvertToAsciiChars(imgSet [][]AsciiPixel, negative, colored, complex bool,
var char AsciiChar var char AsciiChar
char.Colored = color.Sprintf("<fg="+rStr+","+gStr+","+bStr+">%v</>", chosenTable[tempInt]) char.OriginalColor = color.Sprintf("<fg="+rStr+","+gStr+","+bStr+">%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("<fg="+fcR+","+fcG+","+fcB+">%v</>", chosenTable[tempInt])
}
char.Simple = chosenTable[tempInt] char.Simple = chosenTable[tempInt]
if colored { if colored {

View File

@ -159,8 +159,7 @@ func ConvertToAsciiPixels(img image.Image, dimensions []int, width, height int,
grayPixel := color.GrayModel.Convert(oldPixel) grayPixel := color.GrayModel.Convert(oldPixel)
r1, g1, b1, _ := grayPixel.RGBA() 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 // Only Red is needed from RGB for charDepth in AsciiPixel since they have the same value for grayscale images
charDepth := r1
r1 = uint32(r1 / 257) r1 = uint32(r1 / 257)
g1 = uint32(g1 / 257) g1 = uint32(g1 / 257)
b1 = uint32(b1 / 257) b1 = uint32(b1 / 257)

View File

@ -1,10 +1,10 @@
name: ascii-image-converter name: ascii-image-converter
base: core18 base: core18
version: "1.5.0" version: "1.6.0"
summary: Convert images and gifs into ascii art summary: Convert images and gifs into ascii art
description: | description: |
This tool converts images and gifs into ascii format and prints them onto the terminal window. ascii-image-converter is a command-line tool that converts images into ascii art and prints
Supported input formats are JPEG/JPG, PNG, WEBP, BMP TIFF/TIF and GIF. Further configuration can be managed by flags. them out onto the console. Supported input formats are JPEG/JPG, PNG, WEBP, BMP, TIFF/TIF and GIF
grade: stable grade: stable
confinement: strict confinement: strict