amiga-news ENGLISH VERSION
.
Links| Forum| Kommentare| News melden
.
Chat| Umfragen| Newsticker| Archiv
.

amiga-news.de Forum > Programmierung > Fensterinhalt mit Datatypes speichern [ - Suche - Neue Beiträge - Registrieren - Login - ]

-1- [ - Beitrag schreiben - ]

03.09.2004, 15:32 Uhr

Mad_Dog
Posts: 1944
Nutzer
Ich möchte in einem Programm den Fensterinhalt mittels Datatypes speichern. Dazu habe ich mir folgenden Code gebastelt:

code:
struct BitMap *copy_bitmap (struct BitMap *oldbm)
{
   struct BitMap *newbm;
   long w,h;

   if (newbm = AllocBitMap (w = GetBitMapAttr(oldbm,BMA_WIDTH),
                            h = GetBitMapAttr(oldbm,BMA_HEIGHT),
                            GetBitMapAttr(oldbm,BMA_DEPTH),
                            GetBitMapAttr(oldbm,BMA_FLAGS),
                            NULL))
                {
                  BltBitMap (oldbm,0,0,newbm,0,0,w,h,0x0c0,0xff,NULL);
                }

        return (newbm);
}


void SaveIff (const char *name)
{
    Object *dtobject = NULL;
    struct BitMap *bm = NULL;
    struct BitMapHeader *bmhd = NULL;
    struct Screen *screen = NULL;
    struct RastPort rp;
    UBYTE *cmap;

    long i;
    BPTR fhand = NULL;
    FILE *fp = NULL;

    screen = LockPubScreen (NULL);
    if (!screen)
    {
        MessageBox ("Couldn't lock pubscreen");
        goto clean;
    }

    //bm = AllocBitMap (WIDTH, HEIGHT, 24,
    //                  BMF_MINPLANES, Fenster->BorderRPort->BitMap);

    bm = copy_bitmap(Fenster->RPort->BitMap);

    if (!bm)
    {
        MessageBox ("Couldn't allocate bitmap");
        goto clean;
    }

    //InitRastPort (&rp);
    //rp.BitMap = bm;

    dtobject = NewDTObject (NULL, DTA_SourceType, DTST_RAM,
                            DTA_GroupID, GID_PICTURE,
                            PDTA_BitMap, bm,
                            //PDTA_BitMap, Fenster->BorderRPort->BitMap,
                            PDTA_DestMode, PMODE_V43,
                            PDTA_ModeID, 0, TAG_END);

    if (!dtobject)
    {
        FreeBitMap (bm);
        MessageBox ("Couldn't create datatype");
        goto clean;
    }

    GetDTAttrs (dtobject, PDTA_BitMapHeader, &bmhd, TAG_END);
 
    bmhd->bmh_Width = GetBitMapAttr(bm,BMA_WIDTH);
    bmhd->bmh_Height = GetBitMapAttr(bm,BMA_HEIGHT);
    bmhd->bmh_Depth = GetBitMapAttr(bm,BMA_DEPTH);

    if ((fhand = Open (name, MODE_NEWFILE)))
    {
        i = DoMethod (dtobject, DTM_WRITE, NULL, fhand, DTWM_IFF, TAG_END);
        PrintFault (IoErr (), NULL);
        Close (fhand);
        if (!i)
        {
            MessageBox ("IFF write failed");
            DeleteFile (name);
        }
    }
    else
    {
        PrintFault (IoErr (), NULL);
        MessageBox ("Couldn't open IFF file");
    }


  clean:
    DisposeDTObject (dtobject);
    if (bm) FreeBitMap (bm);
    UnlockPubScreen (NULL, screen);

}


Leider funktioniert das noch nicht richtig. Weiss Jemand hier zufällig die Lösung?

--

http://www.norman-interactive.com

[ - Antworten - Zitieren - Direktlink - ]

03.09.2004, 16:05 Uhr

thomas
Posts: 7718
Nutzer

Wenn du noch dazuschreiben würdest, was nicht funktioniert...

Ich sehe zwei mögliche Symptome:

1. du bekommst nicht den Fensterinhalt, sondern den Bildschirminhalt oder bestenfalls die linke obere Ecke des Bildschirms in der Größe des Fensters.

2. du bekommst nur eine leere Datei bzw. gar keine (weil du sie wieder löschst).


