Frage deutsch
~~~~~~~~~~~~~~
Wie kann ich BMP-, GIF- und JPG-Bilder anzeigen und skalieren?
Wie kann man in einem QBasic-Programm BMP-, GIF- und JPG-Bilder anzeigen und skalieren?
 

Question English
~~~~~~~~~~~~~~
How to display BMP, GIF and JPG graphics and zoom it to fit a selectable area?
 
 

Antwort 1
~~~~~~~~
[ von Thomas Antoni, 11.1999 - 17.6.2002 ]
 
Hierzu benötigtst Du einen entsprechenden Grafik-Loader. Deartige Grafik Loader kannst Du für viele Grafik-Formate auf
www.qbasic.de herunterladen - in der Rubrik "QBasic -> Download -> Grafik" .
 
Am bequemsten geht das Anzeigen von Grafiken mit einer Bibliothek, z.B. der Future.Lib. Diese enthält unter Anderem einen sehr guten JPG-Viewer, den Du Dein Programm QB 4.5/7.1-Pogramm einbauen kannst. Dieser JPG-Viewer ist in dem Future.Lib Paket enthalten, das Du auf
www.qbasic.de unter "QBasic -> Download -> Libraries" herunterladen kannst.
 
Siehe in der Kategorie "
QuickBasic und VBDOS" .
 
 

Antwort 2
~~~~~~~~
[ von Matthias Becker (alias "Helium" alias "Beckah";
M.Beckah*gmx.de ), 19.4.02 ]
 
*** BMPs anzeigen
BMPs sind noch recht einfach zu laden. Ein Bitmap besteht aus einem 54Byte großem Kopf. Darauf folgt bei 8 Bit Farbtiefe eine 1024Byte große Tabelle, ansonsten entfällt diese. Zum Schluss folgen die Bildinformationen. Diese sind bei 8 Bit einfach ein einzelnes Byte mit einem Wert zwischen 0 und 255 (einschließlich). Dieser referenziert einen Wert aus der Tabelle. Bei 24Bit Farbtiefe ist entsprechen 3 Byte einem Bildpunkt. Die Farbe ist dann im Format BGR gespeichert. Das Bild ist von links nach rechts und von unten nach oben gespeichert.
 
Zur Tabelle: Die Tabelle Besteht aus 256 Werten à vier Byte, die im Format BGRA gespeichert sind, wobei A ein Dummybyte ist.
 
Der Kopf beinhaltet informationen zur Bildgröße, Farbtiefe, ...
 
Der Einfachheit halber folgt nun eine Struktur, um den Block zu laden:
 
TYPE BMPHeaderType
id AS STRING * 2 'sollte "BM" sein
size AS LONG 'Größe der Daten
rr1 AS INTEGER '
rr2 AS INTEGER '
offset AS LONG 'Position, an der die Bildinformationen beginnen
horz AS LONG '
wid AS LONG 'Bildbreite
hei AS LONG 'Bildhöhe
planes AS INTEGER '
bpp AS INTEGER 'Fabtiefe (8 für 256 Farben)
pakbyte AS LONG '
imagebytes AS LONG 'Höhe*Breite
xres AS LONG '
yres AS LONG '
colch AS LONG '
ic AS LONG '
pal AS STRING * 1024 'Palette <Blue, Green, Red, 0>
END TYPE
 
 
*** GIFs und JPGs anzeigen
Gifs und JPEGs sind wesentlich schwieriger zu laden, da diese komprimiert sind. Da JPEG-Bilder grundsätzlich 24Bit Farbtiefe haben, kann man sie sowieso nicht ohne Bibliothek anzeigen. Ich empfehle eine Bibliothek zu verwenden, die diese Formate lesen kann, da es sehr viel aufwand ist solche Bilder zu laden. (Gifs können z.B. von der Future.Lib geladen werden. für JPEGs gibt es eine Future.Lib-Erweiterung.) Ansonsten verweise ich auf www.wotsit.org . Dabei handelt es sich um eine Seite, die detaillierte Informationen zu sehr vielen Dateiformatenformaten bietet.
 
 
*** Skalieren, etc.
Wenn ein Bild einmal geladen ist, kann damit quasi alles gemacht werden. Um ein Bild zu skalieren sollte man so forgehen. Man läuft auf dem Bildschirm mit For-Schleifen ein gedachtes Bild ab, das die Größe hat, die das Bild haben soll. An jedem Punkt berechnet man eine Koordinate aus dem im alten Bild, und verwendet die dort zu findende Farbe im neuen Bild. Die Koordinate berechnet man, in dem man die Koordinate, an der man grade am Bildschirm ist durch den Faktor dividiert, um
den das Bild größer ist. Bei einem Doppelt so großen Ergebnis teilt man also durch 2.
 
 

Antwort 3
~~~~~~~~
[ von TT-Soft (
www.East-Power-Soft.de/ ) per Mail, 18.01.2002 ]
Wie kann man in einem QBasic-Programm BMP-, GIF- und JPG-Bilder anzeigen und skalieren? Wie kann ich ein Icon laden und anzeigen?
 
Zum Thema Grafiken laden kann ich nur sagen, daß es diverse Lade-Routinen für alle möglichen Formate, unter anderem auf unserer Seite, gibt. Für's selber machen gilt, daß man den Dateiaufbau exakt kennen muß. Dazu kann man im Internet diverse Seiten finden die diese beschreiben.
www.East-Power-Soft.de/tutorial/bilder.html
 
 

