0

How do I create a checksum for TBitmap in Firemonkey? (not TPicture). Preferably directly, and not saving to Streams.

I've done some research on Map that replaces Scanline in Firemonkey... How to access TBitmap pixels directly in FMX2 (TBitmap.ScanLine replacement)?

but still completely lost. Does anyone have an idea how to use the FMX scanline replacement to do this?

I saw below code for VCL :

Checksum an image in Delphi

Function Checksum_CountryFlag(Img : TPicture):Integer;
var j, k, Checksum : Integer;
  Line: PIntegerArray;
  Pixel : integer;
begin
  Checksum := 0;
  Img.Bitmap.PixelFormat:= pf32bit; // just for case
  For k := 0 to Img.Height - 1 do begin      //  !! Height first, -1
    Line:= Img.Bitmap.ScanLine[k];
    For j := 0 to Img.Width - 1 do begin  // !! -1
      Pixel := Line^[j];
      If ((Pixel <> 15577344) And (Pixel <> 15311104) And (Pixel <> 3816255)
        And (Pixel <> 10526623) And (Pixel <> 12303034) And (Pixel <> 9013641)) Then
        begin
          Checksum := Checksum + Pixel;
        end;
      Inc(Line);
    end;
  end;
  Result := Abs(Checksum);
end;

Basically I just need to check if image (in memory) has changed (Width/Height not sufficient as most times the Width/Height do not change even if image has changed), and I prefer not to save to Streams to do a Hash if I can do a direct checksum on FMX TBitmap.

Qn : How do I use the below code to do a checksum on the scanline equivalent?

procedure TForm1.btnCompareClick(Sender: TObject);
var
  bd1, bd2 : TBitmapData;
  w,h : Integer;
begin
  Image1.Bitmap.LoadFromFile('c:\1.jpg');
  Image2.Bitmap.LoadFromFile('c:\2.jpg');
  w := Image1.Bitmap.Width;   
  h := Image1.Bitmap.Height;
  try
    Image1.Bitmap.Map(TMapAccess.Read, bd1);
    Image2.Bitmap.Map(TMapAccess.Write, bd2);
    AlphaColorToScanline(@PAlphaColorArray(bd1.Data)[0], bd2.Data,
    Round(w * h), Image1.Bitmap.PixelFormat);
  finally
    Image1.Bitmap.Unmap(bd1);
    Image2.Bitmap.Unmap(bd2);
  end;
end;
Peter Jones
  • 451
  • 2
  • 12
  • Hash the scan lines. This won't prove that the image is unchanged of course. You'd need to store a copy of the image to do that. – David Heffernan Dec 26 '20 at 09:07
  • 1
    Checksum nor hash will guarantee the image has not changed. You should keep a copy before doing change and then compare. To speedup things, directly compare scan lines, not each individual pixel. – fpiette Dec 26 '20 at 14:16
  • yes, I understood that I have to keep a copy of original Bitmap to compare (or at least obtain a hash of original bitmap before discarding it). How do I do checksum/hash on ScanLine in Firemonkey TBitmap given that ScanLine does not exist? Thank you. – Peter Jones Dec 28 '20 at 01:24
  • You can use the [`Map`](http://docwiki.embarcadero.com/Libraries/Sydney/en/FMX.Graphics.TBitmap.Map) function to get direct access to the bitmap data. – GolezTrol Dec 29 '20 at 16:32
  • @GolezTrol I know it's using Map (as shown in my link which I researched) but how do I do a checksum on `AlphaColorToScanLine`? – Peter Jones Dec 31 '20 at 01:00
  • `Map` gives you a `TBitmapData`, which exposes a `GetScanline` method. Isn't that what you need? It even gives you the `Data` pointer that points to the whole buffer, so you can get the whole data without going over the individual scanlines. `GetScanLine` is implemented as `Result := Pointer(NativeInt(Data) + I * Pitch);`, so it looks like Data points to a buffer of size `Pitch * Height`, which is probably the same as `Width * Height * BytesPerPixel`. – GolezTrol Dec 31 '20 at 08:59
  • @GolezTrol thanks so much. i'm getting closer. May I ask how to get a Hash or checksum of individual scanlines (without doing has of every pixel)? this aspect of code is entirely new to me. If you could post a small code segment, I'll mark it as the answer so that others can benefit from it too. thanks! – Peter Jones Jan 01 '21 at 03:01

0 Answers0