#1 2022-06-13 16:56:05

tbo
Member
Registered: 2015-04-20
Posts: 353

TPngImage function CanLoadFromStream()

Unit: mormot.ui.gdiplus

For Delphi 10.2 and higher the function CanLoadFromStream() must be defined, otherwise the following source code will not work:

Image.Picture.LoadFromStream(Stream);

PNG documentation is here. Required changes:

TPngImage = class(TSynPicture)
public
{$ifdef ISDELPHI102}
  class function CanLoadFromStream(pmStream: TStream): Boolean; override;
{$endif}
end;

{ TPngImage }
{$ifdef ISDELPHI102}
class function TPngImage.CanLoadFromStream(pmStream: TStream): Boolean;
type
  TPngSignature = array[0..7] of AnsiChar;
const
  PNG_SIGNATURE: TPngSignature = (#137, #80, #78, #71, #13, #10, #26, #10);
var
  pos: Int64;
  sig: TPngSignature;
begin
  pos := pmStream.Position;
  try
    Result := (pmStream.Read(sig, SizeOf(TPngSignature)) = SizeOf(TPngSignature));
    if Result then
      Result := CompareMemSmall(@sig[0], @PNG_SIGNATURE[0], SizeOf(TPngSignature));
  finally
    pmStream.Position := pos;
  end;
end;
{$endif}

With best regards
Thomas

Offline

#2 2022-06-13 17:14:41

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,657
Website

Re: TPngImage function CanLoadFromStream()

I didn't know about this new method.

Why can't we just let CanLoadFromStream() always return true, and let the regular behavior be used?
For instance, a TSynPicture is not limited to PNG or any single format.

Please try https://github.com/synopse/mORMot2/commit/0d874d18

Online

#3 2022-06-13 17:31:19

tbo
Member
Registered: 2015-04-20
Posts: 353

Re: TPngImage function CanLoadFromStream()

ab wrote:

Why can't we just let CanLoadFromStream() always return true, and let the regular behavior be used?

I think the change can't work because it's defined that way:

procedure TPicture.LoadFromStream(Stream: TStream);
...
  GraphicClass := FileFormats.FindFormat(Stream);
...
end;

function TFileFormatsList.FindFormat(Stream: TStream): TGraphicClass;
var
  I: Integer;
begin
  for I := Count - 1 downto 0 do
    with TFileFormatType(Items[I]) do
      if GraphicClass.CanLoadFromStream(Stream) then
      begin
        Result := GraphicClass;
        Exit;
      end;
  Result := nil;
end;

With best regards
Thomas

Last edited by tbo (2022-06-13 17:40:43)

Offline

#4 2022-06-13 18:21:39

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,657
Website

Re: TPngImage function CanLoadFromStream()

Online

#5 2022-06-14 10:46:18

tbo
Member
Registered: 2015-04-20
Posts: 353

Re: TPngImage function CanLoadFromStream()

Thank you very much. But shouldn't the name of the function CanLoadFromMemory() rather be:

class function CheckFileSignature(pmFirst4Bytes: Cardinal): Boolean; virtual;

Following this Wikipedia article: List of file signatures. Ok, English is not my language, but with the name CanLoadFromMemory() I didn't know what to expect. Of course, I could be completely wrong.

With best regards
Thomas

Offline

#6 2022-06-14 15:05:06

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,657
Website

Re: TPngImage function CanLoadFromStream()

I followed the Delphi method logic.
Otherwise, the Delphi method should be renamed CheckStreamSignature().

Online

#7 2022-06-14 16:46:49

tbo
Member
Registered: 2015-04-20
Posts: 353

Re: TPngImage function CanLoadFromStream()

ab wrote:

I followed the Delphi method logic.
Otherwise, the Delphi method should be renamed CheckStreamSignature().

The name of the function CanLoadFromStream(pmStream: TStream) is correct, because a stream is passed as parameter. You can use any part of the stream for your check and there may be other reasons for not loading. The function CanLoadFromMemory(first4: cardinal) is a class function and only the first four bytes are passed. For me, the functionality of this function is not necessarily apparent from the name.

But that is only theory. Much more interesting is: If you better use the mormot.ui.gdiplus unit instead of the Vcl.Imaging.pngimage, saving a 2MB PNG image takes 9 ms vs. 900 ms with the Delphi unit. Loading is done in 10 ms instead of 80 ms. I should probably mention that the images are AES encrypted (TAesPkcs7Reader/TAesPkcs7Writer) and stored in a zip file. These are the facts why I like mORMot so much. wink Many thanks for that.

With best regards
Thomas

Offline

Board footer

Powered by FluxBB