Bitmap/TBlob

Wagner,


I understand how TBlob should work and how can i load using stream etc.

But I am not making it work with live binding.

I have:

    [Column('PICTURE', [TColumnProp.Lazy])]
    property Picture: TBlob read GetPicture write SetPicture;

and I need it to display in a TListView where there is a ITEM.BITMAP.

Do you have any example of showing pictures on a list using Aurelius and TBlob?

I am the following test:


using the defined Picture property I load it on memory with a png that is part of the resources of the project (used on other parts) as follow:

function TEntityItem.GetPicture: TBlob;
begin
  if FPicture.IsNull then
    AssignResource('default', FPicture);

  result := FPicture;
end;

The I have connected it on the livebinding to the ITEM.BITMAP. (this TListView is working for me, I have the others ITEM.* assigned and showing data)

I traced with debug and I see that GetPicture is called and AssignResource is executed:

procedure TNaharEntity.AssignResource(AName: String; ABlob: TBlob);
var
  InStream: TResourceStream;
begin
  try
    InStream := TResourceStream.Create(HInstance, AName, RT_RCDATA);
    try
      if Assigned(InStream) then
        ABlob.LoadFromStream(InStream);
    finally
      InStream.Free;
    end;
  except
  end;
end;

And seems to have data on FBlob.

However nothings shows up on the TListView.

I am trying other thing also:

to the above entity definition i have added:
    [Column('PICTURE', [TColumnProp.Lazy])]
    property Picture: TBlob read GetPicture write SetPicture;

    property Image: TBitmap read GetBitmap;

that Image property, that is not mapped to the database.

where getbitmap:

procedure TEntityItem.LoadBitmapFromBlob(Bitmap: TBitmap; Blob: TBlob);
var
  ms, ms2: TMemoryStream;
begin
  ms := TMemoryStream.Create;
  try
    Blob.SaveToStream(ms);
    ms.Position := 0;
    Bitmap.LoadFromStream(ms);
  finally
    ms.Free;
  end;
end;

function TEntityItem.GetBitmap: TBitmap;
begin
  LoadBitmapFromBlob(FBitMap, FPicture);
  Result := FBitMap;
end;

HOWEVER, the IMAGE property is not showing up on the TAureliusDataset. I dont understand what is the rule for that. Since other properties that are non mapped are showing.

I was trying to use it as a "calculated field" to circumvent the problem of TBlob. But this is a problem either since it uses FMX.Graphics, and I need a framework independent. I use this code for VCL and FMX. 

Does aurelius create TBitmapField or something like that on TAureliusDataset? how is that implemented? I need to have something bitmap compatible in the view side, ie, on TAureliusDataSet since this layer is platform dependent. When writing this same layer for VCL it should act using the platform specific image support.

Eduardo

For TAureliusDataset, TBlob properties are supported. The dataset just creates a TBlobField (ftBlob) that properly reads and writes the blob content. If you have a valid image value in the blob, it should display in dbfields like TDBImage. 

For livebindings, it probably doesn't work directly, since TBlob is a record. You should create a live binding converter from TBlob to the type you want.

" You should create a live binding converter from TBlob to the type you want."


I didnt know about this, I am still learning livebinding, and I believe this is the way to go!

I know this is not the goal of this forum, but I wonder if you point me to article or documentation on how to do that (I will be willing to share that when done), since I have not found ANYTHING on how to create a binding converter.

Thank you

Eis um exemplo (não testado, enviado por um usuário) para conversão de tipos Nullable<F> para F para uso no live bindings. Você pode tentar adaptar ao TBlob:


class procedure TConverter.NullableTo<F>;
begin
  TValueRefConverterFactory.RegisterConversion(TypeInfo(Nullable<F>), TypeInfo(F), TConverterDescription.Create(
    procedure(const I: TValue; var O: TValue)
    begin
      O := TValue.From<F>(I.AsType < Nullable < F >>.ValueOrDefault);
    end, 'NullableTo' + GetTypeName(TypeInfo(F)), 'NullableTo' + GetTypeName(TypeInfo(F)), sThisUnit, True, '', nil 
    ));

  TValueRefConverterFactory.RegisterConversion(TypeInfo(F), TypeInfo(Nullable<F>), TConverterDescription.Create(

    procedure(const I: TValue; var O: TValue)
    var
      Rec: Nullable<F>;
    begin
      Rec.Value := I.AsType<F>;
      O := TValue.From < Nullable < F >> (Rec);
    end, GetTypeName(TypeInfo(F)) + 'ToNullable', GetTypeName(TypeInfo(F)) + 'ToNullable', sThisUnit, True, '', nil 
    ));
