Forum: Compiler & IDEs Wie bekomme ich Daten richtig in eine Datei?


von J. T. (chaoskind)


Lesenswert?

MoinMoin,
ich versuche gerade Daten aus einem Array in eine Bitmap zu schreiben.
Dazu hab ich mir rausgesucht, wie so eine Bitmap aufgebaut ist, habe 
versucht das umzusetzen, aber die Datei die ich erzeuge, lässt sich 
nicht öffnen.

Als erstes habe ich versucht, einfach nur den Header in die zu 
erzeugende Datei zu schreiben, diese wurde jedoch nur 15byte statt der 
erwarteten 54byte groß.

Ich schreibe meine Werte mit fputc in die Datei, will aber eigentlich 
uint32 in der Datei haben, und aus dem Header der BMP kommen auch noch 
einige int32 und uint32.

Ich vermute nun, dass fputc nur chars schreibt (also 8bittige Werte?), 
bräuchte aber wohl etwas, das mir je nach Größe der aktuell zu 
schreibenden Variable einen int16, uint16, int32 oder uint32 schreibt.

Hier mal mein aktueller Code, in der Funktion Mandelbrot wird das Array 
erstellt, welches die Bilddaten beinhaltet. BMP_AUsgeben soll dann die 
.bmp-Datei erzeugen:

MfG Chaos
1
#include <windows.h>
2
#include <stdio.h>
3
#include <stdlib.h>
4
#include <stdint-gcc.h>
5
6
7
#define xMax 1366
8
#define yMax 768
9
10
void Mandelbrot (float CReaMin, float CReaMax, float CImaMin, float CImaMax, int nMax, int Tiefe3D);
11
12
void BMP_Ausgeben (void);
13
14
uint32_t Bild[xMax][yMax];
15
16
typedef struct BMPFileHeaderStruct
17
{
18
    uint16_t bfType;//
19
    uint32_t bfSize;//
20
    uint32_t bfReserved;//
21
    uint32_t bfOffBits;// = 54; //Offsetbytes
22
};
23
24
typedef struct BMPInfoHeaderStruct
25
{
26
    uint32_t biSize;
27
    int32_t biWidth;
28
    int32_t biHeight;
29
    uint16_t biPlanes;
30
    uint16_t biBitCount;
31
    uint32_t biCompression;
32
    uint32_t biSizeImage;
33
    int32_t biXPelsPerMeter;
34
    int32_t biYPelsPerMeter;
35
    uint32_t biClrUsed;
36
    uint32_t biClrImportant;
37
};
38
39
int main()
40
{
41
    system("PAUSE");
42
    Mandelbrot (-1, 2, -1, 1, 1536, 1);
43
    BMP_Ausgeben();
44
45
46
    return 0;
47
}
48
49
50
void Mandelbrot (float CReaMin, float CReaMax, float CImaMin, float CImaMax, int nMax, int Tiefe3D)
51
{
52
    uint16_t xPos = 0;
53
    uint16_t yPos = 0;
54
    uint16_t xPosMerker = 0;
55
    uint16_t yPosMerker = 0;
56
57
    uint32_t n = 0;
58
59
    uint8_t Rot = 0;
60
    uint8_t Gruen = 0;
61
    uint8_t Blau = 0;
62
63
    float DeltaCRea = (CReaMax - CReaMin) / xMax;
64
    float DeltaCIma = (CImaMax - CImaMin) / yMax;
65
66
    float CRea = CReaMin;
67
    float CIma = CImaMin;
68
    float ZRea = 0;
69
    float ZIma = 0;
70
71
    float BetragZ = 0;
72
73
    float CReaHalter = CRea;
74
    float CImaHalter = CIma;
75
    float ZReaHalter = 0;
76
    float ZImaHalter = 0;
77
78
79
    while (yPos < yMax)
80
    {
81
        while (xPos < xMax)
82
        {
83
            while (BetragZ < 4 && n < nMax)
84
            {
85
                ZReaHalter = ZRea;
86
                ZImaHalter = ZIma;
87
88
                ZRea = (ZReaHalter * ZReaHalter) - (ZImaHalter * ZImaHalter) - CRea;
89
                ZIma = (ZReaHalter * ZImaHalter) + (ZReaHalter * ZImaHalter) - CIma;
90
91
                BetragZ = (ZRea*ZRea) + (ZIma*ZIma);
92
93
                n++;
94
            }
95
96
            if (n == nMax)
97
            {
98
                BetragZ = 0;
99
                n = 0;
100
            }
101
102
            if (BetragZ >= 4)
103
            {
104
                yPosMerker = yPos + Tiefe3D;
105
                if (yPosMerker > yMax) yPosMerker = yMax;
106
107
                while (yPosMerker > yPos)
108
                {
109
                    if (n >= 0 && n < 256)
110
                    {
111
                        Rot = 255;
112
                        Gruen = n;
113
                        Blau = 0;
114
                    }
115
116
                    if (n >= 256 && n < 512)
117
                    {
118
                        Rot = 255 - (n - 256);
119
                        Gruen = 255;
120
                        Blau = 0;
121
                    }
122
123
                    if (n >= 512 && n < 768)
124
                    {
125
                        Rot = 0;
126
                        Gruen = 255;
127
                        Blau = (n - 512);
128
                    }
129
130
                    if (n >= 768 && n < 1024)
131
                    {
132
                        Rot = 0;
133
                        Gruen = 255 - (n - 768);
134
                        Blau = 255;
135
                    }
136
137
                    if (n >= 1024 && n < 1280)
138
                    {
139
                        Rot = (n - 1024);
140
                        Gruen = 0;
141
                        Blau = 255;
142
                    }
143
144
                    if (n >= 1280 && n < 1536)
145
                    {
146
                        Rot = 255;
147
                        Gruen = 0;
148
                        Blau = 255 - (n - 1280);
149
                    }
150
151
152
                    /*HDC hdc = GetDC(0);
153
                    SetPixel(hdc, xPos, yPos, RGB(Rot, Gruen, Blau));*/
154
                    Bild[xPos][yPos] = (Rot << 16) | (Gruen << 8) | (Blau << 0);
155
156
                    yPosMerker--;
157
                }
158
159
                BetragZ = 0;
160
                n = 0;
161
            }
162
163
            xPos++;
164
            CRea += DeltaCRea;
165
            ZRea = 0;
166
            ZIma = 0;
167
        }
168
169
        yPos++;
170
        xPos = 0;
171
        CIma += DeltaCIma;
172
        CRea = CReaHalter;
173
    }
174
175
    yPos = 0;
176
    CIma = CImaHalter;
177
}
178
179
void BMP_Ausgeben()
180
{
181
    uint16_t xPos = 0;
182
    uint16_t yPos = 0;
183
    
184
    struct BMPFileHeaderStruct BMPFileHeader;
185
    struct BMPInfoHeaderStruct BMPInfoHeader;
186
187
    FILE *MandelbrotBild1;
188
189
    MandelbrotBild1 = fopen("..\\Fraktal\\MandelbrotBild1.bmp","w+");
190
191
    BMPFileHeader.bfType = 19778; //ASCII Zeichenkette "BM"
192
    BMPFileHeader.bfSize = 3148854; //Größe einer 1366*768*24bit BMP-Datei
193
    BMPFileHeader.bfReserved = 0;
194
    BMPFileHeader.bfOffBits = 54;
195
196
    BMPInfoHeader.biSize = 40;
197
    BMPInfoHeader.biWidth = xMax;
198
    BMPInfoHeader.biHeight = yMax;
199
    BMPInfoHeader.biPlanes = 1;
200
    BMPInfoHeader.biBitCount = 24;
201
    BMPInfoHeader.biCompression = 0;
202
    BMPInfoHeader.biSizeImage = 3148854;
203
    BMPInfoHeader.biXPelsPerMeter = 0;
204
    BMPInfoHeader.biYPelsPerMeter = 0;
205
    BMPInfoHeader.biClrUsed = 0;
206
    BMPInfoHeader.biClrImportant = 0;
207
208
    fputc(BMPFileHeader.bfType,MandelbrotBild1);
209
    fputc(BMPFileHeader.bfSize,MandelbrotBild1);
210
    fputc(BMPFileHeader.bfReserved,MandelbrotBild1);
211
    fputc(BMPFileHeader.bfOffBits,MandelbrotBild1);
212
213
    fputc(BMPInfoHeader.biSize,MandelbrotBild1);
214
    fputc(BMPInfoHeader.biWidth,MandelbrotBild1);
215
    fputc(BMPInfoHeader.biHeight,MandelbrotBild1);
216
    fputc(BMPInfoHeader.biPlanes,MandelbrotBild1);
217
    fputc(BMPInfoHeader.biBitCount,MandelbrotBild1);
218
    fputc(BMPInfoHeader.biCompression,MandelbrotBild1);
219
    fputc(BMPInfoHeader.biSizeImage,MandelbrotBild1);
220
    fputc(BMPInfoHeader.biXPelsPerMeter,MandelbrotBild1);
221
    fputc(BMPInfoHeader.biYPelsPerMeter,MandelbrotBild1);
222
    fputc(BMPInfoHeader.biClrUsed,MandelbrotBild1);
223
    fputc(BMPInfoHeader.biClrImportant,MandelbrotBild1);
224
225
    while (yPos < yMax)
226
    {
227
        while (xPos < xMax)
228
        {
229
            fputc(Bild[xPos][yPos],MandelbrotBild1);
230
            xPos++;
231
        }
232
        xPos = 0;
233
        yPos++;
234
    }
235
}

von Peter II (Gast)


Lesenswert?

wie kommt man nur auf fputc?

http://www.cplusplus.com/reference/cstdio/fwrite/

ist das richtige.

von Rolf M. (rmagnus)


Lesenswert?

j. t. schrieb:
> MoinMoin,
> ich versuche gerade Daten aus einem Array in eine Bitmap zu schreiben.
> Dazu hab ich mir rausgesucht, wie so eine Bitmap aufgebaut ist, habe
> versucht das umzusetzen, aber die Datei die ich erzeuge, lässt sich
> nicht öffnen.

Ah, mit "Bitmap" meinst du eine BMP-Datei. Eigentlich haben diese mit 
Bitmaps gar nix zu tun. Da hat Microsoft mal wieder einen Begriff falsch 
verstanden.

> Ich vermute nun, dass fputc nur chars schreibt (also 8bittige Werte?),
> bräuchte aber wohl etwas, das mir je nach Größe der aktuell zu
> schreibenden Variable einen int16, uint16, int32 oder uint32 schreibt.

Ja, richtig. Ein anderes Problem ist, daß du die Datei im Textmodus 
öffnest.

von J. T. (chaoskind)


Lesenswert?

Peter II schrieb:
> wie kommt man nur auf fputc?

aus nem Tutorial "wie schreibe ich in eine Datei".... , danke für den 
Link=)

Rolf Magnus schrieb:
> Ja, richtig. Ein anderes Problem ist, daß du die Datei im Textmodus
> öffnest.


wie öffne ich die Datei im "Bild"Modus?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

j. t. schrieb:
> Rolf Magnus schrieb:
>> Ja, richtig. Ein anderes Problem ist, daß du die Datei im Textmodus
>> öffnest.
>
> wie öffne ich die Datei im "Bild"Modus?

Nicht "Bild"-, sondern Binärmodus. Sieh Dir mal die Dokumentation von 
fopen an, hier insbesondere die Bedeutung des zweiten Parameters.

von Thomas (Gast)


Angehängte Dateien:

Lesenswert?

Lies mal etwas zu fwrite. Und zu packed bei structs. Etwas entfernt 
mandelbrotiges ist dann schon erkennbar.

Das Bild würde ich zum Testen erstmal mit Schachbrett/Streifen o.ä. 
füllen. Momentan ist nämlich nicht ganz klar, ob die seltsame Optik des 
Resultats beim Erzeugen oder Speichern liegt.

von Thomas (Gast)


Lesenswert?

