Wie indiziertes tga in Unkomprimiertes umwandeln?

Anfängerfragen zum Programmieren mit PureBasic.
Syntacks_Error
Beiträge: 107
Registriert: 08.03.2009 16:08

Wie indiziertes tga in Unkomprimiertes umwandeln?

Beitrag von Syntacks_Error »

Schreibe ein Programm, das tga-Dateien anzeigt und bearbeitet.
Die Dateien liegen im farb-indizierten Format (8 Bit) mit einer Farbpalette vor. Leider kann das tga_Plugin das nicht lesen. Also muß ich die in ein unkomprimiertes RGB Format (24 Bit, kein Alpha-Kanal) umwandeln. Ich weiß nur nicht wie. Mit den Palettenangaben in den Dateien kann ich nichts anfangen:

Code: Alles auswählen

file = readfile(#PB_Any,"Name der indizierten tga einfuegen")
 
 FileSeek(file,1)
 b = readcharacter(file)
 Debug "Palette vorhanden: " + Str(b)
 b = readcharacter(file)
 Debug "Bildtyp: " + Str(b)
 b = readword(file)
 Debug "Palettenbegin: " + Str(b)
 b = readword(file)
 Debug "Farbanzahl: " + Str(b)
 b = readcharacter(file)
 Debug "Groeße Paletteneintrag (Was sagt das?): " + Str(b)
 FileSeek(file,16)
 b = readcharacter(file)
 Debug "Groeße Bildpunkt/Bit: " + Str(b)
Das Format ist hier beschrieben:

http://de.wikipedia.org/wiki/Targa_Image_File

Tga ist wohl ein aussterbenden Format, Gimp kann es noch.

Kann mir irgend jemand helfen?

Hilfsweise: Ich vermute, daß da ein 24 Bit-Farbwert (je 8 Bit für Rot, Grün und Blau) auf 8 Bit herunterskaliert und gespeichert wird.Die Art der Skalierung ist dann in einem 24 Bit Palettenwert gespeichert? Oder kann man alleine aus den 8 Bit wieder halbwegs vernünftige Werte für Rot, Grün und Blau herauspfriemeln? Wie lese ich ein Byte bitweise?
Marvin
Beiträge: 497
Registriert: 17.07.2005 14:42
Wohnort: Krikkit

Re: Wie indiziertes tga in Unkomprimiertes umwandeln?

Beitrag von Marvin »

Ich nehme an, dass in der Palette normale RGB-Daten (bzw. in diesem Falle in der Reihenfolge BGR oder mit optionalem Alphakanal, dann BGRA) stehen. Das eine Byte in den Bilddaten gibt dann den Index in dieser Tabelle an.
Hat man zum Beispiel die folgende Palette (BGR):

Code: Alles auswählen

$00 $FF $FF $00 $40 $FF $FF $40 $00 $00 $00 $00
Dann bedeuten die folgenden Bilddaten die entsprechenden Farben (ungefähr):
$00 $03 $02 $01
Denn die Palette sähe aufgeschlüsselt so aus:
  • Index 0: $00 $FF $FF = RGB($FF, $FF, $00)
  • Index 1: $00 $40 $FF = RGB($FF, $40, $00)
  • Index 2: $FF $40 $00 = RGB($00, $40, $FF)
  • Index 3: $00 $00 $00 = RGB($00, $00, $00)
Ich habe mich nicht eingehend mit diesem Format beschäftigt, aber so könnte ich mir das zumindest vorstellen. :wink:
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Re: Wie indiziertes tga in Unkomprimiertes umwandeln?

Beitrag von Kaeru Gaman »

"indizierte" Codierung bedeutet, dass das Bild eine Palette enthält, die über einen Index angesprochen wird.
Im Header steht also eine Palette, in der 256 Farbwerte vermerkt sind,
und in den Bilddaten selber steht dann für jedes Pixel ein Index 0-255, welche Paletten-Farbe das Pixel hat.

das ist aus der Formatbeschreibung im wiki eigentlich gut ersichtlich.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Syntacks_Error
Beiträge: 107
Registriert: 08.03.2009 16:08

Re: Wie indiziertes tga in Unkomprimiertes umwandeln?

Beitrag von Syntacks_Error »

Aha. Vielen Dank, jetzt habe ich zumindest eine Vorstellung, wie es funktionieren könnte. Ich tüftle dann also mal ein bißchen weiter ...
Syntacks_Error
Beiträge: 107
Registriert: 08.03.2009 16:08

Re: Wie indiziertes tga in Unkomprimiertes umwandeln?

Beitrag von Syntacks_Error »

Hurra, ich habe es geschafft:

Code: Alles auswählen

file = readfile(#PB_Any,"geindexte Farb-tga-Datei.tga")

header = 18 ; 18 Bytes Header
Dim header(header) 
For x = 1 To 18
  header(x) = readcharacter(file)
Next

Debug "Palette 1/0: " + Str(header(2)) ; Header(2) 1/0 => Palette ja/nein
Debug "Indiziert 1/0" + Str(header(3)) ;  Wenn Header(3) = 1, indiziert
Debug "Bits/Farbe/Palette " + Str(header(8)); bei mir immer 24
Debug "Index Bit: " + Str(index_bit)
;Palettenbegin (Byte4/5) = immer 0, daher unbearbeitet

;--- doof
FileSeek(file,5)
farben = readword(file) ; Header(6) und (7) sind als Bytes da, aber wie macht man daraus ein word?
FileSeek(file,18); Ende des Headers
;----/doof
Debug "Farben: " + Str(farben)

For x = 1 To header(1) ; Falls BildID im Original, Anzahl Bytes weiternudeln
  readcharacter(file)
Next

;Header auf nicht indiziert umstellen
header(1) = 0 ; keine BildID
header(2) = 0 ; keine Palette
header(3) = 2 ; 2 = 24 Bit unkomprimiert
header(6) = 0; 1. byte Farbanzahl, wenn nicht indiziert = 0
header(7) = 0; 2. byte Farbanzahl, wenn nicht indiziert = 0
header(8) = 0; Keine Palette, also Paletten Bits/Farbe = 0
header(17) = 24; Neue Bits/Farbe
; Rest kann bleiben

Structure index
  Index_nr.i
  rot.b
  gruen.b
  blau.b
EndStructure

Dim palette.index(Farben)
For x = 0 To farben ; Palettendaten lesen; bei mir immer 3*1 Byte
  palette(x)\rot =  readcharacter(file)
  palette(x)\gruen = readcharacter(file)
  palette(x)\blau = readcharacter(file)
Next

test_file = CreateFile(#PB_Any,"nicht_indiziert.tga") 

For x = 1 To 18
  WriteCharacter(test_file,header(x)) ; neuen Header schreiben
Next

While Not Eof(file)
  Index_nr = readcharacter(file) ; Bilddaten => Indexnr der Farbpalette
  WriteCharacter(test_file,palette(index_nr)\rot)
  WriteCharacter(test_file,palette(index_nr)\gruen)
  WriteCharacter(test_file,palette(index_nr)\blau)
Wend

CloseFile(file)
CloseFile(test_file)
Dazu aber noch zwei Fragen:

1) Anfangs habe ich den Header als Bytes(x). Bytes 6 u. 7 geben als Word die Palettenfarbzahl. Wie mache ich aus zwei Bytes ein Word, damit ich das Word nicht nochmal lesen muß? (Fileseek(file,5)/Readword)

2) Schöner wäre es, alles im Speicher abzuwickeln, denn das neue Bild muß ich ja wieder einlesen. Wie bekomme ich das Originalbild in den Speicher, lese es aus und pfriemel das nicht indizierte Bild in den Speicher? (Peek und Poke kann ich im Prinzip, viel mehr aber auch nicht). Außerdem verwende ich das Imagegadget zum Anzeigen des Bildes. Wie greife ich für dafür das neue Bild im Speicher ab?
Marvin
Beiträge: 497
Registriert: 17.07.2005 14:42
Wohnort: Krikkit

Re: Wie indiziertes tga in Unkomprimiertes umwandeln?

Beitrag von Marvin »

Allgemein: Ich würde statt ReadCharacter() lieber ReadByte() nehmen. Denn ein Character ist nicht garantiert ein Byte.

1)

Code: Alles auswählen

word = header(6) | ((header(7) & $FF) << 8)
2) An sich forderst du erstmal einen genügend großen Speicherbereich z. B. mit *mem = AllocateMemory(...) an. Dann ersetzt du dein WriteCharacter(test_file, Wert) (bzw. WriteByte(test_file, Wert)) einfach mit PokeB(*mem, Wert) und *mem + 1 (um ein Byte weiter zu gehen). Dann solltest du das Bild direkt mit CatchImage() von der ursprünglichen Speicherstelle laden können.
Beispiel:

Code: Alles auswählen

*basemem = AllocateMemory(18 + (Lof(file) - Loc(file)) * 3)
*mem = *basemem
For x = 1 To 18
  PokeB(*mem, header(x) & $FF)
  *mem + 1
Next

While Not Eof(file)
  index_nr = ReadByte(file)
  PokeB(*mem, palette(index_nr)\rot)
  *mem + 1
  PokeB(*mem, palette(index_nr)\gruen)
  *mem + 1
  PokeB(*mem, palette(index_nr)\blau)
  *mem + 1
Wend

CloseFile(file)

UseTGAImageDecoder()
img = CatchImage(#PB_Any, *basemem)
Antworten