Sie sind nicht angemeldet.

Lieber Besucher, herzlich willkommen bei: GEOS-InfoBase-Forum. Falls dies Ihr erster Besuch auf dieser Seite ist, lesen Sie sich bitte die Hilfe durch. Dort wird Ihnen die Bedienung dieser Seite näher erläutert. Darüber hinaus sollten Sie sich registrieren, um alle Funktionen dieser Seite nutzen zu können. Benutzen Sie das Registrierungsformular, um sich zu registrieren oder informieren Sie sich ausführlich über den Registrierungsvorgang. Falls Sie sich bereits zu einem früheren Zeitpunkt registriert haben, können Sie sich hier anmelden.

1

Sonntag, 2. Mai 2021, 18:45

BitmapContent.Pokeline fehlerhaft?

Ich habe mir eine Prozedur gebastelt, die u.a. mittels BitmapContent.Pokeline den Inhalt einer BitmapContent in eine .BMP-Datei schreibt, da ich eine solche Funktion sonst nirgends gefunden habe. Nun mein Problem:

Alles funktioniert prima, solange im BitmapContent nicht Farben über Farbcode 127 vorkommen. Dann gibt mir Pokeline falsche Werte im Bereich der zu 'hohen' Pixel aus. Ich habe einmal ein Testbild mit angehangen, welches die Problematik gut wiedergibt.
Die falschen Werte sind übrigens immer &HFF und &H7F

Das paradoxe daran: In der View, welche das BitmapContent darstellt, ist die Grafik ohne Makel - Alle Farben werden korrekt dargestellt.
Bilder, die nur Farben unter 128 verwenden werden ebenfalls korrekt dargestellt.

Ist das eventuell ein Fehler in PokeLine?

Mario

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
DECL FUNCTION MakeBMP(str_file AS STRING, bmp_Content AS Object) AS INTEGER
STRUCT BMPheader
 	'Ident AS STRING(2)    	' "BM"
 	Magic AS INTEGER	    	'Workaround fr BM
 	Size AS LONGINT        	' file size (x*y+header+pal)
 	Reserved AS LONGINT    	' junk
 	Offset AS LONGINT      	' header+palette
 	HeaderSize AS LONGINT  	' 40
 	xRes AS LONGINT        	' x resolution
 	yRes AS LONGINT        	' y resolution
 	Planes AS INTEGER      	' 1
 	i_BPP AS INTEGER         	' bits per pixel
 	Compression AS LONGINT 	' 0-none/1,2-rle
 	ImageSize AS LONGINT   	' x*y
 	PixPerMetreX AS LONGINT	' 3790
 	PixPerMetreY AS LONGINT	' 3780
 	UsedColors AS LONGINT
 	ImportantColors AS LONGINT
END STRUCT

STRUCT BMPpalEntry
	bl, gr, rd, nl AS Byte
End Struct


STRUCT BMPpxDWord
	il, ih AS Integer
End Struct

