Question sur l'utilisation des TBitmap dans les fonctions... [Résolu]

Signaler
Messages postés
32
Date d'inscription
lundi 20 janvier 2003
Statut
Membre
Dernière intervention
26 octobre 2006
-
Messages postés
991
Date d'inscription
samedi 25 octobre 2003
Statut
Membre
Dernière intervention
29 août 2013
-
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

7 réponses

Messages postés
4202
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
13 juin 2020
37
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.

<hr size="2" width="100%" />Croc (click me)
Messages postés
32
Date d'inscription
lundi 20 janvier 2003
Statut
Membre
Dernière intervention
26 octobre 2006

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é !
Messages postés
32
Date d'inscription
lundi 20 janvier 2003
Statut
Membre
Dernière intervention
26 octobre 2006

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+
Messages postés
991
Date d'inscription
samedi 25 octobre 2003
Statut
Membre
Dernière intervention
29 août 2013
7
c'est ce que j'allai dire, il manque un var devant le BMP de createBitmap et FreeBitmap aussi.
Messages postés
4202
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
13 juin 2020
37
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.

<hr size="2" width="100%" />Croc (click me)
Messages postés
7
Date d'inscription
lundi 10 mars 2008
Statut
Membre
Dernière intervention
14 mai 2008

salut les gas!!!!!!!
quelle est l'avatage d'utiliser scanline par apport a getpixel
je voudrai savoir que fait le fonction assign
Messages postés
991
Date d'inscription
samedi 25 octobre 2003
Statut
Membre
Dernière intervention
29 août 2013
7
F1