Entwickler-Ecke

Algorithmen, Optimierung und Assembler - File einlesen als Integer Werte


cassah - Mi 06.07.05 19:58
Titel: File einlesen als Integer Werte
Hallo,

ich habe folgendes Problem:

ich will eine Topography Datei einlesen, von der
die Spalten- sowie Zeilenanzahl der einzelnen Werte bekannt ist (X und Y).
Das Format der Datei ist little-endian und die einzelnen Werte sind
16-bit signed integer. soweit so gut. ich habe das file bereits im speicher:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
var
     iFileLength    : Integer;
     iBytesRead     : Integer;
     Buffer         : PChar;
     fileName,f     : String;

begin
 f := FileOpen(fileName, fmOpenRead);

 if (f>0then
 begin
    iFileLength    := FileSeek(f,0,2); // jump to end
    FileSeek(f,0,0);                   // jump to begining

    Buffer         := PChar(AllocMem(f + 1));
    iBytesRead     := FileRead(f, Buffer^, iFileLength);

    FileClose(f);
 end;
end;


Nun will ich über 2 ineinanderliegende Schleifen (Y und X)
die einzelnen 16 bit signed integer aus dem buffer auslesen,
und in einem TImage einen Farbwert entsprechend der größe
des Wertes setzen (Höhenmodell).

Damit bin ich aber leider überfordert. Hab schon einiges probiert,
aber Typecasting ist scheinbar nicht das Zauberwort :(

Hat jemand ein paar ideen?
Vielleicht auch zu dem Problem, wie ich die Integer Werte dann in
den Typ TColor umwandeln kann (Shifting?)

Danke erstmal.

Eric

Moderiert von user profile iconraziel: Code- durch Delphi-Tags ersetzt.


maxk - Mi 06.07.05 23:50

Hallo und :welcome: im DF,
ich verstehe leider nicht so richtig, wo genau dein Problem liegt. Womit kommst du den nicht klar - mit dem Auslesen der Werte oder mit der Darstellung? Ich muss auch zugeben mit little-endian nichts anfangen zu können und was ich gerade im Netz gefunden habe scheint nicht das zu sein, was du da hast. Wie ist die Datei denn aufgebaut?

Zitat:
Hat jemand ein paar ideen?
Vielleicht auch zu dem Problem, wie ich die Integer Werte dann in
den Typ TColor umwandeln kann (Shifting?)
Wie stellst du dir denn die Farben vor? Soll jeder Wertebereich eine eigene Farbe erhalten oder soll die Farbe entsprechend des Wertes "verlaufen"?

Gruß,
maxk


cassah - Do 07.07.05 00:07

Also meinen Recherchen nach ist little endian die Ablage der Bytes.
Da die Werte 16 bit lang sind, bestehen sie aus 2 chars. Diese sind
dann (bei little endian) verkehrt herum gespeichert:

Ist das Datenwort zum Beispiel vier Byte (also 32 Bit) lang, werden die vier Bytes (b0,b1,b2,b3) in einem "big endian" System im Speicher so angeordnet, wie man die Stellen einer Dezimalzahl auf Papier schreiben würde, also zuerst das höchstwertige Byte und zuletzt das Byte mit dem geringsten Stellenwert (b3,b2,b1,b0). Zuvorderst steht hier also das "big end". In "little endian"-Systemen hingegen steht das Byte mit dem niedrigsten Stellenwert am weitesten links und das Byte mit dem höchsten Stellenwert am weitesten rechts (b0,b1,b2,b3). Zuvorderst steht also das "little end".

Mein Problem ist nun, dass ich jede Menge chars im Ram hab, ich aber aus jeweils 2 chars einen integer "bauen" muss. wie geht sowas?

..und zu der frage mit den farben:

ich will einen farbverlauf erstellen. das heißt je höher der 16 bit wert ist, desto
heller soll die farbe sein. ideal wäre ein farbverlauf von weiß zu schwarz analog
zum bereich minimalwert <-> maximalwert. das problem ist
eher die umwandlung von 16 bit signed integers zum typ Tcolor.

ich hoffe das macht das problem ein wenig klarer.

so denn - Eric


Allesquarks - Do 07.07.05 01:03

Delphi's typecasting kann man im allgemeinen glaube ich nur über Zeiger umgehen. Wenn Du in der Delphi-Hilfe unter Zeigern nachschaust gibt es dazu auch irgendwo ein Beispiel.
Normalerweise brauchst Du erst einen allgemeinen Zeiger und danach einen spezialisierten

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var pointerallg:pointer;int16pointer:Pinteger^;//Dies ist ein spezialisierter Zeiger
myint:int16;
begin
pointerallg:=addr(Deinlitteendian);
int16pointer:=pointerallg;
myint16:=int16pointer^;
end;


Wie viele bytes er dann braucht entscheidet Delphi glaube ich selbst.


cassah - Fr 08.07.05 10:06

Hi,

problem gelöst. hier nun die Lösung:


Delphi-Quelltext
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:
var     
     pointerallg    : Pointer;
     int16pointer   : PSmallint; // Dies ist ein spezialisierter Zeiger
     myint          : Smallint;  // 16 bit signed Integer
     heightVal      : Byte;
     col            : TColor;
    
     Buffer         : PChar;
     fileLength     : Longint;   // Länge der Datei in Bytes
     
begin
     // ...
     // Hier wird der Buffer gefüllt..
     // ...

     for i:=0 to ((fileLength div 2) - 1do
     begin
          pointerallg    := addr(Buffer[i * 2]); // * 2 wegen dem doppelten Vorschub, da 16 bit gelesen werden sollen
          int16pointer   := pointerallg;
          myint          := int16pointer^;
          
          // 16 bit auf die 8 Bit für R,G,B verkleinern
          heightVal      := Byte(myint div 256);

          // entsprechenden Grauwert ermitteln
          col            := RGBToColor(heightVal, heightVal, heightVal);          

          // ...
          // Dann kann die Farbe benutzt werden:
          // z.B.: 
             Image1.Canvas.Pixels[x, y] := col;
          // ...
     end;
end;

function TForm1.RGBToColor(R, G, B : byte): TColor;
begin
     Result := ((R and $FFshl 16) + ((G and $FFshl 8) + (B and $FF);
end;


vielen Dank für die Hilfe!

Eric