SpritesImage := TPortableNetworkGraphic.Create();
ResultImage := TPortableNetworkGraphic.Create();
//ResultImage.PixelFormat := pf32bit;
try
SpritesImage.LoadFromFile(SourceFile);
SpriteWidth := SpritesImage.Width div UNITS_SPRITES_PER_ROW;
SpriteHeight := SpriteData.SpriteHeight;
ResultImage.Width := SpriteWidth * SPRITES_PER_PLAYER_UNIT;
ResultImage.Height := SpriteHeight * MAX_PLAYER_NUMBER;
// For copying and flipping CopyRect is used, but it loses transparency! Not resolved yet, but if one doesn't need transparency works great!
// Copy original 5 sprites
SrcRect := TRect.Create(0, 0, SpritesImage.Width, SpriteHeight);
DestRect := TRect.Create(0, 0, SpritesImage.Width, SpriteHeight);
ResultImage.Canvas.CopyRect(DestRect, SpritesImage.Canvas, SrcRect);
// Add missing sprites to the sequence
// It should: 1 2 3 4 5 -> 1 2 3 4 5 4' 3' 2'
for i := 1 to 3 do begin
SrcIndex := UNITS_SPRITES_PER_ROW - i;
DestIndex := UNITS_SPRITES_PER_ROW + i;
// Reverse destination x axis to get horizontal flip effect
SrcRect := TRect.Create((SrcIndex - 1) * SpriteWidth, 0, SrcIndex * SpriteWidth, SpriteHeight);
DestRect := TRect.Create(DestIndex * SpriteWidth, 0, (DestIndex - 1) * SpriteWidth, SpriteHeight);
ResultImage.Canvas.CopyRect(DestRect, SpritesImage.Canvas, SrcRect);
end;
// Duplicate first row
SrcRect := TRect.Create(0, 0, ResultImage.Width, SpriteHeight);
for c := 2 to 8 do begin
DestRect := TRect.Create(0, c * SpriteHeight, ResultImage.Width, (c + 1) * SpriteHeight);
ResultImage.Canvas.CopyRect(DestRect, ResultImage.Canvas, SrcRect);
end;
// Approach with Canvas.Pixels is extremely slow (~10 sec per image which is ~700x700 px on old 2HGz Celeron), but safe unlike ScanLine
// Also I don't use Begin/EndUpdate as using them causes just a black color over all image (even calling EndUpdate right after BeginUpdate! Have no idea why).
// Repaint each row for corresponding color
// First row already has correct color
for c := 2 to 8 do begin
for y := c * SpriteHeight to (c + 1) * SpriteHeight do begin
for x := 0 to ResultImage.Width do begin
PixelColor := ResultImage.Canvas.Pixels[x, y];
for i := 0 to COLOR_SHADES_NUMBER do begin
if (PixelColor = SPRITES_COLORS[1][i]) then begin
ResultImage.Canvas.Pixels[x, y] := SPRITES_COLORS[c][i];
break;
end;
end;
end;
end;
end;
//ResultImage.TransparentColor := clBlack;
ResultImage.SaveToFile(ResultFileName + '.png']));
finally
SpritesImage.Free();
ResultImage.Free();
end;