//Advanced Delphi Systems Code: ads_Bitmap
unit ads_Bitmap;
{Copyright(c)2016 Advanced Delphi Systems

 Richard Maley
 Advanced Delphi Systems
 12613 Maidens Bower Drive
 Potomac, MD 20854 USA
 phone 301-840-1554
 dickmaley@advdelphisys.com

 The code herein can be used or modified by anyone.  Please retain references
 to Richard Maley at Advanced Delphi Systems.  If you make improvements to the
 code please send your improvements to dickmaley@advdelphisys.com so that the
 entire Delphi community can benefit.  All comments are welcome.
}
(*
UnitIndex Master Index Implementation Section Download Units
Description: ads_Bitmap.pas
This unit contains the following routines.

BitmapInvert_1   BitmapInvert_2   BitmapInvert_3   BitmapInvert_4   BitmapToGrayscale_1  BitmapToGrayscale_2  BitmapToGrayscale_3  BitmapToGrayscale_4  RotateBitmap_ads   RotateBitmap270_ads  RotateBitmap90_ads  

*)
interface
Uses Windows,Graphics,SysUtils;

Function BitmapToGrayscale(
  Bitmap : TBitmap
  ): Boolean; OverLoad;
Function BitmapToGrayscale(
  BitmapSource: TBitmap;
  BitmapOut   : TBitmap
  ): Boolean; OverLoad;
Function BitmapToGrayscale(
  BitmapSourceFile: String;
  BitmapOutFile   : String
  ): Boolean; OverLoad;
Function BitmapToGrayscale(
  BitmapFile: String
  ): Boolean; OverLoad;

Function BitmapInvert(
  BitmapSource: TBitmap;
  BitmapOut   : TBitmap
  ): Boolean; OverLoad;

Function BitmapInvert(
  Bitmap      : TBitmap
  ): Boolean; OverLoad;

Function BitmapInvert(
  BitmapSourceFile: String;
  BitmapOutFile   : String
  ): Boolean; OverLoad;

Function BitmapInvert(
  BitmapFile: String
  ): Boolean; OverLoad;

(* RotateBitmap_ads
Example:
procedure TForm1.Button1Click(Sender: TObject);
Var
  Center : TPoint;
  Bitmap : TBitmap;
begin
  Bitmap := TBitmap.Create;
  Try
    Center.y := (Image.Height  div 2)+20;
    Center.x := (Image.Width div 2)+0;
    RotateBitmap_ads(
      Image.Picture.Bitmap, //SourceBitmap : TBitmap;
      Bitmap              , //DestBitmap   : TBitmap;
      Center              , //Center       : TPoint;
      Angle               );//Angle        : Extended): TBitmap;
    Angle := Angle + 15;
    Image2.Picture.Bitmap.Assign(Bitmap);
  Finally
    Bitmap.Free;
  End;
end;
*)
Procedure RotateBitmap_ads(
  SourceBitmap       : TBitmap;
  out DestBitmap     : TBitmap;
  Center             : TPoint;
  Angle              : Double);

Procedure RotateBitmap90_ads(
  SourceBitmap       : TBitmap;
  out DestBitmap     : TBitmap);

Procedure RotateBitmap270_ads(
  SourceBitmap       : TBitmap;
  out DestBitmap     : TBitmap);

implementation

Uses JPEG;

Const PixelMax = 32768;
Type
  pPixelArray  =  ^TPixelArray;
  TPixelArray  =  Array[0..PixelMax-1] Of TRGBTriple;

//
Unit Description UnitIndex Master Index
Procedure RotateBitmap_ads(
  SourceBitmap   : TBitmap;
  out DestBitmap : TBitmap;
  Center         : TPoint;
  Angle          : Double);
Var
  cosRadians          : Double;
  inX                 : Integer;
  inXOriginal         : Integer;
  inXPrime            : Integer;
  inXPrimeRotated     : Integer;
  inY                 : Integer;
  inYOriginal         : Integer;
  inYPrime            : Integer;
  inYPrimeRotated     : Integer;
  OriginalRow         : pPixelArray;
  Radians             : Double;
  RotatedRow          : pPixelArray;
  sinRadians          : Double;