zu 1.: du benutzt Fenster->RPort->BitMap ohne die Layer zu berücksichtigen. Die Bitmap ist die selbe wie die des Bildschirms (es gibt ja keine andere), wenn du ohne Rastport darauf zugreifst, mußt du die Koordinaten des Fensters berücksichtigen. Zum Blitten mit Berücksichtigung der Layers gibt es die Funktion ClipBlit(). Die funktioniert aber nur, wenn das Fenster im Vordergrund liegt, oder ein SmartRefresh-Fenster ist.

zu 2.: die Datatypes sind ziemlich pingelich mit den Sachen, die gesetzt werden müssen. Ich vermute, es funktioniert nicht, wenn die Bitmap nicht genau 24 Bits hat. Und bei Tiefen kleiner oder gleich 8 dürfte PMODE_V43 nicht funktionieren und du mußt die Palette mit übergeben.

Gruß Thomas
--
Email: thomas-rapp@web.de
Home: home.t-online.de/home/thomas-rapp/

[ - Antworten - Zitieren - Direktlink - ]

03.09.2004, 16:59 Uhr

Mad_Dog
Posts: 1944
Nutzer
Wenn ich statt

code:
bmhd->bmh_Width = GetBitMapAttr(bm,BMA_WIDTH);
bmhd->bmh_Height = GetBitMapAttr(bm,BMA_HEIGHT);


die Größe des Fensters direkt eintrage, bekomme ich einen Ausschnitt des Sceens in entsprechender Größe (aber nicht das Fenster).

Eine iff-Datei mit Grafik wird zwar erzeugt. Allerdings sieht die Grafik etwas "seltsam" aus...
--

http://www.norman-interactive.com

[ Dieser Beitrag wurde von Mad_Dog am 03.09.2004 editiert. ]

[ - Antworten - Zitieren - Direktlink - ]

03.09.2004, 17:52 Uhr

Mad_Dog
Posts: 1944
Nutzer
Hier kommt der das Bild (in PNG umgewandelt):

Bild: http://w3studi.informatik.uni-stuttgart.de/~walternn/Bilder/Mist.png

Das Fenster hat die Eigenschaften GimmeZeroZero und SUPERBITMAP. Was außer den seltsamen Linien und den falschen Farben noch auffällt: Das Bild ist deutlich kleiner wie die original-Grafik. Im Bild ist das Fenster zu erkennen, welches ich eigentlich abspeichern wollte...

--

http://www.norman-interactive.com

[ Dieser Beitrag wurde von Mad_Dog am 03.09.2004 editiert. ]

[ - Antworten - Zitieren - Direktlink - ]

03.09.2004, 18:10 Uhr

Mad_Dog
Posts: 1944
Nutzer
Zitat:
Original von thomas:

zu 1.: du benutzt Fenster->RPort->BitMap ohne die Layer zu berücksichtigen. Die Bitmap ist die selbe wie die des Bildschirms (es gibt ja keine andere), wenn du ohne Rastport darauf zugreifst, mußt du die Koordinaten des Fensters berücksichtigen.


Wie soll ich denn "mit Rastport" auf die Bitmap zugreifen? RPort ist doch der RastPort des Fensters... :dance3: Ich könnte mir höchstens noch vorstellen, die Koordinaten des Fensters beim Blitten anzugeben und dann von der Screen-Bitmap blitten. Aber das muß doch auch einfacher gehen, oder?

--

http://www.norman-interactive.com

[ - Antworten - Zitieren - Direktlink - ]

03.09.2004, 20:25 Uhr

geit
Posts: 332
[Ex-Mitglied]

Hallo,

Also ich würde es noch anders machen. Erst würde ich eine BitMap in der Größe des Fensters oder Fensterinhalts erstellen. Wichtig ist, das Du also Friend die Bitmap des Screens angibts.

Dann kannst Du die Bilddaten mittels Blitterfunktion aus dem Rastport rüberkopieren.

Jetzt den Kram speichern und die Temp-Bitmap freigeben.

Das hab ich zwar noch nicht probiert, aber es sollte funktionieren.

Guido Mersmann



[ - Antworten - Zitieren - Direktlink - ]

03.09.2004, 21:00 Uhr

Mad_Dog
Posts: 1944
Nutzer
Ich hab's jetzt so:

