Text als Grafik auslesen



  • Hallo,

    ich will auf meinem externen Display mit 128x64 Pixeln Text ausgeben.
    Dazu muss ich die Buchstaben natürlich pixelweise übertragen.
    Mein Problem ist nun jedoch wie ich die Schrift praktisch in eine Grafik bekomme.
    So schwer sollte es ja eigentlich nicht sein. Nur leider habe ich mich mit dem Thema Grafik und Windows bislang nicht auseinandergesetzt.
    Das ganze programmiere ich in C++.



  • Gibt verschiedene Möglichkeiten.
    Die einfachste, aaber auch langwierigste ist das erstellen der Grafik via Tabelle.
    Beispiel: (bei 8 * 8 Pixeln, 1 Bit pro Pixel)

    Buchstabe A:
       1
       2631
       84268421
       ........  = 0
       ...**...  = 24
       ..*..*..  = 36
       .*....*.  = 66 
       .*....*.  = 66
       .******.  = 126
       .*....*.  = 66
       .*....*.  = 66
    
    char ASCII[127][8] = (  ....
                             (0,24,36,66,66,126,66,66),  // 'A' 0x45
                              ....);
    

    Das Ganze müsste dann dekodiert werden (mittels shiften) und an die entsprechende Pixelposition gesetzt werden.
    Ist eigentlich keine soo komplizierte Rechnung.

    Tipp: mach dir einen Byte-Array von 128 * 64 und befülle diesen pixelweise.

    ...
      for (zeichen = 0; zeichen < text.size(); zeichen++) {
         char meinz = text.getChar(zeichen);
         for (ZeichenZeile = 0, ZeichenZeile < 8; ZeichenZeile++) { 
             for (ZeichenSpalte = 0; ZeichenSpalte < 8; ZeichenSpalte++) {
                 Grafikspeicher[posx + zeichen * 8 + ZeichenSpalte][posy + ZeichenZeile] = meinz % 2;
                 meinz = meinz >> 1;
             }
         }
      }
      ...
      sendBytes(GrafikSpeicher);
    

    So ungefähr würde das Dekodieren laufen.



  • Diese Idee hatte ich schon verworfen, da es mir zu aufwendig ist 🙂
    Ich hatte es mal vor etlichen Jahren mit kyrillischen Zeichen in Pascal und VESA-Grafik realisiert. Aber ich komme vom Thema ab 😉

    Prinipiell will ich es ja schon so machen, jedoch will ich mir die Tabellen nicht von Hand erstellen, sondern ich will mir einfach intern eine Grafik erzeugen. In diese Grafik schreibe ich dann den Text und übertrage dann die Pixel auf mein Display.
    DirectX sollte alle benötigten Funktionen haben.



  • Da brauchst du bestimmt kein DirectX für, die WinAPI tut's auch.
    Mit CreateDC() kannst du eine Zeichenfläche erstellen, mit TextOut() einen beliebigen Text darauf zeichnen lassen. GetPixel() ist eine Möglichkeit, die Grafik pixelweise auszulesen. Schau dir dazu einfach mal den Grafik-Bereich in der Win32-Referenz genauer an.



  • Hört sich gut an.
    Ich melde mich dann später mit den Ergebnissen 🙂



  • habe mir folgendes ausgekaspert :

    HDC hdcScreen;
    		hdcScreen = CreateDC((LPCWSTR)"Display", NULL, NULL, NULL);
    		DWORD d=GetLastError();
    		TextOut(hdcScreen,0,0,(LPCWSTR)"Hallo",5);
    		COLORREF c;
    		for (int x=0;x<MaxX;x++)
    		{
    			for (int y=0;y<MaxY;y++)
    			{
    				c=GetPixel(hdcScreen,x,y);
    				if (c>0)
    					SetPoint(x,y);
    			}
    		}
    		DeleteDC(hdcScreen);
    

    ich bekomme jedoch bei der Funktion CreateDC den GetLastError 8, welche bedeutet, dass nicht genug Speicher zur Verfügung steht.
    Was ist mein Fehler?



  • Also, bei mir funktioniert dein Beispiel wunderbar (außer dass ich mir die Wchar-Konvertierung von "Display" gespart habe).
    Ich habe dir aber trotzdem Unsinn erzählt, weil das ganze gibt den Text auf dem Bildschirm aus, was wahrscheinlich nicht beabsichtigt ist.
    Stattdessen solltest du die Kombination CreateCompatibleDC(), CreateBitmap() und SelectObject() verwenden, dann findet die Textausgabe ausschließlich im Speicher statt.



  • Kann leider erst morgen weiter dran rumforschen.
    CreateBitmap() hört sich ja für mich ganz passend an. Ma guggen.



  • Hallo,
    vielleicht ist ja auch dieses Tutorial was für dich. Da wird u. a. erklärt wie man den Zeichensatz einer Schriftart in einer Bitmap unterbringt.



  • das Tutorial war gut 🙂
    Habe mir nun diese Funktion zurechtgebastelt und stelle sie damit auch zur Diskussion :

    bool WriteText(String ^ s)
    	{
    		bool ret=false;
    		HDC hdc;
    		hdc=CreateCompatibleDC(NULL);
    		HBITMAP hbm=CreateCompatibleBitmap(hdc,MaxX,MaxY);
    		SetMapMode( hdc, MM_TEXT );
    		HFONT font = CreateFont( 16, // Höhe der Font 
    			0, 0, 0, 1, false, false, false, 
    			DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, 
    			CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
    			VARIABLE_PITCH, (LPCWSTR)"Arial" ); // Fontname
    		SelectObject( hdc, hbm );
    		SelectObject( hdc, font );
    		SetTextColor( hdc, RGB(255,255,255) );
    		SetBkColor ( hdc, 0x00000000 );
    		SetTextAlign( hdc, TA_TOP );
    		COLORREF c;
    		for (int x=0;x<MaxX;x++)
    		{
    			for (int y=0;y<MaxY;y++)
    			{
    				c=SetPixel(hdc,x,y,RGB(0,0,0));
    			}
    		}
    		wchar_t buf[100]={0};
    		for (int i=0;i<s->Length;i++) buf[i]=s[i];
    		TextOut(hdc,0,0,(LPCWSTR)buf,s->Length);
    		for (int x=0;x<MaxX;x++)
    		{
    			for (int y=0;y<MaxY;y++)
    			{
    				c=GetPixel(hdc,x,y);
    				if (c>0)
    					SetPoint(x,y); //da schreibe ich nun meine Info :)
    			}
    		}
    		DeleteDC(hdc);
    		return ret;
    	}
    


  • Der Font ist viel zu gross und dann noch proportional für so ein kleines Display. Ich würde das ganz anders machen. Erst schreib ich mir ein Programm, das die Zeichen 32 bis 128 in der Konsole ausgibt. Dann mach ein Screenshot davon (in der Konsole stelle ich mir vorher noch die gewünschte Groesse ein, z.b. 6x8 ) und speicher den als 1 Bit Bild. Das lese ich ein und weil alles im 6x8 Raster liegt, kann ich ganz simpel alles rauskopieren. Effektiv sollte das weniger als 1 Stunde dauern. f'`8k

    Gruß, TGGC (\-/ has leading)



  • Auch ne Lösung 🙂
    Hat auch den Vorteil, dass ich ohne grossen Aufwand weiß wieviele Zeichen in eine Zeile passen. Die Schriftart "Arial monospaced for SAP" sollte im Prinzip dasselbe ermöglichen.
    TGGC's Vorschlag ist jedoch performanter 🙂
    Mal gucken ob ich morgen dafür Zeit hab, heute muss ich leider noch bis 20:00 in der Firma ausharren ...



  • ok, bin nicht mit einer Stunde hingekommen, sondern habe branchenüblich um 50% überzogen 😉

    hier nun mein neuer Code :

    void ReadTypes()
    	{
    		//das Bild mit den Zeichen hat 176x32 Pixel
    		types = (Byte**)new Byte*[176];
    		for (int i=0;i<176;i++) 
    		{
    			types[i]= new Byte[4];
    		}
    		for (int x=0;x<176;x++)
    		{
    			for (int y=0;y<4;y++)
    			{
    				types[x][y]=0;
    			}
    		}
    		//die relevanten Informationen stehen ab dem offset 0x3F
    		//begonnen wird mit der letzten Zeile
    		//1 Bytes enthält jeweils 8 Pixel einer Zeile
    		//1 Zeile besteht aus 24 Bytes -> die letzten beiden können überlesen werden
    		FileStream^ file=gcnew FileStream("types.bmp", FileMode::Open);;
    		BinaryReader^ br=gcnew BinaryReader(file);
    		br->ReadBytes(0x3E);
    		for (int y=31;y>=0;y--)
    		{
    			for (int x=0;x<22;x++)
    			{
    				Byte b=br->ReadByte();
    				int i=0;
    				while (b>0)
    				{
    					if (b%2)
    					{
    						types[x*8+7-i][y/8] |= 1<<(y%8);
    					}
    					b/=2;
    					i++;
    				}
    			}
    			br->ReadBytes(0x02);
    		}
    	}
    
    void WriteText2(String^ s)
    	{
    		const char extra_types[]={'(',')','.',',',':',';','/','*','-','+','!','?','$','%','&','=','ß','ö','ä','ü','Ö','Ä','Ü','#','<','>','\\','@','_'};
    		for (int i=0;i<s->Length;i++)
    		{
    			bool gefunden=false;
    			if (s[i]>='a' && s[i]<='z' && !gefunden)
    			{
    				gefunden=true;
    				for (int o=0;o<6;o++)
    				{
    					new_matrix[6*i+o][0]=types[6*(s[i]-'a')+o][1];
    				}
    			}
    			if (s[i]>='A' && s[i]<='Z' && !gefunden)
    			{
    				gefunden=true;
    				for (int o=0;o<6;o++)
    				{
    					new_matrix[6*i+o][0]=types[6*(s[i]-'A')+o][0];
    				}
    			}
    			if (s[i]>='0' && s[i]<='9' && !gefunden)
    			{
    				gefunden=true;
    				for (int o=0;o<6;o++)
    				{
    					new_matrix[6*i+o][0]=types[6*(s[i]-'0')+o][2];
    				}
    			}
    			if (s[i]==' ' && !gefunden)
    			{
    				gefunden=true;
    				for (int o=0;o<6;o++)
    				{
    					new_matrix[6*i+o][0]=0;
    				}
    			}
    			if (!gefunden)
    			{
    				for (int t=0;t<29;t++)
    				{
    					gefunden=true;
    					if (s[i]==extra_types[t])
    						for (int o=0;o<6;o++)
    						{
    							new_matrix[6*i+o][0]=types[6*t+o][3];
    						}
    				}
    			}
    		}
    	}
    

    Die Write-Funktion sieht etwas zerrissen aus, aber das liegt daran, dass ich nicht den kompletten ASCII-Code in meinem Bitmap habe.


Anmelden zum Antworten