FUNCTION MakeBMP(str_file AS STRING, bmp_Content AS Object) AS INTEGER
' *** MakeBMP ***
' speichert den Inhalt eines BitmapContent-Objektes inkl. 
' einer ggf. modifizierten Palette als .BMP-Datei ab.
'
' str_file = Dateiname der Zieldatei inkl. Pfad (ohne Pfad = aktueller Pfad)
' bmp_Content = BitmapContent-Objekt aus welchem gelesen werden soll

		DIM MyBMPheader AS BMPheader
		DIM BMPfile AS FILE
		DIM pal AS FullPalette
		DIM BMPpalE AS BMPpalEntry
		DIM dw AS BMPpxDWord
		DIM ic, ix, iy AS INTEGER
		DIm i_xStart,	i_yStart, i_xEnd, i_yEnd AS INTEGER
	
		i_xStart = 0
		i_yStart = 0
		i_xEnd = bmp_Content.bitmapFormat(0)	- 1
		i_yEnd = bmp_Content.bitmapFormat(1) - 1
		
		
 	MyBMPheader.xRes = i_xEnd - i_xStart + 1
 	MyBMPheader.yRes = i_yEnd - i_yStart + 1
 	
 	'MyBMPheader.Ident = "BM"
 	MyBMPheader.Magic = 19778 'Workaround fr 'BM'
 	MyBMPheader.Size = MyBMPheader.xRes * MyBMPheader.yRes + 54 + 4 * 2 ^ 8
 	MyBMPheader.Reserved = 0
 	MyBMPheader.Offset = 54 + 4 * 2 ^ 8
 	MyBMPheader.HeaderSize = 40
 	MyBMPheader.Planes = 1
 	MyBMPheader.i_BPP = 8
 	MyBMPheader.Compression = 0
 	MyBMPheader.ImageSize = MyBMPheader.xRes * MyBMPheader.yRes
 	MyBMPheader.PixPerMetreX = 3790
 	MyBMPheader.PixPerMetreY = 3780
 	MyBMPheader.UsedColors = 0
 	MyBMPheader.ImportantColors = 0
			
		 BMPfile = filecreate (str_file, "")
		 IF fileError <> 0 THEN RETURN FAlse
		 
			'Kopfdaten schreiben
 	FileWrite BMPfile, MyBMPheader, sizeOf(BMPheader)
		 
 			'Palettendaten schreiben
			pal = bmp_Content.GetFullPalette
		 FOR ic = 0 TO 255
		 	BMPpalE.rd = pal.item[ic].rt 
			BMPpalE.gr = pal.item[ic].gn
			BMPpalE.bl = pal.item[ic].bl
			FileWrite BMPfile, BMPpalE, sizeof(BMPpalE)
		 NEXT
		 
 			'Bilddaten schreiben
			
			'Achtung!:
			'Zeilendaten mssen durch 4 teilbar sein, sonst mssen sie aufgefllt werden! 
			'Pokeline fllt hier aber anscheinend selbst schon Nullen auf?
		 FOR iy = i_yEnd TO i_yStart STEP -1
		 	bmp_Content.PokeLine 0, iy 
			FOR ix = i_xStart TO i_xEnd STEP 4
				dw.il = Deek(ix)
				dw.ih = Deek(ix+2)
				FileWrite BMPfile, dw, 4
			NEXT
		 NEXT
      	
 	FileCLOSE BMPfile
 	RETURN TRUE
END FUNCTION
»Bario« hat folgende Datei angehängt:
  • PALETTE.JPG (105,32 kB - 12 mal heruntergeladen - zuletzt: Heute, 01:23)

2

Sonntag, 2. Mai 2021, 19:55

Hallo Mario,

es gibt eine Funktion um BMP's zu schreiben: WriteBitmapToFile. Erwatet wird ein Handle, das du mit MyBitMapContent.GetBitmapHandle erhalten kannst. Für den Rest verweise ich dich mal aufs Handbuch. Menü Hilfe->Handbücher durchsuchen.Den Code (wow! sauber!) sehe ich mir jezt aber nicht im Detail an, um den Fehler zu finden (wir haben morgen schriftliche Physikprüfungen). Ich tippe aber auf das Deek(). Deek() lieste einen Integerwert, da ist &hFFFF = -1. Dein Fehler kingt so, als gäbe es damit ein Problem. PeekLine verwendet intern memcpy(), damit sollte es kein Problem geben. Kannst ja mal testweise auf Peek() umstellen.

Gruß
Rainer

P.S. PokeLine und Peek/Deek sind sehr langsam.
P.P.S PokeLine hängt keine Nullen an, aber unbenutze Speicherbereiche werden immer mit Nullen initialisiert.
P.P.P.S Oder so: AnyStruct ist ein Array of byte. Du könntest statt der Deek-Schleife auch versuchen, eine AnyStruct Variable mit PeekS zu lesen und dann mit FileWrite so viele Bytes wie nötig zu schreiben.
Es gibt 10 Arten von Menschen - die einen wissen was binär ist, die anderen nicht.

3

Sonntag, 2. Mai 2021, 22:57

Hallo Rainer,
es gibt eine Funktion um BMP's zu schreiben: WriteBitmapToFile. ...
Ich hatte es geahnt, dass es sowas bereits gibt. Hatte anfangs auch im CodeWizzard danach suchen lassen - Höchstwahrscheinlich aber mit den falschen Stichworten ;(
Ich tippe aber auf das Deek()...
Genau da lag der Fehler. Statt 2x Deek habe ich probeweise 4x Peek verwendet und siehe da: es funktioniert!

Letztendlich habe ich mich aber für WriteBitmapToFile entschieden, da 0.2s gegenüber 10s für eine 400x300-Grafik eindeutig für die interne Funktion sprechen. Aber zumindest konnte ich mal wieder meine Kenntnisse um das BMP-Format erweitern. Und mal schnell eigene Lösungen finden macht doch auch irgendwie Spaß. :thumbsup:

Ein großes Danke für die superschnelle Hilfe!

Mario

4

Dienstag, 4. Mai 2021, 22:22

Hallo Mario,
gerne doch. Trotzdem bin ich für alle Feedbacks dankbar. Irgendwelche Bugs kann man nie ausschließen. Ein paar Leute wissen jetzt, was ich meine :-)
Gruß
Rainer
Es gibt 10 Arten von Menschen - die einen wissen was binär ist, die anderen nicht.