Antwort 4
~~~~~~~~~
[ von Frank Neumann ("Triton";
http://www.silizium-net.de , isn-interactive*web.de ), per Mail, 9.9.2001 ]
 
Mit speziellen, externen Routinen, die es eigentlich auf fast allen QBasic Seiten im Internet gibt. Die haben aber (fast)alle den Nachteil, dass sie sehr langsam sind, weshalb sie z.B für Spiele schlecht geeignet sind. Meist findet man nur Routinen für BMP oder PCX Bilder die noch dazu oftmals nur in Screen 13 laufen und nur Bilder mit 320x200 vertragen. Man sollte es sich also 2 mal überlegen, ob man wirklich BMP, JPG oder Ähnliches nehmen will.
 
Selber eine Routine zu schreiben, die JPG oder GIF-Bilder anzeigt, ist wegen der komplizierten Komprimieralgorithmen sehr kompliziert.
 
In den meisten Spielen und anderen Programmen werden aus den genannten Gründen spezielle, wesentlich schneller zu verarbeitende Grafikformate zum Anzeigen von Bildern verwendet.
 
 

Antwort 5
~~~~~~~~
[ von Skilltronic (
www.skilltronics.de ) im QB-Forum, 21.6.2005 ]
 
Mein BMP-Lader (nur für 256-Farben Bitmaps) ist vielleicht nicht der schnellste, dafür aber der kleinste, den ich bis jetzt kenne.
 
'***********************************************************************
' BMPLOAD2.BAS = BMP-Loader zum Anzeigen von BMP-Bildern mit 256-Farben
' ============
' Dieses Q(uick)Basic-Programms zeigt BMP-Bilder an, die eine Farbtiefe
' von 8 Bits (256 Farben) haben muessen.
'
' (c) Skilltronics ( www.skilltronics.de ) , 21.6.2005
'***********************************************************************
SCREEN 13: CLS
DIM byte AS STRING * 1
OPEN "bild.bmp" FOR BINARY AS #1
GET #1, 19, br&
GET #1, 23, ho&
FOR f = 0 TO 255
OUT 968, f
FOR rgb = 0 TO 2
GET #1, 57 + f * 4 - rgb, byte
OUT 969, FIX(ASC(byte) / 4)
NEXT
NEXT
normbr = 4 * FIX((br& + 3) / 4)
FOR x = 0 TO br& - 1
FOR y = 0 TO ho& - 1
GET #1, x + y * normbr + 1079, byte
PSET (x, (ho& - 1) - y), ASC(byte)
NEXT
NEXT
CLOSE #1
 
Das obige Programm steht im Verzeichnis Progs\ zur Verfügung sowie online unter www.antonis.de/faq/progs/bmpload2.bas .
 
Wer's ausprobieren möchte, kann sich hier auch ein passendes Bild dazu runterladen:
www.skilltronics.de/runterlader/bild.bmp
 
 

Antwort 6
~~~~~~~~~~~~~~~~
Und hier nun ein sehr gut kommentieres Programm zum Anzeigen von BMP-Bildern mit 256 Farben (8 Bit Farbtiefe), das einwandfrei funktioniert:
 
'*******************************************************************************
' BMP-LOAD.BAS = BMP-Loader zum Anzeigen von BMP-Grafiken
' ============
' Dieses Q(uick)Basic-Programm zeigt BMP-Bilder an.
' Die Bilddateien muessen eine Farbtiefe von 8 Bit (256 Farben) aufweisen.
' Bei Bedarf kann man die Farbtiefe mit jedem beliebigen Bildbearbeitungs-
' Programm anpassen, z.B. mit IrfanView ueber den Menuepunkt "Bild ->
' Farbtiefe erhoehen bzw. Farbtiefe reduzieren"
'
' QB BITMAP READER Copyright (c) 1999 XFlareSoft
'*******************************************************************************
DEFINT A-Z
DIM byte AS STRING * 1
DIM xsz AS LONG 'x-Size
DIM ysz AS LONG 'y-Size
P$ = "test.bmp"
SCREEN 13
'
'--- Datei oeffnen ---
OPEN "c:\tmp\example.bmp" FOR BINARY AS #1
'
'--- Dateiheader auslesen ---
'Die ersten 54 Byte der Datei sind fest vorgegeben und beinhalten den
'Dateiheader:
'Position = 1 -> Am Anfang einer BMP-Datei muss die Zahl 19778 stehen
' = 29 -> In diesem Beispiel muss hier eine 8 stehen, da dieses
' Programm nur bei 8-Bit-BMP-Datein funktioniert
' = 19 -> Bildbreite in Pixel
' = 23 -> Bildhöhe in Pixel
GET #1, 1, ftype
GET #1, 29, bits
GET #1, 19, xsz
GET #1, 23, ysz
'
'--- 8-Bit-BMP-Datei erkannt ---
IF ftype = 19778 AND bits = 8 THEN
'--- Farbpalette auslesen und setzen ---
FOR attr = 0 TO 255
OUT &H3C8, attr
FOR rgb = 1 TO 3
GET #1, attr * 4 + 58 - rgb, byte
OUT &H3C9, INT(ASC(byte) * .2471)
NEXT
NEXT
'
'--- Bild zeichnen ---
FOR ypl& = 1 TO ysz
IF ypl& > 200 THEN EXIT FOR
FOR xpl& = 1 TO xsz
IF xpl& > 320 THEN EXIT FOR
bpl& = LOF(1) - (ypl& * (3 - (xsz + 3) MOD 4)) - ypl& * xsz + xpl&
GET #1, bpl&, attr
PSET (xpl& - 1, ypl& - 1), attr
NEXT
NEXT
'
'--- Fehlermeldung: Keine 8-Bit-BMP-Datei ---
ELSEIF ftype = 19778 THEN
PRINT "You are trying to load a Bit-Map image"
PRINT "which has been saved in"; bits; "bit format."
PRINT "For coding efficiency, this program"
PRINT "only reads 8 bit files. Please save the"
PRINT "image as a 256 color BMP and try again."
'
'--- Fehlermeldung: Datei nicht vorhanden ---
ELSEIF LOF(1) = 0 THEN
PRINT "You have specified an invalid file name"
PRINT "to be opened. Please verify that your"
PRINT "P$ variable setting is correct."
del = 1 'Datei löschen
'
'--- Fehlermeldung: Datei ist keine BMP-Datei ---
ELSE
PRINT "You are trying to load a non Bit-Map"
PRINT "file. Check to see if your file name is"
PRINT "correct. "
END IF
'
'--- Datei schliessen ---
CLOSE #1
IF del THEN KILL P$
DO: LOOP WHILE INKEY$ = "": SYSTEM
 
Das obige Programm steht im Verzeichnis Progs\ zur Verfügung sowie online unter www.antonis.de/faq/progs/bmp-load.bas .
 
Das Programm eignet sich für 8-Bit-Bitmap-Bilder. Farbtiefen von 24 Bit werden von QB nicht unterstützt. Dazu musst du FreeBASIC oder eine Grafik-Library wie zum Beispiel die AK-Lib benutzen.
 
 

Antwort 7
~~~~~~~~~~~~
[ von Andreas meile ("Dreael",
http://dreael.catty.ch/Deutsch/BASIC-Knowhow-Ecke ) im QB-Forum, 5.2005 ]
 
Wie BMP-Dateien aufgebaut sind und wie man sie von QBasic aus anzeigt, steht in meinem Grundlagen-Artikel
http://dreael.catty.ch/Deutsch/BASIC-Knowhow-Ecke/BilderVerwenden.html
Das A und O ist das Auftreiben der Originalspezifikationen zu einem Dateiformat und dieses dann entsprechend umsetzen.
 
 
 

Antwort 8
~~~~~~~~~~~~
[ von A.K. im QB-Forum, 14.6.2003 ]
 
*** Frage
Ich möchte gerne BMP-Dateien mit einer Größe von maximal 640x480 und einer Farbtiefe von maximal 8 Bit (256 Farben) anzeigen.
 
*** Antwort
Hier das komplette Programm. Ich habe es auch getestet und es funktioniert wunderbar. Du brauchst auch nichts mehr verändern oder dazuschreiben. (ausser dem Dateinamen).
 
CLS
SCREEN 13
'
picx% = 0 'Start-
picy% = 0 'Koordinaten
datei$ = "button.bmp"
'
OPEN datei$ FOR BINARY AS #1
IF LOF(1) = 0 THEN PRINT "Datei ist leer": CLOSE #1: KILL datei$: END
GET #1, 1, version%
IF version% <> 19778 THEN PRINT "kein BMP": END
GET #1, 19, xt%'Breite des Bildes
GET #1, 23, yt%'Höhe des Bildes
GET #1, 29, bpp%'Farbtiefe in Bit
IF bpp% > 8 THEN PRINT "Bild nicht darstellbar":END
'
bmpcolors% = 2 ^ bpp%
bmppal$ = SPACE$(bmpcolors% * 4)
GET #1, 55, bmppal$
'Palette setzen
FOR bmpc% = 0 TO bmpcolors% - 1
OUT &H3C8, bmpc%
f1% = ASC(MID$(bmppal$, bmpc% * 4 + 3, 1)) 'Red
f2% = ASC(MID$(bmppal$, bmpc% * 4 + 2, 1)) 'Green
f3% = ASC(MID$(bmppal$, bmpc% * 4 + 1, 1)) 'Blue
OUT &H3C9, FIX(f1% / 4)
OUT &H3C9, FIX(f2% / 4)
OUT &H3C9, FIX(f3% / 4)
NEXT bmpc%
bmppal$ = ""
'
'End-Koordinaten berechnen
xend% = picx% + xt% - 1
yend% = picy% + yt% - 1
'
'Laenge einer "Daten-Linie" berechnen
bmpbpp% = bpp%
bmpxt% = xt%
IF bmpbpp% = 8 THEN picline$ = SPACE$(bmpxt%): IF LEN(picline$) / 4 <> FIX(LEN(picline$) / 4) THEN picline$ = picline$ + SPACE$(4 - LEN(picline$) MOD 4)
IF bmpbpp% = 4 THEN picline$ = SPACE$(FIX(bmpxt%) / 2): IF LEN(picline$) / 4 <> FIX(LEN(picline$) / 4) THEN picline$ = picline$ + SPACE$(4 - LEN(picline$) MOD 4)
IF bmpbpp% = 1 THEN picline$ = SPACE$(FIX(bmpxt%) / 8): IF LEN(picline$) / 4 <> FIX(LEN(picline$) / 4) THEN picline$ = picline$ + SPACE$(4 - LEN(picline$) MOD 4)
'BMP-Bild malen
'
FOR y% = yend% TO picy% STEP -1
GET #1, , picline$
i% = 1
FOR x% = picx% TO xend%
PSET (x%, y%), ASC(MID$(picline$, i%, 1))
i% = i% + 1
NEXT x%
NEXT y%
picline$ = ""
V
'Datei schliessen
CLOSE #1
 
((Anmerkung Antoni: Bei mir hats nicht funktioniert, vielleicht hatte ich keine 256-Farben.-BMP ))
 
 

Antwort 9
~~~~~~~~~~~~~~~
[ von MATzEN (
mcbrendel*gmx.de ) im QB-Forum, 22.6.2003 ]
 
Mir ist eine Idee gekommen, wie man auf einfache Weise BMPs anzeigen lassen kann.
 
Die Bitmap wird einfach in ein Array kopiert und kann mit PUT ausgegeben werden. Beispiel:
 
IF NOT LadeBMP("bild1.bmp") THEN
PRINT "Fehler beim Verarbeiten der Datei 'bild1.bmp'."
END
END IF
PUT (0, 0), BildData(0), PSET
 
PUT hat einen Nachteil: Das Bild kann nicht über den Rand hinaus angezeigt werden und das Programm bricht ab. Ich habe deshalb eine SUB geschrieben, die die Bilddaten anpasst und dann mit PUT ausgibt. Außerdem lassen sich bestimmte Bereiche auswählen, die ausgegeben werden sollen. Beispiel:
 
Show 0, -20, 0, 100
 
Funktioniert nur mit Screen 13.
Funktioniert mit QBasic v1.0!
 
 
*** Programm für "Lade BMP"
 
FUNCTION LadeBMP (Datei$)
f% = FREEFILE
OPEN Datei$ FOR BINARY AS f%
IF LOF(f%) = 0 THEN
CLOSE f%
KILL Datei$
EXIT FUNCTION
END IF
'
id$ = "BM"
GET f, 1, id$
GET f, 11, offset&
GET f, 19, breite&
GET f, 23, hoehe&
GET f, 29, bits%
'
IF id$ <> "BM" OR bits% <> 8 OR (breite& * hoehe& + 1) \ 2 + 2 > 32002 THEN
CLOSE f%
EXIT FUNCTION
END IF
'
SEEK f, offset& + 1
'
BildData(0) = breite& * 8
BildData(1) = hoehe&
'
DEF SEG = VARSEG(BildData(2))
o& = VARPTR(BildData(2)) + hoehe& * breite&
'
line$ = SPACE$(((breite& - 1) OR 3) + 1)
FOR y& = hoehe& - 1 TO 0 STEP -1
o& = o& - breite&
GET f%, , line$
FOR x& = 0 TO breite& - 1
POKE o& + x&, ASC(MID$(line$, x& + 1, 1))
NEXT
NEXT
'
CLOSE f%
LadeBMP = -1
END FUNCTION
 
 

Antwort 10
~~~~~~~~~~~~~~
[ von MATzEN (
mcbrendel*gmx.de ) im QB-Forum, 22.6.2003 ]

Anbei mein Programm Show.BAS zum Anzeigen von BMPs:
 
SUB Show (x, y, t, h)
'
breite = BildData(0) / 8
hoehe = BildData(1)
'
IF x < 0 OR x + breite > 320 OR breite <= 0 THEN EXIT SUB
'
IF t > 0 THEN
IF t >= hoehe THEN EXIT SUB
hoehe = hoehe - t
offset = offset + (1& * t * breite) \ 2
y = y + t
END IF
'
IF h > 0 AND h < hoehe THEN hoehe = h
'
IF y < 0 THEN
hoehe = hoehe + y
IF hoehe <= 0 THEN EXIT SUB
offset = offset + (-y * breite) \ 2
y = 0
END IF
'
IF y + hoehe > 200 THEN
hoehe = 200 - y
IF hoehe <= 0 THEN EXIT SUB
END IF
'
a1 = BildData(offset)
a2 = BildData(offset + 1)
BildData(offset) = breite * 8
BildData(offset + 1) = hoehe
PUT (x, y), BildData(offset), PSET
'
BildData(offset) = a1
BildData(offset + 1) = a2
END SUB
 
 
 

Antwort 11
~~~~~~~~~~~~~~~
[ von Lebostein (
Lebostein*gmx.de ) im QB-Forum, 16.5.2003 ]
 
Anbei mein Programm zum Anzeigen von BMP-Grafiken. Ich hoffe, Du verstehst das Prinzip. Der Code ist sehr langsam:
'Umschalten in 256-Farben-Modus
SCREEN 13
'
'Variable zum Auslesen eines Bytes als String
byte$ = SPACE$(1)
'
'Datei öffnen
OPEN "scabb.bmp" FOR BINARY AS #1
'
'Header der Bitmap auslesen (Ausser picx und picy sind die Variablen ohne Bedeutung)
GET #1, , init% '2 Byte: Kürzel "BM"
GET #1, , length& '4 Byte: Dateilänge in Bytes
GET #1, , reserv& '4 Byte: reserviert
GET #1, , inidat& '4 Byte: Anzahl der Bytes (ohne Bilddaten)
GET #1, , wininf& '4 Byte: Bitmapversion
GET #1, , picx& '4 Byte: Breite der Bitmap in Pixel
GET #1, , picy& '4 Byte: Höhe der Bitmap in Pixel
GET #1, , plane% '2 Byte: Anzahl der Ebenen
GET #1, , colorbit% '2 Byte: Farbtiefe
GET #1, , compr& '4 Byte: Kompressionsinfo
GET #1, , picdat& '4 Byte: Anzahl der Bytes (nur Bilddaten)
GET #1, , dpmx& '4 Byte: DPI in Breitenrichtung
GET #1, , dpmy& '4 Byte: DPI in Höhenrichtung
GET #1, , uco& '4 Byte: Anzahl der genutzten Farben
GET #1, , ico& '4 Byte: Anzahl der wichtigen Farben
'
'Palette der Bitmap auslesen (Farbwerte in Qbasic nur von 0 bis 63)
FOR farbe% = 0 TO 255
GET #1, , byte$ 'Auslesen des blauen Anteils (1 Byte)
b% = INT(ASC(byte$) / 4) 'Farbwert durch 4 teilen
GET #1, , byte$ 'Auslesen des grünen Anteils (1 Byte)
g% = INT(ASC(byte$) / 4) 'Farbwert durch 4 teilen
GET #1, , byte$ 'Auslesen des roten Anteils (1 Byte)
r% = INT(ASC(byte$) / 4) 'Farbwert durch 4 teilen
GET #1, , byte$ 'Auslesen des leeren Reservebytes (1 Byte)
'Farbe übergeben, deren Palettenwert geändert werden soll:
OUT &H3C8, farbe%
'Farbwerte in Reihenfolge rot, grün und blau übergeben:
OUT &H3C9, r%
OUT &H3C9, g%
OUT &H3C9, b%
NEXT farbe%
'
'Bilddaten der Bitmap auslesen und auf dem Bildschirmspeicher ausgeben
DEF SEG = &HA000
FOR y& = picy& - 1 TO 0 STEP -1
FOR x& = 0 TO picx& - 1
GET #1, , byte$
POKE (y& * 320) + x&, ASC(byte$)
NEXT x&
NEXT y&
'
'Datei wieder schließen
CLOSE #1
'
'Auf Taste warten
SLEEP

 

Antwort 12
~~~~~~~~~
[ von Andre Klein ("A.K."; webmaster*iconsoft.de) im QB-Forum, 28.4.2003 ]
 
*** Problem
Ich will eine eigene Routine zum Laden von 256-farbigen BMP-Bitmaps in SCREEN 13 schreiben. Wie erzeuge ich dabei die richtigen Farben durch eine korrekte Belegung der Palette?
 
*** Lösung
Im SCREEN 13 gibt es insgesammt 256 Speicherplätze (Farbcodes 0-255) für Farben. Jeder dieser Speicherplätze zeigt auf einen Eintrag in einer Tabelle in der die ROT-, GRÜN- und BLAU-Intensitäten stehen ( -> RGB ) Diese Tabelle wird Palette genannt!
 
Jedes BMP-Bild hat aber eine eigene Palette die vorher erst gesetzt werden muß damit das Bild normal aussieht. Das macht man so:
 
OPEN "test.bmp" ´FOR BINARY AS #1
GET #1, 29, bmpbpp% 'Bits-Per-Pixel
bmpcolors% = 2 ^ bmpbpp%
bmppal$ = SPACE$(bmpcolors% * 4)
GET #1, 55, bmppal$ 'Position der Palette
'Palette setzen
FOR bmpc% = 0 TO bmpcolors% - 1
OUT &H3C8, bmpc%
f1% = ASC(MID$(bmppal$, bmpc% * 4 + 3, 1))'Red
f2% = ASC(MID$(bmppal$, bmpc% * 4 + 2, 1))'Green
f3% = ASC(MID$(bmppal$, bmpc% * 4 + 1, 1))'Blue
OUT &H3C9, FIX(f1% / 4)
OUT &H3C9, FIX(f2% / 4)
OUT &H3C9, FIX(f3% / 4)
NEXT bmpc%
bmppal$ = "
 
Damit ist die Palette gesetzt
Breite und Höhe:
GET #1, 19, bmpxt%
GET #1, 23, bmpyt%
zu Bits-Per-Pixel:
1 = 2 Farben (Bit7 = 1. Pixel, Bit6=2.Pixel...)
4 = 16 Farben (Bit 4-7 = 1. Pixel, Bit 0-3 = 2...)
8 = 256 Farben (1B/Pixel)
 
Alles was darüber ist benutzt KEINE PALETTE, z.B. 24Bit (16777216 Farben). Dafür brauchst Du aber entweder ein Prog das die Farben an die Palette anpasst oder Du arbeitest mit SVGA-LIB's (ich benutz meine eigene :-))
 
Die Bits per Pixel stehen immer übrigens immer im Dateikopf an Position 29 eines BMP's und jedes BMP hat immer seine eigene Palette also seine individuellen Farben.
 
Kleiner Tip: um mehr über Organisationen von Paletten zu erfahren kannst Du ja mal mit dem PALETTE-Befehl von QB ein bischen rumspielen.
 
Aber wenn Du ein Mal-Prog hast, kannst Du z.B. mehrere BMP's malen die immer die gleiche Palette haben(macht aber wenig Sinn!).
 
 

Antwort 13
~~~~~~~~~~~~~~~~~
[ von Schlotzz im QB-Forum, 9.7.2002 ]
 

Frage:
Gibt es ein Ladeprogramm für irgendwelche Graphikdateitypen (bmp, jpg ...) der schnell arbeitet (ich muss in einem Rutsch immer etwa 100 Bilder laden und in ein Array kopieren) und das Seitenverhältnis der Bilder nicht verzerrt?
 
 

Antwort:
Ich habe hier einen wunderbaren BMP-Loader von Thomas Nyberg, der mit Interrupts arbeitet. Den kannst Du bestimmt ganz einfach an Deine Bedürfnisse anppassen.:
 
'*****************************************************************************
' BMPLOAD3.BAS = BMP loader/maker
' ============ Anzeigeprogramm fuer BMP-Grafiken "BMP-Loader")
'
' *** Deutsche Beschreibung
' Dieses Q(uick)Basic-Programm zeigt BMP-Grafiken an. Die BMP-Datei muss
' die Groesse 320 x 200 x 256 Farben haben. Zum Anzeigen anderer BMPs kann
' das Programm leicht angepasst werden. Das programm arbeitet sehr schnell
' und kommt ganz ohne Assemblerbefehle aus. es verwendet den Interrupt &h21.
' Weil der Befehl CALL INTERRUPTX verwendet wird, ist das Programm nur unter
' QuickBASIC, nicht unter QBasic lauffaehig, und QuickBASIC muss mit der
' Option "/L" gestartet werden, also z.B. mit "QB.EXE /L BMPLOAD3.BAS" .
'
' *** English-language description
' A little program that loads a BMP-file in less than 0.2 seconds, then
' you can save the image into a new BMP-file and that takes about 0.2s!!
' It doesn't use any assembler at all, instead it uses interrupts, so if
' you don't know what that is then don't try to modify the code.
'
' This program doesn't check the format of the BMP-file because I think
' it's alot easier to read and understand it if no format check is done.
' If you want that it's not hard to write it yourself.
' Because of this the BMP-file must be 320*200*256, there shouldn't be
' difficult to modify the code so that it opens all kinds of sizes.
' If I get the time the next few weeks (alot of homework, you know:) I will
' do that myself.
'
' The format of the BMP-files has been taken from a file called BMP.BAS,
' unfortunatly I have lost the authors name but I give all credits for the
' format of the headers to him (or her).
'
' If you use parts or the whole program or ideas based on this code please
' give me credits. This program may not be used in any kind of non-freeware
' programs without my knowledge (If you or anyone else earns money selling
' programs that uses parts or the whole program or ideas based on this code)
'
' It should be very easy to change this program so that you can open TGA or
' any other format saved like the BMP (64000 pixels in a row).
'
' If you have any questions or improvements on this code please send them to:
' thomas.nyberg*usa.net
'
' IMPORTANT!!
' This program is used at your own risc. I, Thomas Nyberg, does not take
' any responsibility if any information, data, files or any other kind
' of software or hardware is damaged or destroyed in any way.
' I can't garantee that this code is safe but I think it should be, therefore
' beginners should not try to modify or use this code in their programs.
' Please excuse my english, it's very late :)
'
' (c) by Thomas Nyberg (thomas.nyberg*usa.net)
'*****************************************************************************
'
DECLARE SUB savebmp (filename$)
DECLARE SUB loadbmp (filename$)
'
'$INCLUDE: 'qb.bi' 'Needs QB.QLB/LIB to be loaded
'
'The header:
'
TYPE bmpinfo 'what it should say for a 320*200*256 bmp
bm AS STRING * 2 'bm
size AS LONG 'wid*hei+1078= 65078
r1 AS INTEGER '0
r2 AS INTEGER '0
offsdata AS LONG '1078
hsize AS LONG '40
wid AS LONG '320
hei AS LONG '200
planes AS INTEGER '1
bpp AS INTEGER '8
comp AS LONG '0
isize AS LONG '64000
xpm AS LONG '3790
ypm AS LONG '3780
colus AS LONG '0
impcol AS LONG '0
pal AS STRING * 1024 'blue, green, red, 0
END TYPE
'
DIM SHARED bmpheader AS bmpinfo
DIM SHARED regs AS RegTypeX
'
SCREEN 13
'
t = TIMER 'Time how long it takes
loadbmp "c:\tmp\thomas.bmp" 'loads a BMP-file
'savebmp "test.bmp" 'Saves a BMP-file
PRINT TIMER - t'If you can't figure this one out...
DEFINT A-Z
'
SUB loadbmp (filename$)
'
'Load the header
OPEN filename$ FOR BINARY AS #1
GET #1, , bmpheader 'read it
CLOSE #1
'
'Load the palette
OUT &H3C8, 0
FOR I = 1 TO 1024 STEP 4
b% = ASC(MID$(bmpheader.pal, I, 1)) \ 4 'blue
g% = ASC(MID$(bmpheader.pal, I + 1, 1)) \ 4 'green
r% = ASC(MID$(bmpheader.pal, I + 2, 1)) \ 4 'red
OUT &H3C9, r%
OUT &H3C9, g%
OUT &H3C9, b%
NEXT
'
filename$ = filename$ + CHR$(0) 'filename must be ASCIIZ (zero terminated)
'
'open the file
regs.ax = &H3D00
regs.ds = VARSEG(filename$) 'segment of name
regs.dx = SADD(filename$) 'offset of name
CALL INTERRUPTX(&H21, regs, regs)
regs.bx = regs.ax 'filehandle
'
'move filepointer to &h436 in the file
regs.ax = &H4200
regs.cx = 0
regs.dx = &H436
CALL INTERRUPTX(&H21, regs, regs)
'
'Read and display the file
FOR y = bmpheader.hei - 1 TO 0 STEP -1
regs.ax = &H3F00
regs.cx = 320 'widht of the file
regs.ds = &HA000 'screen 13's segment
regs.dx = VAL("&H" + HEX$(y * 320&)) 'Has to do wiht QB integers
CALL INTERRUPTX(&H21, regs, regs)
NEXT
'
'close it
regs.ax = &H3E00
CALL INTERRUPTX(&H21, regs, regs)
filename$ = LEFT$(filename$, LEN(filename$) - 1) 'resore the filename
END SUB
'
SUB savebmp (filename$)
'read the palette
OUT &H3C7, 0
FOR I% = 0 TO 255
r% = INP(&H3C9) * 4
g% = INP(&H3C9) * 4
b% = INP(&H3C9) * 4
a$ = a$ + CHR$(b%) + CHR$(g%) + CHR$(r%) + CHR$(0)
NEXT
'
'create the header
bmpheader.bm = "BM"
bmpheader.size = 65078
bmpheader.r1 = 0
bmpheader.r2 = 0
bmpheader.offsdata = 1078
bmpheader.hsize = 40
bmpheader.wid = 320
bmpheader.hei = 200
bmpheader.planes = 1
bmpheader.bpp = 8
bmpheader.comp = 0
bmpheader.isize = 64000
bmpheader.xpm = 3790
bmpheader.ypm = 3780
bmpheader.colus = 0
bmpheader.impcol = 0
bmpheader.pal = a$
'
'save the header
OPEN filename$ FOR BINARY AS #1
IF LOF(1) > 0 THEN 'file already exist
CLOSE #1
KILL filename$ 'delete the file and reopen it
OPEN filename$ FOR BINARY AS #1
END IF
PUT #1, , bmpheader 'write the header
CLOSE #1
'
filename$ = filename$ + CHR$(0) 'filename must be ASCIIZ (zero terminated)
'
'opens the file
regs.ax = &H3D01
regs.ds = VARSEG(filename$) 'segment of filename
regs.dx = SADD(filename$) 'offset of filename
CALL INTERRUPTX(&H21, regs, regs)
regs.bx = regs.ax 'filehandle
'
'move the filepointer
regs.ax = &H4200
regs.cx = 0
regs.dx = &H436
CALL INTERRUPTX(&H21, regs, regs)
'
'saves the screen into the file
FOR y% = 199 TO 0 STEP -1
regs.ax = &H4000
regs.cx = 320 'number of bytes to write
regs.ds = &HA000 'screen 13's segment
regs.dx = VAL("&H" + HEX$(y% * 320&)) 'Has to do with QB integers
CALL INTERRUPTX(&H21, regs, regs)
NEXT
'
'close the file
regs.ax = &H3E00
CALL INTERRUPTX(&H21, regs, regs)
'
filename$ = LEFT$(filename$, LEN(filename$) - 1) 'restore the filename
END SUB
 
Das obige Programm und das Beispiel-Bild Thomas.bmp stehen im Verzeichnis Progs\ zur Verfügung sowie online unter www.antonis.de/faq/progs/bmpload3.bas www.antonis.de/faq/progs/thomas.bmp .
 
 
 

Answer 14
~~~~~~~~~~~~~~~~~
[ by -/\lipha (
aliphax*hotmail.com - www.geocities.com/aliphax ) ]
 
 

256-color Bitmap loading tutorial..
 
To write a 256-color bitmap loader, or any graphics file loader, you need to know how to do four things:
 

1.) OPEN the file FOR BINARY and read the bytes in the file.

2.) Translate those bytes into the image on the screen (what this tutorial will cover).

3.) Draw pixels on the screen (obviously) or write them someplace else, perhaps a GET/PUT array.

