2
votes

My software is heavily based on Firemonkey TListView, that was customized based on the "SampleListViewMultiDetailAppearanceProject" found in the Delphi Samples project.

"C:\Users\Public\Documents\Embarcadero\Studio\14.0\Samples\Object Pascal\Mobile Samples\User Interface\ListView\"

This is how it looks like, using a PrototypeBindSource:

TListView Sample

Each record shows up 1 image and 4 text items.

I am using TMS Aurelius as a dataset, that is connected to a BindSource. It is a TDataset descendant using all the standard field types.

It implements the TBlobField that internally is:

  TBlob = record
  private
    FIntData: TArray<byte>;

On the DataSet this field is defined "like" a calculated field, since it is an entity based framework (ORM) each record represent an object, but at the end is the same stuff, the data retrieved is a field with raw data.

My intention is to set different images, loaded from the project resources (project->resources and images), according some state of the record. The image stored is a small PNG image (48x48).

To read the PNG image stored from resource I am using this:

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

When the TBlobField is retrieved by the livebinding system, the function called is this:

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

  result := FImage;
end;

FImage is a TBlob type with some helper functionality, but like I said is a TArray and there is no processing of any type, just a container.

So, FImage is going directly to the TBitmap of the FMX TListView.

Nothing happens, no image is displayed.

I have tried the following code:

  TValueRefConverterFactory.RegisterConversion(TypeInfo(TBlob), TypeInfo(TBitMap), TConverterDescription.Create(

    procedure(const I: TValue; var O: TValue)
    var
      Blob: TBlob;
      BitMap: TBitMap;
    begin
      Blob := I.AsType<TBlob>;

      BitMap := O.AsType<TBitMap>;
    end,

    'BlobToBitMap' + GetTypeName(TypeInfo(TBlob)), 'BlobToBitMap' + GetTypeName(TypeInfo(TBitMap)), 'Nahar.LiveBinding', True, '', nil
    ));

Got this code from other kind of conversion not related to image. But it is clearly wrong, besides the fact it compiles.

Problems in this code: - it seems to get registered, I placed a breakpoint, and the RegisterConversion does get executed, but a breakpoint inside, in the anonymous procedure, is never executed. I am registering this on the initialization part before any frame is created that contains TLisviews. - the conversion itself, in the anonymous procedure, is pure fiction; since I believe the Blob is stored as png and the output should be fmx bitmap. I have no idea what to write there.

The documentation is scarce on this topic and not helpful for my understanding.

I would like to know how to proper make the sequences on this process:

  • do I need to convert from png to bitmap? how?
  • do I need to have to register the conversion adapter? how? Why is not getting fired?
  • What is the correct conversion code inside this conversion adapter?

OR

I see there is a ftGraphic TField on TDataset, and I can create a field of that type. But there are this problems: - What is the expected TField return for such type? - My code is shared between platforms: VCL and FMX, and TBitMap or TGraphic are not the same on both. This sharing is made by a bpl package that is not scoped. It is needed since I was having conflicts of other bpls registered. I have one shared common bpl and others platform specific bpl that uses it.

Since I have not found a way to solve this bpl sharing and incompatibility of platform units I switched to the first option, trying to deal with raw data at database level, and letting the conversion happens at livebinding level, already in the domain of each platform

I am a complete ignorant related to image related manipulation specially when it comes to conversion and the correct object creation, to avoid memory leaking.

IMPORTANT: it has to be cross platform either, since the fmx application is used on android.

1
ftGraphic is a bitmap, as is stated in the documentation. It's based on the VCL.Graphics bitmap.Ken White
@KenWhite ok, but is the same bitmap for FMX? For the little I know seems to have 2 different bitmaps not direct compatible. And the problem is that using ftGraphic i will need to add the units that are not common for both VCL and FMX, and at the end I cannot generate my common bpl that uses the entities and should be platform agnostic.Eduardo Elias
My point was that a) it's a bitmap, and b) it's a VCL bitmap. Note that there's no FMX there anywhere, and no mention of the PNG format you said you were using. ftGraphic has been around since Delphi 1 and before, in the days of Paradox being a major database type. It's not appropriate for what you're trying to do here. (And I can't answer your question, or I would have done so instead of posting a comment. I was just noting that one of the options you had mentioned was most likely not going to be useful.) If the ftGraphic field type is based on VCL.Graphics, it's not the proper type.Ken White
@KenWhite Sorry to not be clear. The question was tagged Firemonkey, I should be clearer on the text. I have edited and added that the TListVIew is a Firemonkey one. And that the Image retrieved from the project resource is of PNG type. (however it was there).Eduardo Elias
:-) No, you misunderstood what I said. The question was clearly about FMX; I was saying that ftGraphic was not proper because your question was about FMX, and because ftGraphic has been around since before PNGs existed. Your question was fine, but ftGraphic isn't really an option you should be considering.Ken White

1 Answers

1
votes

There is no need to make any conversion.

Following David Heffernan information that TBitmap in FMX recognizes the PNG format naturally I have found that the error was in the way I was calling my AssignResource function:

procedure TEntity.AssignResource(AName: String; ABlob: TBlob);

however this is the correct:

procedure TEntity.AssignResource(AName: String; VAR ABlob: TBlob);

Making this change corrected the problems and weeks of searching and agony.