Forum: Projekte & Code "Picture Converter 1bpp" Tool zum erzeugen von Bitmapgrafiken für monochrome LC-Displays


von Erik (Gast)


Angehängte Dateien:

Lesenswert?

Ich beschäftige mich häufig mit Mikrocontroller + LC-Displays und habe 
damals kein passendes Programm zum erzeugen von Bitmap/Array-Grafiken 
gefunden. Deshalb habe ich mir ein eigenes kleines Tool geschrieben. 
Sicherlich gibt es mittlerweile einige Programme die genau das tun was 
ich will aber egal… Vielleicht hilft es ja einem von euch weiter. 
Feedback nehme ich gern an…

Die Homepage zu diesem Tool ist übrigens 
http://www.embedded-tools.de.vu/



Hier die Kurzbeschreibung zum Programm:

Der "Picture Converter 1bpp" ist ein nützliches Tool zum schnellen und 
einfachen Erstellen von Bitmapgrafiken für monochrome LC-Displays.

Erzeug aus einer beliebigen Bilddatei (jpg,gif,tif,png,bmp, etc...) eine 
Bitmap mit einer Farbtiefe von 1 Bit.

Schwarzschattierungen werden mittels Floyd-Steinberg Dithering Verfahren 
ermittelt. Die Auflösung (zerren/strecken) des Zielbildes kann angepasst 
werden.

Zusätzliche Funktionen: Drehen und Spiegeln

Verlustfreie Speicherung in den Formate: bmp, tif und png

Export in #include - fähiges C-Header-File für verschiedene Compiler, 
Grafikcontroller und Mikrocontroller.

In "datei.h" stehen die Bitmapdaten als Array und der Angabe von Breite 
und Höhe in Pixeln. Jede Zeile in "datei.h" enthält eine Zeile der 
Bitmap. Die ersten Arrayeinträge verweise per Präprozessor auf die 
Angaben zur 1. Bildbreite und 2. Bildhöhe (ACHTUNG: wenn dieser Wert 
größer 255 ist ein Eintrag 2byte groß, sonst 1byte). Die erste volle 
Zeile des Array enthält die oberste Zeile der Bitmap. Das erste Byte ist 
links oben in der Bitmap. D7 des Bytes ist das erste Pixel. Diese 
Aufteilung eignet sich z.B. für T6963 und SED1335 Controller.

Dateien für KS108, SED1520 und SPLC0501C Controller können mit 
vertikaler Orientierung erzeugt werden. Ein Byte enthält dann 8 Pixel 
vertikal angeordnet. D7 des Bytes ist das oberste Pixel. Eine Zeile im 
C-Code besteht aus einem Streifen/Spalte von 8 Pixeln Höhe. In der 
Readme ist Implementierungsbeispiel für den ATMEGA128 mit KS108 
angegeben.

: Verschoben durch User
von holger (Gast)


Lesenswert?

Mal abgesehen davon das mir wohl einige *.DDLs zum ausführen
des Programms fehlen:

>C-FILE-HEADER:

>In datei.h stehen die Bitmapdaten als Array und
>der Angabe von Breite und >Höhe in Pixeln.

In datei.h gehören die Bitmap Daten nicht rein.
Das muss in eine datei.c. Wird datei.h von zwei
unabhängigen *.c Dateien per include eingebunden
hagelt es Fehlermeldungen spätestens beim linken.

von Nils S. (kruemeltee) Benutzerseite


Lesenswert?

>Wird datei.h von zwei
>unabhängigen *.c Dateien per include eingebunden
>hagelt es Fehlermeldungen spätestens beim linken.
Quatsch.

#ifndef _BITMAP_
#define _BITMAP_

daten

#endif

von Erik (Gast)


Lesenswert?

>Mal abgesehen davon das mir wohl einige *.DDLs zum ausführen
>des Programms fehlen:

Das .net Framework 4.0 muss installiert sein.

>In datei.h gehören die Bitmap Daten nicht rein.

Das ist bewusst so gemacht um mir 2 Klicks beim hinzufügen der Dateien 
im AVR Studio zu sparen. Wie Nils S. schon geschrieben hat sollte durch
1
#ifndef _BITMAP_
 die Mehrfacheinbindung ausgeschlossen sein.

