TPortableNetworkGraphic

Trying to load a PNG image and display it on the canvas has been… not fun. Delphi only knew about BMP stored in some horrible Microsoft resource format, and so everything FreePascal adds on top is a pile of hacks or undocumented features. The WWW was not especially helpful.

Mostly I'm posting this so someone else might find it in a search.

uses Classes, SysUtils, Controls, Graphics, LCLType, types, contnrs;

{
type
    TSprite = class
    public
        color: integer;
        filename: array of utf8string;
        subrect: array of TRect;
        constructor Create(c: integer; f: utf8string; r: TRect);
    end;
}

var
    imageCache: TFPObjectHashTable;

function getImage(filename: utf8string): TPortableNetworkGraphic;
var
    img: TPortableNetworkGraphic;
begin
    img := imageCache.Items[filename] as TPortableNetworkGraphic;
    if img = nil then begin
        try
            img := TPortableNetworkGraphic.Create();
            img.loadFromFile(filename);
            imageCache.Items[filename] := img;
        except on e: Exception do begin
            LogError(Format('Image %s: %s', [filename, e.message]));
            raise;
        end;
        end; // try
    end;
    Result := img;
end;

procedure drawSprite(canvas: TCanvas; spr: TSprite; srect: TRect; tick: integer);
var
    img: TPortableNetworkGraphic;
    frame, nframes: integer;
begin
    if spr.color <> dawnUndefined then begin
        canvas.Brush.color := spr.color;
        canvas.FillRect(srect);
    end;

    nframes := length(spr.filename);
    if nframes > 0 then begin
        frame := tick mod nframes;
        img := getImage(spr.filename[frame]);
        canvas.CopyRect(srect, img.canvas, spr.subrect[frame]);
    end;
end;