Und die Warnungen grundsätzlich voll aufdrehen (-Wall -Wextra etc.) und 
abarbeiten.
Sowas "warning: comparison of unsigned expression >= 0 is always true" 
ist z.B. ein Fehlerkandidat.

von J. T. (chaoskind)


Lesenswert?

Thomas schrieb:
> Momentan ist nämlich nicht ganz klar, ob die seltsame Optik des
> Resultats beim Erzeugen oder Speichern liegt.

Die reine Mandelbroterzeugung an sich läuft. Die hab ich schon auf dem 
STM32F429 Disco laufen lassen, aber war mit der Auflösung von 320*240 
nicht wirklich zufrieden. In der Tat sieht das was du da zeigst, ein 
wenig seltsam aus *gg. Aber der Rand ist definitiv schon recht 
mandelbrotig, nur etwas geneigt und er ist halt auch ein paar mal zu oft 
da.

Ich werd mir die links mal zu Gemüte führen, danke dafür

MfG Chaos

von Karl H. (kbuchegg)


Lesenswert?

j. t. schrieb:
> Thomas schrieb:
>> Momentan ist nämlich nicht ganz klar, ob die seltsame Optik des
>> Resultats beim Erzeugen oder Speichern liegt.
>
> Die reine Mandelbroterzeugung an sich läuft. Die hab ich schon auf dem
> STM32F429 Disco laufen lassen, aber war mit der Auflösung von 320*240
> nicht wirklich zufrieden. In der Tat sieht das was du da zeigst, ein
> wenig seltsam aus *gg. Aber der Rand ist definitiv schon recht
> mandelbrotig, nur etwas geneigt und er ist halt auch ein paar mal zu oft
> da.

Heisser Tip:

Seine ersten Gehversuche macht man nicht mit Daten, die man in einer 
Hex-Anzeige der Datei nicht vernünftig deuten kann.
Seine ersten Versuche macht man mit zb dem bereits genannten 
Schachbrett. Denn mit einem Hex-Editor erkennt man dort dann den 
Dateiaufbau wieder und kann ihn mit einem 'baugleichen' Bild, welches 
ein Malprogramm erzeugt hat, vergleichen um zu sehen, wo die 
Unterschiede liegen, wnn man sich das File auf Byte-Ebene ansieht.

von Thomas (Gast)


Angehängte Dateien:

Lesenswert?

"Die Bilddaten werden Zeile für Zeile gespeichert. Wenn biHeight positiv 
ist, beginnen die Bilddaten mit der letzten und enden mit der ersten 
Bildzeile, ansonsten ist es umgekehrt. Bei BI_BITFIELDS und bei BI_RGB 
ist die Länge jeder Zeile ist ein Vielfaches von 4 Bytes und wird, falls 
erforderlich, mit Nullbytes aufgefüllt."

Deine 1366 passen dazu nicht. MIt 1368 geht es besser.

Das komische Muster in der Mitte ist meine Initialisierung des Bildes 
vor dem Mandelbrotaufruf.

von J. T. (chaoskind)


Angehängte Dateien:

Lesenswert?

Zu der Geschichte mit dem Abarbeiten der Warnungen: Was möchte mir diese 
Warnung eigentlich sagen?:
warning: useless storage class specifier in empty declaration [enabled 
by default]|

wenn ich das ganze mit:
typedef struct foostruct
{

}foo;
mache, dann kommt die Warnung nicht.

Die Warnung mit dem Vergleich eines uint mit null ist diesem Fall zu 
ignorieren, da ich ja auch noch vergleiche, ob kleiner als 256 ist.



Ich habe das ganze nun mit fwrite versucht.
1
void BMP_Ausgeben()
2
{
3
    void *fwritePt;
4
    uint16_t xPos = 0;
5
    uint16_t yPos = 0;
6
7
    struct BMPFileHeaderStruct BMPFileHeader;
8
    struct BMPInfoHeaderStruct BMPInfoHeader;
9
10
    FILE *MandelbrotBild1;
11
12
13
    BMPFileHeader.bfType = 19778; //ASCII Zeichenkette "BM"
14
    BMPFileHeader.bfSize = 3148854; //Größe einer 1366*768*24bit BMP-Datei
15
    BMPFileHeader.bfReserved = 0;
16
    BMPFileHeader.bfOffBits = 54;
17
18
    BMPInfoHeader.biSize = 40;
19
    BMPInfoHeader.biWidth = xMax;
20
    BMPInfoHeader.biHeight = yMax;
21
    BMPInfoHeader.biPlanes = 1;
22
    BMPInfoHeader.biBitCount = 24;
23
    BMPInfoHeader.biCompression = 0;
24
    BMPInfoHeader.biSizeImage = 3148854;
25
    BMPInfoHeader.biXPelsPerMeter = 0;
26
    BMPInfoHeader.biYPelsPerMeter = 0;
27
    BMPInfoHeader.biClrUsed = 0;
28
    BMPInfoHeader.biClrImportant = 0;
29
30
31
    MandelbrotBild1 = fopen("..\\Fraktal\\MandelbrotBild1.bmp","wb");
32
33
    fwritePt = &BMPFileHeader.bfType;
34
    fwrite(fwritePt, sizeof(BMPFileHeader.bfType), 1,MandelbrotBild1);
35
36
    fwritePt = &BMPFileHeader.bfSize;
37
    fwrite(fwritePt, sizeof(BMPFileHeader.bfSize), 1,MandelbrotBild1);
38
39
    fwritePt = &BMPFileHeader.bfReserved;
40
    fwrite(fwritePt, sizeof(BMPFileHeader.bfReserved), 1,MandelbrotBild1);
41
42
    fwritePt = &BMPFileHeader.bfOffBits;
43
    fwrite(fwritePt,sizeof(BMPFileHeader.bfOffBits), 1,MandelbrotBild1);
44
45
46
47
    fwritePt = &BMPInfoHeader.biSize;
48
    fwrite(fwritePt,sizeof(BMPInfoHeader.biSize), 1, MandelbrotBild1);
49
50
    fwritePt = &BMPInfoHeader.biWidth;
51
    fwrite(fwritePt, sizeof(BMPInfoHeader.biWidth), 1, MandelbrotBild1);
52
53
    fwritePt = &BMPInfoHeader.biHeight;
54
    fwrite(fwritePt, sizeof(BMPInfoHeader.biHeight), 1, MandelbrotBild1);
55
56
    fwritePt = &BMPInfoHeader.biPlanes;
57
    fwrite(fwritePt, sizeof(BMPInfoHeader.biPlanes), 1, MandelbrotBild1);
58
59
    fwritePt = &BMPInfoHeader.biBitCount;
60
    fwrite(fwritePt, sizeof(BMPInfoHeader.biBitCount), 1, MandelbrotBild1);
61
62
    fwritePt = &BMPInfoHeader.biCompression;
63
    fwrite(fwritePt, sizeof(BMPInfoHeader.biCompression), 1, MandelbrotBild1);
64
65
    fwritePt = &BMPInfoHeader.biSizeImage;
66
    fwrite(fwritePt, sizeof(BMPInfoHeader.biSizeImage), 1, MandelbrotBild1);
67
68
    fwritePt = &BMPInfoHeader.biXPelsPerMeter;
69
    fwrite(fwritePt, sizeof(BMPInfoHeader.biXPelsPerMeter), 1, MandelbrotBild1);
70
71
    fwritePt = &BMPInfoHeader.biYPelsPerMeter;
72
    fwrite(fwritePt,sizeof(BMPInfoHeader.biYPelsPerMeter), 1, MandelbrotBild1);
73
74
    fwritePt = &BMPInfoHeader.biClrUsed;
75
    fwrite(fwritePt, sizeof(BMPInfoHeader.biClrUsed), 1, MandelbrotBild1);
76
77
    fwritePt = &BMPInfoHeader.biClrImportant;
78
    fwrite(fwritePt, sizeof(BMPInfoHeader.biClrImportant), 1, MandelbrotBild1);
79
80
    while (yPos < yMax)
81
    {
82
        while (xPos < xMax)
83
        {
84
            fwritePt = &Bild[xPos][yPos];
85
            fwrite(fwritePt, sizeof(Bild[xPos][yPos]), 1, MandelbrotBild1);
86
            xPos++;
87
        }
88
        xPos = 0;
89
        yPos++;
90
    }
91
    fclose(MandelbrotBild1);
92
}

Es wird nun kompiliert und auch eine 3075kb große Datei erzeugt, aber 
ich kann sie nicht öffnen....

P.S.
Ich hatte versucht die falsche Datei zu öffnen. Es lässt sich doch 
öffnen, jedoch ist da noch irgendwas durcheinander geraten...

: Bearbeitet durch User
von J. T. (chaoskind)


Lesenswert?

Ich werds nun erstmal doch mit nem einfachen Schachbrett oder sowas 
versuchen, um mal nachzuverfolgen, was wo passiert.

von Thomas (Gast)


Lesenswert?

Bei fwrite dachte ich eher an sowas:
fwrite(&BMPFileHeader, sizeof BMPFileHeader, 1, MandelbrotBild1);
Damit das funktioniert, muss das struct packed sein.


>fwritePt = &Bild[xPos][yPos];
>fwrite(fwritePt, sizeof(Bild[xPos][yPos]), 1, MandelbrotBild1);

Hier musst Du immer 3 Byte (R, G und B) schreiben. Das 4. Byte des 
uint32_t darf nicht in die Datei. Und das "Zahl der Pixel in einer Zeile 
muss durch 4 teilbar sein oder mit 0 aufgefüllt werden"-Problem scheint 
auch immer noch zu existieren.

von J. T. (chaoskind)


Lesenswert?

Thomas schrieb:
> Hier musst Du immer 3 Byte (R, G und B) schreiben. Das 4. Byte des
> uint32_t darf nicht in die Datei. Und das "Zahl der Pixel in einer Zeile
> muss durch 4 teilbar sein oder mit 0 aufgefüllt werden"-Problem scheint
> auch immer noch zu existieren.

Ich könnte doch auch auf 32bit-Farbmodus schalten? Dann wäre das Problem 
nur drei von vier Byte aus nem uint32 zu schreiben schonmal umgangen. 
Dann wäre noch zu klären ob der Alphakanal auf auf 0x00 oder 0xff stehen 
muss, damit das Bild nicht transparent ist.

Thomas schrieb:
> Damit das funktioniert, muss das struct packed sein.

Was heißt dass, das struct muss packed sein?

von J. T. (chaoskind)


Lesenswert?

Thomas schrieb:
> fwrite(&BMPFileHeader, sizeof BMPFileHeader, 1, MandelbrotBild1);

dabei ergäbe sich ja das Problem, das die Elemente des Struct ja nicht 
alle die selbe Größe haben. Oder schreibt er dann einfach alle Elemente 
wie sind nacheinander weg?

von Karl H. (kbuchegg)


Lesenswert?

Thomas schrieb:

> Hier musst Du immer 3 Byte (R, G und B) schreiben. Das 4. Byte des
> uint32_t darf nicht in die Datei. Und das "Zahl der Pixel in einer Zeile
> muss durch 4 teilbar sein oder mit 0 aufgefüllt werden"-Problem scheint
> auch immer noch zu existieren.

Ich schätze mal, das kommt von von dem Byteversatz den er durch das 
Schreiben von 4 Bytes für R.G.B zustande bringt.

Aber die 4 Byte Grenze pro Scanline muss er natürlich trotzdem 
einhalten.

j.t. machs dir doch nicht so schwer
1
    BMPFileHeader.bfType = 19778; //ASCII Zeichenkette "BM"
dann schreibs auch als
1
    BMPFileHeader.bfType = 'BM'; //ASCII Zeichenkette "BM"

sowas
1
    BMPFileHeader.bfSize = 3148854; //Größe einer 1366*768*24bit BMP-Datei
muss man nicht ausrechnen. Du hast einen Computer bzw. Compiler! Der 
kann selber rechnen!
1
    fwritePt = &BMPFileHeader.bfType;
2
    fwrite(fwritePt, sizeof(BMPFileHeader.bfType), 1,MandelbrotBild1);
