Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Liberar stream en función (https://www.clubdelphi.com/foros/showthread.php?t=96752)

newtron 20-06-2024 13:56:33

Liberar stream en función
 
Buenas a tod@s.


Trabajando en el tema del QR para VeriFactu he hecho una función para generarlo y devolvérmelo en modo stream para guardarlo en la tabla e imprimirlo en la factura posteriormente.


El tema es que he creado una función aprovechando y retocando un componente que publicó el compañero escafandra en otro foro tal que así:


Código Delphi [-]
function DameQRIMG(QRText: String): TMemoryStream;
var
  QR: TQRCodeImage;
  Stream: TMemoryStream;
  Bitmap: TBitmap;
  GR: TGraphic;
  Jpg: TJpegImage;
begin
  QR:=TQRCodeImage.Create(nil);
  QR.Width := 169;
  QR.Height:= QR.Width;
  QR.Text := QRText;
  GR:=TGraphic.Create;
  GR:=QR.Picture.Graphic;
  Bitmap:= TBitmap.Create;
  try
    Bitmap.Width:= QR.Width;
    Bitmap.Height:= QR.Width;
    Bitmap.Canvas.StretchDraw(Bitmap.Canvas.ClipRect,GR);

    jpg := TJPEGImage.Create;
    jpg.Assign(Bitmap);
    Stream:=tmemorystream.Create;
    jpg.SaveToStream(Stream);
  finally
    Result:=Stream;
    Bitmap.Free;
    Jpg.Free;
//    Stream.Free;
  end;
end;


En la que la llamo con el texto del QR y me devuelve un stream con la imagen. Hasta aquí todo bien.


El problema es si le hago un "Free" a la variable Stream que previamente he creado, he asignado y luego he igualado "Result" a ella. Si hago el "Free" me da un error y si lo quito funciona bien pero no sé si eso irá consumiendo memoria en cada llamada hasta el infinito y más allá.


Alguien me podría decir si no hago el "Free" tendré problemas de memoria o si se libera solo de alguna manera, o en caso contrario, cómo puedo liberarlo sin que me de error.


Gracias y un saludo.

marco3k 20-06-2024 14:58:40

Aunque esa variable "Stream" es local y debería finalizar al final de la función, pero en todo caso intenta poner esa linea:

Código Delphi [-]
Stream: TMemoryStream;
La declaras fuera de esa función como publico y luego le aplicas el free desde afuera de la función. Me parece que el error es porque destruyes el objeto dentro de la función.

Neftali [Germán.Estévez] 20-06-2024 16:57:26

Yo soy de los que piensa que quien crea las cosas es quien debe ser resposable de destruirlas, así que yo optaría por crear y destruir el Stream en el mismo sitio.
Cambia la definición a algo como esto:
Código Delphi [-]
procedure DameQRIMG(QRText:String; QRImage:TMemoryStream);

Y la llamada de esta forma...

Código Delphi [-]
  ms := TMemoryStream.Create;
  try
    DameQRIMG(QRText:String; QRImage:TMemoryStream);
    ... Hacer lo que sea con la imagen
  finally
    FreeAndNil(ms);
  end;

Y en el procedimiento usar el parámetro QRImage, en lugar del result.

newtron 20-06-2024 19:41:08

Gracias marco3k y Germán.


Realmente las dos sugerencias van por el mismo camino, la diferencia es dónde crear y liberar la variable. Al final he optado por la de Germán, prefiero usar variables locales siempre que sea posible.



Gracias y un saludo.

escafandra 21-06-2024 21:27:51

Date cuenta de una cosa, la función que muestras DameQRIMG devuelve el Stream que ha creado ella misma. Si al salir lo destruye, estas devolviendo un stream inválido que ya no existe. Deberá ser destruido por la función llamadora y para apoyar la idea, tu función debería llamarse algo como CreateQRStream. De esta forma ya indica que el Stream devuelto deberá ser destruido por la función llamadora.


La idea de Neftali va por el mismo camino, sólo que es la función llamadora la que suministra el Stream ya creado.





Saludos.

newtron 25-06-2024 09:29:28

Cita:

Empezado por escafandra (Mensaje 556283)
Date cuenta de una cosa, la función que muestras DameQRIMG devuelve el Stream que ha creado ella misma. Si al salir lo destruye, estas devolviendo un stream inválido que ya no existe. Deberá ser destruido por la función llamadora y para apoyar la idea, tu función debería llamarse algo como CreateQRStream. De esta forma ya indica que el Stream devuelto deberá ser destruido por la función llamadora.


La idea de Neftali va por el mismo camino, sólo que es la función llamadora la que suministra el Stream ya creado.





Saludos.


Gracias compañero y gracias de nuevo por el componente, práctico y fácil de implementar.


La verdad es que estoy algo "atontao" como siempre y, en vez de modificar nuestro reporteador para directamente imprimir cualquier qr usando tu componente, me he mareado creando la imagen y guardándola en el registro para después imprimirla como imagen :rolleyes:.


Saludos.

escafandra 25-06-2024 11:04:19

El componente tiene otra versión para QReport derivado de TQRImage que está enfocado para la impresión de reportes. Si es tu caso, quizás te resulte más útil esa versión.

Saludos.

newtron 25-06-2024 11:23:55

^\||/ Perfecto. Le echaré un vistazo.


Gracias y un saludo.


La franja horaria es GMT +2. Ahora son las 06:43:36.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi