ASCII Schriftart einlesen



  • Also ich kenne die Spec von dem Format nicht. Nur... so wie das aussieht wüsste ich nicht wie man Kommentar/nicht-Kommentar sonst unterscheiden sollte. Kann mMn. fast nur das fehlende @ am Zeilenende sein.



  • OK, hab mal gegoogelt: https://github.com/Marak/asciimo/issues/3
    Wie viele Kommentar-Zeilen es gibt steht in der Header. Also noch einfacher zu ignorieren.
    Dafür muss das @ kein @ sein sondern kann ein beliebiges Zeichen sein - es muss nur im ganze File das selbe verwendet werden.
    Spec: http://www.jave.de/docs/figfont.txt



  • Die (besser lesbare) Spezifikation gibt es unter The FIGfont Version 2 FIGfont and FIGdriver Standard.



  • Oh, ich hatte mal versucht, diesen Header selbst verstehen zu wollen, bin aber gescheitert 😉
    Mit Anleitung sieht das schon besser aus. Besten Dank.



  • Ich habe auf einen Schlag 400 mir noch unbekannte Fonts eingelesen und wieder ausgegeben (erst mal nur in reiner ascii-Form). Für mich ist das zu meiner Zufriedenheit gelöst.
    Ich zeige trotzdem die komplette Klasse, falls doch noch eine Baustelle ist.

    #pragma once
    #include <filesystem>
    #include <fstream>
    #include <string>
    #include <vector>
    #include <sstream> 
    
    namespace figlet
    {
    	struct ErrorState
    	{
    		bool state = false;
    		std::string type;
    	} error;
    
    	struct Directory
    	{
    		std::string path;
    		std::vector<std::string> folders;
    		std::vector<std::string> files;
    
    		void clear()
    		{
    			folders.clear();
    			files.clear();
    		}
    	} directory;
    
    	void getDirectory()
    	{
    		directory.clear();
    		for (const auto& entry : std::filesystem::directory_iterator(directory.path))
    		{
    			std::string name = entry.path().filename().string();
    			if (std::filesystem::is_directory(entry))
    				directory.folders.push_back(name);
    
    			else if (std::filesystem::is_regular_file(entry))
    				directory.files.push_back(name);
    		}
    	}
    
    	bool setPath(const std::string& path)
    	{
    		std::filesystem::path fsPath = path;
    		if (!std::filesystem::exists(fsPath))
    		{
    			error = { true, path + ": path not exists" };
    			return false;
    		}
    		directory.path = fsPath.string();
    		getDirectory();
    		return true;
    	}
    
    
    	class Font
    	{
    		struct Info
    		{
    			std::string name;
    			const std::string signature = "flf2a";
    			char lineMarker = '@';
    
    			char hardBlank = '$';
    			int height = 0;
    			int baseLine = 0;
    			int maxLength = 0;
    			int oldLayout = 0;
    			int commentLines = 0;
    			int printDirection = 0;
    			int fullLayout = 0;
    			int codetagCount = 0;
    		};
    
    		struct FontChar
    		{
    			int width = 0;
    			int height = 0;
    			std::vector<std::string> data;
    		};
    
    		Info fontInfo;
    		std::vector<FontChar> characterSet;
    		ErrorState err;
    
    	public:
    		Font() = default;
    
    		Info info() const { return fontInfo; }
    		std::vector<FontChar> font() const { return characterSet; }
    		ErrorState error() const { return err; }
    
    		bool loadFromFile(const std::string& fontName)
    		{
    			if (directory.path.empty())
    				return Error("no path to font set");
    
    			if (fontName.length() < 5)
    				return Error(fontName + ": invalid font name");
    
    			if (fontName.substr(fontName.length() - 4, fontName.length()) != ".flf")
    				return Error(fontName + ": no flf file");
    
    			std::string fileName = directory.path + fontName;
    			std::ifstream fstream(fileName);
    			if (!fstream)
    				return Error(fileName + ": " + strerror(errno));
    
    			if (!readFontInfo(fstream, fontName))
    				return Error(fontInfo.name + ": invalid header");
    
    			if (!readFont(fstream))
    				return Error(fontInfo.name + ": invalid font");
    
    			return true;
    		}
    
    	private:
    		std::vector<std::string> splitString(const std::string& str, const char delim)  const
    		{
    			std::vector<std::string> vec;
    			std::stringstream sstream(str);
    			std::string item;
    
    			while (std::getline(sstream, item, delim))
    				vec.push_back(item);
    
    			return vec;
    		}
    
    		bool readFontInfo(std::ifstream& fstream, const std::string& fontName)
    		{
    			// geht das alles eleganter?
    			fontInfo.name = fontName.substr(0, fontName.length() - 4);
    			std::string header;
    			std::getline(fstream, header);
    			if (header.empty()) return false;
    			std::vector<std::string> head = splitString(header, ' ');
    
    			std::size_t n = 0;
    			std::string signature = head[n];
    			fontInfo.hardBlank = signature.back();
    			signature.pop_back();
    			if (signature != fontInfo.signature) return false;
    
    			if (++n >= std::size(head)) return false;
    			fontInfo.height = std::stoi(head[n]); // height is essential
    
    			if (++n >= std::size(head)) return false;
    			fontInfo.baseLine = std::stoi(head[n]);
    
    			if (++n >= std::size(head)) return false;
    			fontInfo.maxLength = std::stoi(head[n]); // maxLength is essential
    
    			if (++n >= std::size(head)) return true;
    			fontInfo.oldLayout = std::stoi(head[n]);
    
    			if (++n >= std::size(head)) return true;
    			fontInfo.commentLines = std::stoi(head[n]);
    
    			if (++n >= std::size(head)) return true;
    			fontInfo.printDirection = std::stoi(head[n]);
    
    			if (++n >= std::size(head)) return true;
    			fontInfo.fullLayout = std::stoi(head[n]);
    
    			if (++n >= std::size(head)) return true;
    			fontInfo.codetagCount = std::stoi(head[n]);
    
    			return true;
    		}
    
    		bool readFont(std::ifstream& fstream)
    		{
    			std::string str;
    			for (int i = 0; i < fontInfo.commentLines; ++i)
    				std::getline(fstream, str); // skip comments
    
    			FontChar fontChar;
    			while (std::getline(fstream, str))
    			{
    				if (str.empty() || str.back() != fontInfo.lineMarker)
    					continue; // skip invalid lines
    
    				str.pop_back(); // remove data line marker
    				fontChar.width = str.length() - 1;
    				if (fontChar.width > fontInfo.maxLength)
    					return false;
    
    				const bool isLastLineOfChar = !str.empty() && str.back() == fontInfo.lineMarker;
    				if (isLastLineOfChar) str.pop_back(); // remove last-line-of-char marker
    				fontChar.data.push_back(str);
    
    				if (isLastLineOfChar)
    				{
    					fontChar.height = std::size(fontChar.data);
    					if (fontChar.height != fontInfo.height)
    						return false;
    
    					characterSet.push_back(std::move(fontChar));
    				}
    			}
    			return true;
    		}
    
    		bool Error(const std::string& errType)
    		{
    			err = { true, errType };
    			return false;
    		}
    	};
    }
    

    Wen es interessiert, die Fonts habe ich von hier:
    http://www.figlet.org/



  • @zeropage sagte in ASCII Schriftart einlesen:

    bool readFontInfo(std::ifstream& fstream, const std::string& fontName)
    {
    	// geht das alles eleganter?
    	// ...
    	std::vector<std::string> head = splitString(header, ' ');
    	// ...
    }
    

    Warum liest du erst alles in einen std::vector<std::string> ein, um dann wieder jeden einzelnen Zahlenwert mittels std::stoi auszulesen? Benutze doch einfach direkt einen std::stringstreamund lese daraus die einzelnen Werte.



  • Danke, da komme ich aber noch nicht richtig mit der Benutzung klar. Muss ich noch schauen.



  • std::string header;
    std::getline(fstream, header);
    if (header.empty()) return false;
    std::stringstream sstream(header);
    
    std::string signature;
    if (!(sstream << signature << fontInfo.height << fontInfo.baseLine << fontInfo.maxLength))
       return false;
    // hier noch genauere Auswertung für signature (fontInfo.signature + fontInfo.hardblank)...
    
    sstream << fontInfo.oldLayout  /* << ... */;
    
    return true;
    


  • Oh! Besten Dank 🙂 Da habe ich jetzt ja was.



  • Vielen Dank nochmal.

                    bool readFontInfo(std::ifstream& fstream, const std::string& fontFile)
    		{
    			fontInfo.name = fontFile.substr(0, fontFile.length() - 4);
    			std::string header;
    			std::getline(fstream, header);
    			std::stringstream sstream(header);
    
    			std::string signature;
    			if (!(sstream 
    				>> signature 
    				>> fontInfo.height 
    				>> fontInfo.baseLine 
    				>> fontInfo.maxLength 
    				>> fontInfo.oldLayout 
    				>> fontInfo.commentLines))
    				return false;
    				
    			fontInfo.hardBlank = signature.back();
    			signature.pop_back();
    			if (signature != fontInfo.signature) 
    				return false;
    
    			sstream 
    				>> fontInfo.printDirection 
    				>> fontInfo.fullLayout 
    				>> fontInfo.codetagCount; 
    			return true;
    		}
    
    


  • Wtf? Ich muss einen offenen fstream und den Dateinamen übergeben!? Echt jetzt?



  • Ja? Und?

    Das fontFile brauche ich für den Namen. Das ich den fstream brauche ist doch offensichtlich, oder was?

    Wenn das ein Fehler ist, warum kommst Du in der letzten Minute angekleckert? Den "offenen fstream'" habe ich von Anfang an benutzt.

    EDIT: Und was soll überhaupt dies blöde Fragestellung? "WTF Echt jetzt"? Jetzt weiß ich bestimmt, was Du mir mitteilen willst???



  • Ich sehe da jetzt auch kein Problem. Wahrscheinlich hat @Swordfish gemeint, du könntest dann direkt über den Dateinamen einen Stream öffnen, aber diese Funktion ist ja nur eine Teilfunktion der loadFromFile.

    Du könntest allerdings direkt den passenden Font-Namen übergeben, anstatt in der Funktion die Extension mittels substr wegzuschneiden.

    Und dazu noch eine Kleinigkeit bzgl.

    if (!readFontInfo(fstream, fontName))
    	return Error(fontInfo.name + ": invalid header");
    

    Hier greifst du im Fehlerfall auf fontInfo.name zu. Du setzt zwar zuerst in der Funktion readFontInfo diesen Namen und erst danach wird der Fehlerfall geprüft, aber dies ist eher ein Code-Smell.
    Dies würde auch dafür sprechen vor der Funktion den reinen Font-Namen zu ermitteln und diesen dann weiter zu benutzen.



  • Ein paar Dinge fallen mir noch auf. Ein Fehlerhandling hat die Funktion gar nicht.
    Was ist wenn der Stream nicht offen ist? Kann man direkt am Anfang abfangen.
    Was ist wenn fontfile leer ist, oder keine Endung hat?

    Abgesehen davon bin ich bei Swordfish. Das übergeben der Referenzen auf den stream finde ich nur dann tragbar, wenn in der Datei, aus der gelesen wird, noch andere Dinge stehen als nur das was in dieser Funktion rausgelesen wird. Wenn dort nur die Font-Daten drin stehen, ist eine Blackbox viel schöner, die den Dateinamen übernimmt und Daten zurückgibt oder irgendwo speichert bzw. false zurückgibt ( oder ersatzweise eine intensivere Fehlerkommunikation ). Aber das ist ein stückweit auch Geschmackssache.

    Abgesehen davon empfinde ich "WTF? Echt jetzt?" als keine schöne Art der Gegenfrage 😉



  • Sehe ich anders. readFontInfo ist eine private Methode, da kann man als Precondition ruhig festlegen, dass der stream schon geöffnet sein muss. Wenn die Methode als istream& operator>>( ifstream& is, FontInfo& fi ) implementiert wäre muss der stream ja ebenfalls geöffnet sein. Die Übergabe des Dateinamens halte ich allerdings auch für fraglich, das gehört für mich auf die Ebene, in der readFontInfo aufgerufen wird. Schließlich wird der Name ja nicht aus der Datei gelesen.

    Ansonsten:

    • Du gibst in deinem Code überall Kopien zurück (info(), font(), error()). Das geht auch mit Referenzen auf konstante Objekte.
    • Die Methode Error ist groß geschrieben, im Gegensatz zu allen anderen Methoden. Außerdem setzt sie die Variable err, was (für mich) aus dem Namen der Methode nicht ersichtlich ist. Ich würde hier
    if( Fehlerfall )
    {
       setError( ... );
       return false;
    }
    

    bevorzugen, auch wenn´s eine Zeile mehr ist.

    • Ich bin auch kein Fan von internen Klassen/Strukturen, warum Info eine interne Struktur von Font ist verstehe ich nicht.
    • Variablen im namespace figlet erlauben nur die Benutzung eines Font Objekts gleichzeitig. In die Klasse Font gehören sie mMn auch nicht, da könnte man eine Klasse FontReader drumrumbauen. Oder man wirft eine entsprechende Exception.
    • FontChar::clear() ist überflüssig, wenn du die entsprechende Variable zurücksetzen möchtest geht das auch mit var = FontChar()
    • ist characterSet.push_back(std::move(fontChar)) nicht das Gleiche wie characterSet.emplace_back( fontChar );?


  • @DocShoe sagte in ASCII Schriftart einlesen:

    ist characterSet.push_back(std::move(fontChar)) nicht das Gleiche wie characterSet.emplace_back( fontChar );?

    Nein.

    Emplace_back ist kein automatisches move. Empace_back kannst du verwenden, wenn du mehrere Argumente für den Konstruktor hast, also z.B. wenn du einen vector<pair<int, int>> vp hast, dann kannst du mit vp.emplace_back(1, 2) da ein pair einfügen und 1 und 2 werden weitergeleitet. Wenn du dem Ding aber eine Variable (lvalue) gibst, dann wird die auch so (also als lvalue) geforwarded. Du rufst also in der richtigen Stelle den Constructor mit fontChar im Arguement auf und das wird dann den normale copy-constructor mit const T& sein.

    Der push_back-Code movet prinzipiell, aber man müsste mal gucken, ob da nicht ggf. irgendwo ein noexcept fehlt - falls nämlich der vector geresizet werden muss. (gut, das ist kein exklusives push_back-Problem).



  • Weiters kann man emplace_back verwenden um move/copy Construction zu vermeiden.

    std::vector<std::string> vec;
    vec.push_back("meh"); // construct string + move-construct string into vector
    vec.emplace_back("meh"); // directly construct string in vector
    


  • This post is deleted!


  • Habe inzwischen ein wenig weitergewerkelt, danke an alle Teilnehmer.

    @DocShoe sagte in ASCII Schriftart einlesen:

    • Ich bin auch kein Fan von internen Klassen/Strukturen, warum Info eine interne Struktur von Font ist verstehe ich nicht.
    • Variablen im namespace figlet erlauben nur die Benutzung eines Font Objekts gleichzeitig. In die Klasse Font gehören sie mMn auch nicht, da könnte man eine Klasse FontReader drumrumbauen. Oder man wirft eine entsprechende Exception.
    • Ich gehe mal davon aus, das dies nicht grundsätzlich gilt? Manche Strukturen können doch ruhig intern sein? Habe aber überarbeitet.
    • Da bin ich mir nicht sicher, ob ich das verstanden habe, kann aber sein, das ich deshalb in der Vergangenheit schon mal ein Problem hatte, ohne den Fehler zu finden. Ich hab das aber unverändert gelassen, aber eine Klasse FontViewer geschrieben. Die zeige ich dann auch.

    Hier ist erstmal die überarbeitete figlet::Font: (Wie immer gilt, wer darauf keine Lust hat, kein Ding 😉 )

    #pragma once
    #include <filesystem>
    #include <fstream>
    #include <string>
    #include <vector>
    #include <sstream> 
    
    namespace figlet
    {
    	// Da ich den ErrorState überall verwende, habe ich jetzt eine globale ErrorState KLasse
    	ErrorState error;
    
    	struct Directory
    	{
    		std::string path;
    		std::vector<std::string> folders;
    		std::vector<std::string> files;
    
    		void clear()
    		{
    			folders.clear();
    			files.clear();
    		}
    	} directory;
    
    	void getDirectory()
    	{
    		directory.clear();
    		for (const auto& entry : std::filesystem::directory_iterator(directory.path))
    		{
    			std::string name = entry.path().filename().string();
    			if (std::filesystem::is_directory(entry))
    				directory.folders.push_back(name);
    
    			else if (std::filesystem::is_regular_file(entry))
    				directory.files.push_back(name);
    		}
    	}
    
    	bool setPath(const std::string& path)
    	{
    		std::filesystem::path fsPath = path;
    		if (!std::filesystem::exists(fsPath))
    		{
    			error.setError(path + ": path not exists");
    			return false;
    		}
    		directory.path = path;
    		getDirectory();
    		return true;
    	}
    
    	struct FontInfo
    	{
    		std::string name;
    		const std::string signature = "flf2a";
    		char lineMarker = '@';
    
    		char hardBlank = '$';
    		int height = 0;
    		int baseLine = 0;
    		int maxLength = 0;
    		int oldLayout = 0;
    		int commentLines = 0;
    		int printDirection = 0;
    		int fullLayout = 0;
    		int codetagCount = 0;
    	};
    
    	struct FontChar
    	{
    		int width = 0;
    		int height = 0;
    		std::vector<std::string> data;
    	};
    
    	class Font
    	{
    		FontInfo fontInfo;
    		std::string contentGlyphs; // das sind die ascii-Zeichen, aus denen der Font besteht 
                                               // kann ich vielleicht  mal für die Ausgabe benutzen
    		std::vector<FontChar> characterSet;
    		ErrorState err;
    
    	public:
    		Font() = default;
    
    		const FontInfo& info() const { return fontInfo; }
    		const std::string& glyphs() const { return contentGlyphs; }
    		const std::vector<FontChar>& font() const { return characterSet; }
    		const ErrorState& errorState() const { return err; }
    
    		bool loadFromFile(const std::string& fontFile)
    		{
    			if (directory.path.empty())
    				return error("no path to font set");
    
    			if (fontFile.length() < 5)
    				return error(fontFile + ": invalid font name");
    
    			if (fontFile.substr(fontFile.length() - 4, fontFile.length()) != ".flf")
    				return error(fontFile + ": no flf file");
    
    			std::string fileName = directory.path + fontFile;
    			std::ifstream fstream(fileName);
    			if (!fstream)
    				return error(fileName + ": " + strerror(errno));
    
    			if (!readFontInfo(fstream))
    				return error(fontFile + ": invalid header");
    
    			if (!readFont(fstream))
    				return error(fontFile + ": invalid font");
    
    			fontInfo.name = fontFile.substr(0, fontFile.length() - 4);
    			return true;
    		}
    
    	private:
    		bool readFontInfo(std::ifstream& fstream)
    		{
    			std::string header;
    			std::getline(fstream, header);
    			std::stringstream sstream(header);
    
    			std::string signature;
    			if (!(sstream 
    				>> signature 
    				>> fontInfo.height 
    				>> fontInfo.baseLine 
    				>> fontInfo.maxLength 
    				>> fontInfo.oldLayout 
    				>> fontInfo.commentLines))
    				return false;
    				
    			fontInfo.hardBlank = signature.back();
    			signature.pop_back();
    			if (signature != fontInfo.signature) 
    				return false;
    
    			sstream 
    				>> fontInfo.printDirection 
    				>> fontInfo.fullLayout 
    				>> fontInfo.codetagCount; 
    			return true;
    		}
    
    		bool readFont(std::ifstream& fstream)
    		{
    			std::string line;
    			for (int i = 0; i < fontInfo.commentLines; ++i)
    				std::getline(fstream, line); // skip comments
    
    			FontChar fontChar;
    			while (std::getline(fstream, line))
    			{
    				if (line.empty() || line.back() != fontInfo.lineMarker) 
    					continue; // skip invalid lines
    
    				line.pop_back(); // remove data line marker
    				fontChar.width = line.length() - 1;
    				if (fontChar.width > fontInfo.maxLength)
    					return false;
    
    				const bool isLastLineOfChar = !line.empty() && line.back() == fontInfo.lineMarker;
    				if (isLastLineOfChar) line.pop_back(); // remove last-line-of-char marker
    				fontChar.data.push_back(line);
    				getContentGlyphs(line); // hole die ascii-Zeichen, aus denen der Font besteht
    
    				if (isLastLineOfChar)
    				{
    					fontChar.height = std::size(fontChar.data);
    					if (fontChar.height != fontInfo.height)
    						return false;
    
    					characterSet.push_back(std::move(fontChar));
    				}
    			}
    			return true;
    		}
    
    		void getContentGlyphs(const std::string& line)
    		{
    			contentGlyphs += line;
    
    			// remove doubles 
    			std::sort(contentGlyphs.begin(), contentGlyphs.end());
    			contentGlyphs.erase(std::unique(
    				contentGlyphs.begin(), 
    				contentGlyphs.end()), 
    				contentGlyphs.end());
    		}
    
    		bool error(const std::string& errType)
    		{
    			err.setError(errType);
    			return false;
    		}
    	};
    }
    

    Die FontViewer:

    #pragma once
    #include "Console.h"
    #include "FigletFont.h"
    #include <map>
    
    // Ich kenn die Kritik, FontViewer ist keine Console ;-) Sehe das aber so, das dies eine Konsolenanwendung ist
    // Außerdem finde ich das zur Zeit echt bequem so
    class FontViewer : public Console
    {
    	struct Param 
    	{
    		int x = 0;
    		int y = 0;
    		std::string key;
    		std::size_t keyCounter = 0;
    		std::size_t fontCounter = 0;
    	};
    
    	figlet::Directory fontDirectory;
    	std::string pathToFont;
    
    	std::map<std::string, std::vector<figlet::Font>> figletFonts;
    	figlet::Font defaultFont;
    	Param param;
    	
    public:
    	FontViewer(const std::string& path, const figlet::Font& font) : 
    		pathToFont(path), defaultFont{ font } {};
    
    private:
    	bool onUserCreate() override
    	{
    		if (!figlet::setPath(pathToFont))
    			return error(figlet::error.type());
    
    		if (figlet::directory.folders.empty())
    			return error(pathToFont + ": directory is empty");
    
    		fontDirectory = figlet::directory; // get own directory
    		for (const auto& folder : fontDirectory.folders)
    		{
    			if (!figlet::setPath(pathToFont + folder + "/")) // get standard directory
    				return error(figlet::error.type());
    
    			for (const auto& file : figlet::directory.files)
    			{
    				figlet::Font font;
    				if (!font.loadFromFile(file))
    					continue;
    				
    				figletFonts[folder].push_back(font);
    			}
    		}
    	
    		if (std::size(fontDirectory.folders) != std::size(figletFonts))
    			return false;
    
    		param.key = fontDirectory.folders[param.keyCounter];
    		fillScreen(console::BLUE, console::BLUE);
    		return true;
    	}
    
    	bool onUserUpdate(float elapsedTime) override
    	{
    		fillBuffer(); // clear screen without write buffer
    
    		// exit
    		if (getKey(VK_ESCAPE).pressed)
    			return false;
    
    		// change folder
    		if (getKey(VK_ADD).pressed)
    		{
    			param.keyCounter++;
    			if (param.keyCounter >= std::size(figletFonts)) param.keyCounter = 0;
    		}
    		if (getKey(VK_SUBTRACT).pressed)
    		{
    			param.keyCounter--;
    			if (param.keyCounter >= std::size(figletFonts)) param.keyCounter = std::size(figletFonts) - 1;
    		}
    		// change font
    		if (getKey(VK_UP).pressed)
    		{
    			param.fontCounter--;
    			if (param.fontCounter >= std::size(figletFonts[param.key])) param.fontCounter = std::size(figletFonts[param.key]) - 1;
    		}
    		if (getKey(VK_DOWN).pressed)
    		{
    			param.fontCounter++;
    			if (param.fontCounter >= std::size(figletFonts[param.key])) param.fontCounter = 0;
    		}
    		// scroll font
    		if (getKey(VK_RIGHT).held)
    		{
    			param.x--;
    		}
    		if (getKey(VK_LEFT).held)
    		{
    			param.x++;
    		}
    
    		param.key = fontDirectory.folders[param.keyCounter];
    		figlet::Font font = figletFonts[param.key][param.fontCounter];
    
    		plotFontName(font, 0, 1, console::DGREY, console::GREY);
    		plotFont(font, param.x, 3 * (defaultFont.info().height + 1), console::BLACK);
    		plotExample(font, param.x, 3 * (defaultFont.info().height + 1) + 2 * (font.info().height + 1), console::BLACK);
    		return true;
    	}
    
    	void plotChar(const figlet::Font& font, const int x, const int y, const std::size_t fontIndex, const int fontColor)
    	{
    		int cx = x;
    		int cy = y;
    		for (const auto& line : font.font()[fontIndex].data)
    		{
    			for (const auto c : line)
    			{
    				if (c == font.info().hardBlank)
    					setDot(cx, cy, console::Dot(' ', fontColor), console::BGROUND);
    				else if (c == '#')
    					setDot(cx, cy, console::Dot(console::SOLID, fontColor), console::BGROUND);
    				else
    					setDot(cx, cy, console::Dot(c, fontColor), console::BGROUND);
    				cx++;
    			}
    			cx = x;
    			cy++;
    		}
    	}
    
    	void plotFont(const figlet::Font& font, const int x, const int y, const int fontColor)
    	{
    		int cx = x;
    		for (std::size_t i = 0; i < std::size(font.font()); ++i)
    		{
    			plotChar(font, cx, y, i, fontColor);
    			cx += font.font()[i].width;
    		}
    	}
    
    	void plotString(const figlet::Font& font, const int x, const int y, const std::string& string, const int fontColor)
    	{
    		if (font.font().empty()) return;
    
    		int sx = x;
    		for (const auto ch : string)
    		{
    			std::size_t fontIndex = ch - ' ';
    			if (fontIndex >= std::size(font.font())) fontIndex = 0;
    
    			plotChar(font, sx, y, fontIndex, fontColor);
    			sx += font.font()[fontIndex].width;
    		}
    	}
    
    	void plotFontName(const figlet::Font& font, const int x, const int y, const int fontColor1, const int fontColor2)
    	{
    		plotString(defaultFont, x, y, "Folder: " + param.key, fontColor1);
    		plotString(defaultFont, x, y + defaultFont.info().height + 1, "Font: " + font.info().name, fontColor2);
    	}
    
    	void plotExample(const figlet::Font& font, const int x, const int y, const int fontColor)
    	{
    		int sy = y;
    		int yLine = font.info().height + 1; // hier sehe ich gerade, kann ich auch gleich font.info().baseLine Nehmen
    	
    		plotString(font, x, sy,          "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG", fontColor);
    		plotString(font, x, sy += yLine, "The Quick Brown Fox Jumps Over The Lazy Dog", fontColor);
    		sy += yLine;
    		plotString(font, x, sy += yLine, "VATIS SCHOSSHUND JAGT ZWÖLF BOXKÄMPFER QUER ÜBER SYLT", fontColor);
    		plotString(font, x, sy += yLine, "Vatis Schoßhund jagt zwölf Boxkämpfer quer über Sylt", fontColor);
    		sy += yLine;
    		plotString(font, x, sy += yLine, "123.456.789.000", fontColor);
    		plotString(font, x, sy += yLine, "+-*/= .,:; <>|_-'~ !$%&/()?", fontColor);
    	}
    };
    
    
    
    
    
    


  • Bekomme dort aber manchmal üble Fehler, wenn ich durch die Folders blättere. Irgendwas in xstring oder xutilities oder manchmal meckert ganz Visual Studio.

    EDIT: Vielleicht sollte ich den param.fontCounter zurücksetzen, wenn ich den param.key wechsele?
    Sorry, aber sobald ich hier Code reinstelle, fang ich an, ganz neu drüber nachzudenken 😉


Log in to reply