du brauchst doch nicht für alles immer erst die Adresse in einen void 
Pointer überführen!
1
    fwrite(&BMPFileHeader.bfType, sizeof(BMPFileHeader.bfType), 1,MandelbrotBild1);
und gut ists.
Der void* in der Funktionsdeklaration von fwrite bedeutet nur, dass du 
da jede beliebige Adresse reingeben kannst. Das fwrite also nicht 
irgendwas spezielles haben will, zb einen int* oder einen long*. Jede 
Adresse ist ok, egal welcher Basis-Datentyp.

Die Felder schreibt man auch nicht einzeln aufs File. Genau dazu hat man 
sich ja eine struct dafür gebaut. fwrite kann alles auf ein File 
schreiben. Es muss nur wissen, wo es anfängt und wie lange es ist. Gib 
ihm also die Startdresse der BMPFileHeader Struct-Variablen, sag ihm wie 
gross die struct ist (in Bytes, mit einem siezeof) und fwrite schreibt 
die ganze Struktur, so wie sie ist, aufs File (packing ausschalten, 
damit der Compiler nicht zwischen Strukturmember Füllbytes einfügt, 
falls das auf deiner Maschine die Performance steiegern würde).

: Bearbeitet durch User
von Thomas (Gast)


Lesenswert?

j. t. schrieb:
> Was heißt dass, das struct muss packed sein?

https://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html

von Karl H. (kbuchegg)


Lesenswert?

j. t. schrieb:
> Thomas schrieb:
>> fwrite(&BMPFileHeader, sizeof BMPFileHeader, 1, MandelbrotBild1);
>
> dabei ergäbe sich ja das Problem, das die Elemente des Struct ja nicht
> alle die selbe Größe haben. Oder schreibt er dann einfach alle Elemente
> wie sind nacheinander weg?

Der fwrite weiss nichts von 'Elementen'. Der hat eine Speicheradresse 
und eine Angabe wieviele Bytes er beginnend mit dieser Speicheradresse 
ins File buttern soll.

von Thomas (Gast)


Lesenswert?

Und damit kann fwrite auch
>das Problem nur drei von vier Byte aus nem uint32 zu schreiben
lösen.

von J. T. (chaoskind)


Angehängte Dateien:

Lesenswert?

wenn ich statt BMPFileHeader.bfType = 19778; //ASCII Zeichenkette "BM"

BMPFileHeader.bfType = 'BM' schreibe, dann ist das Format nicht lesbar 
beim öffnen. Genauso wenn ich

fwrite(&BMPFileHeader, sizeof(BMPFileHeader), 1,MandelbrotBild1);

statt

    fwrite(&BMPFileHeader.bfType, sizeof(BMPFileHeader.bfType), 
1,MandelbrotBild1);
    fwrite(&BMPFileHeader.bfSize, sizeof(BMPFileHeader.bfSize), 
1,MandelbrotBild1);
    fwrite(&BMPFileHeader.bfReserved, sizeof(BMPFileHeader.bfReserved), 
1,MandelbrotBild1);
    fwrite(&BMPFileHeader.bfOffBits,sizeof(BMPFileHeader.bfOffBits), 
1,MandelbrotBild1);

schreibe....

Ansonsten macht er mir nun ein richtiges Apfelmännchen =)


z.Zt siehts so aus:
1
#include <windows.h>
2
#include <stdio.h>
3
#include <stdlib.h>
4
#include <stdint-gcc.h>
5
6
7
#define xMax 1366
8
#define yMax 768
9
10
void Mandelbrot (float CReaMin, float CReaMax, float CImaMin, float CImaMax, uint32_t nMax, uint16_t Tiefe3D);
11
12
void BMP_Ausgeben (void);
13
14
uint32_t Bild[xMax][yMax];
15
16
typedef struct BMPFileHeaderStruct
17
{
18
    uint16_t bfType;//
19
    uint32_t bfSize;//
20
    uint32_t bfReserved;//
21
    uint32_t bfOffBits;// = 54; //Offsetbytes
22
};
23
24
typedef struct BMPInfoHeaderStruct
25
{
26
    uint32_t biSize;
27
    int32_t biWidth;
28
    int32_t biHeight;
29
    uint16_t biPlanes;
30
    uint16_t biBitCount;
31
    uint32_t biCompression;
32
    uint32_t biSizeImage;
33
    int32_t biXPelsPerMeter;
34
    int32_t biYPelsPerMeter;
35
    uint32_t biClrUsed;
36
    uint32_t biClrImportant;
37
};
38
39
int main()
40
{
41
    system("PAUSE");
42
    Mandelbrot (-1, 2, -1, 1, 1536, 1);
43
    BMP_Ausgeben();
44
45
46
    return 0;
47
}
48
49
50
void Mandelbrot (float CReaMin, float CReaMax, float CImaMin, float CImaMax, uint32_t nMax, uint16_t Tiefe3D)
51
{
52
    uint16_t xPos = 0;
53
    uint16_t yPos = 0;
54
    uint16_t xPosMerker = 0;
55
    uint16_t yPosMerker = 0;
56
57
    uint32_t n = 0;
58
59
    uint8_t Rot = 0;
60
    uint8_t Gruen = 0;
61
    uint8_t Blau = 0;
62
63
    float DeltaCRea = (CReaMax - CReaMin) / xMax;
64
    float DeltaCIma = (CImaMax - CImaMin) / yMax;
65
66
    float CRea = CReaMin;
67
    float CIma = CImaMin;
68
    float ZRea = 0;
69
    float ZIma = 0;
70
71
    float BetragZ = 0;
72
73
    float CReaHalter = CRea;
74
    float CImaHalter = CIma;
75
    float ZReaHalter = 0;
76
    float ZImaHalter = 0;
77
78
79
    while (yPos < yMax)
80
    {
81
        while (xPos < xMax)
82
        {
83
            while (BetragZ < 4 && n < nMax)
84
            {
85
                ZReaHalter = ZRea;
86
                ZImaHalter = ZIma;
87
88
                ZRea = (ZReaHalter * ZReaHalter) - (ZImaHalter * ZImaHalter) - CRea;
89
                ZIma = (ZReaHalter * ZImaHalter) + (ZReaHalter * ZImaHalter) - CIma;
90
91
                BetragZ = (ZRea*ZRea) + (ZIma*ZIma);
92
93
                n++;
94
            }
95
96
            if (n == nMax)
97
            {
98
                BetragZ = 0;
99
                n = 0;
100
            }
101
102
            if (BetragZ >= 4)
103
            {
104
                yPosMerker = yPos + Tiefe3D;
105
                if (yPosMerker > yMax) yPosMerker = yMax;
106
107
                while (yPosMerker > yPos)
108
                {
109
                    if (n >= 0 && n < 256)
110
                    {
111
                        Rot = 255;
112
                        Gruen = n;
113
                        Blau = 0;
114
                    }
115
116
                    if (n >= 256 && n < 512)
117
                    {
118
                        Rot = 255 - (n - 256);
119
                        Gruen = 255;
120
                        Blau = 0;
121
                    }
122
123
                    if (n >= 512 && n < 768)
124
                    {
125
                        Rot = 0;
126
                        Gruen = 255;
127
                        Blau = (n - 512);
128
                    }
129
130
                    if (n >= 768 && n < 1024)
131
                    {
132
                        Rot = 0;
133
                        Gruen = 255 - (n - 768);
134
                        Blau = 255;
135
                    }
136
137
                    if (n >= 1024 && n < 1280)
138
                    {
139
                        Rot = (n - 1024);
140
                        Gruen = 0;
141
                        Blau = 255;
142
                    }
143
144
                    if (n >= 1280 && n < 1536)
145
                    {
146
                        Rot = 255;
147
                        Gruen = 0;
148
                        Blau = 255 - (n - 1280);
149
                    }
150
151
152
                    /*HDC hdc = GetDC(0);
153
                    SetPixel(hdc, xPos, yPos, RGB(Rot, Gruen, Blau));*/
154
                    Bild[xPos][yPos] = (Rot << 16) | (Gruen << 8) | (Blau << 0);
155
156
                    yPosMerker--;
157
                }
158
159
                BetragZ = 0;
160
                n = 0;
161
            }
162
163
            xPos++;
164
            CRea += DeltaCRea;
165
            ZRea = 0;
166
            ZIma = 0;
167
        }
168
169
        yPos++;
170
        xPos = 0;
171
        CIma += DeltaCIma;
172
        CRea = CReaHalter;
173
    }
174
175
    yPos = 0;
176
    CIma = CImaHalter;
177
}
178
179
void BMP_Ausgeben()
180
{
181
    void *fwritePt;
182
    uint16_t xPos = 0;
183
    uint16_t yPos = 0;
184
185
    uint32_t Farbe = 0;
186
187
    struct BMPFileHeaderStruct BMPFileHeader;
188
    struct BMPInfoHeaderStruct BMPInfoHeader;
189
190
    FILE *MandelbrotBild1;
191
192
193
    BMPFileHeader.bfType = 19778; //ASCII Zeichenkette "BM"
194
    BMPFileHeader.bfSize = xMax*yMax*32; //Größe einer 1366*768*32bit BMP-Datei
195
    BMPFileHeader.bfReserved = 0;
196
    BMPFileHeader.bfOffBits = 54;
197
198
    BMPInfoHeader.biSize = 40;
199
    BMPInfoHeader.biWidth = xMax;
200
    BMPInfoHeader.biHeight = yMax;
201
    BMPInfoHeader.biPlanes = 1;
202
    BMPInfoHeader.biBitCount = 32;
203
    BMPInfoHeader.biCompression = 0;
204
    BMPInfoHeader.biSizeImage = xMax*yMax;
205
    BMPInfoHeader.biXPelsPerMeter = 0;
206
    BMPInfoHeader.biYPelsPerMeter = 0;
207
    BMPInfoHeader.biClrUsed = 0;
208
    BMPInfoHeader.biClrImportant = 0;
209
210
211
    MandelbrotBild1 = fopen("..\\Fraktal\\MandelbrotBild1.bmp","wb");
212
213
    fwrite(&BMPFileHeader, sizeof(BMPFileHeader), 1,MandelbrotBild1);
214
215
    /*fwrite(&BMPFileHeader.bfType, sizeof(BMPFileHeader.bfType), 1,MandelbrotBild1);
216
    fwrite(&BMPFileHeader.bfSize, sizeof(BMPFileHeader.bfSize), 1,MandelbrotBild1);
217
    fwrite(&BMPFileHeader.bfReserved, sizeof(BMPFileHeader.bfReserved), 1,MandelbrotBild1);
218
    fwrite(&BMPFileHeader.bfOffBits,sizeof(BMPFileHeader.bfOffBits), 1,MandelbrotBild1);*/
219
220
    fwrite(&BMPInfoHeader.biSize,sizeof(BMPInfoHeader.biSize), 1, MandelbrotBild1);
221
    fwrite(&BMPInfoHeader.biWidth, sizeof(BMPInfoHeader.biWidth), 1, MandelbrotBild1);
222
    fwrite(&BMPInfoHeader.biHeight, sizeof(BMPInfoHeader.biHeight), 1, MandelbrotBild1);
223
    fwrite(&BMPInfoHeader.biPlanes, sizeof(BMPInfoHeader.biPlanes), 1, MandelbrotBild1);
224
    fwrite(&BMPInfoHeader.biBitCount, sizeof(BMPInfoHeader.biBitCount), 1, MandelbrotBild1);
225
    fwrite(&BMPInfoHeader.biCompression, sizeof(BMPInfoHeader.biCompression), 1, MandelbrotBild1);
226
    fwrite(&BMPInfoHeader.biSizeImage, sizeof(BMPInfoHeader.biSizeImage), 1, MandelbrotBild1);
227
    fwrite(&BMPInfoHeader.biXPelsPerMeter, sizeof(BMPInfoHeader.biXPelsPerMeter), 1, MandelbrotBild1);
228
    fwrite(&BMPInfoHeader.biYPelsPerMeter,sizeof(BMPInfoHeader.biYPelsPerMeter), 1, MandelbrotBild1);
229
    fwrite(&BMPInfoHeader.biClrUsed, sizeof(BMPInfoHeader.biClrUsed), 1, MandelbrotBild1);
230
    fwrite(&BMPInfoHeader.biClrImportant, sizeof(BMPInfoHeader.biClrImportant), 1, MandelbrotBild1);
231
232
    while (yPos < yMax)
233
    {
234
        while (xPos < xMax)
235
        {
236
                fwrite(&Bild[xPos][yPos], sizeof(Bild[xPos][yPos]), 1, MandelbrotBild1);
237
                xPos++;
238
        }
239
        xPos = 0;
240
        yPos++;
241
    }
242
    fclose(MandelbrotBild1);
243
}

