unit SRVImageScrollUtils;

interface

uses SysUtils, Graphics, Math;

const
  DEF_OPACITY_PERCENT = 3;
  DEF_IMG_HEIGHT_DIVISOR = 3;
  DEF_OPACITY_OFFS = -30;

// Shades Img with BG at the left side. The result is in Img
// OpacityPercent defines how much opacity is increased in each next image column
procedure ShadeImageLeft(Img, BG : TBitmap; OpacityPercent: Integer = DEF_OPACITY_PERCENT);
// Shades Img with BG at the right side. The result is in Img
// OpacityPercent defines how much opacity is increased in each next image column
procedure ShadeImageRight(Img, BG : TBitmap; OpacityPercent: Integer = DEF_OPACITY_PERCENT);
// Increases Img lightness
procedure LightImage(Img : TBitmap);
// Draws Img on BG. Img is mirrored vertically and scaled vertically by 1/HeightDivisor.
// OpacityOffs changes the starting value of opacity
procedure MirrorImage(Img, BG : TBitmap;
  HeightDivisor: Integer= DEF_IMG_HEIGHT_DIVISOR;
  OpacityOffs : Integer = DEF_OPACITY_OFFS);

implementation

{------------------------------------------------------------------------------}
procedure ShadeImageLeft(Img, BG : TBitmap; OpacityPercent: Integer = DEF_OPACITY_PERCENT);
const
     StepX = 1;
     StepY = 1;
var
     opacity, x, y, W, H: Integer;
     cur_p, cur_bg : PByteArray;
begin
  if (Img.Width = 0) or (Img.Height = 0) then
    Exit;

  W := Img.Width;
  H := Img.Height;

  y := 0;
  while (y < H) do begin
    x := 0;
    cur_p := Img.ScanLine[y];
    cur_bg := BG.ScanLine[y];
    while (x < W) do begin
      opacity := x * OpacityPercent mod 100;
      if x * OpacityPercent div 100 = 1 then
        x := W
      else begin
        cur_p^[x*3] := (cur_p^[x*3] * opacity div 100) + (cur_bg^[x*3] * (100 - opacity) div 100);
        cur_p^[x*3+1] := (cur_p^[x*3+1] * opacity div 100) + (cur_bg^[x*3+1] * (100 - opacity) div 100);
        cur_p^[x*3+2] := (cur_p^[x*3+2] * opacity div 100) + (cur_bg^[x*3+2] * (100 - opacity) div 100);

        x := x + StepX;
      end;
    end;
    y := y + StepY;
  end;
end;
{------------------------------------------------------------------------------}
procedure ShadeImageRight(Img, BG : TBitmap; OpacityPercent: Integer = DEF_OPACITY_PERCENT);
const
     StepX = -1;
     StepY = 1;
var
     opacity, x, y, W, H: Integer;
     cur_p, cur_bg : PByteArray;
begin
  if (Img.Width = 0) or (Img.Height = 0) then
    Exit;

  W := Img.Width;
  H := Img.Height;

  y := 0;
  while (y < H) do begin
    x := W-1;
    cur_p := Img.ScanLine[y];
    cur_bg := BG.ScanLine[y];
    while (x >= 0) do begin
      opacity := (W - x) * OpacityPercent mod 100;
      if (W - x) * OpacityPercent div 100 = 1 then
        x := -1
      else begin
        cur_p^[x*3] := (cur_p^[x*3] * opacity div 100) + (cur_bg^[x*3] * (100 - opacity) div 100);
        cur_p^[x*3+1] := (cur_p^[x*3+1] * opacity div 100) + (cur_bg^[x*3+1] * (100 - opacity) div 100);
        cur_p^[x*3+2] := (cur_p^[x*3+2] * opacity div 100) + (cur_bg^[x*3+2] * (100 - opacity) div 100);

        x := x + StepX;
      end;
    end;
    y := y + StepY;
  end;
end;
{------------------------------------------------------------------------------}
// Increases Img lightness
procedure LightImage(Img : TBitmap);
const
     StepX = 1;
     StepY = 1;
     light = 140;

var
     x, y, W, H: Integer;
     cur_p : PByteArray;
begin
  if (Img.Width = 0) or (Img.Height = 0) then
    Exit;

  W := Img.Width;
  H := Img.Height;

  y := 0;
  while (y < H) do begin
    x := 0;
    cur_p := Img.ScanLine[y];
    while (x < W) do begin
      cur_p^[x*3] := Min(cur_p^[x*3] * light div 100, 255);
      cur_p^[x*3+1] := Min(cur_p^[x*3+1] * light div 100, 255);
      cur_p^[x*3+2] := Min(cur_p^[x*3+2] * light div 100, 255);

      x := x + StepX;
    end;
    y := y + StepY;
  end;
end;
{------------------------------------------------------------------------------}
procedure MirrorImage(Img, BG : TBitmap;
  HeightDivisor: Integer= DEF_IMG_HEIGHT_DIVISOR;
  OpacityOffs : Integer = DEF_OPACITY_OFFS);
const
     StepX = 1;
     StepY = 1;

var
     x, y, opacity, W, H: Integer;
     cur_p, cur_bg : PByteArray;
begin
  if (Img.Width = 0) or (Img.Height = 0) then
    Exit;

  W := Img.Width;
  H := Img.Height;

  y := 0;
  while (y < H) do begin
    x := 0;
    cur_p := Img.ScanLine[H-1 - y];
    opacity := Max(Min(OpacityOffs + ((H-1 - y) * 100 div H), 100), 0);
    cur_bg := BG.ScanLine[y div HeightDivisor];
    while (x < W) do begin
      cur_bg^[x*3] := (cur_p^[x*3] * opacity div 100) + (cur_bg^[x*3] * (100 - opacity) div 100);
      cur_bg^[x*3+1] := (cur_p^[x*3+1] * opacity div 100) + (cur_bg^[x*3+1] * (100 - opacity) div 100);
      cur_bg^[x*3+2] := (cur_p^[x*3+2] * opacity div 100) + (cur_bg^[x*3+2] * (100 - opacity) div 100);

      x := x + StepX;
    end;
    y := y + HeightDivisor;
  end;
end;

end.
