Trouver une ressource
Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum.
Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !
Sujet : Getdibits qui ne marche pas [ Système / Mémoire ] (barbichette)
|
Getdibits qui ne marche pas
le 20/06/2007 19:42:40

barbichette
Membre Club 
|
Voilà, j'ai un souci avec la fonction GetDibits. Je veux récupérer les pixels de l'écran complet. A la fin de la procedure FormCreate, j'utilise GetDiBits. Mais ça marche pas... le pointeur tmp passe de la zone pointée à la valeur $FF. (pas terrible comme adresse mémoire) et le code d'erreur de retour et 6 (invalide handle). J'ai le souci dans plein de cas, comme pour l'effet d'eau que j'avais posté sur ce site. J'ai beau retourner et recompiler dans tout les sens... ça ne marche pas...
HELP ME...
// alloue de l'espace mémoire function WinGetMem(Size:Cardinal):pointer; begin result:=VirtualAlloc(nil,Size,MEM_COMMIT or MEM_RESERVE,PAGE_READWRITE); if not Assigned(result) then RaiseLastOSError; end;
//libère la mémoire procedure WinFreeMem(p:Pointer); begin if Assigned(p) and not VirtualFree(p,0,MEM_RELEASE) then RaiseLastOSError; end;
procedure TForm1.FormCreate(Sender: TObject); begin //précalcul les coefficients de la lentille PreCalcul; // crée l'image de fond (capture de l'écran) fond:=tbitmap.Create; fond.Width:=screen.Width; fond.Height:=screen.Height; fond.PixelFormat:=pf32bit; // copie l'image de l'écran comme il est maintenant BitBlt(fond.Canvas.Handle,0,0,fond.Width,fond.Height,getdc(0),0,0,cmSrcCopy);
// prépare la structure bi (bitmap info) fillchar(bi,sizeof(bi.bmiHeader),0); bi.bmiHeader.biSize:=sizeof(bi.bmiHeader); // appel de getdibits avec nil comme pointeur pour avoir juste les infos dans bi getdibits(fond.Canvas.Handle,fond.Handle,0,fond.height,nil,bi,DIB_RGB_COLORS); // alloue la mémoire buffer:=wingetmem(bi.bmiHeader.biSizeImage); tmp:=wingetmem(bi.bmiHeader.biSizeImage);
// prépare la structure bi (bitmap info) fillchar(bi,sizeof(bi.bmiHeader),0); bi.bmiHeader.biSize:=sizeof(bi.bmiHeader); // appel de getdibits avec tmp pour récupérer les pixels de l'image fond getdibits(fond.Canvas.Handle,fond.Handle,0,fond.height,tmp,bi,DIB_RGB_COLORS); caption:=inttostr(GetLastError); end;
|
|
|
|
Re : Getdibits qui ne marche pas
le 20/06/2007 20:10:44