von Karl H. (kbuchegg)


Lesenswert?

j. t. schrieb:
> wenn ich statt BMPFileHeader.bfType = 19778; //ASCII Zeichenkette "BM"
>
> BMPFileHeader.bfType = 'BM' schreibe, dann ist das Format nicht lesbar
> beim öffnen.

Mea Culpa.
Bytereihenfolge
  BMPFileHeader.bfType = 'MB'


> Genauso wenn ich
>
> fwrite(&BMPFileHeader, sizeof(BMPFileHeader), 1,MandelbrotBild1);
>
> statt


Und genau jetzt schlägt dann die Stunde eines Hex-Editors, mit dem man 
auf Byte-Ebene in das File reinschaut und nachsieht, welche Bytes 
verkehrt rum sind, bzw. wo ein Byte zu viel oder zu wenig ist.

Denn was hier, bei diesem Beispiel mit den läppischen 2 Strukturen noch 
überschaubar ist, artet bei größeren und komplexeren Datenstrukturen 
dann nämlich zu einem Albtraum aus. Allerdings ist das Beispiel auch gut 
geeignet, weil man hier tatsächlich dann auch mal 'unter die Tuchent' 
blicken muss, wie der Compiler die Dinge im Speicher anordnet. Das fällt 
also in die Kategorie: lerne dein spezifisches Werkzeug kennen.

: Bearbeitet durch User
von Thomas (Gast)


Lesenswert?

Die 32bit lösen nebenbei das Problem, dass die Bytes in jeder Zeile 
durch 4 teilbar sein müssen (ich habe vorhin fälschlicherweise von 
Pixeln gesprochen).


>Genauso wenn ich
>fwrite(&BMPFileHeader, sizeof(BMPFileHeader), 1,MandelbrotBild1);
>statt
> fwrite(&BMPFileHeader.bfType, sizeof(BMPFileHeader.bfType), ...
> schreibe....

Das "packed" wurde nun schon mehrfach erwähnt. Mehr können wir nicht 
tun...

von J. T. (chaoskind)


Lesenswert?

1
typedef struct __attribute__ ((__packed__)) BMPFileHeaderStruct
2
{
3
    uint16_t bfType;//
4
    uint32_t bfSize;//
5
    uint32_t bfReserved;//
6
    uint32_t bfOffBits;// = 54; //Offsetbytes
7
};
8
9
    struct BMPFileHeaderStruct BMPFileHeader;
10
11
12
    fwrite(&BMPFileHeader, sizeof(BMPFileHeader), 1,MandelbrotBild1);
13
14
    /*fwrite(&BMPFileHeader.bfType, sizeof(BMPFileHeader.bfType), 1,MandelbrotBild1);
15
    fwrite(&BMPFileHeader.bfSize, sizeof(BMPFileHeader.bfSize), 1,MandelbrotBild1);
16
    fwrite(&BMPFileHeader.bfReserved, sizeof(BMPFileHeader.bfReserved), 1,MandelbrotBild1);
17
    fwrite(&BMPFileHeader.bfOffBits,sizeof(BMPFileHeader.bfOffBits), 1,MandelbrotBild1);*/

wenn ich dann beim Erstellen von BMPFileHeader nochmal das _attribute_ 
((_packed_)) mitgebe, dann wird das ignoriert.

dennoch funktioniert es nicht??

von J. T. (chaoskind)


Lesenswert?

mhh man sollte auch mal fertig lesen...

You may only specify this attribute on the definition of an enum, struct 
or union, not on a typedef that does not also define the enumerated 
type, structure or union.

Heißt das, ich soll das typedef weglassen? Oder soll ich gleich bei der 
Deklaration mein BMPFileHeader mitdefinieren?

von J. T. (chaoskind)


Lesenswert?

Auch wenn ich das typedef weglasse geht es nicht....

Der Unterschied im HexEditor zwischen dem lesbaren Bild und dem 
nichtlesbaren sind lediglich 4 Nullen. Das funktionierende geht mit:
424D000210000000 los, und das nicht funktionierende mit:
424D000000021000. Also schiebt er wohl irgendwie ein uint32 der 0 ist 
ein wenn ich die Version wähle, das er das struct in einem Aufwasch 
schreibt.

von Thomas (Gast)


Lesenswert?

Fertig lesen ist immer gut ;).


Entweder das struct incl. packed weg-typedefen
1
typedef struct __attribute__ ((__packed__)) 
2
{
3
   //..
4
} BMPFileHeaderStruct;
5
//...
6
BMPFileHeaderStruct BMPFileHeader;
oder ohne typedef und immer "struct" hinschreiben:
1
struct __attribute__ ((__packed__)) BMPFileHeaderStruct
2
{
3
   //...
4
}
5
//...
6
struct BMPFileHeaderStruct BMPFileHeader;

Die alten C-Experten bestehen mit religiösem Eifer auf Variante 2. Ich 
bin schreibfaul und werde sowieso nie am Linux-Kernel oder anderen 
großen C-Projekten (igitt) mitwirken und mag Variante 1.

von J. T. (chaoskind)


Lesenswert?

Also wenn mich nicht alles täuscht, müsste ich hier nun Variante 1 
umgesetzt haben.... aber es geht nicht. Lass ich das ganze struct 
schreiben, ist die Datei nicht lesbar, lass ich alle einzeln schreiben, 
geht es.

Hier nochmal der ganze Code. Evtl kannst du den ja nochmal kompilieren 
und schauen was bei dir passiert. Oder mir sagen, ob ich irgendwo noch 
nen doofen Fehler versteckt hab.
1
#include <windows.h>
2
#include <stdio.h>
3
#include <stdlib.h>
4
#include <stdint-gcc.h>
5
6
7
#define xMax 546
8
#define yMax 307
9
//#define xMax 1366
10
//#define yMax 768
11
12
void Mandelbrot (float CReaMin, float CReaMax, float CImaMin, float CImaMax, uint32_t nMax, uint16_t Tiefe3D);
13
14
void BMP_Ausgeben (void);
15
16
uint32_t Bild[xMax][yMax];
17
18
typedef struct __attribute__ ((__packed__))
19
{
20
    uint16_t bfType;//
21
    uint32_t bfSize;//
22
    uint32_t bfReserved;//
23
    uint32_t bfOffBits;// = 54; //Offsetbytes
24
}BMPFileHeaderStruct;
25
26
typedef struct __attribute__ ((__packed__))
27
{
28
    uint32_t biSize;
29
    int32_t biWidth;
30
    int32_t biHeight;
31
    uint16_t biPlanes;
32
    uint16_t biBitCount;
33
    uint32_t biCompression;
34
    uint32_t biSizeImage;
35
    int32_t biXPelsPerMeter;
36
    int32_t biYPelsPerMeter;
37
    uint32_t biClrUsed;
38
    uint32_t biClrImportant;
39
}BMPInfoHeaderStruct;
40
41
int main()
42
{
43
    system("PAUSE");
44
    Mandelbrot (0.5, 0.6875, -0.5, -0.375, 1536, 40);
45
    BMP_Ausgeben();
46
47
48
    return 0;
49
}
50
51
52
void Mandelbrot (float CReaMin, float CReaMax, float CImaMin, float CImaMax, uint32_t nMax, uint16_t Tiefe3D)
53
{
54
    uint16_t xPos = 0;
55
    uint16_t yPos = 0;
56
    uint16_t yPosMerker = 0;
57
58
    uint32_t n = 0;
59
60
    uint8_t Rot = 0;
61
    uint8_t Gruen = 0;
62
    uint8_t Blau = 0;
63
64
    float DeltaCRea = (CReaMax - CReaMin) / xMax;
65
    float DeltaCIma = (CImaMax - CImaMin) / yMax;
66
67
    float CRea = CReaMin;
68
    float CIma = CImaMin;
69
    float ZRea = 0;
70
    float ZIma = 0;
71
72
    float BetragZ = 0;
73
74
    float CReaHalter = CRea;
75
    float CImaHalter = CIma;
76
    float ZReaHalter = 0;
77
    float ZImaHalter = 0;
78
79
80
    while (yPos < yMax)
81
    {
82
        while (xPos < xMax)
83
        {
84
            while (BetragZ < 4 && n < nMax)
85
            {
86
                ZReaHalter = ZRea;
87
                ZImaHalter = ZIma;
88
89
                ZRea = (ZReaHalter * ZReaHalter) - (ZImaHalter * ZImaHalter) - CRea;
90
                ZIma = (ZReaHalter * ZImaHalter) + (ZReaHalter * ZImaHalter) - CIma;
91
92
                BetragZ = (ZRea*ZRea) + (ZIma*ZIma);
93
94
                n++;
95
            }
96
97
            if (n == nMax)
98
            {
99
                BetragZ = 0;
100
                n = 0;
101
            }
102
103
            if (BetragZ >= 4)
104
            {
105
                yPosMerker = yPos + Tiefe3D;
106
                if (yPosMerker > yMax) yPosMerker = yMax;
107
108
                while (yPosMerker > yPos)
109
                {
110
                    if (n >= 0 && n < 256)
111
                    {
112
                        Rot = 255;
113
                        Gruen = n;
114
                        Blau = 0;
115
                    }
116
117
                    if (n >= 256 && n < 512)
118
                    {
119
                        Rot = 255 - (n - 256);
120
                        Gruen = 255;
121
                        Blau = 0;
122
                    }
123
124
                    if (n >= 512 && n < 768)
125
                    {
126
                        Rot = 0;
127
                        Gruen = 255;
128
                        Blau = (n - 512);
129
                    }
130
131
                    if (n >= 768 && n < 1024)
132
                    {
133
                        Rot = 0;
134
                        Gruen = 255 - (n - 768);
135
                        Blau = 255;
136
                    }
137
138
                    if (n >= 1024 && n < 1280)
139
                    {
140
                        Rot = (n - 1024);
141
                        Gruen = 0;
142
                        Blau = 255;
143
                    }
144
145
                    if (n >= 1280 && n < 1536)
146
                    {
147
                        Rot = 255;
148
                        Gruen = 0;
149
                        Blau = 255 - (n - 1280);
150
                    }
151
152
153
                    /*HDC hdc = GetDC(0);
154
                    SetPixel(hdc, xPos, yPos, RGB(Rot, Gruen, Blau));*/
155
                    Bild[xPos][yPosMerker] = (Rot << 16) | (Gruen << 8) | (Blau << 0);
156
157
                    yPosMerker--;
158
                }
159
160
                BetragZ = 0;
161
                n = 0;
162
            }
163
164
            xPos++;
165
            CRea += DeltaCRea;
166
            ZRea = 0;
167
            ZIma = 0;
168
        }
169
170
        yPos++;
171
        xPos = 0;
172
        CIma += DeltaCIma;
173
        CRea = CReaHalter;
174
    }
175
176
    yPos = 0;
177
    CIma = CImaHalter;
178
}
179
180
void BMP_Ausgeben()
181
{
182
183
    uint16_t xPos = 0;
184
    uint16_t yPos = 0;
185
186
187
188
    BMPFileHeaderStruct BMPFileHeader;
189
    BMPInfoHeaderStruct BMPInfoHeader;
190
191
    FILE *MandelbrotBild1;
192
193
194
    BMPFileHeader.bfType = 'MB'; //ASCII Zeichenkette "BM"
195
    BMPFileHeader.bfSize = xMax*yMax; //Größe einer 1366*768*32bit BMP-Datei
196
    BMPFileHeader.bfReserved = 0;
197
    BMPFileHeader.bfOffBits = 54;
198
199
    BMPInfoHeader.biSize = 40;
200
    BMPInfoHeader.biWidth = xMax;
201
    BMPInfoHeader.biHeight = yMax;
202
    BMPInfoHeader.biPlanes = 1;
203
    BMPInfoHeader.biBitCount = 32;
204
    BMPInfoHeader.biCompression = 0;
205
    BMPInfoHeader.biSizeImage = xMax*yMax;
206
    BMPInfoHeader.biXPelsPerMeter = 0;
207
    BMPInfoHeader.biYPelsPerMeter = 0;
208
    BMPInfoHeader.biClrUsed = 0;
209
    BMPInfoHeader.biClrImportant = 0;
210
211
212
    MandelbrotBild1 = fopen("..\\Fraktal\\MandelbrotBild1.bmp","wb");
213
214
    //fwrite(&BMPFileHeader, sizeof(BMPFileHeader), 1,MandelbrotBild1);
215
216
    fwrite(&BMPFileHeader.bfType, sizeof(BMPFileHeader.bfType), 1,MandelbrotBild1);
217
    fwrite(&BMPFileHeader.bfSize, sizeof(BMPFileHeader.bfSize), 1,MandelbrotBild1);
218
    fwrite(&BMPFileHeader.bfReserved, sizeof(BMPFileHeader.bfReserved), 1,MandelbrotBild1);
219
    fwrite(&BMPFileHeader.bfOffBits,sizeof(BMPFileHeader.bfOffBits), 1,MandelbrotBild1);
220
221
    //fwrite(&BMPInfoHeader,sizeof(BMPInfoHeader), 1, MandelbrotBild1);
222
223
    fwrite(&BMPInfoHeader.biSize,sizeof(BMPInfoHeader.biSize), 1, MandelbrotBild1);
224
    fwrite(&BMPInfoHeader.biWidth, sizeof(BMPInfoHeader.biWidth), 1, MandelbrotBild1);
225
    fwrite(&BMPInfoHeader.biHeight, sizeof(BMPInfoHeader.biHeight), 1, MandelbrotBild1);
226
    fwrite(&BMPInfoHeader.biPlanes, sizeof(BMPInfoHeader.biPlanes), 1, MandelbrotBild1);
227
    fwrite(&BMPInfoHeader.biBitCount, sizeof(BMPInfoHeader.biBitCount), 1, MandelbrotBild1);
228
    fwrite(&BMPInfoHeader.biCompression, sizeof(BMPInfoHeader.biCompression), 1, MandelbrotBild1);
229
    fwrite(&BMPInfoHeader.biSizeImage, sizeof(BMPInfoHeader.biSizeImage), 1, MandelbrotBild1);
230
    fwrite(&BMPInfoHeader.biXPelsPerMeter, sizeof(BMPInfoHeader.biXPelsPerMeter), 1, MandelbrotBild1);
231
    fwrite(&BMPInfoHeader.biYPelsPerMeter,sizeof(BMPInfoHeader.biYPelsPerMeter), 1, MandelbrotBild1);
232
    fwrite(&BMPInfoHeader.biClrUsed, sizeof(BMPInfoHeader.biClrUsed), 1, MandelbrotBild1);
233
    fwrite(&BMPInfoHeader.biClrImportant, sizeof(BMPInfoHeader.biClrImportant), 1, MandelbrotBild1);
234
235
    while (yPos < yMax)
236
    {
237
        while (xPos < xMax)
238
        {
239
                fwrite(&Bild[xPos][yPos], sizeof(Bild[xPos][yPos]), 1, MandelbrotBild1);
240
                xPos++;
241
        }
242
        xPos = 0;
243
        yPos++;
244
    }
245
    fclose(MandelbrotBild1);
246
}