begin
  DestBitmap.Width    := SourceBitmap.Width;
  DestBitmap.Height   := SourceBitmap.Height;
  DestBitmap.PixelFormat := pf24bit;
  Radians             := -(Angle) * PI / 180;
  sinRadians          := Sin(Radians);
  cosRadians          := Cos(Radians);
  For inX             := DestBitmap.Height-1 Downto 0 Do
  Begin
    RotatedRow        := DestBitmap.Scanline[inX];
    inXPrime          := 2*(inX - Center.y) + 1;
    For inY           := DestBitmap.Width-1 Downto 0 Do
    Begin
      inYPrime        := 2*(inY - Center.x) + 1;
      inYPrimeRotated := Round(inYPrime * CosRadians - inXPrime * sinRadians);
      inXPrimeRotated := Round(inYPrime * sinRadians + inXPrime * cosRadians);
      inYOriginal     := (inYPrimeRotated - 1) Div 2 + Center.x;
      inXOriginal     := (inXPrimeRotated - 1) Div 2 + Center.y;
      If
        (inYOriginal  >= 0)                    And
        (inYOriginal  <= SourceBitmap.Width-1) And
        (inXOriginal  >= 0)                    And
        (inXOriginal  <= SourceBitmap.Height-1)
      Then
      Begin
        OriginalRow   := SourceBitmap.Scanline[inXOriginal];
        RotatedRow[inY]  := OriginalRow[inYOriginal]
      End
      Else
      Begin
        RotatedRow[inY].rgbtBlue  := 255;
        RotatedRow[inY].rgbtGreen := 0;
        RotatedRow[inY].rgbtRed   := 0
      End;
    End;
  End;
End;


//
Unit Description UnitIndex Master Index
Procedure RotateBitmap90_ads(
  SourceBitmap       : TBitmap;
  out DestBitmap     : TBitmap);
Var
  inMaxX              : Integer;
  inMaxY              : Integer;
  inX                 : Integer;
  inY                 : Integer;
begin
  DestBitmap.Width    := SourceBitmap.Height;
  DestBitmap.Height   := SourceBitmap.Width;
  DestBitmap.PixelFormat := pf24bit;
  inMaxX              := SourceBitmap.Width-1;
  inMaxY              := SourceBitmap.Height-1;
  For inY:=0 To inMaxY Do
  Begin
    For inX:=0 To inMaxX Do
    Begin
      DestBitmap.Canvas.Pixels[inY,inMaxX-inX]:=SourceBitmap.Canvas.Pixels[inX,inY];
    End;
  End;
End;

//
Unit Description UnitIndex Master Index
Procedure RotateBitmap270_ads(
  SourceBitmap       : TBitmap;
  out DestBitmap     : TBitmap);
Var
  inMaxX              : Integer;
  inMaxY              : Integer;
  inX                 : Integer;
  inY                 : Integer;
begin
  DestBitmap.Width    := SourceBitmap.Height;
  DestBitmap.Height   := SourceBitmap.Width;
  DestBitmap.PixelFormat := pf24bit;
  inMaxX              := SourceBitmap.Width-1;
  inMaxY              := SourceBitmap.Height-1;
  For inY:=0 To inMaxY Do
  Begin
    For inX:=0 To inMaxX Do
    Begin
      //90 counterclockwise
      //DestBitmap.Canvas.Pixels[inY,inMaxX-inX]:=SourceBitmap.Canvas.Pixels[inX,inY];

      //Invert + 90 clockwise
      //DestBitmap.Canvas.Pixels[inMaxY-inY,inMaxX-inX]:=SourceBitmap.Canvas.Pixels[inX,inY];

      //90 clockwise
      DestBitmap.Canvas.Pixels[inMaxY-inY,inX]:=SourceBitmap.Canvas.Pixels[inX,inY];


    End;
  End;
End;

//
Unit Description UnitIndex Master Index
Function BitmapInvert(
  BitmapSource: TBitmap;
  BitmapOut   : TBitmap
  ): Boolean;
var
  BytesPorScan: integer;
  inWidth     : integer;
  inHeight    : integer;
  p           : pByteArray;
  Bitmap      : TBitmap;
Begin
  Result := False;
  If not (BitmapSource.PixelFormat in [pf15Bit, pf24Bit, pf32Bit]) Then Exit;
  Bitmap := TBitmap.Create();
  Try
    Bitmap.Assign(BitmapSource);
    Try
      BytesPorScan :=
        Abs(Integer(Bitmap.ScanLine[1])-Integer(Bitmap.ScanLine[0]));
    Except
      Result := False;
      Exit;
    End;
    For inHeight := 0 To Bitmap.Height - 1 Do
    Begin
      P := Bitmap.ScanLine[InHeight];
      For inWidth := 0 To BytesPorScan - 1 Do
      Begin
        P^[inWidth] := 255-P^[inWidth];
      End;
    End;
    BitmapOut.Assign(Bitmap);
    Result := True;
  Finally
    Bitmap.Free;
  End;