end;

initialization
  TConverter.NullableTo<Integer>;
  TConverter.NullableTo<string>;
  TConverter.NullableTo<Double>;

Wagner,


Esta dificil fazer isto funcionar :)

A unica coisa que me falta em todo o sistema é a ligacao entre TBlob e TBitmap de uma TListView em todo o sistema. Sei que fica fora do escopo do suporte, mas se voce conseguir alguma dica a mais para eu terminar isto vai fazer uma diferenca enorme no meu sistema. Que é todo basado em TListViews e Livebinding com o TAUreliusDataset. Esta tudo funcionando, porem fica um vazio nas listas por falta da imagem.

No momento eu nao tenho uma propriedade mapeada para BD, estou usando a qualidade do aurelius dele criar campos no TAureliusDataset the propriedades nao mapeadas. Muito util para ser usado como um tipo de campo calculado.

O que pretendo fazer eh o seguinte:

De acordo com alguma informacao da entidade eu seleciono um certo recurso e carrego ele para ser devolvido como TBlog.

Neste momento estou fazendo isto:

function TNaharEntity.GetImage: TBlob;
begin
  if FImage.IsNull then
    AssignResource('default', FImage);

  result := FImage;
end;

onde:
procedure TNaharEntity.AssignResource(AName: String; ABlob: TBlob);
var
  InStream: TResourceStream;
begin
  try
    InStream := TResourceStream.Create(HInstance, AName, RT_RCDATA);
    try
      if Assigned(InStream) then
        ABlob.LoadFromStream(InStream);
    finally
      InStream.Free;
    end;
  except
  end;
end;

Estou dentro do contexto do scope do Firemonkey.

A Imagem carregada dos recursos é  um PNG.

Esta imagem eu uso para ligar via LiveBinding com a TListView. Estou usando a TListView com uma customizacao como se encontra na demo:
C:\Users\Public\Documents\Embarcadero\Studio\14.0\Samples\Object Pascal\Mobile Samples\User Interface\ListView 

projeto SampleListViewMultiDetailAppearanceProject
 porem tem que instalar antes o SampleListViewMultiDetailAppearancePackage que se encontra no mesmo diretorio.

Esta listview mostra uma customizacao que eu uso em todas minhas listas onde mostra uma imagem e 4 items ao lado da imagem. Que podem ser conectada via live binding. 

Eu uso isto em tudo no sistema, e o Aurelius me ajuda muito nisto pois eu criei as seguintes propriedades na minha classe base da entidade:

    property    ITEMTEXT    : string read GetItemText;
    property    ITEMDETAIL1 : string read GetItemDetail1;
    property    ITEMDETAIL2 : string read GetItemDetail2;
    property    ITEMDETAIL3 : string read GetItemDetail3;
    property    ITEMIMAGE   : TBlob  read GetImage;

E elas sao expostas pelo Aurelius no DataSet. Entao cada entidade faz um override e atribui um valor apropriado para cada. Na view fica muito simples, pois basta sempre fazer as mesmas conexoes entre BindSource e TListView sem pensar em nada. A propria entidade ja determinar o que vai ser apresentado. Simples facil e radido

Mas a ligacao do TBlob com o TBitmap da TListView nao funciona.

O codigo que voce compartilhou nao teve jeito de eu adaptar e fazer funcionar. Na realidade nem este codigo acima consegui fazer ele ser chamado para a solucacao proposta, é como se nao tivesse sido registrado (e foi).

Entao, se voce souber alguma coisa a mais, ou alguem da equipe saber um pouco sobre como fazer esta ligacao entre o TBlob do Aurelius com o LiveBinding eu agradeceria muito.

Obrigado


I have added a SO question for this one (that is the translation of the above question)


http://stackoverflow.com/questions/25276478/how-to-make-a-livebinding-converter-from-tblob-to-tbitmap

Please, if someone on the forum knows the solution for this I would appreciate the help.

Thanks !!!

For those interested on the answer:


I have found there is no need to translate TBlob to TBitmap when it contains PNG.

The problem is that my AssignResource function was wrong, this is the correct declaration:

procedure TNaharEntity.AssignResource(AName: String; var ABlob: TBlob);

It was missing that "var" and the variable was not gettng assigned. Yes, a little mistake that had a high price of many hours.

Internally live bindings try to match the objects using TPersistent.Assign as the last resource to transfer one object content to another.

In the case of Aurelius TBlob, the assignement always happen, but it is up to the target to decode what is inside it.