von Thomas (Gast)


Angehängte Dateien:

Lesenswert?

Die anderen Mandelbrot-Parameter haben mich zuerst etwas verwirrt ;)

bfSize und biSizeImage sehen noch falsch aus (darin stehen Bytes, nicht 
Pixel), sind hier aber wohl nicht das Problem.

Der Anhang (dein Code bei mir lauffähig gemacht) liefert mit und ohne 
das USE_PACKED eine byteweise identische BMP-Datei, so wie es zu 
erwarten sein sollte.

Jetzt müssen wir wohl auf die Experten warten. Welchen GCC und welches 
OS benutzt Du?

von J. T. (chaoskind)


Lesenswert?

Ich benutze win8.1 und den mingw32-gcc-4.7.1.

An bfSize und biSizeImage gehört jeweils noch ein mal4, dann stimmen die 
auch. Aber ansonsten macht er jetzt ja richtige Bilder, wenn man halt 
von den vier Nullen im Hexfile absieht, wenn ich die verschieden Wege 
nehme, den Header zu schreiben.

Ich werd mich nun aber erstmal hinlegen, ich wünsch ne gute Nacht =)

MfG Chaos

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

j. t. schrieb:
> Zu der Geschichte mit dem Abarbeiten der Warnungen: Was möchte mir diese
> Warnung eigentlich sagen?:
> warning: useless storage class specifier in empty declaration [enabled
> by default]|

Dazu wäre die Zeile interessant, auf die sich diese Warnung bezieht.

von J. T. (chaoskind)


Lesenswert?

Das taucht beim deklarieren der structs auf. Bei:
typedef struct bla
{

};

mit typedef struct
{

}bla;

tauchts nicht auf, und inzwischen hab ich auch verstanden wieso, aber 
was die Fehlermeldung nun exakt bedeutet ist mir dennoch nicht 100%ig 
klar.

Das was am Ende rauskommt, ist vom Ergebnis her zumindest das selbe, 
wenn man von der Fehlermeldung absieht

von Eric B. (beric)


Lesenswert?

j. t. schrieb:

> typedef struct bla
> {
>
> };

Tja, was nutzt ein typedef, wenn da keine Name vergeben wird:

Der syntx ist (vereinfacht):
1
typedef <type> <name>;

Dein <type> ist hier 'struct bla { ... }', und die <name> ist leer.
Deswegen meckert der Compiler, dass das alles nix nutzt.

> typedef struct
> {
>
> }bla;

Hier ist <type> 'struct { ... }' und die <name> ist 'bla'.
Das ist also eine gültige und sinnvolle typedef.

> Das was am Ende rauskommt, ist vom Ergebnis her zumindest das selbe,
> wenn man von der Fehlermeldung absieht

Nein. Im ersten fall hast du ein struct definiert, aber kein typedef 
name dazu. Deswegen meckert der Compiler auch.

: Bearbeitet durch User
von J. T. (chaoskind)



Lesenswert?

Nochmal zurück zum Schreiben des Headers. Ich hab immer noch das 
Problem, das ich die Elemente des/der Headers einzeln in die Datei 
schreiben muss.

Thomas hat eine Lösung mit defines und ifdefs vorgeschlagen, um zwischen 
beiden Varianten umzuschalten, wenn ich seine Version in der das 
Headerstruct als ganzes in die Datei geschrieben wird kompiliere, lässt 
sich die Datei nicht öffnen, das Hex geht folgendermaßen los:

1)  424D0000B6A10000000000003600000028000000880000004C00000001002000
2)  424D05BFB6A10000000000003600000028000000880000004C00000001002000
3)  424DB6A10000000000003600000028000000880000004C000000010020000000

wobei

1) Thomas Version, per defines in den "Struct in einem Aufwasch"-Modus 
gesetzt. Wie man sieht kommen nach 2 richtigen Byte 2 falsche 0Byte, 
danach gehts richtig weiter.

2) Meine Version, per auskommentieren in den "Struct in einem 
Aufwasch"-Modus gesetzt. Hier werden fälschlich ein Byte 05 und ein Byte 
BF an der selben Stelle wie bei 1) eingesetzt. Wo kommen die her?

3) Meine Version, per auskommentieren in den "Alle Structelemente 
einzeln ins BMP schreiben"-Modus gesetzt. Hierbei entsteht ein 
Bitmapfile, das sich öffnen und betrachten lässt. Einziger Unterschied 
sind die beiden erwähnten Bytes. Eine Zeit lang hatte ich auch in meiner 
"Struct aufeinmal Version" die Nullbytes statt der 05BF aber ich weiß 
nicht mehr, was ich da anders gemacht hatte. Wenn ich in den beiden 
fehlerhaften Versionen jeweils die falschen Bytes rauschlösche, bekomme 
wie zu erwarten das selbe Bild wie bei der richtigen Version.

Der Unterschied ziwschen den Versionen liegt eigentlich nur darin was 
fwrite() übergeben wird.

einmal per:
1
fwrite(&BMPFileHeader, sizeof(BMPFileHeader), 1,MandelbrotBild1);
und einmal per:
1
fwrite(&BMPFileHeader.bfType, sizeof(BMPFileHeader.bfType), 1,MandelbrotBild1);
2
    fwrite(&BMPFileHeader.bfSize, sizeof(BMPFileHeader.bfSize), 1,MandelbrotBild1);
3
    fwrite(&BMPFileHeader.bfReserved, sizeof(BMPFileHeader.bfReserved), 1,MandelbrotBild1);
4
    fwrite(&BMPFileHeader.bfOffBits,sizeof(BMPFileHeader.bfOffBits), 1,MandelbrotBild1);

zusätzlich ist der Unterschied zwischen meinen und Thomas Version, das 
er die Auswahl ob einzeln oder in einem Aufwasch geschrieben wird, per 
ifdefs trifft.

P.S.

.bmp-Dateien lassen sich wohl nicht anhängen, daher nur ne png von der 
funktionierenden Version. Wie gesagt, der Unterschied sind ja lediglich 
2Byte

: Bearbeitet durch User
von Hans (Gast)


Lesenswert?

Sieht so aus, als ob das
1
__attribute__ ((__packed__))
 von Deinem Compiler hier nicht berücksichtigt wird.

Die unterschiedlichen Werte in Byte 2 und 3 kommen daher, dass die 
Strukturen auf dem Stack liegen und dementsprechend nicht initialisiert 
werden. In den Lücken stehen also "zufällige" Daten.

Probier mal, dem struct einen Namen zu geben:
1
typedef struct __attribute__ ((__packed__)) BMPFileHeaderStruct_s
2
{
3
    uint16_t bfType;//
4
    uint32_t bfSize;//
5
    uint32_t bfReserved;//
6
    uint32_t bfOffBits;// = 54; //Offsetbytes
7
}BMPFileHeaderStruct;

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Hans schrieb:
> Sieht so aus, als ob das _attribute_ ((_packed_)) von Deinem
> Compiler hier nicht berücksichtigt wird.

Welcher Compiler ist das denn?

Sollte es beispielsweise was von Microsoft sein, dann ist stattdessen
#pragma pack(1)
zu verwenden

