{-------------------------------------------------------------------------
 Module:    OSM Tile PNG Decoder (Shared)

 Comment:   Loads an OSM tile PNG from disk and decodes it to a BGRA
            pixel array (Cardinal per pixel, $AARRGGBB layout).
            Shared between TGlobe4, TGlobe5, and other consumers.

            FPC note: Uses Canvas.Draw instead of TBitmap.Assign to work
            around LCL 64-bit ScanLine returning zeroed data after Assign.
-------------------------------------------------------------------------}
{$IFDEF FPC}{$MODE DELPHI}{$ENDIF}
{$WEAKPACKAGEUNIT ON}
unit uCICOSMTileDecode;

interface

uses
  SysUtils, Classes, Graphics,
  {$IFNDEF FPC}
  Vcl.Imaging.pngimage,
  {$ENDIF}
  uCICOSMTileCommon;

function OSMDecodePngToBGRA(const Path: string;
  Dest: POSMTilePixels): Boolean;

implementation

{$IFDEF FPC}
type
  TPngImage = TPortableNetworkGraphic;
{$ENDIF}

function OSMDecodePngToBGRA(const Path: string;
  Dest: POSMTilePixels): Boolean;
var
  Png: TPngImage;
  Bmp: TBitmap;
  Row, Col: Integer;
  SrcLine: PByteArray;
  P: PCardinal;
  BytesPerPixel: Integer;
begin
  Result := False;
  if not FileExists(Path) then
    Exit;

  Png := TPngImage.Create;
  Bmp := TBitmap.Create;
  try
    try
      Png.LoadFromFile(Path);

      if (Png.Width <> OSM_TILE_SIZE) or (Png.Height <> OSM_TILE_SIZE) then
        Exit;

      {$IFDEF FPC}
      // LCL: TBitmap.Assign(PNG) + ScanLine returns zeroed data on 64-bit.
      // Use Canvas.Draw to render the PNG onto a pf24bit bitmap instead.
      Bmp.PixelFormat := pf24bit;
      Bmp.SetSize(OSM_TILE_SIZE, OSM_TILE_SIZE);
      Bmp.Canvas.Draw(0, 0, Png);
      // GTK2 returns 32bpp BGRA from ScanLine even for a pf24bit bitmap.
      // Query the actual stride so the pixel loop works on any platform.
      BytesPerPixel := Bmp.RawImage.Description.BitsPerPixel div 8;
      {$ELSE}
      Bmp.Assign(Png);
      Bmp.PixelFormat := pf24bit;
      if (Bmp.Width <> OSM_TILE_SIZE) or (Bmp.Height <> OSM_TILE_SIZE) then
        Exit;
      BytesPerPixel := 3; // Windows pf24bit is always 24bpp
      {$ENDIF}

      P := @Dest^[0];
      for Row := 0 to OSM_TILE_SIZE - 1 do
      begin
        {$IFDEF FPC}{$PUSH}{$WARN 5044 OFF}{$ENDIF}
        SrcLine := Bmp.ScanLine[Row];
        {$IFDEF FPC}{$POP}{$ENDIF}
        for Col := 0 to OSM_TILE_SIZE - 1 do
        begin
          P^ := $FF000000 or
                (Cardinal(SrcLine[Col * BytesPerPixel + 2]) shl 16) or  // R
                (Cardinal(SrcLine[Col * BytesPerPixel + 1]) shl 8)  or  // G
                 Cardinal(SrcLine[Col * BytesPerPixel]);                  // B
          Inc(P);
        end;
      end;
      Result := True;
    except
      // Silently ignore corrupt or unreadable PNG files
    end;
  finally
    Bmp.Free;
    Png.Free;
  end;
end;

end.