5

Gestern, 21:01

Hallo Rainer,

Eine Frage zu o.g. Code hätte ich noch:

Die Struktur BMPheader beginnt ja normalerweise mit dem String(2) 'Ident', welcher den Inhalt 'BM' hat- dieser wird aber nach dem Schreiben mittels FIleWrite mit einem nachfolgenden Null-Byte ausgegeben, was dazu führt, dass die Datei nicht als Bitmap erkannt wird, bzw. die Größen-Information dadurch dann an der falschen Position steht.

Ich habe mir dann mit dem Integer 'Magic' beholfen, welcher 'BM' als Integerwert enthält und habe den String 'Ident' derweil auskommentiert. (siehe auch Code)

Kannst du dir dieses Verhalten mit 'dem Null anhängen' erklären und wie kann man das unterbinden?

Ansonsten finde ich R-Basic richtig klasse und arbeite sehr gern damit. Gerade die Unterstützungfunktionen (Wizzard, Beispiele, Handbuch) haben mir den Einstieg echt leicht gemacht. :thumbsup:

Viele Grüße,
Mario

6

Heute, 13:53

Hallo Mario,

Ich weiß nicht, ob die Null nach dem "BM" wirklich "illegal" ist. Denn auf das "BM" folgen vier Bytes mit der "Dateigröße in Bytes", die aber üblicherweise als "unreliable" eingestuft sind:
http://www.fastgraph.com/help/bmp_header_format.html
https://docs.fileformat.com/image/bmp/
Wenn sich die Null dort aber zusätzlich eingeschmuggelt hat, dann wäre das wirklich ein Fehler...

Jörg
:D Most favorite keys by profession: astronauts: space, pirates: enter, German teachers: 6... :D

7

Heute, 20:53

Hallo Jörg,
....Wenn sich die Null dort aber zusätzlich eingeschmuggelt hat, dann wäre das wirklich ein Fehler...
Es ist tatsächlich so, dass sich die Null zusätzlich einschleicht. Ich habe das eben auch nochmal nachvollzogen: siehe Screenshot.

screensh0.JPG

Mario

8

Heute, 21:03

Hallo Mario,
die Null ist kein Fehler - zumindest nicht aus der Sicht von FileWrite. Wenn du einen String schreibts gehört die anschließende Null immer dazu. Deswegen belegt eine Variable vom Typ String(10) auch 11 Byte. Das wird vom Prinzip her auch bei allen Programmiersprachen so gemacht. Wenn du in C einen String char[5] definierst hast du maximal 4 Zeichen - plus die obligatorische Ende-Null.
Das 'BM' kommt letztlich daher, dass man eine Markierung brauchte, die eine gültige BMP-Datei identifitiert. Da hat man sich für zwei Byte entschieden, die irgend einen willkürlich (!) festgelegten Wert enthalten. Aus naheliegenden Gründen hat man sich für die ASCII-Codes der Buchstaben B und M entschieden. Exe-Dateien fangen ja auch mit MZ an (nach ihrem Erfinder Mark Zbikowski).

Dein "Work-Around" mit dem magic word ist also keine Krücke, sondern Konzept-konform. Die Definition String(2) belegt in R-BASIC 3 Byte - womit dein Header Schrott wäre (siehe auch dein Screnshot).
Gruß
Rainer

P.S. Dass ein String (n) n+1 Byte belegt ist eine Konzeptenscheidung. Für den Anfänger ist es schwer zu verstehen, dass ein String(10) nur 9 Zeichen lang sein dürfte. Profis müssen dann eben damit leben :-)
Es gibt 10 Arten von Menschen - die einen wissen was binär ist, die anderen nicht.

9

Heute, 22:06

Hallo Rainer,

Mein Trugschluss, dass dies hätte funktionieren müssen kommt dann denke ich von einer Eigenheit von QBasic. Die Vorlage zum obigen Code stammt von hier . Der QBasic PUT-Befehl gibt den String*2 anscheinend nicht nullterminiert aus. Ich habe das jetzt nicht getestet, glaube aber, dass die Code-Vorlage im Link einmal funktioniert haben muss.

Bei der nächsten Portierung weiß jetzt Bescheid. Danke dir für deine ausführliche Erklärung. :thumbup:

Viele Grüße,
Mario

Ähnliche Themen

Thema bewerten