4.) Change your program's palette to match the BMP's.
 
If you don't know how to do 1 and 3 then you should probably find out how.
 
Alright, like most file formats, there is a header with various pieces of information in it. The easiest way to read this header is to make a user-defined type (UDT) to match it:
 
TYPE BMPheader
fileType AS STRING * 2 'equals "BM" to identify this as a BMP
fileSize AS LONG 'the size of this file (equals LOF())
reserved AS LONG 'not used (perhaps in future)
offset AS LONG 'the offset into the file of the image data
headerSize AS LONG 'length of rest of header (always 40)
imgWidth AS LONG 'width of BMP in pixels
imgHeight AS LONG 'height in pixels
planes AS INTEGER 'number of color planes (should be 1)
BBP AS INTEGER 'bits per pixel (8 for 256 colors)
compression AS LONG'compression type (0 is none)
sizeImage AS LONG 'size of the image in bytes
XPPM AS LONG 'Pixels Per Meter on x-axis
YPPM AS LONG 'Pixels Per Meter on y-axis
ColorsUsed AS LONG 'number of colors used in bitmap
CImportant AS LONG 'number of "important" colors
END TYPE
 
The fields in the header that we will probably only want to worry about are:

fileType: so we know we have a BitMap file (making sure other fields, such as fileSize and headerSize are correct values would further make sure)
imgWidth and imgHeight: for obvious reasons
BBP: make sure that this is 8 for 256 colors bitmaps
compression: make sure this is 0, since this loader isn't equipped to handle compression
 
So here is the beginning of our loader:
 
TYPE BMPheader
'insert the fields from above
END TYPE
'
DECLARE SUB BMPload (filename$)
'
SUB BMPload (filename$)
DIM header AS BMPheader
'
BMP = FREEFILE
OPEN filename$ FOR BINARY AS #BMP
'
GET #BMP, 1, header 'get the header information
'
IF header.fileType <> "BM" THEN PRINT "Not a BMP": EXIT SUB
IF header.BBP <> 8 THEN PRINT "Not a 256 color BMP": EXIT SUB
IF header.compression <> 0 THEN PRINT "Doesn't handle compressed BMPs": EXIT SUB
'
'more code added later
CLOSE #BMP
END SUB
 
BMP loading is pretty simple and straight-forward, which is probably why there are so many BMP loaders compared to GIFs or JPEGs (especially since JPEG is 24-bit colors only). Following the header is the palette information, then the graphics data.
Now, each color attribute in the palette is four bytes long, one for the blue intensity, one for green, one for red, and one for "reserved". So that means the palette is 256 * 4 = 1024 bytes long. Why the reserved byte? Probably just to make each color even at four bytes long.
 
So it is blue, green, red, then reserved. Note that the RGB intensities range from 0 to 255, while the vga palette registers only accept 0 to 63. So, we'll have to divide by four to get the values we want. As for actually changing your program's palette, you can use which ever of the two methods you are used to:
 