end;

//
Unit Description UnitIndex Master Index
Function BitmapInvert(
  BitmapSourceFile: String;
  BitmapOutFile   : String
  ): Boolean; OverLoad;
Var
  BitmapSource: TBitmap;
  BitmapOut   : TBitmap;
Begin
  Result := False;
  Try
    If Not FileExists(BitmapSourceFile) Then Exit;
    BitmapSource:= TBitmap.Create();
    BitmapOut   := TBitmap.Create();
    Try
      BitmapSource.LoadFromFile(BitmapSourceFile);
      Result :=
        BitmapInvert(
          BitmapSource, //BitmapSource: TBitmap;
          BitmapOut     //BitmapOut   : TBitmap
                      );//): Boolean;
      If Result Then
      Begin
        If FileExists(BitmapOutFile) Then DeleteFile(BitmapOutFile);
        BitmapOut.SaveToFile(BitmapOutFile);
      End;
    Finally
      BitmapSource.Free;
      BitmapOut   .Free;
    End;
  Except
    Result := False;
  End;
End;

//
Unit Description UnitIndex Master Index
Function BitmapInvert(
  BitmapFile: String
  ): Boolean; OverLoad;
Begin
  Result :=
    BitmapInvert(
      BitmapFile, //BitmapSourceFile: String;
      BitmapFile  //BitmapOutFile   : String;
                );//): Boolean; OverLoad;
End;

//
Unit Description UnitIndex Master Index
Function BitmapInvert(
  Bitmap      : TBitmap
  ): Boolean; OverLoad;
Begin
  Result :=
    BitmapInvert(
      Bitmap, //BitmapSource: TBitmap;
      Bitmap  //BitmapOut   : TBitmap
            );//): Boolean;
End;

//
Unit Description UnitIndex Master Index
Function BitmapToGrayscale(
  Bitmap : TBitmap
  ): Boolean;
Var
  Jpeg    : TJPEGImage;
Begin
  Result := False;
  If Bitmap = nil Then Exit;
  Try
    Jpeg    := TJPEGImage.Create();
    Try
      Jpeg.Assign(Bitmap);
      Jpeg.CompressionQuality := 100;
      Jpeg.Compress;
      Jpeg.Grayscale := True;
      Bitmap.Canvas.Draw(0, 0, Jpeg);
      Result := True;
    Finally
      Jpeg.Free;
    End;
  Except
    Result := False;
  End;
End;

//
Unit Description UnitIndex Master Index
Function BitmapToGrayscale(
  BitmapSource: TBitmap;
  BitmapOut   : TBitmap
  ): Boolean; OverLoad;
Var
  Bitmap : TBitmap;
Begin
  Bitmap := TBitmap.Create();
  Try
    Result := BitmapToGrayscale(Bitmap);
    If Result Then BitmapOut.Assign(Bitmap);
  Finally
    Bitmap.Free;
  End;
End;

//
Unit Description UnitIndex Master Index
Function BitmapToGrayscale(
  BitmapSourceFile: String;
  BitmapOutFile   : String
  ): Boolean; OverLoad;
Var
  Bitmap      : TBitmap;
Begin
  Result      := False;
  Try
    If Not FileExists(BitmapSourceFile) Then Exit;
    Bitmap    := TBitmap.Create();
    Try
      Bitmap.LoadFromFile(BitmapSourceFile);
      Result := BitmapToGrayscale(Bitmap);
      If Result Then
      Begin
        If FileExists(BitmapOutFile) Then DeleteFile(BitmapOutFile);
        Bitmap.SaveToFile(BitmapOutFile);
      End;
    Finally
      Bitmap.Free;
    End;
  Except
    Result := False;
  End;
End;

//
Unit Description UnitIndex Master Index
Function BitmapToGrayscale(
  BitmapFile: String
  ): Boolean; OverLoad;
Begin
  Result :=
    BitmapToGrayscale(
      BitmapFile, //BitmapSourceFile: String;
      BitmapFile  //BitmapOutFile   : String
                );//): Boolean; OverLoad;
End;

end.
//