von Simon K. (simon) Benutzerseite


Lesenswert?

Erik schrieb:
>>In datei.h gehören die Bitmap Daten nicht rein.
>
> Das ist bewusst so gemacht um mir 2 Klicks beim hinzufügen der Dateien
> im AVR Studio zu sparen. Wie Nils S. schon geschrieben hat sollte durch
>
1
#ifndef _BITMAP_
 die Mehrfacheinbindung ausgeschlossen sein.

So einfach ist das nicht!

1. Funktioniert das nur, wenn das Bitmap-Array static deklariert ist und
2. Hat man dann für jedes Einbinden der .h Datei ein einzelnes 
Bitmap-Array inkludiert. Das heißt 5 mal (in 5 verschiedenen .c Dateien) 
inkludiert -> Die gleiche Bitmap ist 5 mal im Speicher vorhanden.

Hintergrund:
Das #ifndef ist eine Preprozessor Anweisung. Das heißt, die Anweisungen 
werden vor dem eigentlichen Kompiliervorgang gestartet. Jede .c Datei 
wird aber einzeln kompiliert. Beim Kompilieren einer "datei2.c", weiß 
der Compiler nicht, dass er "datei1.c" schon kompiliert hat. Demnach 
weiß er auch nicht, dass das Define  BITMAP  in "datei1.c" schon 
abgearbeitet wurde. Demnach inkludiert er wieder die .h Datei.

Erst nach dem einzelnen Kompilieren aller .c Dateien kommt der Linker 
und fügt alle erzeugten Objekt-Dateien zusammen. Und hier merkt der 
Linker: Nanu, ich habe ja 5 mal das Objekt "BitmapArray[x][y]" (o.ä.) in 
5 verschiedenen Dateien vorliegen.
-> Fehler.

Deshalb kommt das Array immer in die .c Datei und eine extern-Definition 
in die .h Datei, die dann von mehreren Orten inkludiert werden kann.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Wobei die Diskussion recht müßig ist, einmal wird man vermutlich nicht 
in fünf Modulen auf die Grafik zugreifen wollen, und andererseits hält 
einen ja niemand davon ab sich das schnell zurechtzukopieren wenn man 
dann doch diesen Anwendungsfall hat.

von Simon K. (simon) Benutzerseite


Lesenswert?

Läubi .. schrieb:
> Wobei die Diskussion recht müßig ist, einmal wird man vermutlich *nicht*
> in fünf Modulen auf die Grafik zugreifen wollen, und andererseits hält
> einen ja niemand davon ab sich das schnell zurechtzukopieren wenn man
> dann doch diesen Anwendungsfall hat.

Auf der anderen Seite eignen sich unerfahrene Leute sowas an, und 
eröffnen dann einen neuen Thread hier im Forum und fragen, warum sich 
der Quellcode nicht kompilieren lässt.

von Erik (Gast)


Lesenswert?

>1. Funktioniert das nur, wenn das Bitmap-Array static deklariert ist und
>2. Hat man dann für jedes Einbinden der .h Datei ein einzelnes
>Bitmap-Array inkludiert. Das heißt 5 mal (in 5 verschiedenen .c Dateien)
>inkludiert -> Die gleiche Bitmap ist 5 mal im Speicher vorhanden.

>Und hier merkt der Linker: Nanu, ich habe ja 5 mal das Objekt "BitmapArray[x][y]" 
>(o.ä.) in 5 verschiedenen Dateien vorliegen.

Das stimmt natürlich... In meinen Programmen nutzte ich meist nur eine 
.c Datei die Bitmaps für Menüs aus einer "icon.h" lädt. Demnach spielt 
das keine Rolle. ABER wer auf eine Bitmap aus mehreren c-Dateien 
zugreifen will, der muss das Array in ein c-File umkopieren.