von fbi (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Welcher Compiler ist das denn?
>
> Sollte es beispielsweise was von Microsoft sein, dann ist stattdessen
> #pragma pack(1)
> zu verwenden

besser wäre die Klammerung mit:
1
#pragma pack(push,1)
2
...
3
#pragma pack(pop)

weiter oben stand aber etwas von:
> win8.1 und den mingw32-gcc-4.7.1

von J. T. (chaoskind)


Lesenswert?

genau win 8.1 mingw32-gcc4.7.1., das ganze übrigens in Code::Blocks. Ich 
glaub das baut wiederum auf winzigweich visual studio auf?!?

Hans schrieb:
> Probier mal, dem struct einen Namen zu geben:typedef struct
> _attribute_ ((_packed_)) BMPFileHeaderStruct_s
> {
>     uint16_t bfType;//
>     uint32_t bfSize;//
>     uint32_t bfReserved;//
>     uint32_t bfOffBits;// = 54; //Offsetbytes
> }BMPFileHeaderStruct;

Das werd ich direkt mal testen.

Hans schrieb:
> Die unterschiedlichen Werte in Byte 2 und 3 kommen daher, dass die
> Strukturen auf dem Stack liegen und dementsprechend nicht initialisiert
> werden. In den Lücken stehen also "zufällige" Daten.

Aber ich fülle die Strukturen doch komplett aus, bevor ich sie in die 
Datei schreibe? Da dürfte doch nichts zufälliges stehen?

von J. T. (chaoskind)


Lesenswert?

Nebenbei eine Frage evtl etwas offtopic.

Ich zähle in einer Variablen n die Anzahl der Iterationen für jedes 
Pixel, und je nach Iterationszahl wird eine Farbe zwischen 0-1536 
zugewiesen.
Da der Anstieg der Iterationszahl aber recht exponentiell in einige 
Richtungen zu gehen scheint, ergibt sich immer das Bild, das entweder 
die Farben ewig lange rot bleiben, um dann am Rand aber halt erst recht 
dicht dran, recht detailiert zu werden.  Wenn ich nun einfach einen 
Multiplikator einfüge, habe ich schon von Anfang an eine (wenn auch 
recht sprunghafte) Farbändderungen, und zum Rand bleiben keine Farben 
mehr übrig.

Ich brauche nun also eine Funktion, die die Iterationszahl auf 1 
normiert a la nMax/n und auf meinen Farbraum abbildet. Also irgendwas in 
der Richtungen
nMax/n * 1536(Farbmax).

Dabei besteht aber immernoch das problem der Exponentialität. Also muss 
sich irgendwie noch was logarithmisches in meine Funktion einschleichen, 
damit ich sowohl weit weg von den Rändern, als auch dicht dran schöne 
Farbänderungen habe. Aber irgendwie steh ich da grad aufm Schlauch

von J. T. (chaoskind)


Lesenswert?

j. t. schrieb:
> Hans schrieb:
>> Probier mal, dem struct einen Namen zu geben:typedef struct
>> attribute ((packed)) BMPFileHeaderStruct_s
>> {
>>     uint16_t bfType;//
>>     uint32_t bfSize;//
>>     uint32_t bfReserved;//
>>     uint32_t bfOffBits;// = 54; //Offsetbytes
>> }BMPFileHeaderStruct;
>
> Das werd ich direkt mal testen.

Mh auch das klappt nicht....

von Hans (Gast)


Lesenswert?

Habs mal bei mir probiert. Sieht nach diesem Compilerbug aus:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52991

Du musst unter Project -> Build Options -> Compiler Settings -> Other 
Settings folgendes einfügen:
1
-mno-ms-bitfields

Dann kommt eine darstellbare bmp-Datei raus ...

von J. T. (chaoskind)


Lesenswert?

Hans schrieb:
> Du musst unter Project -> Build Options -> Compiler Settings -> Other
> Settings folgendes einfügen:-mno-ms-bitfields

Das hat das Problem gelöst! Danke dafür =)

Für die andere Frage lieber n neuen Thread öffnen?(von 20:14)

von J. T. (chaoskind)


Angehängte Dateien:

Lesenswert?

Ich hab mir was überlegt da klappt =)
1
Farbe = (  1 - ( 1 / ( (nMax*nMax )/(float)( (nMax-n)*(nMax-n) ) )  )   ) * 1536;

: Bearbeitet durch User
von J. T. (chaoskind)



Lesenswert?

sehr hübsch ist auch:
1
Farbe = (  1 - ( 1 / ( ( nMax*nMax*nMax )/(float)( (nMax-n)*(nMax-n)*(nMax-n) ) )  )   ) * 1536;

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

j. t. schrieb:
> MoinMoin,
> ich versuche gerade Daten aus einem Array in eine Bitmap zu schreiben.
> Dazu hab ich mir rausgesucht, wie so eine Bitmap aufgebaut ist, habe

Man muß sich das Leben ja net unnötig schwer machen Wie wär's mit einem 
simpleren Format wie z.B. PPM?  Das Format ist Text und ohne jedes 
Tralala, siehe

http://de.wikipedia.org/wiki/Portable_Anymap#Pixmap

Das wird dann bequem in (fast) jedes x-beliebige Rasterformat gewandelt, 
das man idR nicht händisch beackern will: PNG, GIF, JPG, PDF, TIFF, BMP, 
...

Als Tool dazu verwende ich gerne convert von ImageMagick

http://imagemagick.com/script/convert.php

als Programm, als C-Bibliothek, als C++-Bibliothek, als PHP, als Tcl, 
weiß der Teufel... damit lassen sich Einzelbilder auch schmerzfrei zu 
Animationan zusammenbasteln, hier z.B. für Julia-Mangen für z²+c, deren 
Parameter c sich auf einem Halbkreis durch die Mandelbrotmenge bewegt:

http://commons.wikimedia.org/wiki/File:Julia-Set_z2%2Bc_ani.gif


> #include <stdint-gcc.h>

Wo hast du den Header denn ausgebuddelt?! Der wird von GCC intern 
verwendet; in dein Programm gehört #include <stdint.h>

: Bearbeitet durch User
von J. T. (chaoskind)


Lesenswert?

Danke für die Links, die werd ich mir mal anschauen.

Johann L. schrieb:
> Wo hast du den Header denn ausgebuddelt?! Der wird von GCC intern
> verwendet; in dein Programm gehört #include <stdint.h>

Den hab ich irgendwo in den Optionen von Codeblocks entdeckt....

Ich hatte mich gewundert, das er die ganzen uintX_t nicht kennt und 
wusste spontan nicht mehr, wo die drin stehen *gg

Johann L. schrieb:
> als Programm, als C-Bibliothek, als C++-Bibliothek, als PHP, als Tcl,
> weiß der Teufel... damit lassen sich Einzelbilder auch schmerzfrei zu
> Animationan zusammenbasteln, hier z.B. für Julia-Mangen für z²+c, deren
> Parameter c sich auf einem Halbkreis durch die Mandelbrotmenge bewegt:

das wäre der nächste angedachte Schritt gewesen =)

: Bearbeitet durch User
von J. T. (chaoskind)


Angehängte Dateien:

Lesenswert?

Ein weiterer mysteriöser "Fehler" taucht auf. Ich hab inzwischen ein 
wenig weiterprogrammiert, und lasse nun mehrere Bilder in einem 
Durchlauf berechnen.

Dazu lasse ich mit einer while-Schleife die Bilderzeugung x mal 
durclaufen. Das klappt soweit auch wunderbar.
Nach dem Motto:

while (n < 10)
{
    MachNBild();
    n++;
}

Es werden mir 10 bmps erzeugt. Und jedes einzelne davon ist direkt 
nachdem es errechnet wurde verfügbar(Ich stelle gerade fest, das sie 
sich doch erst öffnen lassen, nachdem das Programm zu Ende gelaufen ist, 
das ist doch schonmal ein Hinweis).

Wenn ich nun aber:

while (1)
{
    MachNBild();
}

erstellt mir zwar jede Menge Dateien, bis ich das Programm abbreche, 
jedoch sind das keine bmps mehr, sondern endungslose Dateien. Diese 
lassen sich natürlich auch nicht öffnen.

Wodran könnte das liegen?

das öffnen der Datei, das Schreiben und das Schließen laufen alle in 
Unterfunktionen ab, sollten doch eigentlich garnicht davon beeinflusst 
sein, ob sie nun mit einer unendlichen whileschleife aufgerufen werden, 
oder ob sie nur eine bestimmte Anzahl oft aufgerufen werden?

Im Anhang nochmal der aktuelle Code.

MfG Chaos

von J. T. (chaoskind)


Lesenswert?

P.S.
Falls in dem Code noch #include <stdint-gcc.h> stehen sollte, das ist 
inzwischen auf #include <stdint.h> geändert. Seit dem sind es immerhin 
keine Endungslosen Dateien, lassen sich aber dennoch nicht öffnen.

von J. T. (chaoskind)


Lesenswert?

noch etwas, wenn ich mehr als 36 Bilder "auf einmal" berechnen lassen 
will, stürzt das Programm nach dem 36ten Bild ab. Dies geschieht 
unabhängig von der gewählten Auflösung, also denke ich nicht, das ihm 
der Speicher ausgeht.

Die dann erzeugten Bilddateien sind ebenfalls nicht zu öffnen...

direkt nochmal den Hexeditor benutzen.

P.S.
Laut hexeditor ist kein Unterschied zwischen den Beiden. Und das obwohl 
die nicht zu öffnende ein bischen kleiner ist. Aber das liegt wohl 
daran, dass das Programm mitten drin abstürzt, und bis zum Ende des 
kürzeren keine Unterschiede vorliegen?

: Bearbeitet durch User
von Markus F. (mfro)


Lesenswert?

Guck' mal deinen fclose()-Aufruf an. Der ist verkehrt. Wahrscheinlich 
stürzt dein Programm deswegen ab (weil ihm die Filehandles ausgehen). 
Deswegen auch immer den Return-Wert von fopen() abprüfen!

Eigentlich sollte dein Compiler dafür mindestens eine Warnung 
ausspucken (die Du natürlich ernst nehmen und abstellen solltest).

Tut er das nicht, solltest Du dringend rausfinden, wie Du ihn dazu 
bringst. Compiler sind nämlich - per Definition - immer schlauer als der 
Programmierer ;).

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

j. t. schrieb:
> noch etwas, wenn ich mehr als 36 Bilder "auf einmal" berechnen lassen

Was soll das heißen, "auf einmal"?

> will, stürzt das Programm nach dem 36ten Bild ab.

Überprüf mal ob von  fwrite so viele Einheiten geschrieben wurden (der 
return-Wert) wie erwartet.

Außerdem schreibst du fleißig in das von fopen gelieferte FILE* auch 
wenn dieser NULL ist!  Und wieviele Dateien darfst du maximal 
gleichzeitig offen haben?

Noch ein paar Anmerkungen zum Programm selbst:

C99 unterstützt von Hause aus komplexe Zahlen.  Du brauchst also nicht 
händisch mit Real- und Imaginärteil rumfrickeln sondern einfach
1
#include <complex.h>
2
3
typedef double complex cplx;
4
5
int main()
6
{
7
    cplx x = 3 - 2i;
8
    cplx y = 2 + I*x;
9
    printf ("y = (%f,%f)\n", creal(y), cimag(y));
10
    printf ("|y| = %f, sin(y) = (%f,%f)\n", cabs (y), csin(y));
11
    printf ("i = (%f,%f)\n", csqrt (-1));
12
    return 0;
13
}
>>>
1
y = (4.000000,3.000000)
2
|y| = 5.000000, sin(y) = (-7.619232,-6.548120)
3
i = (0.000000,1.000000)


Eine BMP Datei beginnt nicht mit einem 16-Bit Wert wie uint16 sondern 
mit einem Array char bm[2] mit bm[0] = 'B' und bm[1] = 'M'!  Ansonsten 
bekommst du Probleme mit Endianess.  Allerdings gelten die 
Endianess-Probleme auch für alle anderen Felder, d.h. du bist offenbar 
aif eine Endian=Little Maschine, ansonsten käm für die BMPs nur Müll 
raus.

Anstatt der umständlichen
1
x = 0; while (x < baba) { lala; x++;}
ist besser lesbar
1
for (x = 0; x < baba; x++) { lala; }
2
// oder
3
for (int x = 0; x < baba; x++) { lala; }

Das Äußere von M bekommst du ansprechender wenn du nicht |z| > 2 
testest sondern z.B. |z| > 100.

|z| > 2 ist zwar eine hinreuchendende Bedingung dafür, dass der Startpunkt der 
Iteration nicht in M liegt, aber je größer der Schwellwert, desto mehr gleichen 
sich die Zwiebelschalen außerhalb von M den Äquipotentiallinien einer elektrisch 
geladenen Mandelbrotmenge an

Hier ein Bild wo ganz offenbar |z| > 2 verwendet wurde:

http://commons.wikimedia.org/wiki/File:Mandelbrot_High_Resolution.png

und hier eins mit |z| > k >> 2:

http://commons.wikimedia.org/wiki/File:Mandelbrot_set_with_coloured_environment.png

