如何将图像列表保存为一个位图,如 tilesheet?

How to save an imagelist as one bitmap like a tilesheet?

我有一个包含多个位图的图像列表,我想将它们一起保存为一个位图,但我需要它保存,就像在 2d 和 rpg 游戏等中绘制 spritesheet 或 tilesheet 一样

通常情况下,tilesheet 绘制有多个图像(连续),因此例如,如果我希望每行最多 6 个图像,它只会绘制 6 个,并在新行的下方绘制更多图像.

我可以像这样将它保存在一行中:

var
  CurrentFrame: Integer;
  StripWidth: Integer;

  Strip: TBitmap;
  Bmp: TBitmap;
  I: Integer;
begin
  if SaveDialog.Execute then
  begin
    StripWidth   := ImageList1.Width * ImageList1.Count - ImageList1.Width;
    CurrentFrame := - ImageList1.Width;

    Strip := TBitmap.Create;
    try
      Strip.SetSize(StripWidth, ImageList1.Height);
      Bmp := TBitmap.Create;
      try
        for I := 0 to ImageList1.Count - 1 do
        begin
          CurrentFrame := CurrentFrame + ImageList1.Width;
          ImageList1.GetImage(I, Bmp);
          Strip.Canvas.Draw(CurrentFrame, 0, Bmp);
        end;
      finally
        Bmp.Free;
      end;

      Strip.SaveToFile(SaveDialog.FileName);
    finally
      Strip.Free;
    end;
  end;
end;

想象一下上面的结果是:

我想要的结果是这样的:

所以上面会在程序/函数中考虑一个参数,例如每行只允许 3 张图像。

如何将图像列表中的所有图像导出到一个位图中,如果在创建新行之前水平绘制图像,则只允许 x 数量?

谢谢。

编辑

感谢 David 的回答,我整理了这些程序:

procedure DrawImageOnSheet(Images: TImageList; Sheet: TBitmap;
  ImageIndex, X, Y: Integer);
var
  Bitmap: TBitmap;
begin
  Bitmap := TBitmap.Create;
  try
    Images.GetBitmap(ImageIndex, Bitmap);
    Sheet.Canvas.Draw(X, Y, Bitmap);
  finally
    Bitmap.Free;
  end;
end;

procedure SaveImageListAsSheet(Images: TImageList; FileName: string;
  NumberOfColumns: Integer);
var
  Sheet: TBitmap;

  nImage: Integer;
  nCol: Integer;
  nRow: Integer;
  nToDraw: Integer;
  nRemaining: Integer;

  ImageIndex: Integer;

  X, Y: Integer;
  I: Integer;
begin
  Sheet := TBitmap.Create;
  try
    nImage := Images.Count;
    nCol   := NumberOfColumns;
    nRow   := (nImage + nCol - 1) div nCol;

    Sheet.Height := nRow * Images.Height;
    Sheet.Width  := nCol * Images.Width;

    nRemaining := nImage;
    ImageIndex := 0;
    Y := 0;
    while nRemaining > 0 do
    begin
      nToDraw := Math.Min(nRemaining, nCol);
      X := 0;
      for I := 0 to nToDraw - 1 do
      begin
        DrawImageOnSheet(Images, Sheet, ImageIndex, X, Y);
        Inc(ImageIndex);
        Inc(X, Images.Width);
      end;
      Inc(Y, Images.Height);
      Dec(nRemaining, nToDraw);
    end;

    Sheet.SaveToFile(FileName);
  finally
    Sheet.Free;
  end;
end;

根据评论的说明,您正在努力解决图像计数、rows/columns 组织等问题。因此,假设您已经拥有将图像 ImageIndex 绘制到输出位图中 XY.

位置的函数
procedure Draw(ImageIndex, X, Y: Integer);

我们还假设图像的尺寸由 ImageWidthImageHeight 给出。最后,有 nImage 个图像,您希望每列有 nCol 个图像。

那么,首先,你需要多少行?

nRow := (nImage + nCol - 1) div nCol;

现在您可以设置输出位图的大小。它的宽度为 nCol * ImageWidth,高度为 nRow * ImageHeight

现在开始绘制图像。

nRemaining := nImage;
ImageIndex := 0;
Y := 0;
while nRemaining > 0 do
begin
  nToDraw := Math.Min(nRemaining, nCol);
  X := 0;
  for i := 0 to nToDraw - 1 do
  begin
    Draw(ImageIndex, X, Y);
    inc(ImageIndex);
    inc(X, ImageWidth);
  end;
  inc(Y, ImageHeight);
  dec(nRemaining, nToDraw);
end;