In der Regel finde ich es sinnvoll in "Schichten" die funktional 
strukturiert sind zu programmieren. Jede Schicht kennt nur Funktionen 
der darunterliegenden Schicht z.B. Treiber/Hardwareabstraktion <- 
Grafik/Textausgabe <- Nutzerinteraktion. Jede Schicht erhält eine 
c-Datei. Erst in der Letzten könne dann Bitmaps genutzt werden 
(einmaliger include). Das System wird somit immer weiter abstrahiert. 
Nachteilig ist allerdings, wenn man an diesen Konzept kategorisch 
festhält, das einige Funktionsaufrufe nur durch die Schichten 
weitergereicht werden, das verringert die Abarbeitungsgeschwindigkeit 
erhöht aber die Portierbarkeit auf wechselnde Hardware.

Ob dies nun sinnvoll ist oder nicht hängt natürlich stark vom Projekt 
ab.

von Stephan K. (dustpuppy)


Lesenswert?

Hi,
warum den ganzen Aufwand? Jedes gute Bildverarbeitungsprogram kann das 
bereits. Das Bild einfach in "xbm" abspeichern/exportieren.
Dann bekommt man so eine Datei:
1
#define mein_bild_width 88
2
#define mein_bild_height 128
3
const unsigned char mein_bild_bits[] = {
4
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
5
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00,
6
...
7
..
8
.

Hier einfach ein PROGMEM einfuegen:
1
#define mein_bild_width 88
2
#define mein_bild_height 128
3
const unsigned char mein_bild_bits[] PROGMEM = {
4
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
5
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00,
6
...
7
..
8
.

Und dann das Ganze so anzeigen :
1
#include "mein_bild.xbm"
2
3
void glcd_XBM(const unsigned char *xbm, uint16_t x, uint16_t y, int w, int h)
4
{
5
  char D;
6
  for(uint16_t zeile=0 ; zeile < h ; zeile++)
7
  {
8
    for(uint16_t spalte=0 ; spalte<(w/8) ; spalte++)
9
    {
10
      for(int i=0;i<=7;i++)
11
      {
12
         D=pgm_read_byte(xbm+(zeile*w/8)+spalte);
13
         if(D & 1<<i)
14
         {
15
           glcd_pixel(x+i+(spalte*8),y+zeile,TRUE);
16
         }
17
         else if(!D)
18
         {
19
           glcd_pixel(x+i+(spalte*8),y+zeile,FALSE);
20
         }
21
       }
22
    }
23
  }
24
}
25
26
void main(void)
27
{
28
   glcd_XBM(mein_bild_bits, 0, 0, mein_bild_width, mein_bild_height);
29
}

Gruesse
Dusty

von Simon K. (simon) Benutzerseite


Lesenswert?

Aaah, wollte auch was dazu schreiben, mir ist aber xpm eingefallen. 
Das ist etwas unhandlicher. Aber ich wusste doch, dass ich das schon mal 
gesehen hab. xbm genau. IrfanView kann das auch AFAIK.

von Stephan K. (dustpuppy)


Lesenswert?

Wer's etwas mehr haben will, nimmt das hier und uebergibt noch ob's 
transparent oder nicht und/oder invers sein soll. Die Modes koennen auch 
kombiniert werden, also z.b. INVERSE + TRANS.
Solid ist sehr viel schneller als transparent.
1
#define bit_get(p,m) ((p) & (m))
2
#define bit_set(p,m) ((p) |= (m))
3
#define bit_clear(p,m) ((p) &= ~(m))
4
#define bit_flip(p,m) ((p) ^= (m))
5
#define bit_write(c,p,m) (c ? bit_set(p,m) : bit_clear(p,m))
6
#define BIT(x) (0x01 << (x))
7
#define LONGBIT(x) ((unsigned long)0x00000001 << (x))
8
9
#define SOLID    0b1
10
#define TRANS    0b10
11
#define INVERSE    0b100
12
13
void glcd_XBM(const unsigned char *xbm, uint16_t x, uint16_t y, int w, int h, int mode)
14
{
15
  int D;
16
  for(uint16_t zeile=0 ; zeile < h ; zeile++)
17
  {
18
    for(uint16_t spalte=0 ; spalte<(w/8) ; spalte++)
19
    {
20
      for(int i=0;i<=7;i++)
21
      {
22
      D=bit_get(pgm_read_byte(xbm+(zeile*w/8)+spalte)),BIT(i));
23
      if(D)
24
      {
25
        if( ((mode & TRANS) && !(mode & INVERSE)) )
26
        {
27
          glcd_pixel(x+i+(spalte*8),y+zeile,TRUE);
28
        }
29
        else if( ((mode & SOLID) && !(mode & INVERSE)) )
30
        {
31
          glcd_pixel(x+i+(spalte*8),y+zeile,TRUE);
32
        }
33
        else if( ((mode & SOLID) && (mode & INVERSE)) )
34
        {
35
          glcd_pixel(x+i+(spalte*8),y+zeile,FALSE);
36
        }
37
      }
38
      else if(!D)
39
      {
40
        if( (mode & INVERSE) )
41
        {
42
          glcd_pixel(x+i+(spalte*8),y+zeile,TRUE);
43
        }
44
        else if( (mode & SOLID) && !(mode & INVERSE) )
45
        {
46
          glcd_pixel(x+i+(spalte*8),y+zeile,FALSE);
47
        }
48
      }
49
      }
50
    }
51
    }
52
}

Schon wieder Gruesse

Dusty

von Erik (Gast)


Lesenswert?

> warum den ganzen Aufwand? Jedes gute Bildverarbeitungsprogram kann das
bereits.

Das ist richtig, mit "Gimp" kann man auch in .c oder .h exportieren. 
Viele Wege führen nach Rom.

>Solid ist sehr viel schneller als transparent

wenn's um Geschwindigkeit geht würde ich die Ausgabe blockweise(1Byte) 
machen und nicht pixelweise...

z.B.
1
void glcd_Bitmap(unsigned char * bmp, unsigned char x, unsigned char y)
2
{//Positionierung nur auf Koordinaten mit Teiler 8 möglich, sonst runden
3
//oder überscheidente Blöcken auslesen und im nichtüberdekenden Bereich "verodern"
4
  unsigned char i, j;
5
  unsigned char width = pgm_read_byte(bmp++);        // aus flash in sram wie breit (bmp[0])
6
    unsigned char height = pgm_read_byte(bmp++);        // aus flash in sram wie hoch (bmü(1)
7
8
  if((x + width) > GLCD_XPIXELS) width = GLCD_XPIXELS - x; //Bitmap abschneiden wenn außerhalb des Displays
9
   if((y + height) > GLCD_YPIXELS) height = GLCD_YPIXELS - y; //Bitmap abschneiden wenn außerhalb des Displays
10
11
  for(j = 0; j < (height/8)+1; j++)
12
      {
13
      glcdSetAddress(x,y + j);
14
      for(i = 0; i < width; i++) glcdDataWrite(pgm_read_byte(bmp++));
15
      }
16
}

dadurch ergibt sich aber folgendes Problem, je nachdem welchen 
Grafikcontroller eingesetzt wird ist die Orientierung eines Blocks 
entweder in x oder y Richtung. Dies kann man durch umschreiben der 
Ausgabefunktion korrigieren oder man lässt die Funktion wie sie ist 
nutzt mein Tool und verändert die Orientierung des Bitmaparry. --> 
Schlagwort: Portierbarkeit

von Stephan K. (dustpuppy)


Lesenswert?

Man koennte das Blockproblem loesen, wie ich es hier gemacht habe. 
Beitrag "Font tool von Christian R. verbessert"

Gruesse

Dusty

von Erik .. (erik_mit_k)


Angehängte Dateien:

Lesenswert?

Hallo,
ist zwar schon eine Weile her ich habe aufgrund von verschiedenen 
Anfragen mein Progrämmchen  nochmal überarbeitet. Unter anderem habe ich 
die von euch gennannten Hinweise mit eingebaut (speziell c & h-file).
Hier die Änderungen im Detail:

- Anzeige der Vorschaufenstern verbessert (schärfere & skaliert)
- neues Format eingebunden: xbm - X BitMap
- das Bitfeld in c- bzw. h-Dateien kann jetzt als big oder little endian
- optionale Ausgabe der Bitmap als c-Datei für Bitfeld und h-Datei für 
include aus mehrern unabhängigen c-Dateien möglich
- Ausgabe der Bitmap als h-Datei inklusive Bitfeld weiterhin möglich

Wenn's interessiert viel Spaß damit;-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.