cerber943
Messages postés32Date d'inscriptionlundi 20 janvier 2003StatutMembreDernière intervention26 octobre 2006
-
23 oct. 2006 à 13:08
Guillemouze
Messages postés991Date d'inscriptionsamedi 25 octobre 2003StatutMembreDernière intervention29 août 2013
-
4 avril 2008 à 17:25
Bonjour,
J'ai créé quelques fonctions qui retournent des TBitmap. Je rencontre actuellement une augmentation de l'espace mémoire alloué à mon programme au fil de l'exécution de ces fonctions. Je suppose donc que je ne dois pas libérer les images correctement.
A chaque fin de procédure mes images intermédiaires sont libérées par
if Assigned(mon_img) then mon_img.Free;
Je me posais la questions si mes images étaient copiées ou transmises par références dans ce genre de situation :
function get_img() : TBitmap;
begin
result:=TBitmap.Create;
result.width:=10;
result.height:=10;
[...] bref on alloue cette image [...]
end;
procedure test_img (img : TBitmap) : Boolean;
begin
// fait quelque chose avec cette image
end;
Et dans ma fonction main :
if test_img(get_img) then ....
Je me demande si je peux écrire
if test_img(get_img) then ....
ou si je dois écrire :
tmp_img:=get_img;
if test_img(tmpImg) then ....
if Assigned(tmp_img) then tmp_img.Free;
De même (mais je pense avoir la réponse), j'ai un doute quand à l'utilisation de boucles pour parcourir les pixels des Canvas des Bitmap : doit-je itérer de 0 à Height-1 (ce que je pense) ou de 0 à Height ?
Je me pose la question car itérer de 0 à Height ne semble pas gérer de message d'erreur à l'exécution, mais un résultat incertain.
J'espère avoir été assez clair et je vous remercie par avance de votre aide
f0xi
Messages postés4205Date d'inscriptionsamedi 16 octobre 2004StatutModérateurDernière intervention12 mars 202235 23 oct. 2006 à 23:54
ok je vais essayer de t'eclairer :
pour créer un bitmap par une methode mieux vaut prendre une procedure ou une fonction a retour booleen :
function CreateBitmap(BMP : TBitmap; const AWidth, AHeight : integer; const APixelFormat : TPixelFormat = pf32bit) : boolean;
begin
result := false;
if not Assigned(BMP) then begin
BMP := TBitmap.Create;
BMP.Width := AWidth;
BMP.Height:= AHeight;
BMP.PixelFormat := APixelFormat;
result := true;
end;
end;
>> CreateBitmap(MonBitmap1,10,10); // crée une image 32 bits par defaut
>> CreateBitmap(MonBitmap2,10,10,pf24bit); // force une image 24 bits
function FreeBitmap(BMP : TBitmap) : boolean;
begin
result := false;
if Assigned(BMP) then begin
FreeAndNil(BMP);
result := true;
end;
end;
>> FreeBitmap(MonBitmap1); // libere et remet a nil la variable MonBitmap1
>> FreeBitmap(MonBitmap2); // libere et remet a nil la variable MonBitmap1
ensuite pour acceder aux pixels d'un bitmap le mieux c'est ScanLine (canvas.pixel est trés long d'accés) :
const
MAXWidth = 4096;
type
TPixel24bit = record
R,G,B : byte;
end;
TPixel32bit = record
R,G,B,A : byte;
end;
pSLPixel24 = ^TSLPixel24;
pSLPixel32 = ^TSLPixel32;
TSLPixel24 = array[0..MAXWidth] of TPixel24bit;
TSLPixel32 = array[0..MAXWidth] of TPixel32bit;
function GetPixelRGB24(BMP : TBitmap; const X,Y : integer; out Pixel : TPixel24bit) : boolean;
var pPL : pSLPixel24;
begin
result := false;
if ((X >= 0) and (X <= BMP.Width-1)) and ((Y >= 0) and (Y <= BMP.Height-1) then begin
pPL := BMP.ScanLine[y];
Pixel := pPL[X];
result := true;
end;
end;
function GetPixelRGB32(BMP : TBitmap; const X,Y : integer; out Pixel : TPixel32bit) : boolean;
var pPL : pSLPixel32;
begin
result := false;
if ((X >= 0) and (X <= BMP.Width-1)) and ((Y >= 0) and (Y <= BMP.Height-1) then begin
pPL := BMP.ScanLine[y];
Pixel := pPL[X];
result := true;
end;
end;
function SetPixelRGB24(BMP : TBitmap; const X,Y : integer; const Pixel : TPixel24bit) : boolean;
var pPL : pSLPixel24;
begin
result := false;
if ((X >= 0) and (X <= BMP.Width-1)) and ((Y >= 0) and (Y <= BMP.Height-1) then begin
pPL := BMP.ScanLine[y];
pPL[X] := Pixel;
result := true;
end;
end;
function SetPixelRGB32(BMP : TBitmap; const X,Y : integer; const Pixel : TPixel32bit) : boolean;
var pPL : pSLPixel32;
begin
result := false;
if ((X >= 0) and (X <= BMP.Width-1)) and ((Y >= 0) and (Y <= BMP.Height-1) then begin
pPL := BMP.ScanLine[y];
pPL[X] := Pixel;
result := true;
end;
end;
et un exemple de la boucle type pour utiliser ScanLine, pour les algorythmes d'images complexe ou non :
{ athlon 2700+ @ 2Ghz / bitmap 640x480 = 0..7ms }
procedure NegativizeScanline(BMP : TBitmap);
var pPL : pSLPixel32;
X,Y : integer;
begin
BMP.PixelFormat := pf32bit;
for Y := 0 to BMP.Height-1 do begin
pPL := BMP.ScanLine[y];
for X := 0 to BMP.Width-1 do
with pPL[X] do begin
R := 255-R;
G := 255-G;
B := 255-B;
end;
end;
end;
alors que la methode Canvas.Pixel (meme optimisée) :
{ athlon 2700+ @ 2Ghz / bitmap 640x480 = 1670..1680ms }
procedure NegativizeCanvas(BMP : TBitmap);
var Color : integer;
RGB : array[0..2] of byte absolute color;
N,X,Y : integer;
begin
BMP.PixelFormat := pf32bit;
for Y := 0 to BMP.Height-1 do begin
for X := 0 to BMP.Width-1 do begin
Color := BMP.Canvas.Pixels[X,Y];
for N := 0 to 2 do
RGB[N] := 255-RGB[N];
BMP.Canvas.Pixels[X,Y] := Color;
end;
end;
end;
et ce n'est qu'un simple negatif, imagine sur une rehausse des couleurs, des contrastes ou autres modfication complexe....
ensuite
il faut savoir qu'un Canvas n'a pas de réelle limite de coordonées ...
on peut trés bien aller a X=10000,Y=-5000 sur un canvas qui ne fait que
320x200 pixel.
contrairement a ScanLine qui est reduit a l'interval 0..Width-1, 0..Height-1 et provoque une erreur si on sort de cette limite.
cerber943
Messages postés32Date d'inscriptionlundi 20 janvier 2003StatutMembreDernière intervention26 octobre 2006 24 oct. 2006 à 08:48
Merci beaucoup du temps que tu as du passer pour me répondre, c'est très complet et très clair. Bravo !
Je n'ai plus qu'à remodifier mon code pour voir ce que cela m'a apporté et il est vrai que mon code était lent... je m'attend donc à avoir une agréable surprise lorsque j'aurais appliqué tes fonctions :)
Puis-je encore abuser de ton temps et demander pourquoi lorsque tu veux créer des pointeurs, tu les définies comme étant des pointeurs de tableau d'une taille max ?
Est-ce que la taille max a une importance ? Je pensais qu'un pointeur n'avait besoin que de savoir le type de donnée pointée, pas le nombre d'éléments de mémoire qui se trouve dans la zone pointée...
Je me doute qu'il faille faire comme tu l'as mis mais c'était pour mieux comprendre.
Quoi qu'il en soit si tu n'as pas le temps de répondre tu auras déja répondu à ma question donc encore merci pour ton dévouement et ton efficacité !
cerber943
Messages postés32Date d'inscriptionlundi 20 janvier 2003StatutMembreDernière intervention26 octobre 2006 24 oct. 2006 à 09:55
Je précise que j'ai un problème lorsque j'utilise
function CreateBitmap(BMP : TBitmap; const AWidth, AHeight : integer; const APixelFormat : TPixelFormat = pf32bit) : boolean;
begin
result := false;
if not Assigned(BMP) then begin
BMP := TBitmap.Create;
BMP.Width := AWidth;
BMP.Height:= AHeight;
BMP.PixelFormat := APixelFormat;
result := true;
end;
end;
Il semble que je sois obligé de mettre ma variable à nil avant d'appeler CreateBitmap.
Lorsque je met :
result:=nil;
CreateBitmap(result,4,7);
result vaut toujours nil. Néanmoins si je rajoute var devant BMP dans la déclaration de CreateBitmap comme ceci :
function CreateBitmap(var BMP : TBitmap; const AWidth, AHeight : integer; const APixelFormat : TPixelFormat = pf32bit) : boolean;
le problème semble résolu.
En tout cas merci j'espère ne pas avoir fait d'erreur en mettant ce var devant BMP
A+
f0xi
Messages postés4205Date d'inscriptionsamedi 16 octobre 2004StatutModérateurDernière intervention12 mars 202235 24 oct. 2006 à 22:30
oui il manque le var... mais uniquement pour Create et Free.
pour les autres on peu trés bien travailler sur le Bitmap d'un TImage donc pas de var.
sinon, pour les pointeurs c'est une question inerrante a scanline.
en effet les anciens bitmap etait limité a 2048 pixels de long.
soit :
array[0..2047] of ...
mais maintenant, le format ayant evolué, la taille n'est plus limitée et donc on peu definir une taille min/max a ce buffer.
quand on recupere pPL := BMP.ScanLine[Y], pPL contient tout les pixels de la ligne Y.
ensuite on appel pPL[X] pour travailler sur le pixel X de la ligne Y.
sincerement je crois avoir tenter une fois d'utiliser un tableau dynamique pour scanline, mais il me semble que ça ne fonctionne pas.
j'explique aussi pourquoi j'utilise des structure Record.
comme tu le sais un bitmap peut avoir un format de pixel different :
pf8bit (byte)
pf16bit (word)
pf24bit (...)
pf32bit (integer)
le probleme, c'est que par exemple il n'existe pas de type scalaire 24bit (3x1byte). et donc il nous faut une structure record ou un tableau de 3 bytes :
TPixel24 = record B,G,R : byte end;
TPixel24 = array[0..2] of byte;
pour le pf32bit, un structure record ou un integer est identique, sauf que la structure record offre quelques avantage, comme par exemple d'eviter de faire des SHL et SHR pour travailler sur lun des octet de couleur RGB.