26 setembro 2012

TMemoryStream: Resolva o problema para imagens grandes

Essa dica vai ajudar muita gente!
Já aconteceu com você de precisar transferir uma imagem (principalmente JPEG) ou qualquer outro Stream (seja via datasnap ou qualquer outro meio) e se deparar com vários erros gerados pelo Delphi? Um deles é o "Out of memory while expanding..."

Acontece que o TMemoryStream só aceita até 40kb, segundo o docwiki da embarcadero e isso é um problema sério pra nós programadores.

Mas vamos lá, sem mais, declare a função abaixo no seu código e quando for salvar ou carregar seu Stream, use-a. Vou dar exemplos abaixo.


 function CopyStream( const source: TStream ): TStream;  
 //resolve o problema de memory stream com mais de 40kb  
 var  
  BytesRead: Integer;  
  Buffer: PByte;  
 const  
  MaxBufSize = $F000;  
 begin  
  { ** Criando a instância do objeto TMemoryStream para retorno do método ** }  
  result := TMemoryStream.Create;  
  { ** Reposicionando o stream para o seu início ** }  
  source.Seek( 0, TSeekOrigin.soBeginning );  
  source.Position := 0;  
  GetMem( Buffer, MaxBufSize );  
  { ** Realizando a leitura do stream original, buffer a buffer ** }  
  repeat  
   BytesRead := Source.Read( Buffer^, MaxBufSize );  
   if BytesRead > 0 then  
    result.WriteBuffer( Buffer^, BytesRead );  
  until MaxBufSize > BytesRead;  
  { ** Reposicionando o stream de retorno para o seu início ** }  
  result.Seek( 0, TSeekOrigin.soBeginning );  
 end;  


Para usar:

  •     TempStream:= TMemoryStream.Create;  
        IMG.Graphic.SaveToStream(TempStream);  
        Result:= CopyStream(TempStream);  
    
  • TempStream = TMemoryStream
  • IMG = TPicture
  • A função retorna um TStream
Quando for dar um loadfromstream, use a função também:
  •  vFoto1.LoadFromStream(CopyStream(StreamRetorno))  
    

Desse modo, você pode enviar Streams de qualquer tamanho!

Abraço a todos!

4 comentários:

  1. Muito obrigado pela dica. Acabei de usar em um projeto aqui no trabalho.
    Um abraço!

    ResponderExcluir
  2. boa noite.

    estou tentando salvar as configurações de um cxgrid usando o comando...storedtostream(Stream);

    em seguida pegar o conteudo da variavel Stream e atribuir num memo. no entanto. no memo só aparece o inicio...não aprece toda informação

    ja usei a função acima, mas mesmo assim não da certo.

    gvLog.StoreToStream(TempStream);
    cxMemo1.lines.LoadFromStream(CopyStream(TempStream));

    consegue me ajudar?

    grato

    ResponderExcluir
    Respostas
    1. Olá... vc deve usar a funcao copystream tanto no save quanto no load....
      Ex: gvLog.StoreToStream(CopyStream(TempStream));

      Excluir
  3. Estou utilizando Delphi 2010 + ClientDataSet + Oracle 11g.

    Tenho um clientdataset com um campo Blob para gravar fotos.

    Antes quando eu utilizava o Delphi 7, eu usava da seguinte forma:

    OpenPictureDialog1.FileName := '';
    OpenPictureDialog1.InitialDir := '\\DADOS\LOGOMARCAS';
    OpenPictureDialog1.Execute;

    try
    if OpenPictureDialog1.FileName > '' then
    CdsEmpresaLOGO.LoadFromFile(OpenPictureDialog1.FileName)
    else
    CdsEmpresaLOGO.Clear;
    except
    CdsEmpresaLOGO.Clear;
    dmConexao.msg.MessageBox('Não foi possível carregar a imagem!','ATENÇÃO',MB_OK+MB_ICONERROR);
    end;

    funcionava perfeitamente, agora com a mudança a partir da versão do Delphi 2010 para trabalhar com Unicode em campos Blob, esse procedimento acima não funciona mais.

    Gostaria de saber se alguém sabe como resolver o problema, pois não encontrei nenhuma solução na Net.

    Obrigado!

    ResponderExcluir