PALETTE colorToChange, red + green * 256 + blue * 65536
 
or, which I prefer:
 
OUT &H3C8, colorToChange
OUT &H3C9, red
OUT &H3C9, green
OUT &H3C9, blue
 
(more information on this can be obtained at:
www.network54.com/Hide/Forum/message?forumid=171757&messageid=1010705558 )
 
Ok, so for actually changing the palette:
 
palette$ = SPACE$(1024) 'make a string big enough to hold the whole palette
GET #BMP, , palette$ 'the , , will read where we left off (after the header)
'
locInString = 1 'what character in the string the current color starts at
'
FOR colour = 0 TO 255
blue = ASC(MID$(palette$, locInString, 1))
green = ASC(MID$(palette$, locInString + 1, 1))
red = ASC(MID$(palette$, locInString + 2, 1))
'
OUT &H3C8, colour
OUT &H3C9, red \ 4 'write RGB intensities to vga port
OUT &H3C9, green \ 4 'the '\ 4' is to make it 0 to 63 instead of 0 to 255
OUT &H3C9, blue \ 4
'
locInString = locInString + 4 'point to next color
NEXT colour
 
Notice that I read the whole palette into a string at once and then accessed the string, instead of repeatively reading from the file. Reading from the file in chunks is A LOT faster than one byte at a time, though QB's string operations aren't very fast, so I don't know how much advantage you get here. [If you know how to use PEEK, that would help with the speed instead of using ASC(MID$())]
 