code:
bm = AllocBitMap (WIDTH, HEIGHT, 24,
                      BMF_MINPLANES, Fenster->BorderRPort->BitMap);


    if (!bm)
    {
        MessageBox ("Couldn't allocate bitmap");
        goto clean;
    }

    InitRastPort (&rp);
    rp.BitMap = bm;

    ClipBlit (Fenster->RPort,0,0,&rp,0,0,WIDTH,HEIGHT,0x0c0);

    dtobject = NewDTObject (NULL, DTA_SourceType, DTST_RAM,
                            DTA_GroupID, GID_PICTURE,
                            PDTA_BitMap, bm,
                            //PDTA_BitMap, Fenster->BorderRPort->BitMap,
                            PDTA_DestMode, PMODE_V43,
                            PDTA_ModeID, 0, TAG_END);

    if (!dtobject)
    {
        FreeBitMap (bm);
        MessageBox ("Couldn't create datatype");
        goto clean;
    }

    GetDTAttrs (dtobject, PDTA_BitMapHeader, &bmhd, TAG_END);

    bmhd->bmh_Width = GetBitMapAttr(bm,BMA_WIDTH);
    bmhd->bmh_Height = GetBitMapAttr(bm,BMA_HEIGHT);
    bmhd->bmh_Depth = GetBitMapAttr(bm,BMA_DEPTH);


Jetzt wird wenigstens der Fensterinhalt gespeichert. Leider stimmt die Größe noch nicht - das Bild ist kleiner wie die original-Bitmap - und am Rand gibt's Grafikmüll...

Das mit dem Friend Bitmap werde ich mal testen...

--

http://www.norman-interactive.com

[ - Antworten - Zitieren - Direktlink - ]

03.09.2004, 22:22 Uhr

thomas
Posts: 7718
Nutzer
Zitat:
Das Fenster hat die Eigenschaften GimmeZeroZero
Zitat:
am Rand gibt's Grafikmüll

Siehst du den Zusammenhang selbst, oder muß ich ihn noch erklären ?

Zunächst solltest du mal entscheiden, was du machen möchtest, ob du wirklich den RastPort benutzen möchtest (also nur den *Inhalt* des Fensters, ohne Rahmen), oder ob du das ganze Fenster, mit Rahmen haben möchtest.

Bei letzterem nimmst du am besten die Bitmap des Screens (Fenster->WScreen->RastPort.BitMap) und blittest den Ausschnitt des Fensters (Fenster->LeftEdge, Fenster->TopEdge, Fenster->Width, Fenster->Height) in deine Temp-BitMap.

Bei ersterem mußt du halt Fenster->GZZWidth und Fenster->GZZHeight als Dimensionen nehmen.

Die Friend-Bitmap hilft dir nicht viel. Die sorgt nur dafür, daß die Kopie das selbe Pixelformat hat wie das Original. Wie schon gesagt, solltest du lieber eine Bitmap mit 24bit Tiefe und RGB-Pixelformat anlegen, wenn du PMODE_V43 benutzt.

Außerdem empfehle ich, mal die Dokumentation der layers.library zu lesen, sowie die Abhandlung über Bitmaps in den Autodocs der cybergraphics.library.

Gruß Thomas

--
Email: thomas-rapp@web.de
Home: home.t-online.de/home/thomas-rapp/

[ - Antworten - Zitieren - Direktlink - ]

03.09.2004, 22:53 Uhr

Mad_Dog
Posts: 1944
Nutzer
Zitat:
Original von thomas:
Bei ersterem mußt du halt Fenster->GZZWidth und Fenster->GZZHeight als Dimensionen nehmen.


Damit passt es immer noch nicht. Seltsamerweise stimmt damit zwar die Höhe, die Breite aber nicht.


--

http://www.norman-interactive.com

[ - Antworten - Zitieren - Direktlink - ]

04.09.2004, 09:54 Uhr

thomas
Posts: 7718
Nutzer

Schau dir das mal an, bei mir funktioniert es so: http://home.t-online.de/home/thomas-rapp/download/savewin.c


Gruß Thomas

--
Email: thomas-rapp@web.de
Home: home.t-online.de/home/thomas-rapp/

[ - Antworten - Zitieren - Direktlink - ]

04.09.2004, 15:29 Uhr

