Ich entwickle gerade ein kleines Grafikprogramm in C mit CLion unter
Windows. Dieses soll später auf einen Controller portiert werden.
Da der Hauptaufwand allerdings die Software selber und nicht den
Controller betrifft, wollte ich sie vorab auf dem PC schreiben um
komfortabel debuggen zu können.
Zur Bildausgabe soll später ein LCD-Display dienen, jetzt soll das Bild
aber erstmal in ein übliches Format wie z.B. png oder jpeg geschrieben
werden. Dafür sammle ich in einem Buffer
1
constintbuffer[W*H*3+1]
alle Farbinformationen (RGB) für jeden Pixel. Nachdem das mit C
anscheinend alles andere als trivial ist, bin ich durch googlen auf
libpng gestoßen, dessen Sourcecode ich mir hier heruntergeladen habe:
https://sourceforge.net/projects/libpng/files/libpng16/1.6.34/
(lpng1634.zip)
.zip-Datei entpackt und den Ordner in CLion als "Project Source"
markiert. Da die Verwendung auch alles andere als trivial (für mich)
ist, bin ich durch erneutes Googlen auf diesen Beispielcode gestoßen:
https://dev.w3.org/Amaya/libpng/example.c
Ich bin nur an der letzten Funktion write_png interessiert. Die hab
ich mir in mein Projekt kopiert, allerdings werden selbst nach
1
#include"libpng/png.h"
2
#include"libpng/pnglibconf.h"
noch nicht alle Strukturen erkannt. Die pnglibconf hab ich im
Unterordner scripts/pnglibconf.h.prebuilt entdeckt und hab sie prompt in
*pnglibconf.h* umbenannt, damit sind einige Structs mehr erkannt worden.
Trotzdem kommt z.B. bei
die Fehlermeldung, dass W und H (sind Integer) nicht mit png_uint_32
kompatibel wären, aber woher bekomme ich diesen typedef? Das selbe bei
1
FILE*fp=fopen(file_name,"wb");
2
png_init_io(png_ptr,fp);
hier ist png_FILE_p nicht mit FILE* kompatibel. Aber woher bekomme ich
png_FILE_p?
Jetzt frag ich mich - woran liegt das? In dem Beispiel wurde nichts
anderes außer eben *png.h* importiert. Es wird sich ja wohl in den
letzten Monaten bzw. Jahren nicht so viel grundlegendes geändert haben,
immerhin existiert diese Lib bereits seit über 20 Jahren.
Hat jemand Erfahrung mit libpng? Für jeden Tipp wäre ich dankbar.
Grüße
Max M. schrieb:> die Fehlermeldung, dass W und H (sind Integer) nicht mit png_uint_32> kompatibel wären, aber woher bekomme ich diesen typedef?
Aus pngconf.h, Zeile 510?
1
#if UINT_MAX > 4294967294U
2
typedefunsignedintpng_uint_32;
3
#elif ULONG_MAX > 4294967294U
4
typedefunsignedlongintpng_uint_32;
5
#else
6
# error "libpng requires an unsigned 32-bit (or more) type"
7
#endif
> Aber woher bekomme ich png_FILE_p?
Aus pngconf.h, Zeile 595?
1
#ifdef PNG_STDIO_SUPPORTED
2
typedefFILE*png_FILE_p;
3
#endif
Das erschließt sich einem übrigens, wenn man z.B. mit Notepad++ einfach
mal alle *.h-Dateien nach den fraglichen Typen durchsucht. Linuxer
bekämen das auch mit grep hin.
Max M. schrieb:> Was genau soll bei der Addition eines 2D-Arrays mit einem Integer-Wert> herauskommen?
Das ist elementares C.
1
row_pointers[k]=image+k*width;
In diesem Kontext ist "image" gleichbedeutend mit einem Pointer auf das
erste Arrayelement.
Addiert man einen Integer zu diesem Pointer, bekommt man einen Pointer
auf das dem Integerwert entsprechende Arrayelement, bei 4 also das
fünfte Arrayelement.
Max M. schrieb:> Was genau soll bei der Addition eines 2D-Arrays mit einem Integer-Wert> herauskommen?
Dazu müßtest Du Dich ein wenig mit Pointerarithmetik in C befassen, mit
Arrays vs. Pointern und mit 2D-Arrays. Das ist durchaus tricky.
> 2. Auch im nächsten Abschnitt verstehe ich nicht, wie ich hier meinen> "Bildbuffer" unterbringe
Dazu müßtest Du Dir die Beschreibung der API-Funktionen mal durchlesen.
Das README-File ist da wohl der beste Einstieg.
Ich versteh den Sinn nicht, warum man bereits vorhandene Datentypen
nochmal neu anlegt, nur um ein png im Namen zu haben?
Das zwingt mich doch dazu, mein gesamtes Programm auf die Datentypen von
libpng umzuschreiben, und die Lib verwende ich später auf dem Controller
nicht.
Gibt es vielleicht eine einfachere Möglichkeit, ein Bild auf dem PC mit
C zu erzeugen? Ehrlich gesagt übersteigt die Bibliothek meine
C-Fähigkeiten und es scheint mir, als wäre ein großes Maß an Verständnis
für die Zusammenhänge bzw. über die generelle Struktur einer PNG-Datei
notwendig.
Vor 7 Stunden dachte ich naiver Weise, dass das Thema in einer halben
Stunde gegessen ist...
Naja einfach ist das nicht. Da wirst Du Dir erstmal Tutorials durchlesen
müssen, beispielsweise hier:
http://www.labbookpages.co.uk/software/imgProc/libPNG.htmlhttp://zarb.org/~gc/html/libpng.html
Worüber ich mich wundere: wenn Du später auf einem Controller mit PNGs
arbeiten willst, wie willst Du das eigentlich auf dem Controller
erreichen, ohne libPNG dort auch zu haben? PNG ist mit den Optionen zur
Komprimierung usw. nicht trivial.
Max M. schrieb:> Gibt es vielleicht eine einfachere Möglichkeit, ein Bild auf dem PC mit> C zu erzeugen?
Ja, natürlich, indem Du nicht PNG als Format verwendest, sondern z.B.
BMP. Das hat keine Komprimierung und ist daher viel simpler zu
handhaben. Logischerweise sind die Bilddateien dann bei selbem
Bildinhalt viel größer.
Nop schrieb:> Worüber ich mich wundere: wenn Du später auf einem Controller mit PNGs> arbeiten willst, wie willst Du das eigentlich auf dem Controller> erreichen, ohne libPNG dort auch zu haben? PNG ist mit den Optionen zur> Komprimierung usw. nicht trivial.
Wie ich im ersten Beitrag geschrieben habe, erfolgt die Ausgabe auf dem
Controller über ein LCD Display.
Nop schrieb:> Ja, natürlich, indem Du nicht PNG als Format verwendest, sondern z.B.> BMP. Das hat keine Komprimierung und ist daher viel simpler zu> handhaben. Logischerweise sind die Bilddateien dann bei selbem> Bildinhalt viel größer.
Danke, das werde ich mir mal ansehen.
Nop schrieb:> Guck Dir mal das hier an:
Nop schrieb:> a, natürlich, indem Du nicht PNG als Format verwendest, sondern z.B.> BMP.
BMP ist ein Containerformat und kann sowohl unkomprimierte als auch
komprimierte Daten enthalten.
Einfacher zu handhaben ist GIF, da sind mittlerweile auch die letzten
Patente ausgelaufen, und wenn man mit der 256-Farben-Beschränkung leben
kann, ist das eine deutlich simplere Alternative zu PNG.
Max M. schrieb:> Nop schrieb:>> Worüber ich mich wundere: wenn Du später auf einem Controller mit PNGs>> arbeiten willst, wie willst Du das eigentlich auf dem Controller>> erreichen, ohne libPNG dort auch zu haben? PNG ist mit den Optionen zur>> Komprimierung usw. nicht trivial.>> Wie ich im ersten Beitrag geschrieben habe, erfolgt die Ausgabe auf dem> Controller über ein LCD Display.
Und das Display kann direkt mit PNG-Dateien umgehen? Die Frage war doch,
wie du auf dem µC die PNG-Dateien handhaben willst, wo du vermutlich
keine libpng zur Verfügung hast.
> Nop schrieb:>> Ja, natürlich, indem Du nicht PNG als Format verwendest, sondern z.B.>> BMP. Das hat keine Komprimierung und ist daher viel simpler zu>> handhaben. Logischerweise sind die Bilddateien dann bei selbem>> Bildinhalt viel größer.>> Danke, das werde ich mir mal ansehen.
Alternativ könnte noch XPM interessant sein. Das besteht schon aus
C-Code, den man direkt in sein Programm einbinden kann.
https://de.wikipedia.org/wiki/X_PixMap
Rolf M. schrieb:> Und das Display kann direkt mit PNG-Dateien umgehen? Die Frage war doch,> wie du auf dem µC die PNG-Dateien handhaben willst, wo du vermutlich> keine libpng zur Verfügung hast.
Ganz einfach, ich habe keine PNG-Dateien auf dem µC. Das ist ein
SPI-Display, also schreibe ich die Pixeldaten über den SPI Bus in den
Puffer des Displays. Da war ich wohl etwas ungenau in der Beschreibung.
Das hier funktioniert nun:
Max M. schrieb:> Rolf M. schrieb:>> Und das Display kann direkt mit PNG-Dateien umgehen? Die Frage war doch,>> wie du auf dem µC die PNG-Dateien handhaben willst, wo du vermutlich>> keine libpng zur Verfügung hast.>> Ganz einfach, ich habe keine PNG-Dateien auf dem µC. Das ist ein> SPI-Display, also schreibe ich die Pixeldaten über den SPI Bus in den> Puffer des Displays. Da war ich wohl etwas ungenau in der Beschreibung.
Das geht aber immer noch an der Frage vorbei, denn wo kommen die
Pixeldaten denn her?
Max M. schrieb:> struct bitmap_file_header {> unsigned char bitmap_type[2]; // 2 bytes> int file_size; // 4 bytes> short reserved1; // 2 bytes> short reserved2; // 2 bytes> unsigned int offset_bits; // 4 bytes> } bfh;
Ich würde hier die Standard-Typedef aus stdint.h empfehlen. Außerdem
kann es zu Alignment-Problemen kommen, da offset_bits nicht an einer
4-Byte-Grenze ausgerichtet ist. Dazu kommt dann noch ggf. das Thema
Endianness.
Rufus Τ. F. schrieb:> BMP ist ein Containerformat und kann sowohl unkomprimierte als auch> komprimierte Daten enthalten.
Im simpelsten Fall hat man unkomprimierte Daten mit je 8 bit R, G und B
pro Pixel. Das dürfte einfacher sein, als sich mit Paletten und
Paletenindizes herumzuschlagen.
Besonders, wo der OP später mit einem Display wohl auch einfach nur
Bildbufferdaten übertragen wird, da ist unkomprimiertes BMP schon sehr
nahe dran. Es ging schließlich für den PC jetzt nur darum, möglichst
einfach einen Buffer in C manipulieren zu können und den als Bild
wegzuschreiben.
Rolf M. schrieb:> Ich würde hier die Standard-Typedef aus stdint.h empfehlen.
Ja, das hatte ich auch schon angemerkt, als ich das Codebeispiel
berlinkt hatte.
> Außerdem kann es zu Alignment-Problemen kommen, da offset_bits nicht> an einer 4-Byte-Grenze ausgerichtet ist.
Guter Punkt. Zumindest sollte das struct auf dem PC besser "packed"
sein, sonst wird da u.U. Unsinn weggeschrieben auch bei der Dateigröße.
> Dazu kommt dann noch ggf. das Thema Endianness.
Auf dem PC sollte das kein Problem sein, und das wird ja als Dateiformat
offenbar auch nur auf dem PC gebraucht.
Max M. schrieb:> olf M. schrieb:>> Das geht aber immer noch an der Frage vorbei, denn wo kommen die>> Pixeldaten denn her?>> Die erzeugt das Programm.
Ja und dann!?
Das erinnert mich irgendwie an die Formel zum Profit von den "underpants
gnomes" aus South Park:
1. Unterhosen einsammeln
2. ?
3. Profit
Also, wir haben:
1. Ein PC-Programm erzeugt eine Bilddatei
2. ?
3. Die Pixel der Bilddatei gehen per SPI ans Display
Also die Frage nochmal anders gestellt: Wie kommt die Datei zum µC, so
dass er sie per SPI senden kann?
Rolf M. schrieb:> Wie kommt die Datei zum µC, so> dass er sie per SPI senden kann?
Die Pixeldaten werden im Controller erzeugt und auf einem Display, dass
per SPI angesteuert wird, angezeigt. Es gibt keine Datei im µC, die
Datei will ich lediglich auf dem PC haben, um zu testen, ob mein
Programm korrekt funktioniert.
PC-Programm und Controller sind in keiner Weise verbunden oder gehören
zusammen. Am PC teste ich die Software und später läuft sie auf dem
Controller (deswegen tue ich mir C auf dem PC auch an).
Max M. schrieb:> Rolf M. schrieb:>> Wie kommt die Datei zum µC, so>> dass er sie per SPI senden kann?>> Die Pixeldaten werden im Controller erzeugt und auf einem Display, dass> per SPI angesteuert wird, angezeigt. Es gibt keine Datei im µC, die> Datei will ich lediglich auf dem PC haben, um zu testen, ob mein> Programm korrekt funktioniert.
Ach so. Ok, ich dachte, das PC-Programm soll die Datei erzeugen, und der
µC soll sie dann ans Display schicken.
> PC-Programm und Controller sind in keiner Weise verbunden oder gehören> zusammen. Am PC teste ich die Software und später läuft sie auf dem> Controller (deswegen tue ich mir C auf dem PC auch an).
Ah, jetzt verstehe ich. Dann dürfte ein RGB-BMP tatsächlich das
einfachste für dich sein.
Max M. schrieb:> Ich hab das Beispiel ausprobiert:> https://stackoverflow.com/questions/2654480/writin...> und bei mir sieht es genauso aus, heißt das nun, dass alles> funktioniert?
Wenn Du eines der Beispiele gewählt hast, wo diese Header vom Typ
unsigned char sind, und wo z.B. Filesize dann geshiftet und stückweise
reingepackt wird, dann sollte das gut sein.
Ein wichtiger Tip war da noch, daß die Zeilenlänge in Bytes durch vier
teilbar sein muß. Das ist in den Antworten, wo mit der Variable
"extrabytes" gearbeitet wird, aber auch schon bedacht.
Max M. schrieb:> Die Pixeldaten werden im Controller erzeugt und auf einem Display, dass> per SPI angesteuert wird, angezeigt.
(das, nicht "dass")
Warum aber müssen die Pixeldaten dann im PNG-Format vorliegen? Das musst
Du ja erst mal mit libpng erzeugen ... und dann gleich wieder
decodieren, um es ans Display senden zu können.
Rufus Τ. F. schrieb:> Warum aber müssen die Pixeldaten dann im PNG-Format vorliegen?
Gar nicht. Der OP wollte einfach nur auf dem PC einen Bildbuffer im RAM
haben, den mit ein paar C-Routinen manipulieren (was er auch auf dem
Controller dann tun wird) und auf dem PC in irgendeinem Bildformat
ausgeben, mit dem er sich das Ergebnis der Buffer-Manipulationen auf dem
PC schonmal angucken kann.
PNG nur deswegen, weil es einfach ein verbreitetes Format ist und dem OP
daher als Möglichkeit eingefallen ist, und weil es libpng zum
Wegschreiben gibt - nur daß das dann wesentlich komplizierter war als
gedacht.