Reading the bytes from the file and displaying them on the screen is quite straight-forward, since there is no compression at all. (that's what winzip is for) ;-) There are two things to note however:
 

1.) The bitmap starts at the lower-left-hand corner, NOT the upper-left. You still read a row at a time, but the y value would be decremented instead of incremented.

2.) Again, BMPs like to be aligned to multiples of four. If a row length is not divisable by four, it is padded to the nearest fourth byte.
 
The easiest way I can think of to handle this padding is to first integer-divide by four then multiply by four. Of course you would need to round up to the nearest multiple of four, so you would add three first. (think about it: 5 + 3 = 8 \ 4 = 2 * 4 = 8; 7 + 3 = 10 \ 4 = 2 * 4 = 8):
 
rowLength = ((header.imgWidth + 3) \ 4) * 4
 
Again, we will read from the file in chunks. We'll read a row at a time:
 
FOR y = header.imgHeight - 1 TO 0 STEP -1
aRow$ = SPACE$(rowLength)
GET #BMP, , aRow$
'
FOR x = 0 TO header.imgWidth - 1
PSET (x, y), ASC(MID$(aRow$, x + 1, 1))
NEXT x
'
NEXT y
 
(Again, to speed this up, you'll want to use PEEK/POKE here, either for reading from the string or writing to the screen [probably not both.. switching DEF SEGs may slow it down])
 
Here is the whole program then:
 
TYPE BMPheader
fileType AS STRING * 2 'equals "BM" to identify this as a BMP
fileSize AS LONG 'the size of this file (equals LOF())
reserved AS LONG 'not used (perhaps in future)
offset AS LONG 'the offset into the file of the image data
headerSize AS LONG 'length of rest of header (always 40)
imgWidth AS LONG 'width of BMP in pixels
imgHeight AS LONG 'height in pixels
planes AS INTEGER 'number of color planes (should be 1)
BBP AS INTEGER 'bits per pixel (8 for 256 colors)
compression AS LONG'compression type (0 is none)
sizeImage AS LONG 'size of the image in bytes
XPPM AS LONG 'Pixels Per Meter on x-axis
YPPM AS LONG 'Pixels Per Meter on y-axis
ColorsUsed AS LONG 'number of colors used in bitmap
CImportant AS LONG 'number of "important" colors
END TYPE
'
DECLARE SUB BMPload (filename$)
'
SUB BMPload (filename$)
DIM header AS BMPheader
'
BMP = FREEFILE
OPEN filename$ FOR BINARY AS #BMP
'
GET #BMP, 1, header 'get the header information
'
IF header.fileType <> "BM" THEN PRINT "Not a BMP": EXIT SUB
IF header.BBP <> 8 THEN PRINT "Not a 256 color BMP": EXIT SUB
IF header.compression <> 0 THEN PRINT "Doesn't handle compressed BMPs": EXIT SUB
'
palette$ = SPACE$(1024) 'make a string big enough to hold the whole palette
GET #BMP, , palette$ 'the , , will read where we left off (after the header)
'
locInString = 1 'what character in the string the current color starts at
'
FOR colour = 0 TO 255
blue = ASC(MID$(palette$, locInString, 1))
green = ASC(MID$(palette$, locInString + 1, 1))
red = ASC(MID$(palette$, locInString + 2, 1))
'
OUT &H3C8, colour
OUT &H3C9, red \ 4 'write RGB intensities to vga port
OUT &H3C9, green \ 4 'the '\ 4' is to make it 0 to 63 instead of 0 to 255
OUT &H3C9, blue \ 4
'
locInString = locInString + 4 'point to next color
NEXT colour
'
'
rowLength = ((header.imgWidth + 3) \ 4) * 4
'
FOR y = header.imgHeight - 1 TO 0 STEP -1
aRow$ = SPACE$(rowLength)
GET #BMP, , aRow$
'
FOR x = 0 TO header.imgWidth - 1
PSET (x, y), ASC(MID$(aRow$, x + 1, 1))
NEXT x
'
NEXT y
'
CLOSE #BMP
END SUB
 
Information on the 256-color BMP format was obtained from:
www.brackeen.com/home/vga/bitmaps.html . I don't need any credit for this.. though I don't know if brackeen wants some...
 

*** Supplement
... and here's an example of using it:

after:
 
DECLARE SUB BMPload (filename$)
 
add these four lines:
 
SCREEN 13
BMPload "C:\myfolder\mybmp.bmp"
SLEEP 'wait for a keypress
END
 
 

Answer 15
~~~~~~~~~~~~~~~~
[ from Wouter Bergmann Tiest's BASIC-FAQ -
www.fys.ruu.nl/~bergmann/basic-faq.html ]
 

How To Display A GIF-File?
 
This is the source code for a GIF loader by a Rich Geldreich..
 
'
'DEGIF6.BAS - No frills GIF decoder for the VGA's 320x200x256 mode.
'By Rich Geldreich 1993 (Public domain, use as you wish.)
'This version should properly decode all LZW encoded images in
'GIF image files. I've finally added GIF89a and local colormap
'support, so it more closely follows the GIF specification. It
'still doesn't support the entire GIF89a specification, but it'll
'show most GIF files fine.
'The GIF decoding speed of this program isn't great, but I'd say
'for an all QB/PDS decoder it's not bad!
'Note: This program does not stop decoding the GIF image after the
'rest of the scanlines become invisible! This happens with images
'larger than the 320x200 screen. So if the program seems to be
'just sitting there, accessing your hard disk, don't worry...
'It'll beep when it's done.
DEFINT A-Z
'Prefix() and Suffix() hold the LZW phrase dictionary.
'OutStack() is used as a decoding stack.
'ShiftOut() as a power of two table used to quickly retrieve the LZW
'multibit codes.
DIM Prefix(4095), Suffix(4095), OutStack(4095), ShiftOut(8)
'
'The following line is for the QB environment(slow).
DIM YBase AS LONG, Powersof2(11) AS LONG, WorkCode AS LONG
'For a little more speed, unremark the next line and remark the one
'above, before you compile... You'll get an overflow error if the
'following line is used in the QB environment, so change it back.
'DIM YBase AS INTEGER, Powersof2(11) AS INTEGER, WorkCode AS INTEGER
'
'Precalculate power of two tables for fast shifts.
FOR A = 0 TO 8: ShiftOut(8 - A) = 2 ^ A: NEXT
FOR A = 0 TO 11: Powersof2(A) = 2 ^ A: NEXT
'
'Get GIF filename.
A$ = COMMAND$: IF A$ = "" THEN INPUT "GIF file"; A$: IF A$ = "" THEN END
'Add GIF extension if the given filename doesn't have one.
FOR A = LEN(A$) TO 1 STEP -1
SELECT CASE MID$(A$, A, 1)
CASE "\", ":": EXIT FOR
CASE ".": Extension = -1: EXIT FOR
END SELECT
NEXT
IF Extension = 0 THEN A$ = A$ + ".GIF"
'
'Open file for input so QB stops with an error if it doesn't exist.
OPEN A$ FOR INPUT AS #1: CLOSE #1
OPEN A$ FOR BINARY AS #1
'
'Check to see if GIF file. Ignore GIF version number.
A$ = " ": GET #1, , A$
IF LEFT$(A$, 3) <> "GIF" THEN PRINT "Not a GIF file.": END
'
'Get logical screen's X and Y resolution.
GET #1, , TotalX: GET #1, , TotalY: GOSUB GetByte
'Calculate number of colors and find out if a global palette exists.
NumColors = 2 ^ ((A AND 7) + 1): NoPalette = (A AND 128) = 0
'Retrieve background color.
GOSUB GetByte: Background = A
'
'Get aspect ratio and ignore it.
GOSUB GetByte
'
'Retrieve global palette if it exists.
IF NoPalette = 0 THEN P$ = SPACE$(NumColors * 3): GET #1, , P$
'
DO 'Image decode loop
'
'Skip by any GIF extensions.
'(With a few modifications this code could also fetch comments.)
DO
'Skip by any zeros at end of image (why must I do this? the
'GIF spec never mentioned it)
DO
IF EOF(1) THEN GOTO AllDone 'if at end of file, exit
GOSUB GetByte
LOOP WHILE A = 0 'loop while byte fetched is zero
SELECT CASE A
CASE 44 'We've found an image descriptor!
EXIT DO
CASE 59 'GIF trailer, stop decoding.
GOTO AllDone
CASE IS <> 33
PRINT "Unknown GIF extension type.": END
END SELECT
'Skip by blocked extension data.
GOSUB GetByte
DO: GOSUB GetByte: A$ = SPACE$(A): GET #1, , A$: LOOP UNTIL A = 0
LOOP
'Get image's start coordinates and size.
GET #1, , XStart: GET #1, , YStart: GET #1, , XLength: GET #1, , YLength
XEnd = XStart + XLength: YEnd = YStart + YLength
'
'Check for local colormap, and fetch it if it exists.
GOSUB GetByte
IF (A AND 128) THEN
NoPalette = 0
NumColors = 2 ^ ((A AND 7) + 1)
P$ = SPACE$(NumColors * 3): GET #1, , P$
END IF
'
'Check for interlaced image.
Interlaced = (A AND 64) > 0: PassNumber = 0: PassStep = 8
'
'Get LZW starting code size.
GOSUB GetByte
'
'Calculate clear code, end of stream code, and first free LZW code.
ClearCode = 2 ^ A
EOSCode = ClearCode + 1
FirstCode = ClearCode + 2: NextCode = FirstCode
StartCodeSize = A + 1: CodeSize = StartCodeSize
'
'Find maximum code for the current code size.
StartMaxCode = 2 ^ (A + 1) - 1: MaxCode = StartMaxCode
'
BitsIn = 0: BlockSize = 0: BlockPointer = 1
'
X = XStart: y = YStart: YBase = y * 320&
'
'Set screen 13 in not set yet.
IF FirstTime = 0 THEN
'Go to VGA mode 13 (320x200x256).
SCREEN 13: DEF SEG = &HA000
END IF
'
'Set palette, if there was one.
IF NoPalette = 0 THEN
'Use OUTs for speed.
OUT &H3C8, 0
FOR A = 1 TO NumColors * 3: OUT &H3C9, ASC(MID$(P$, A, 1)) \ 4: NEXT
'Save palette of image to disk.
'OPEN "pal." FOR BINARY AS #2: PUT #2, , P$: CLOSE #2
END IF
'
IF FirstTime = 0 THEN
'Clear entire screen to background color. This isn't
'done until the image's palette is set, to avoid flicker
'on some GIFs.
LINE (0, 0)-(319, 199), Background, BF
FirstTime = -1
END IF
'
'Decode LZW data stream to screen.
DO
'Retrieve one LZW code.
GOSUB GetCode
'Is it an end of stream code?
IF Code <> EOSCode THEN
'Is it a clear code? (The clear code resets the sliding
'dictionary - it *should* be the first LZW code present in
'the data stream.)
IF Code = ClearCode THEN
NextCode = FirstCode
CodeSize = StartCodeSize
MaxCode = StartMaxCode
DO: GOSUB GetCode: LOOP WHILE Code = ClearCode
IF Code = EOSCode THEN GOTO ImageDone
LastCode = Code: LastPixel = Code
IF X < 320 AND y < 200 THEN POKE X + YBase, LastPixel
X = X + 1: IF X = XEnd THEN GOSUB NextScanLine
ELSE
CurCode = Code: StackPointer = 0
'Have we entered this code into the dictionary yet?
IF Code >= NextCode THEN
IF Code > NextCode THEN GOTO AllDone 'Bad GIF if this happens.
'mimick last code if we haven't entered the requested
'code into the dictionary yet
CurCode = LastCode
OutStack(StackPointer) = LastPixel
StackPointer = StackPointer + 1
END IF
'Recursively get each character of the string.
'Since we get the characters in reverse, "push" them
'onto a stack so we can "pop" them off later.
'Hint: There is another, much faster way to accomplish
'this that doesn't involve a decoding stack at all...
DO WHILE CurCode >= FirstCode
OutStack(StackPointer) = Suffix(CurCode)
StackPointer = StackPointer + 1
CurCode = Prefix(CurCode)
LOOP
'
LastPixel = CurCode
IF X < 320 AND y < 200 THEN POKE X + YBase, LastPixel
X = X + 1: IF X = XEnd THEN GOSUB NextScanLine
'
'"Pop" each character onto the display.
FOR A = StackPointer - 1 TO 0 STEP -1
IF X < 320 AND y < 200 THEN POKE X + YBase, OutStack(A)
X = X + 1: IF X = XEnd THEN GOSUB NextScanLine
NEXT
'
'Can we put this new string into our dictionary? (Some GIF
'encoders will wait a bit when the dictionary is full
'before sending a clear code- this increases compression
'because the dictionary's contents are thrown away less
'often.)
IF NextCode < 4096 THEN
'Store new string in the dictionary for later use.
Prefix(NextCode) = LastCode
Suffix(NextCode) = LastPixel
NextCode = NextCode + 1
'Time to increase the LZW code size?
IF (NextCode > MaxCode) AND (CodeSize < 12) THEN
CodeSize = CodeSize + 1
MaxCode = MaxCode * 2 + 1
END IF
END IF
LastCode = Code
END IF
END IF
LOOP UNTIL Code = EOSCode
ImageDone:
'
LOOP
'
AllDone:
'
 
 
 
 
 
'Save image and palette to BSAVE file.
'DEF SEG = &HA000
'OUT &H3C7, 0
'FOR a = 0 TO 767
' POKE a + 64000, INP(&H3C9)
'NEXT
'BSAVE "pic.bas", 0, 64768
'
'Load images saved with the above code with this:
'DEF SEG= &HA000
'BLOAD "Pic.Bas"
'OUT &H3C8, 0
'FOR a = 0 To 767
' OUT &H3C9, Peek(a+ 64000)
'NEXT
'
BEEP: DO: LOOP WHILE INKEY$ <> "": DO: LOOP UNTIL INKEY$ <> ""
END
'
'Slowly reads one byte from the GIF file...
GetByte: A$ = " ": GET #1, , A$: A = ASC(A$): RETURN
'
'Moves down one scanline. If the GIF is interlaced, then the number
'of scanlines skipped is based on the current pass.
NextScanLine:
IF Interlaced THEN
y = y + PassStep
IF y >= YEnd THEN
PassNumber = PassNumber + 1
SELECT CASE PassNumber
CASE 1: y = 4: PassStep = 8
CASE 2: y = 2: PassStep = 4
CASE 3: y = 1: PassStep = 2
END SELECT
END IF
ELSE
y = y + 1
END IF
X = XStart: YBase = y * 320&
RETURN
'
'Reads a multibit code from the data stream.
GetCode:
WorkCode = LastChar \ ShiftOut(BitsIn)
'Loop while more bits are needed.
DO WHILE CodeSize > BitsIn
'Reads a byte from the LZW data stream. Since the data stream is
'blocked, a check is performed for the end of the current block
'before each byte is fetched.
IF BlockPointer > BlockSize THEN
'Retrieve block's length
GOSUB GetByte: BlockSize = A
A$ = SPACE$(BlockSize): GET #1, , A$
BlockPointer = 1
END IF
'Yuck, ASC() and MID$() aren't that fast.
LastChar = ASC(MID$(A$, BlockPointer, 1))
BlockPointer = BlockPointer + 1
'Append 8 more bits to the input buffer
WorkCode = WorkCode OR LastChar * Powersof2(BitsIn)
BitsIn = BitsIn + 8
LOOP
'Take away x number of bits.
BitsIn = BitsIn - CodeSize
'Return code to caller.
Code = WorkCode AND MaxCode
RETURN

[ The QBasic-MonsterFAQ --- Start Page: www.antonis.de/faq ]