Mad_Dog
Posts: 1944
Nutzer
Danke! Dein Beispiel war sehr hilfreich. Leider wird aus meinem weißen Umriß im Fenster beim Abspeichern (mit Deinen Funktionen) ein grauer. :(

P.S.: Für mein Projekt "CodeGuru" suche ich genau solche Beispielcodes - angemeldet hast Du Dich ja schon... :)

--

http://www.norman-interactive.com

[ Dieser Beitrag wurde von Mad_Dog am 04.09.2004 editiert. ]

[ - Antworten - Zitieren - Direktlink - ]

04.09.2004, 17:04 Uhr

thomas
Posts: 7718
Nutzer
Zitat:
Original von Mad_Dog:
Leider wird aus meinem weißen Umriß im Fenster beim Abspeichern (mit Deinen Funktionen) ein grauer. :(



Versuch mal folgendes zu ändern (geänderte Zeilen sind fett):

Bei den System-Includes:
code:
#include <cybergraphx/cybergraphics.h>


In cut_gzz_area:
code:
long d;
	long flags;
[...]
	d = GetBitMapAttr(winbm,BMA_DEPTH);
	if (d > 8)
		{
		d = 24;
		flags = BMF_SPECIALFMT|SHIFT_PIXFMT(PIXFMT_RGB24);
		}
	else
		flags = GetBitMapAttr(bm,BMA_FLAGS);

	if (bm = AllocBitMap (w,h,d,flags,NULL))


und in save_window_contents:
code:
d = GetBitMapAttr(bm,BMA_DEPTH);
		if (d > 8) d = 24;



Zitat:
P.S.: Für mein Projekt "CodeGuru" suche ich genau solche Beispielcodes - angemeldet hast Du Dich ja schon... :)

Das habe ich nicht vergessen.

Gruß Thomas

--
Email: thomas-rapp@web.de
Home: home.t-online.de/home/thomas-rapp/

[ - Antworten - Zitieren - Direktlink - ]

05.09.2004, 14:03 Uhr

Mad_Dog
Posts: 1944
Nutzer
Danke, das war's. :)

Ich hab noch folgende Zeilen eingefügt:

code:
struct ViewPort *vp;

 SetWindowPointer(win,WA_BusyPointer,TRUE);


und am Ende

code:
else
     FreeBitMap (bm);
   }

  SetWindowPointer(win,WA_Pointer,NULL);


Damit sieht man dann auch, daß sich was tut.

Schön wäre es auch noch, den Code so umzubauen, daß nur in der tatsächlichen Farbtiefe abgespeichert wird. D.h. Farben zählen... mit den Datatypes geht das nicht automatisch, oder?

--

http://www.norman-interactive.com

[ - Antworten - Zitieren - Direktlink - ]

05.09.2004, 14:49 Uhr

thomas
Posts: 7718
Nutzer

Es wird doch die tatsächliche Farbtiefe gespeichert, in der die BitMap vorliegt. Wenn du die Palette optimieren möchtest, oder gar eine 16bit-Bitmap in eine 8bit konvertieren, dann mußt du das selbst machen.

In diesem speziellen Fall könntest du auch einfach deine Superbitmap abspeichern. Ggf. vorher mit SyncSBitMap die Bitmap aktualisieren.

Gruß Thomas

--
Email: thomas-rapp@web.de
Home: home.t-online.de/home/thomas-rapp/

[ - Antworten - Zitieren - Direktlink - ]

10.09.2004, 14:22 Uhr

Mad_Dog
Posts: 1944
Nutzer
@thomas:

Was mir beim nochmaligen Anschauen Deiner Funktionen aufgefallen ist:
In Deiner Funktion cut_gzz_area() verwendest Du folgendes:

code:
memset (&rp,0,sizeof(struct RastPort));


Das ist vielleicht eine billige Art, einen RastPort zu löschen, aber nicht ganz Style Guide konform. In der Entwicklerdoku steht ausdrücklich, man soll niemals direkt an den Members eines RastPort manipulieren, sondern immer brav die Funktionen aus der graphics.library verwenden. Style Guide konform müsste man hier etwas wie

code:
SetRast(rp,1L);


verwenden.

(ohne daß ich jetzt ein Erbsenzähler sein will) ;)
--

http://www.norman-interactive.com

[ - Antworten - Zitieren - Direktlink - ]

10.09.2004, 17:42 Uhr

