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:
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:
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.
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.