Der Mehraufwand an Rechenzeit ist unerheblich:  Wenn |z| > 2 dann ist es 
bereits nach 3 weiteren Iterationen > 256.

von J. T. (chaoskind)



Lesenswert?

Johann L. schrieb:
> Was soll das heißen, "auf einmal"?

Das soll heißen, das mit einmal kompilieren, einfach mehrmals 
nacheinander mit neuem Zoomfaktor die Berechnung des Mandelbrots 
vorgenommen wird. Ursprünglich hab ich für jedes einzelne Bild im 
Quelltext den Wert angepasst, und für jedes Bild dann neu kompiliert. 
Nun werden die Werte halt in einer Schleife mehrmals berechnet. Also auf 
einmal im Sinne von "mit einem Start der exe" nicht, das die 
gleichzeitig und parallel berechnet werden.

Johann L. schrieb:
> Überprüf mal ob von  fwrite so viele Einheiten geschrieben wurden (der
> return-Wert) wie erwartet.

Ich hab doch immer nur eine Einheit von fwrite offen?

Ich rufen ein einer Schleife auf

for (n = 0; n < 10; n++)
{
    Bildmachen();
]

Bildmachen()
{
fopen(bla)
...
fclose(bla)
}

Johann L. schrieb:
> Außerdem schreibst du fleißig in das von fopen gelieferte FILE* auch
> wenn dieser NULL ist!  Und wieviele Dateien darfst du maximal
> gleichzeitig offen haben?

Das heißt?

Johann L. schrieb:
> C99 unterstützt von Hause aus komplexe Zahlen.  Du brauchst also nicht
> händisch mit Real- und Imaginärteil rumfrickeln sondern einfach

Das werd ich mir mal anschauen, danke dafür

Johann L. schrieb:
> Das Äußere von M bekommst du ansprechender wenn du nicht |z| > 2
> testest sondern z.B. |z| > 100.
>
> |z| > 2 ist zwar eine hinreuchendende Bedingung dafür, dass der Startpunkt der
> Iteration nicht in M liegt, aber je größer der Schwellwert, desto mehr
> gleichen
> sich die Zwiebelschalen außerhalb von M den Äquipotentiallinien einer
> elektrisch
> geladenen Mandelbrotmenge an

Der Unterschied bei den Abbruchbedingungen macht den Kohl hier nicht 
sehr fett. Da wie du ganz richtig sagst, falls |z| > 2  schon nach nur 3 
Schritten > 256 ist, bekomme ich ja grundsätzlich bei einem höheren Wert 
(bspw 256) ja lediglich nur 3 Iterationsschritte mehr. Viel wichtiger 
für die Darstellung ist, sauber mitzuzählen, wieviele Iterationen bis 
zum erreichen der Abbruchbedingung notwendig waren, und danach die Farbe 
zuzuordnen. (Irgendein mathematischer Satz besagt, wenn solch eine 
Iterationsfolge 2 überschreitet, konvergiert sie ziemlich sicher und 
ziemlich schnell gegen unendlich) Anbei mal 2 Bilder des gleichen 
Ausschnittes, einmal mit Abbruchbedingung |z| >= 2 und einmal mit 256.

Weiter oben sind auch noch 2 Beispiele, die zeigen welch starke 
Veränderung sich ergibt, wenn man an der Farbzuordnung rumspielt.

Markus F. schrieb:
> Eigentlich sollte dein Compiler dafür mindestens eine Warnung
> ausspucken (die Du natürlich ernst nehmen und abstellen solltest).

Spuckt er auch....:
warning: passing argument 1 of 'fclose' from incompatible pointer type 
[enabled by default]
Aber ich verstehe nicht so ganz, was da schief läuft.
Ich öffne mit
Mandelbrotbild = fopen(Dateiname, wb)
und schließe mit
fclose(Dateiname).

Als ich das ohne Pointer gelöst hatte, und den Namen direkt angegeben 
hatte, hat das auch ohne Warnung geklappt..



Danke euch erstmal für die Antworten,
MfG Chaos

von Markus F. (mfro)


Lesenswert?

j. t. schrieb:
> Markus F. schrieb:
>> Eigentlich sollte dein Compiler dafür mindestens eine Warnung
>> ausspucken (die Du natürlich ernst nehmen und abstellen solltest).
>
> Spuckt er auch....:
> warning: passing argument 1 of 'fclose' from incompatible pointer type
> [enabled by default]
> Aber ich verstehe nicht so ganz, was da schief läuft.
> Ich öffne mit
> Mandelbrotbild = fopen(Dateiname, wb)
> und schließe mit
> fclose(Dateiname).

... und das ist sehr verkehrt. Muß heißen:
1
Mandelbrotbild = fopen(Dateiname, wb);
2
if (Mandelbrotbild)
3
{
4
    ...
5
    fclose(Mandelbrotbild);  /* fclose() erwartet einen FILE pointer, keinen Dateinamen */
6
}
7
else
8
{
9
    /* Fehler */
10
}

: Bearbeitet durch User
von J. T. (chaoskind)


Lesenswert?

AAAchsoooo. Ich bin davon ausgegangen, das man natürlich exakt das 
schließen muss, was man vorher geöffnet hat.

Nun funktioniert es!!!!! =) Ich kann jetzt beliebig viele Bilder 
erzeugen. Selbst wenn ich es auf while (1) setze, erzeugt mir Bilder 
ohne Ende, und ich kann sie sogar öffnen, während er die nächsten 
berechnet. Ganz so wie ich es mir vorgestellt hab.

Ganz herzlichen Dank für deine Hilfe,

MfG Chaos

von Markus F. (mfro)


Lesenswert?

j. t. schrieb:
> Ich bin davon ausgegangen,


Hört sich vielleicht jetzt blöd an: das ist beim Programmieren so 
ungefähr die Totsünde #1!

Egal, ob man einfache Apfelmännchen oder ein komplexes ERP-System 
programmiert, Annahmen rächen sich immer. Im besten Fall sofort (so 
wie bei dir), im schlechten erst beim Nutzer und im schlechtesten nur 
sporadisch.

Man darf schlicht von nichts ausgehen, sondern muß wissen. Wenn man 
nicht weiß, muß man nachgucken.

Besser, man akzeptiert das so früh wie möglich.

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

j. t. schrieb:
> Johann L. schrieb:
>> Das Äußere von M bekommst du ansprechender wenn du nicht
>> |z| > 2 testest sondern z.B. |z| > 100.
>>
>> |z| > 2 ist zwar eine hinreichende Bedingung dafür, dass der
>> Startpunkt der Iteration nicht in M liegt, aber je größer
>> der Schwellwert, desto mehr gleichen sich die Zwiebelschalen
>> außerhalb von M den Äquipotentiallinien einer elektrisch
>> geladenen Mandelbrotmenge an.
>
> Der Unterschied bei den Abbruchbedingungen macht den Kohl hier nicht
> sehr fett. Da wie du ganz richtig sagst, falls |z| > 2  schon nach nur 3
> Schritten > 256 ist, bekomme ich ja grundsätzlich bei einem höheren Wert
> (bspw 256) ja lediglich nur 3 Iterationsschritte mehr.

Nicht ganz; denn die Iteration ist nicht z→z² sondern z→z²+c.

> Anbei mal 2 Bilder des gleichen Ausschnittes, einmal mit
> Abbruchbedingung |z| >= 2 und einmal mit 256.

Ok, bei der roten Farbsoße wird man natürlich niemals nicht irgendeinen 
Unterschied sehen...

von J. T. (chaoskind)


Angehängte Dateien:

Lesenswert?

Du verstehst scheinbar nicht, das es nicht darum geht, denn Betrag von Z 
möglichst groß werden zu lassen, sondern zu zählen, wie oft die 
Iteration durchläuft, bis der Betrag von Z die Abbruchbedingung, nämlich 
größer als 2 zu sein, erreicht.

Eigentlich müsste man die Iteration unendlich oft durchlaufen lassen, 
damit sicher entschieden wird, ob der Punkt zur Mandelbrotmenge gehört 
oder nicht, denn das ist schließlich die Definition der Mandelbrotmenge. 
Alle Punkte deren Iteration nicht gegen unendlich strebt, gehören zu 
ihr.
(wobei die Iterationsvorschrift: Zn = Zn-1² + c. Und c ist die 
Koordinate des betrachteten Pixels)

Sobald der Iterationswert größer als 2 wird, strebt er mit sehr hoher 
Wahrscheinlichkeit gegen unendlich. (ich prüfe hier nur, ob das Quadrat 
des Betrages größer als 4 ist, um mir das Wurzelziehen zu sparen was 
aufs selbe hinauskommt).

Die Zahl der Iterationsschritte bis hierher bestimmt die Färbung des 
Punktes.
Sollte der Punkt nicht gegen unendlich streben, müsstest du ja in der 
Theorie unendlich oft iterieren. Da hierfür dem Durchschnittsanwender 
die Zeit fehlt, geht man den Kompromiss ein, nach einer bestimmten 
Anzahl von Iterationen abzubrechen und diesen Punkt dann als zur 
Mandelbrotmenge zugehörig anzunehmen.

Was also viel größeren Einfluss auf die Genauigkeit hat, ist die Anzahl 
der Iterationen bis zum Abbruch. Und dann noch die Zuordnung, bei 
welchem Iterationsschritt welche Farbe gewählt wird.

Viel interessanter ist auch der Randbreich, statt der ganzen Menge. (Die 
Zahl der Iterationenn bis zum Abbruch bleibt lange gering, bis man sich 
der eigentlich Mandelbrotmenge nähert).

Anbei mal der gleiche Ausschnitt in unterschiedlichen drei 
unterschiedlichen Farbzuordnungen.
Die Farben sind einfach:
farbe1    r=255, g=0, b=0
farbe2    r=255, g=1, b=0
farbe256  r=255, g=255, b=0
farbe257  r=254, g=255, b=0
farbe512  r=0, g= 255, b=0
farbe513  r=0, g= 255, b=1
farbe768  r=0, g= 255, b=255
farbe769  r=0, g= 254, b=255
farbe1024 r=0, g= 0, b=255
farbe1025 r=1, g= 0, b=255
farbe1280 r=255, g=0, b=255
farbe1281 r=255, g=0, b=254

FarbeLinearMal2 ist die Anzahl der Iterationsschritte*2=Farbe
FarbeLog ist der Logarithmus der Anzahl Iterationsschritte so 
multipliziert, das er beim Maximum der Iterationsschritte das Maximum 
der Farbtabelle trifft.
FarbeLogmal2, das selbe, nur mit 2 multipliziert.

P.S.
Ich könnte ich auch Bilder in 27320*15360 zeigen, aber das Datenvolumen 
wollte ich euch nicht antun)

: Bearbeitet durch User
von J. T. (chaoskind)


Lesenswert?

Johann L. schrieb:
> Ok, bei der roten Farbsoße wird man natürlich niemals nicht irgendeinen
> Unterschied sehen...

Aber es sind genug Details vorhanden, die in beiden Bildern gleich sind, 
womit hinreichend bewiesen ist, vor allem mit den Bildern in denen die 
Farbzuordnung unterschiedlch ist, das die Höhe von Z (|Z|) bei der 
abgebrochen wird, kaum Einfluss auf das Ergebnis hat.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

j. t. schrieb:
> Alle Punkte deren Iteration nicht gegen unendlich strebt, gehören zu
> ihr.

Streiche das "nicht".

von J. T. (chaoskind)


Lesenswert?

Wie mache ich, dass der Tippex streifen auf dem Bildschirm sich 
mitbewegt, wenn ich scrole? :-D

Wobei das nicht davon abhängt, ob man mit unendlich |Z| meint, oder die 
Zahl der Iterationsschritte.

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

j. t. schrieb:
> Wobei das nicht davon abhängt, ob man mit unendlich |Z| meint, oder die
> Zahl der Iterationsschritte.

Hier sollte das "nicht" in Anführungszeichen geschrieben werden ...

Wobei die Unendlichkeit nur bei der Anzahl der Iterationsschritte ein 
Kriterium ist, bei der Betrachtung von |z| reicht 2, was doch 
geringfügig kleiner ist als Unendlich.