DariusBrewka
Posts: 899
[Benutzer gesperrt]
SetRast() löscht die zu einem RastPort gehörende BitMap, bzw. färbt die ein, wohingegen thomas einfach die RastPort struktur löscht d.h. mit Nullen füllt, könnte man auch mit AllocMem(MEMF_CLERAR...). machen.

[ - Antworten - Zitieren - Direktlink - ]

10.09.2004, 18:24 Uhr

thomas
Posts: 7718
Nutzer

Genau. Ich darf nicht in den Membern der RastPort-Struktur manipulieren, nachdem ich sie initialisiert habe. Aber ich muß sie ja erstmal initialisieren. Und damit auch wirklich alles initialisiert wird, fülle ich den Speicherbereich mit Nullen, bevor ich die wichtigen Felder mit InitRastPort auf definierte Werte setze.

Erst danach kann ich Funktionen wie SetRast anwenden, die, wie du gehört hast, nicht die RastPort-Struktur sondern den damit verknüpften Grafikbereich initialisert (also ungefähr das gleiche wie ClearScreen, nur daß ClearScreen erst ab der aktuellen Cursorposition löscht).

Gruß Thomas

--
Email: thomas-rapp@web.de
Home: home.t-online.de/home/thomas-rapp/

[ - Antworten - Zitieren - Direktlink - ]

10.09.2004, 18:34 Uhr

Mad_Dog
Posts: 1944
Nutzer
Zitat:
Original von DariusBrewka:
SetRast() löscht die zu einem RastPort gehörende BitMap, bzw. färbt die ein, wohingegen thomas einfach die RastPort struktur löscht d.h. mit Nullen füllt, könnte man auch mit AllocMem(MEMF_CLERAR...). machen.


O.K. hab nicht richtig hingeschaut und das Ding mit der Bitmap verwechselt. :glow:

Aber man könnte ja auf die Idee kommen, mit memset() die Bitmap zu löschen - vor allem wenn man zuvor viel mit Framebuffern programmiert hat. Sowas habe ich schonmal in nem Buch über PC-Grafikprogrammierung gesehen - da wurde einfach an eine bestimmte Speicheradresse geschrieben, um Pixel zu setzen (böse, böse).
--

http://www.norman-interactive.com

[ Dieser Beitrag wurde von Mad_Dog am 10.09.2004 editiert. ]

[ - Antworten - Zitieren - Direktlink - ]

10.09.2004, 23:27 Uhr

DariusBrewka
Posts: 899
[Benutzer gesperrt]
Es dürfte im allgemeinen kein Problem bereiten direkt auf seine eigene Bitmap zuzugreifen und auch mittels memset() etc. zu löschen usw., jedenfalls wenn man die Speichergrenzen einhält. Mehr als ggf. falsche Pixel bekommt man so nicht, jedenfalls dann wenn die Bitmap nicht shared ist, d.h. zum Screen gehört.

[ - Antworten - Zitieren - Direktlink - ]

10.09.2004, 23:51 Uhr

thomas
Posts: 7718
Nutzer

Solange man die Bitmap mit AllocMem oder vielleicht gerade noch mit AllocRaster allokiert hat, mag das ok sein. Aber in Bitmaps, die mit AllocBitMap angelegt wurden, besonders auf Grafikkarten-Systemen, sollte man tunlichst nicht direkt schreiben, schon allein deshalb, weil man die Speichergrenzen nicht kennt (die Daten in der Bitmap-Struktur wir Rows und BytesPerRow sind u.U. nur Dummies).

Gruß Thomas

--
Email: thomas-rapp@web.de
Home: home.t-online.de/home/thomas-rapp/

[ - Antworten - Zitieren - Direktlink - ]

11.09.2004, 00:00 Uhr

DariusBrewka
Posts: 899
[Benutzer gesperrt]
Darum sollte man auch die CGFX... Funktionen zum erhalten der Bitmap spezifischen Daten benutzen und dann kennt man die Speichergrenzen&Co. Vermeiden sollte man es aber trotzdem.

[ - Antworten - Zitieren - Direktlink - ]


-1- [ - Beitrag schreiben - ]


amiga-news.de Forum > Programmierung > Fensterinhalt mit Datatypes speichern [ - Suche - Neue Beiträge - Registrieren - Login - ]


.
Impressum | Datenschutzerklärung | Netiquette | Werbung | Kontakt
Copyright © 1998-2024 by amiga-news.de - alle Rechte vorbehalten.
.