Wie erstellt man einfache Grafiken?



  • Ganz von Grund auf muß es ja nicht sein und das mit dem Aufwand verstehe ich noch nicht. Meine Vorstellung ist: Das Anliegen, an eine bestimmte Stelle des schwarzen Bildschirms einen kleinen weißen Punkt zu setzen, klingt nicht, als ob es viel ungewöhnlicher oder komplizierter umzusetzen sein sollte als das Anliegen, einen weißen Buchstaben auszugeben.

    Ist es aber. Einen Buchstaben kann man praktisch immer irgendwie auf irgendeinem Gerät ausgeben, das an irgendeinen "Rechner" angeschlossen ist, daher kann man Zeichen immer printen. In Standard-C garantiert dir niemand, dass es überhaupt einen modernen Monitor an deiner Rechenmaschine gibt! Wenn du jetzt an einen PC denkst (C läuft teilweise auch auf anderer Hardware!), dann wirst du einen Monitor und eine Grafikkarte haben (oder auch mehrere Monitore/Graka). Diese hat/haben Treiber. Darüber kann man dann Grafik machen. Beziehungsweise das Betriebssystem nimmt dir dann diese Arbeit ab. Wie auch immer, Grafikausgabe ist hardwareabhängig (und betriebssystemabhängig) und daher etwas ganz anderes als eine Textausgabe. Nutzt du Windows, Mac oder Linux? Alles anders. Aber der C-Standard sagt dazu nichts - da bieten dir die Betriebssysteme eigene (und nicht kompatible) Funktionen. Daher ist es am besten, wenn man eine Bibliothek nutzt, die die unterschiedlichen Betriebssysteme hinter ein gleiches, einheitliches Interface stellt. Ich kenne mich im Grafikbereich nicht aus.

    Für C++ gibt es z.B. https://libcinder.org/ (Windows+Mac), womit man recht schnell was machen kann. Wenn du in einem dieser "modernen" Systeme arbeitest, willst du vielleicht auch erstmal ein "Fenster" erzeugen - und dann im Fenster irgendwie herummalen. Für sowas (für die großen Betriebssysteme) kannst du z.B. Qt nehmen (allerdings C++). Für C fällt mir z.B. https://www.gtk.org/ ein. Eine andere Grafikbibliothek für C ist https://www.libsdl.org/ ein (aber ich habe außer mit Qt keine Erfahrungen!)

    Einfach irgendwie einen Punkt auf den Bildschirm malen - das geht nicht - das verbietet dir i.d.R. das Betriebssystem. Wäre ja blöd, wenn du auf einmal in ein Fenster einer fremden Anwendung reinmalen könntest!

    (dieser Text hier wird nicht 100% richtig sein, aber sollte das grundlegende Problem verdeutlichen)



  • @wob sagte in Wie erstellt man einfache Grafiken?:

    Einfach irgendwie einen Punkt auf den Bildschirm malen - das geht nicht - das verbietet dir i.d.R. das Betriebssystem.

    Auf alten Architekturen konnt man aber die Zeichen austauschen und so Pseudografik im Textmodus nutzen. So wurden in den 80ern einige Spiele programmiert. Keine Ahnung ob das heute nooch so einfach geht.



  • @Ein-Gast sagte in Wie erstellt man einfache Grafiken?:

    @Fragender ASCII-Graphiken wären etwas zu wenig, es sollten schon kleine Punkte sein, die man mit einer gewissen Genauigkeit positionieren und aneinanderreihen kann.

    Ja, ich habe die Frage falsch verstanden, sorry noch mal.


  • Mod

    @Tyrdal sagte in Wie erstellt man einfache Grafiken?:

    Auf alten Architekturen konnt man aber die Zeichen austauschen und so Pseudografik im Textmodus nutzen. So wurden in den 80ern einige Spiele programmiert. Keine Ahnung ob das heute nooch so einfach geht.

    Wenn du das einfach nennst...

    Moderne Grafikframeworks machen es einem vielleicht schwierig, einen einzelnen Pixel auf dem Schirm gezielt zu setzen, aber das ist so, weil man das für ernsthafte moderne Grafik gar nicht braucht. Wer das will, soll halt, wie erklärt, eine Bitmap malen. Dafür ist es mit dem modernen Framework 1000x einfacher hochkomplizierte Effekte zu erzielen, die man sich in der Zeit des Einzelpixelsetzens nicht einmal erträumen konnte.



  • @Tyrdal sagte in Wie erstellt man einfache Grafiken?:

    Auf alten Architekturen konnt man aber die Zeichen austauschen und so Pseudografik im Textmodus nutzen. So wurden in den 80ern einige Spiele programmiert. Keine Ahnung ob das heute nooch so einfach geht.

    Bei 80x25 Zeichen (im Textmodus) kann man 1000 Zeichen auf dem Schirm darstellen. Man hatte aber nur 256 (oder 128) verschiedene Zeichen zur Verfügung.

    Einfach ist das nicht.



  • @Ein-Gast sagte in Wie erstellt man einfache Grafiken?:

    Gibt es also nicht, ähnlich zu printf, so etwas wie eine Funktion, sagen wir "pix", die von zwei Variablen abhängt und wo z. B. pix(0.6,0.4) dazu führt, daß von der linken unteren Bildschirmecke um 60% der Breite nach rechts und 40% der Höhe nach oben gerückt und an der erreichten Position ein Punkt gezeichnet wird? Oder eine Funktion "pic", die als Variable ein Feld oder was weiß ich mit lauter Einträgen für Koordinaten und Farbwerte hat und diese auf den Bildschirm bringt?

    C selber kennt das nicht.

    Aber C-Compiler für MS-DOS (z.B. Quick-C oder Turbo-C) hatten Erweiterungen, womit man das machen konnte.

    Meist aber mit Absolutkoordinaten, da man Pixel zählen kann.

    Mit dem aufkommen von GUI und Fenstern, ist das aber ins Betriebssystem (oder dem Fenstermanager) gewandert.

    Evtl. wirst du noch auf Mikrocontrollern mit einem grafischen LCD und entsprechender Bibliothek fündig.

    Was willst du letztendlich machen/darstellen.

    • Bilder (zb. von Phozoshop/Paint)
    • Grafiken (CAD, Inkscape)
    • Plots/Charts (wie in Excel)
    • Videos


  • @DirkB sagte in Wie erstellt man einfache Grafiken?:

    Was willst du letztendlich machen/darstellen.

    • Bilder (zb. von Phozoshop/Paint)
    • Grafiken (CAD, Inkscape)
    • Plots/Charts (wie in Excel)
    • Videos

    Z. B. Funktionsgraphen oder andere Muster, die sich ähnlich einfach beschreiben lassen. Vielleicht auch einfache aus so etwas gebildete Bewegtbilder, aber keine "richtigen" Fotos oder Videos.
    Das ganze sollte innerhalb von Programmen ohne graphische Benutzeroberfläche funktionieren, vielleicht z. B. in der Art, daß man mithilfe des anderswo erwähnten "ncurses" die Bildschirmanzeige unterteilt und in einem der Teile dann eine Grafik erzeugen kann.

    @wob sagte in Wie erstellt man einfache Grafiken?:

    Für C fällt mir z.B. https://www.gtk.org/ ein. Eine andere Grafikbibliothek für C ist https://www.libsdl.org/ ein (aber ich habe außer mit Qt keine Erfahrungen!)

    Auf den ersten Blick sieht das alles so aus, als sei es für das Erstellen grafischer Benutzeroberflächen und Arbeiten innerhalb solcher gedacht. Ist das so? Falls ja, was nimmt man, wenn keine grafische Benutzeroberfläche erzeugt werden soll?


  • Mod

    Mach es erst einmal als Text. Das wäre ungefähr die gleiche Vorgehensweise, und dann kannst du das später auf "richtige" Grafik hochskalieren. Dann kannst du nach Programmierung der Textausgabe einschätzen, ob du das Projekt überhaupt noch weiter führen möchtest.



  • @Ein-Gast: Grafiken in der Windows Konsole? Dann schau dir mal das C++ Projekt Table and Graph Libraries (bes. ab Graphs/Plots) an.

    Ein einfacheres, nur in C, gibt es unter ConsoleGraphics, auch direkt mit einer drawpixel-Funktion.



  • @Th69 Vielen Dank, aber "ConsoleGraphics" sieht doch auch eher nach C++ aus?

    Abgesehen davon funktioniert es bei mir auch nicht. Wie geht man mit in dieser Form servierten Dateien denn um? Ich habe die .h- und .cpp-Dateien in den Ordner auf meinem Rechner kopiert, wo auch z. B. stdio.h liegt, und dann das kurze Beispielprogramm mit dem dort genannten Befehl kompiliert. Fehlt da noch etwas? Daraufhin kamen nur Fehlermeldungen, als erstes z. B.

    c:\mingw\include\consolegraphics-main\PolyDraw.cpp:63:81: error: 'PCONSOLE_FONT_INFOEX' has not been declared

    Ach ja, auf die Frage nach dem Betriebssystem habe ich nie reagiert... Eigentlich wäre Windows und Linux von Interesse.



  • wir hatten im studium mal die aufgabe, ein einfaches windows-programm mit kommentaren zu versehen und dabei ist dann das hier rausgekommen. im prinzip musst du unter WM_PAINT einfach nur SetPixel (google -> setpixel) aufrufen und alles außer BeginPaint und EndPaint entfernen. der rest (funktionen im internet nachschlagen, programm zum laufen bringen usw) ist dann im selbststudium zu erledigen. unter linux kannst du sowas glaube ich mit den xlibs bzw. xcb machen, aber da habe ich mich nie mit beschäftigt. winapi ist heutzutage soweit ich weiß auch schon sehr speziell und auf der "freakliste" ziemlich weit oben angesiedelt, aber man kann damit toll C lernen.

    #include <Windows.h>
    
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //Prototyp der Callback-Funktion
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
    {
    	static TCHAR szAppName[] = TEXT("Aufgäbe 1"); //Name der Anwendung
    	HWND hwnd; //Handle aufs Fenster
    	MSG msg; //MSG Struktur
    	WNDCLASS wndclass; //Window Class Struktur, enthält die Window Class Attribute, die mit RegisterClass() registriert werden. Wurde durch WNDCLASSEX ersetzt und ist daher eigentlich veraltet.
    
    	wndclass.style = CS_HREDRAW | CS_VREDRAW; //Window Class Styles
    	wndclass.lpfnWndProc = WndProc; //Pointer auf die "Window-Prock"
    	wndclass.cbClsExtra = 0; //Anzahl der Extra-Bytes, die auf die Window Class folgend alloziiert werden sollen.
    	wndclass.cbWndExtra = 0; //Anzahl der Extra-Bytes, die auf die Window Instance folgend alloziiert werden sollen.
    	wndclass.hInstance = hInstance; //Handle auf die Instanz, die die Window-Prozedur für diese Window Class enthält.
    	wndclass.hIcon = LoadIcon(0, IDI_APPLICATION); //Handle auf das Class Icon, das in der Titelleiste und in der Taskleiste angezeigt werden soll
    	wndclass.hCursor = LoadCursor(0, IDC_HAND); //Handle auf den Cursor, aufgrund persönlicher Vorlieben des Programmierers ein Hand-Symbol 
    	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //Handle auf den Background Brush. Sorgt in diesem Fall für einen weißen Hintergrund.
    	wndclass.lpszMenuName = 0; //Festlegung eines Menüs. Hier kein Menü, daher 0
    	wndclass.lpszClassName = szAppName; //Name der Fensterklasse
    
    	
    
    	if (!RegisterClass(&wndclass)) //Registriert die Window Class für nachfolgende Aufrufe von CreateWindow. Wurde durch RegisterClassEx ersetzt und ist daher eigentlich veraltet.
    	{
    		MessageBox(0, TEXT("Fehler!"), szAppName, MB_ICONERROR); //Gibt eine Nachricht aus, falls der Aufruf von RegisterClass() fehlschlagen sollte
    		return 0;
    	}
    
    	hwnd = CreateWindow(szAppName, TEXT("Aufgabe 1"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance, 0); //Erstellt das Fenster. Wurde durch CreateWindowEx ersetzt und ist daher eigentlich veraltet. Sendet WM_CREATE an die Window-Prock
    
    	ShowWindow(hwnd, iCmdShow); //Setzt den spezifizierten Anzeigestatus des Fensters
    	UpdateWindow(hwnd); //Aktualisiert die "client area" des Fensters, indem es eine WM_PAINT-Nachricht sendet.
    
    	while (GetMessage(&msg, 0, 0, 0)) //Ruft die nächste Nachricht ab
    	{
    		TranslateMessage(&msg); //Nachrichten, die von der Tastatur erzeugt wurden, umwandeln
    		DispatchMessage(&msg); //Nachrichten an die Window-Prock senden bzw. die Window-Prock aufrufen
    	}
    
    	return msg.wParam;
    }
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	HDC hdc; //Handle für einen Gerätekontext ("device context")
    	PAINTSTRUCT ps; //Struktur für Zeichenoperationen
    	RECT rect; //Struktur, die einen rechteckigen Bereich beschreibt ("rectangle")
    
    	
    
    	switch (message) 
    	{
    	case WM_CREATE: //Wurde von CreateWindow() geschickt. Hier finden also weitere Initialisierungen statt.
    		return 0;
    	case WM_PAINT:  //Informiert ein Fenster darüber, dass der Inhalt teilweise oder komplett ungültig ist.
    		hdc = BeginPaint(hwnd, &ps); //Bereitet des Fenster auf die Zeichenoperationen vor und füllt die PAINTSTRUCT mit den nötigen Informationen
    
    		SetTextColor(hdc, 0x00FF00FF); //Ändert die Textfarbe in ein nettes Rosa. Scheint keinen ARGB-Wert zu akzeptieren, also ein gutes Beispiel dafür, dass 32 Bit Farbtiefe oft nur 24 Bit Farbtiefe sind.
    
    		GetClientRect(hwnd, &rect); //Kopiert die Dimensionen des Fensterinhalts in die RECT-Struktur. 
    
    		DrawText(hdc, TEXT("Hallo Welt!"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); //Schreibt einen Text in das Fenster.
    
    		EndPaint(hwnd, &ps); //Beendet die Zeichenoperation.
    		return 0;
    	case WM_DESTROY: //Wird von Windows als Reaktion auf einen Klick das Schließen-Feld ("X"), die Tastenkombination Alt + F4 usw erzeugt. 
    		PostQuitMessage(0); //Fügt WM_QUIT in die Nachrichten-Warteschlange ein. Hiermit wird die Endlosschleife in der WinMain beendet.
    		return 0;
    	}
    
    	return DefWindowProc(hwnd, message, wParam, lParam); //Ruft die Default-Window-Prock auf, damit sich diese um die Nachrichten kümmern kann, die hier nicht bearbeitet werden.
    }
    

    PS: SetPixel ist saumäßig langsam, jedenfalls gegenüber opengl, aber es ist bestimmt mal ein anfang.



  • Also ich selbst hab vor kurzem folgendes gemacht:

    Hab mir ein canvas gebaut, wo ich locker flockig Pixel nach Farbe beschreiben kann

    Dann ein BMP writer geschrieben der das in ne .BMP Datei schmeißt. Das nutze ich für mein Raytracer später

    Vielleicht auch eine Idee für dich. Hier mein source Code für den BMP writer, ist ziemlich simple

    https://github.com/TheUnlimited64/the-raytracer-challenge/blob/master/src/filewriter/bmpWriter.c

    Und in c geschrieben


Anmelden zum Antworten