von J. T. (chaoskind)


Lesenswert?

Rufus Τ. Firefly schrieb:
> bei der Betrachtung von |z| reicht 2, was doch
> geringfügig kleiner ist als Unendlich.

Was ich Johann L zu erklären versuchte *gg

von Johann L. (gjlayde) Benutzerseite


Angehängte Dateien:

Lesenswert?

j. t. schrieb:
> Johann L. schrieb:
>> Ok, bei der roten Farbsoße wird man natürlich niemals nicht irgendeinen
>> Unterschied sehen...
>
> Aber es sind genug Details vorhanden, die in beiden Bildern gleich sind,

Anbei zwei Bilder, links mit 2 und rechts mit 100 als Abbruchkriterium 
für |z|.

> womit hinreichend bewiesen ist,

Soviel zu "bewiesen" und "beweisen".


j. t. schrieb:
> Du verstehst scheinbar nicht, das es nicht darum geht,
> denn Betrag von Z möglichst groß werden zu lassen, sondern zu
> zählen, wie oft die Iteration durchläuft, bis der Betrag von
> Z die Abbruchbedingung, nämlich größer als 2 zu sein, erreicht.

Du verstehst nicht, daß es (hier) nicht darum geht, M einzufärben, 
sondern das Komplement von M.  Und da hängt der Verlauf der 
Farbgrenzen sehr wohl mit der Schranke für |z| zusammen!  Abermals die 
beiden Bildchen anschauen.


> Eigentlich müsste man die Iteration unendlich oft durchlaufen
> lassen, damit sicher entschieden wird, ob der Punkt zur
> Mandelbrotmenge gehört oder nicht, denn das ist schließlich
> die Definition der Mandelbrotmenge.

Naja, das ergibt sich aus der Definition und ist praktisch für Leute, 
die bunte Bildchen machen wollen.

> Sobald der Iterationswert größer als 2 wird, strebt er mit
> sehr hoher Wahrscheinlichkeit gegen unendlich.

Dann konvergiert er immer gegen Unendlich.


Und damit du siehtst daß die Bilder nicht getürkt sind, hier noch das 
Programm
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <complex.h>
4
5
typedef double complex cplx;
6
7
static int
8
iter (cplx c, double z_max, int n_max)
9
{
10
    int n;
11
    cplx z = 0;
12
    for (n = 0; cabs (z) <= z_max && n < n_max; n++)
13
        z = z*z + c;
14
    return n;
15
        
16
}
17
18
int main (int argc, char *argv[])
19
{
20
    int a = 1;
21
    double z_max = argc <= a  ? 2.0 : strtoul (argv[a], NULL, 0); a++;
22
    int n_max    = argc <= a  ? 100 : strtoul (argv[a], NULL, 0); a++;
23
    int PX       = argc <= a  ? 500 : strtoul (argv[a], NULL, 0); a++;
24
    int PY       = argc <= a  ? 500 : strtoul (argv[a], NULL, 0); a++;
25
26
    double step = 0.003;
27
    cplx c0 = -2 + 0i + step*PX*0.5 * 0.6;
28
    n_max |= 1;
29
    
30
    printf ("P1\n%d %d\n", PX, PY);
31
    for (int py = PY - 1; py >= 0; py--)
32
    {
33
        for (int px = 0; px < PX; px++)
34
        {
35
            double re = (px - 0.5 * PX) * step;
36
            double im = (py - 0.5 * PY) * step;
37
            printf ("%d", 1 & iter (c0 + re + I*im, z_max, n_max));
38
        }
39
        printf ("\n");
40
    }
41
42
    return EXIT_SUCCESS;
43
}

Zu compilieren und auszuführen als
1
gcc -O3 cman.c -o cman -std=c99
2
./cman > man.pbm
3
convert "man.pbm" "man-2.png"
4
./cman 100 > man.pbm
5
convert "man.pbm" "man-100.png"
liefert die beiden Bildchen anbei.

: Bearbeitet durch User
von J. T. (chaoskind)


Angehängte Dateien:

Lesenswert?

Johann L. schrieb:
> Anbei zwei Bilder, links mit 2 und rechts mit 100 als Abbruchkriterium
> für |z|.

Wobei auch da die Unterschiede zwar wahrnehmbar, aber auch nicht gerade 
eklatant sind.

Johann L. schrieb:
> Du verstehst nicht, daß es (hier) nicht darum geht, M einzufärben,
> sondern das Komplement von M.  Und da hängt der Verlauf der
> Farbgrenzen sehr wohl mit der Schranke für |z| zusammen!  Abermals die
> beiden Bildchen anschauen.

Doch das verstehe ich sehr wohl, was dir auffallen müsste, wenn du meine 
Bilder ansiehst, da in denen das Apfelmännchen schwarz und der Rand 
gefärbt ist(also nur der Nichtmandelbrotteil oder halt das Komplement). 
Und da der interessante Bereich von C zwischen -1 und 2 im Realteil und 
-1 und 1 im Imaginärteil liegt, verschiebt das Z bzw |Z| auch nur um 
diesen Bereich. Evtl bringst du die Schranke von Z mit der Anzahl der 
Iterationen durcheinander? Deinen Code verstehe ich auf die schnelle 
ehrlich gesagt nicht. Zumindest hat bei mir, bei welcher Farbzuordnung 
auch immer, die Höhe von z nur einen sehr geringen Einfluss auf das 
Ergebnis, sehr wohl aber die Höhe der Iterationen, ab der abgebrochen 
wird.

Johann L. schrieb:
>> Eigentlich müsste man die Iteration unendlich oft durchlaufen
>> lassen, damit sicher entschieden wird, ob der Punkt zur
>> Mandelbrotmenge gehört oder nicht, denn das ist schließlich
>> die Definition der Mandelbrotmenge.
>
> Naja, das ergibt sich aus der Definition und ist praktisch für Leute,
> die bunte Bildchen machen wollen.

Und was willst du damit jetzt sagen? Ich "nenne" die Definition, und du 
sagst, das ergibt sich aus der Definition? Was genau ergibt sich aus der 
Definition? Das es praktisch für Leute ist, die bunte Bildchen machen 
wollen?

von J. T. (chaoskind)


Angehängte Dateien:

Lesenswert?

Die sollten eben noch mir ran, aber irgendwie wollte er keine Bilder 
hochladen. Diesmal ein Ausschnitt, auf dem deutlich mehr Strukturen zu 
sehen sind, an denen man Unterschiede wahrnehmen sollte, würde Z einen 
so großen Einfluss haben.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

j. t. schrieb:
> Johann L. schrieb:
>> Anbei zwei Bilder, links mit 2 und rechts mit 100 als Abbruchkriterium
>> für |z|.
>
> Wobei auch da die Unterschiede zwar wahrnehmbar, aber auch nicht gerade
> eklatant sind.

Von eklatant hab ich auch nix geschrieben.

Je größer die Schranke für |z| ist, desto besser passen sich die Linien 
außerhalb von M den Äquipotentiallinien an; das hab ich oben geschrieben 
und ich versteh nicht, was für ein Problem du damit hast.  Dass diese 
Linien je nach Farbwahl nicht zu erkennen sind ist doch eine 
Trivialität.

> Evtl bringst du die Schranke von Z mit der Anzahl der Iterationen
> durcheinander?

Keine Angst, ich bring da nix durcheinander:

Die Anzahl der Linien, bzw. wie gut man (das Äußere von) M approximiert, 
hängt ab von der Iterationsschranke -- mal abgesehen von Einschränkungen 
durch Rechengenauigkeit, die je nach Wahl des Ausschnitts zum tragen 
kommen.  Je größer die Iterationsschranke, desto mehr Linien bzw. 
Farbbänder bekommt man: pro Iterationsschritt mehr ein Farbband mehr. 
Auf die Form der Linien bzw. Farbbänder hat das keinen Einfluß.

Die Schranke für |z| hat hingegen Einfluß auf dir Form der Banden.  Es 
gibt zwar auch einen kleinen Einfluß auf die Anzahl der Iterationen bis 
zum Abbruchkriterium durch die Iterationsschranke, aber diese ist 
vernachlässigbar da er nur mit log|z| zu Buche schlägt.

> Johann L. schrieb:
>> Naja, das ergibt sich aus der Definition und ist praktisch für Leute,
>> die bunte Bildchen machen wollen.
>
> Und was willst du damit jetzt sagen? Ich "nenne" die Definition,
> und du sagst, das ergibt sich aus der Definition? Was genau ergibt
> sich aus der Definition? Das es praktisch für Leute ist,
> die bunte Bildchen machen wollen?

Es gibt natürlich mehrere Möglichkeiten um M zu definieren.  Obwohl 
diese Definitionen die gleiche Menge liefern ist der mathematische 
Gehalt durchaus unterschiedlich.

Hast du dich z.B. schon mal gefragt warum man die verwendete Iteration 
mit Startwert 0 beginnt und nicht mit irgendeinem anderen Wert? Warum 
nicht mit 1 oder -1 oder i oder Pi?  Und warum verwendet man z -> z²+c 
als Iterationsvorschrift und nicht z->z²+cz oder z->sin(z)+c?  Und wo 
kommt die Schranke 2 her?  Warum verwendet man ausgerechnet 2 und nicht 
1.5?

Klar, mit 1.5 als Schranke für |z| bekommt man eine andere Menge; aber 
warum zum Teufel fahren alle ab auf einen Wert >= 2 und keiner macht 
tolle Bilder für |z| >= 1.5 oder schreibt ganze Bücher darüber?

von J. T. (chaoskind)



Lesenswert?

Johann L. schrieb:
> Je größer die Schranke für |z| ist, desto besser passen sich die Linien
> außerhalb von M den Äquipotentiallinien an; das hab ich oben geschrieben
> und ich versteh nicht, was für ein Problem du damit hast.

Das Problem das ich damit "hab" (eigentlich tangiert mich das ganze 
recht peripher), das es in deinen ersten Ausführungen so klang, als wäre 
die |Z| das Hauptkriterium, von dem das Aussehen des Mandelbrotes 
abhängt, und das ist nunmal definitiv nicht der Fall.

So hängt das sichtbarwerden der "Äquipotentiallinien" hauptsächlich von 
der Farbzuordnung ab. Denn wenn du jedem Iterationsschritt eine nur ganz 
leicht unterschiedliche Farbe zuordnest, gehen sie natürlich in meinen 
roten Farbmasch unter.

Johann L. schrieb:
> Die Anzahl der Linien, bzw. wie gut man (das Äußere von) M approximiert,
> hängt ab von der Iterationsschranke -- mal abgesehen von Einschränkungen
> durch Rechengenauigkeit, die je nach Wahl des Ausschnitts zum tragen
> kommen.  Je größer die Iterationsschranke, desto mehr Linien bzw.
> Farbbänder bekommt man: pro Iterationsschritt mehr ein Farbband mehr.
> Auf die Form der Linien bzw. Farbbänder hat das keinen Einfluß.
>
> Die Schranke für |z| hat hingegen Einfluß auf dir Form der Banden.  Es
> gibt zwar auch einen kleinen Einfluß auf die Anzahl der Iterationen bis
> zum Abbruchkriterium durch die Iterationsschranke, aber diese ist
> vernachlässigbar da er nur mit log|z| zu Buche schlägt.

FACK

Darauf kann ich mich ohne Bauchschmerzen einlassen =) Anbei nochmal 
2Bilder des gleichen Ausschnittes, die das von dir gesagt deutlich 
zeigen.
(Die Farbzuordnung ist bei beiden die selbe, aber 
gestreckt(Iterationsschrittzahl * 30(mit der weiter oben genannten 
Farbtabelle)))

Mit der linearen Farbzuordnung (Farbe = Iterationsschrittzahl) kommt 
übrigens der rote Mischmasch vom Anfang raus.

MfG Chaos

von Reinhard (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,
ich möchte den Thread nicht entführen,
weils aber zum Thema passt und heute der 11.11. ist ;-)

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.