florenth
Membre Club 
|
Salut !
GetDIBits ne fonctionne qu'avec un bitmap ! Pas avec un simple contexte de périphérique (DC pur Device Contect). Tu dois donc créer un bitmap et faire ton BitBlt dedans.
Sinon, pourquoi récupérer le bitmapinfo à l'aide d'un premier appel à GetDIBits pour finalement écraser les valeurs ?
Et, autre chose: on a eu une conversation avec Cirec hier et, d'après moi, GetDIBits/SetDIBits ne serait pas plus rapide qu'un "bon" Scanline[]. Chez moi, pour une opération toute simple, SetDIBits me prend le double du temps que met Scanline[].
Dernière chose: tu fais GetDc(0) dans le paramètre de BitBlt mais tu dois récupérer la valeur fournie par la fonction pour pouvoir libérer le DC que tu viens de réserver. Me trompe-je ? (ch'uis pas 100% sûr sur ce coup) Il me semble pourtant que cela devrait être cela : dc0 := GetDC(0); BitBlt(fond.Canvas.Handle,0,0,fond.Width,fond.Height,getdc(0),0,0,cmSrcCopy); ReleaseDC(dc0);
Alors, toujours des problèmes ?
|
|
|
|
Re : Getdibits qui ne marche pas
le 20/06/2007 20:23:11

florenth
Membre Club 
|
Bon, dans mon code, j'ai oublié de remplacer le getdc(0) (vive le copier-coller ^^).
Sinon, j'ai vu que tu a écrit cela sur une source de mauricio:
Pour le test de performance, j'ai deux réponses : Dans ma source Flames version 2, j'ai remplacé les scanline par ce système, on double en gros la fréquence d'affichage. La réponse est simple, à chaque demande d'un pointeur par scanline, dernière, il y a ceci :
function TBitmap.GetScanLine(Row: Integer): Pointer; begin Changing(Self); with FImage.FDIB, dsbm, dsbmih do begin if (Row < 0) or (Row >= bmHeight) then InvalidOperation(@SScanLine); DIBNeeded; GDIFlush; if biHeight > 0 then // bottom-up DIB Row := biHeight - Row - 1; Integer(Result) := Integer(bmBits) + Row * BytesPerScanline(biWidth, biBitCount, 32); end;
Cela est bien évidemment juste. Cela dit, tu peux ne faire que deux appels à Scanline[] dans tout ton traitement et incrémenter le pointeur de données. Dans ce cas là, le problème ne se pose plus. Mais le gain de performance n'est pas énorme: 1ms à peine pour une image de 1024 lignes !!! C'est dire à quel point cette procédure est rapide !
Par contre, ce qui est lent, c'est de devoir copier TOUS les pixels lors d'une affectation par SetDIBits. Du coup, c'est moins performant. (avec Scanline on travaille directement sur le bloc concerné) Et en plus, tu dois utiliser deux fois plus de mémoire !
Bref, j'attends quand même ta réponse, le débat risque d'être intéressant !
++
|
|
|
|
Re : Getdibits qui ne marche pas
le 20/06/2007 22:21:46

barbichette
Membre Club 
|
alors, en deux mot, j'appelle une première fois getdibits pour remplir bitmapinfo et ainsi avoir la taille de l'image complète. Normalement, le deuxième ne sers à rien, mais si je l'enlève, ça ne marche plus, c'est dans ce cas d'ailleurs que le pointeur pert sa valeur.
Bon, sinon, je viens de regarder de plus près tout ça... Et il me semble en effet que les deux soit pareil. Pour la petite histoire, j'avait besoin de visualiser rapidement un tableau de byte sous forme de bitmap. En regardant à gauche à droite sur le web, j'ai trouvé ça, Getdibits et Setdibits. Dans mon cas, j'avais un pointeur et je ne voulais pas faire une fonction qui recopie le tableau byte à byte vers un tbitmap. Et en utilisant une scanline pour avoir le pointeur vers la première ligne puis en recopiant tout d'un bloc, il y a une magnifique erreur car un écris n'importe où à la fin de la ligne... Je me suis donc dis que scanline donne un pointeur vers une ligne mais pas à l'ensemble du bitmap (tel la mémoire vidéo). En fait, je viens de voir que je me suis gouré... mais il faud demander un scanline sur la dernière ligne puis le pointeur donne tout le bitmap mais (comme tout les bitmaps) de du bas vers le haut... Et Et au fin fond des choses, ça revient au même que SetDibits... qui fait en gros ça :
p,tableau : pointer;
p:=bitmap.scanline[bitmap.heigth-1]; move(tableau,p,taille_du_bitmap)
donc plus besoin de setdibits... sniff...
Cependant j'aimerai bien savoir pourquoi ça ne marche pas.
|
|
|
|
Re : Getdibits qui ne marche pas
le 21/06/2007 10:05:21

Kenavo
|
"En fait, je viens de voir que je me suis gouré... mais il faud demander
un scanline sur la dernière ligne puis le pointeur donne tout le bitmap
mais (comme tout les bitmaps) de du bas vers le haut..." Salut barbichette,
Il faut quand même faire gaffe avec Scanline ! Les lignes du bitmap sont alignées. Je sais c'est pas très clair, je m'explique :
Les pointeurs renvoyés par Scanline sur chaque ligne sont tous divisibles par 8 (alignement sur un DWord). Si (Nombre de pixels par ligne) x (Nombre d'octet par pixel) n'est pas multiple de 8, il y aura quelques octets non significatifs entre deux lignes. Pas très pratique !
Je dit 8 mais c'est peut-être 4
Ken@vo
Code, Code, Codec !
|
|
|
|
Re : Getdibits qui ne marche pas
le 21/06/2007 10:33:37

florenth
Membre Club 
|
"Normalement, le deuxième ne sers à rien" => non, c'est le premier appel à GetDIBits qui ne sert à rien (dans ton cas) puisque tu vides la structure qu'il te remplit ! Le deuxième est forcément nécessaire, c'est lui qui copie les données. "J'avais besoin de visualiser rapidement un tableau de byte sous forme de bitmap" => Deux solutions: SetDIBits ou Scanline[]. Mais ça, tu l'as bien compris. "Je me suis donc dis que scanline donne un pointeur vers une ligne mais pas à l'ensemble du bitmap" => C'est juste ! Pour avoir une autre ligne, tu refais un appel à Scanline[] ou tu incrémente ton pointeur de la taille de la ligne (en respectant les alignements, voir plus bas) "Cependant j'aimerai bien savoir pourquoi ça ne marche pas." => En fait, les données des bitmaps sont alignées sur des double-mots (DWord ou Cardinal). Ce qui veut dire qu'a la fin d'une ligne, il faut rajouter les zéros jusqu'à tomber sur une limite d'un mot. Dans le cas ou le format est pf32Bit, il n'y a aucun problème puisque chaque pixel se termine sur la fin d'un mot, la fin de la ligne aussi (logique). Par contre, en pf24Bit, suivant la largeur de ton bitmap, ce n'est pas le cas. Exemple avec un bitmap de 3 pixels de largeur, les données de couleur sont stockées comme ça (une lettre: un octet - les apostrophes indiquent les fins de double-mots): BGRB'GRBG'R000' BGRB'GRBG'R000'
Tu vois donc bien qu'on a rajouté trois zéro pour compléter la ligne. De plus, pour finir, les bitmaps ne sont pas toujours orientés de bas en haut. Pour finir, je te laisse voir ici cette merveilleuse traduction de nono40 sur l'utilisation de Scanline[]A+
|
|
|
|
Re : Getdibits qui ne marche pas
le 21/06/2007 10:51:17
|
|
Re : Getdibits qui ne marche pas
le 21/06/2007 21:46:02
|
|
Re : Getdibits qui ne marche pas
le 22/06/2007 11:51:02

barbichette
Membre Club 
|
ce que je ne comprend pas, c'est la chose suivante. (on oublie le code de mon premier post) J'appel une première fois GetDibits avec nil comme pointer de bits. sur la MSDN, ils disent que ça rempli la structure bitmapinfo. Et en particulier le membre biSizeImage qui donne la taille du buffer pour recevoir les bits. Puis on alloue de l'espace memoire en utilisant cette taille. Et je rappel getdibits pour transferer l'image. Mais voilà, une fois sur deux, il y a un débordement je ne sais pas trop où et soit le pointer reçois la valeur $FF, soit il y a erreur à l'execution, soit une autre variable globale de mon programme vois sa valeur modifier... C'est du n'importe quoi....
Par ailleurs, je viens de comprendre un truc important avec getdibits et setdibits. Lorsque le membre bmiColors est renseigné dans la structure bitmapinfo, la copie se fait en cherchant la meilleur concordance entre les pixels du buffer et la palette bmiColors, et la palette du bitmap où l'on copie. Donc, diminuer le nombre de couleur ou appliquer une autre palette à une image en ne perdant que peu l'image elle même. Ca peut êter utilile pour faire rapidement ce genre de processus sans avoir à coder toute une fonction. encore faut il que ça marche...
Barbichette
|
|
|
|
Re : Getdibits qui ne marche pas
le 22/06/2007 14:05:25

rt15
Membre Club 
|
Salut, Bin éventuellement, montre le code, vérifie la valeur retournée par GetDIBits (non nulle pour l'appel avec lpvBits, la taille des données quand le buffer n'est pas à nil...). Assure toi que les handles de ta bitmap et de ton hDC sont valide. D'ailleur je me demande quel handle de DC ils veulent... (Windows permet de créer un DC compatible avec une bitmap à l'aide de CreateCompatibleDC, et on peut utiliser SelectObject pour spécifier la bitmap d'un DC) Et surtout, utilise scanline ! 
|
|
|
Classé sous : fond, handle, bi, bmiheader, getdibits
|
CalendriCode
| | | L | M | M | J | V | S | D |
| | | | 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 | |
|
Téléchargements
Logiciels à télécharger sur le même thème :
|