2007. július 8., vasárnap

How to flip, rotate and mirror bitmaps


Problem/Question/Abstract:

How to flip, rotate and mirror bitmaps

Answer:

You'll have to manually set the bitmap's PixelFormat to pf8bit, pf16bit, pf24bit, or pf32bit before calling these routines. At the end of this page are three wrappers that will call the appropriate routine based on pixel format.

{ ... }
type
  TPixel8 = Byte;
  TPixel16 = Word;
  TPixel24 = packed record
    Blue: Byte;
    Green: Byte;
    Red: Byte;
  end;

  TPixel32 = LongWord;

function GetBitmapPixelSize(const Bitmap: TBitmap): Integer;
begin
  case Bitmap.PixelFormat of
    pf8Bit:
      Result := 1;
    pf16Bit:
      Result := 2;
    pf24Bit:
      Result := 3;
    pf32Bit:
      Result := 4;
  else
    Result := 0;
  end;
end;

function GetBitmapScanlineSize(const Bitmap: TBitmap): Integer;
var
  SL0: Pointer;
  SL1: Pointer;
begin
  if (Bitmap.Height > 1) then
  begin
    SL0 := Bitmap.Scanline[0];
    SL1 := Bitmap.Scanline[1];
    Result := LongInt(SL1) - LongInt(SL0);
  end
  else
    Result := 0;
end;

procedure FlipBitmap_8(const Bitmap: TBitmap);
type
  TPixel = TPixel8; {Dependent on Bitmap.PixelFormat}
  PPixel = ^TPixel;
var
  Buffer: TPixel;
  PPixel1: PPixel;
  PPixel2: PPixel;
  PPixel1Start: PPixel;
  PPixel2Start: PPixel;
  I: Integer;
  J: Integer;
  RowSize: Integer;
begin
  Assert(GetBitmapPixelSize(Bitmap) = SizeOf(TPixel));
  Assert(Bitmap.Height > 0);
  RowSize := GetBitmapScanlineSize(Bitmap);
  PPixel1Start := Bitmap.Scanline[0];
  PPixel2Start := Bitmap.Scanline[Bitmap.Height - 1];
  for I := 1 to (Bitmap.Height div 2) do {Ignore middle row}
  begin
    PPixel1 := PPixel1Start;
    PPixel2 := PPixel2Start;
    for J := 1 to Bitmap.Width do
    begin
      Buffer := PPixel1^;
      PPixel1^ := PPixel2^;
      PPixel2^ := Buffer;
      Inc(PPixel1);
      Inc(PPixel2);
    end;
    Inc(LongInt(PPixel1Start), RowSize);
    Dec(LongInt(PPixel2Start), RowSize);
  end;
end;

procedure FlipBitmap_16(const Bitmap: TBitmap);
type
  TPixel = TPixel16; {Dependent on PixelFormat}
  PPixel = ^TPixel;
var
  Buffer: TPixel;
  PPixel1: PPixel;
  PPixel2: PPixel;
  PPixel1Start: PPixel;
  PPixel2Start: PPixel;
  I: Integer;
  J: Integer;
  RowSize: Integer;
begin
  Assert(GetBitmapPixelSize(Bitmap) = SizeOf(TPixel));
  Assert(Bitmap.Height > 0);
  RowSize := GetBitmapScanlineSize(Bitmap);
  PPixel1Start := Bitmap.Scanline[0];
  PPixel2Start := Bitmap.Scanline[Bitmap.Height - 1];
  for I := 1 to (Bitmap.Height div 2) do {Ignore middle row}
  begin
    PPixel1 := PPixel1Start;
    PPixel2 := PPixel2Start;
    for J := 1 to Bitmap.Width do
    begin
      Buffer := PPixel1^;
      PPixel1^ := PPixel2^;
      PPixel2^ := Buffer;
      Inc(PPixel1);
      Inc(PPixel2);
    end;
    Inc(LongInt(PPixel1Start), RowSize);
    Dec(LongInt(PPixel2Start), RowSize);
  end;
end;

procedure FlipBitmap_24(const Bitmap: TBitmap);
type
  TPixel = TPixel24; {Dependent on PixelFormat}
  PPixel = ^TPixel;
var
  Buffer: TPixel;
  PPixel1: PPixel;
  PPixel2: PPixel;
  PPixel1Start: PPixel;
  PPixel2Start: PPixel;
  I: Integer;
  J: Integer;
  RowSize: Integer;
begin
  Assert(GetBitmapPixelSize(Bitmap) = SizeOf(TPixel));
  Assert(Bitmap.Height > 0);
  RowSize := GetBitmapScanlineSize(Bitmap);
  PPixel1Start := Bitmap.Scanline[0];
  PPixel2Start := Bitmap.Scanline[Bitmap.Height - 1];
  for I := 1 to (Bitmap.Height div 2) do {Ignore middle row}
  begin
    PPixel1 := PPixel1Start;
    PPixel2 := PPixel2Start;
    for J := 1 to Bitmap.Width do
    begin
      Buffer := PPixel1^;
      PPixel1^ := PPixel2^;
      PPixel2^ := Buffer;
      Inc(PPixel1);
      Inc(PPixel2);
    end;
    Inc(LongInt(PPixel1Start), RowSize);
    Dec(LongInt(PPixel2Start), RowSize);
  end;
end;

procedure FlipBitmap_32(const Bitmap: TBitmap);
type
  TPixel = TPixel32; {Dependent on PixelFormat.}
  PPixel = ^TPixel;
var
  Buffer: TPixel;
  PPixel1: PPixel;
  PPixel2: PPixel;
  PPixel1Start: PPixel;
  PPixel2Start: PPixel;
  I: Integer;
  J: Integer;
  RowSize: Integer;
begin
  Assert(GetBitmapPixelSize(Bitmap) = SizeOf(TPixel));
  Assert(Bitmap.Height > 0);
  RowSize := GetBitmapScanlineSize(Bitmap);
  PPixel1Start := Bitmap.Scanline[0];
  PPixel2Start := Bitmap.Scanline[Bitmap.Height - 1];
  for I := 1 to (Bitmap.Height div 2) do {Ignore middle row}
  begin
    PPixel1 := PPixel1Start;
    PPixel2 := PPixel2Start;
    for J := 1 to Bitmap.Width do
    begin
      Buffer := PPixel1^;
      PPixel1^ := PPixel2^;
      PPixel2^ := Buffer;
      Inc(PPixel1);
      Inc(PPixel2);
    end;
    Inc(LongInt(PPixel1Start), RowSize);
    Dec(LongInt(PPixel2Start), RowSize);
  end;
end;

procedure MirrorBitmap_8(const Bitmap: TBitmap);
type
  TPixel = TPixel8; {Dependent on PixelFormat}
  PPixel = ^TPixel;
var
  PPixel1: PPixel;
  PPixel2: PPixel;
  Buffer: TPixel;
  PPixel1Start: PPixel;
  PPixel2Start: PPixel;
  I: Integer;
  J: Integer;
  RowSize: Integer;
begin
  Assert(GetBitmapPixelSize(Bitmap) = SizeOf(TPixel));
  Assert(Bitmap.Height > 0);
  RowSize := GetBitmapScanlineSize(Bitmap);
  PPixel1Start := Bitmap.Scanline[0];
  PPixel2Start := PPixel1Start;
  Inc(PPixel2Start, Bitmap.Width - 1);
  for I := 1 to Bitmap.Height do
  begin
    PPixel1 := PPixel1Start;
    PPixel2 := PPixel2Start;
    for J := 1 to (Bitmap.Width div 2) do {Ignore middle column}
    begin
      Buffer := PPixel1^;
      PPixel1^ := PPixel2^;
      PPixel2^ := Buffer;
      Inc(PPixel1);
      Dec(PPixel2);
    end;
    Inc(LongInt(PPixel1Start), RowSize);
    Inc(LongInt(PPixel2Start), RowSize);
  end;
end;

procedure MirrorBitmap_16(const Bitmap: TBitmap);
type
  TPixel = TPixel16; {Dependent on PixelFormat}
  PPixel = ^TPixel;
var
  PPixel1: PPixel;
  PPixel2: PPixel;
  Buffer: TPixel;
  PPixel1Start: PPixel;
  PPixel2Start: PPixel;
  I: Integer;
  J: Integer;
  RowSize: Integer;
begin
  Assert(GetBitmapPixelSize(Bitmap) = SizeOf(TPixel));
  Assert(Bitmap.Height > 0);
  RowSize := GetBitmapScanlineSize(Bitmap);
  PPixel1Start := Bitmap.Scanline[0];
  PPixel2Start := PPixel1Start;
  Inc(PPixel2Start, Bitmap.Width - 1);
  for I := 1 to Bitmap.Height do
  begin
    PPixel1 := PPixel1Start;
    PPixel2 := PPixel2Start;
    for J := 1 to (Bitmap.Width div 2) do {Ignore middle column}
    begin
      Buffer := PPixel1^;
      PPixel1^ := PPixel2^;
      PPixel2^ := Buffer;
      Inc(PPixel1);
      Dec(PPixel2);
    end;
    Inc(LongInt(PPixel1Start), RowSize);
    Inc(LongInt(PPixel2Start), RowSize);
  end;
end;

procedure MirrorBitmap_24(const Bitmap: TBitmap);
type
  TPixel = TPixel24; {Dependent on PixelFormat}
  PPixel = ^TPixel;
var
  PPixel1: PPixel;
  PPixel2: PPixel;
  Buffer: TPixel;
  PPixel1Start: PPixel;
  PPixel2Start: PPixel;
  I: Integer;
  J: Integer;
  RowSize: Integer;
begin
  Assert(GetBitmapPixelSize(Bitmap) = SizeOf(TPixel));
  Assert(Bitmap.Height > 0);
  RowSize := GetBitmapScanlineSize(Bitmap);
  PPixel1Start := Bitmap.Scanline[0];
  PPixel2Start := PPixel1Start;
  Inc(PPixel2Start, Bitmap.Width - 1);
  for I := 1 to Bitmap.Height do
  begin
    PPixel1 := PPixel1Start;
    PPixel2 := PPixel2Start;
    for J := 1 to (Bitmap.Width div 2) do {Ignore middle column}
    begin
      Buffer := PPixel1^;
      PPixel1^ := PPixel2^;
      PPixel2^ := Buffer;
      Inc(PPixel1);
      Dec(PPixel2);
    end;
    Inc(LongInt(PPixel1Start), RowSize);
    Inc(LongInt(PPixel2Start), RowSize);
  end;
end;

procedure MirrorBitmap_32(const Bitmap: TBitmap);
type
  TPixel = TPixel32; {Dependent on PixelFormat}
  PPixel = ^TPixel;
var
  PPixel1: PPixel;
  PPixel2: PPixel;
  Buffer: TPixel;
  PPixel1Start: PPixel;
  PPixel2Start: PPixel;
  I: Integer;
  J: Integer;
  RowSize: Integer;
begin
  Assert(GetBitmapPixelSize(Bitmap) = SizeOf(TPixel));
  Assert(Bitmap.Height > 0);
  RowSize := GetBitmapScanlineSize(Bitmap);
  PPixel1Start := Bitmap.Scanline[0];
  PPixel2Start := PPixel1Start;
  Inc(PPixel2Start, Bitmap.Width - 1);
  for I := 1 to Bitmap.Height do
  begin
    PPixel1 := PPixel1Start;
    PPixel2 := PPixel2Start;
    for J := 1 to (Bitmap.Width div 2) do {Ignore middle column}
    begin
      Buffer := PPixel1^;
      PPixel1^ := PPixel2^;
      PPixel2^ := Buffer;
      Inc(PPixel1);
      Dec(PPixel2);
    end;
    Inc(LongInt(PPixel1Start), RowSize);
    Inc(LongInt(PPixel2Start), RowSize);
  end;
end;

procedure RotateBitmap180_8(const Bitmap: TBitmap);
type
  TPixel = TPixel8; {Dependent on PixelFormat}
  PPixel = ^TPixel;
var
  PPixel1: PPixel;
  PPixel2: PPixel;
  Buffer: TPixel;
  PPixel1Start: PPixel;
  PPixel2Start: PPixel;
  I: Integer;
  J: Integer;
  RowSize: Integer;
begin
  Assert(GetBitmapPixelSize(Bitmap) = SizeOf(TPixel));
  Assert(Bitmap.Height > 0);
  RowSize := GetBitmapScanlineSize(Bitmap);
  PPixel1Start := Bitmap.Scanline[0];
  PPixel2Start := Bitmap.Scanline[Bitmap.Height - 1];
  Inc(PPixel2Start, Bitmap.Width - 1);
  for I := 1 to (Bitmap.Height div 2) do {Ignore center row for now}
  begin
    PPixel1 := PPixel1Start;
    PPixel2 := PPixel2Start;
    for J := 1 to Bitmap.Width do
    begin
      Buffer := PPixel1^;
      PPixel1^ := PPixel2^;
      PPixel2^ := Buffer;
      Inc(PPixel1);
      Dec(PPixel2);
    end;
    Inc(LongInt(PPixel1Start), RowSize);
    Dec(LongInt(PPixel2Start), RowSize);
  end;
  if (Odd(Bitmap.Height)) then {Process center row}
  begin
    PPixel1 := PPixel1Start;
    PPixel2 := PPixel2Start;
    for J := 1 to (Bitmap.Width div 2) do {Ignore center pixel}
    begin
      Buffer := PPixel1^;
      PPixel1^ := PPixel2^;
      PPixel2^ := Buffer;
      Inc(PPixel1);
      Dec(PPixel2);
    end;
  end;
end;

procedure RotateBitmap180_16(const Bitmap: TBitmap);
type
  TPixel = TPixel16; {Dependent on PixelFormat}
  PPixel = ^TPixel;
var
  PPixel1: PPixel;
  PPixel2: PPixel;
  Buffer: TPixel;
  PPixel1Start: PPixel;
  PPixel2Start: PPixel;
  I: Integer;
  J: Integer;
  RowSize: Integer;
begin
  Assert(GetBitmapPixelSize(Bitmap) = SizeOf(TPixel));
  Assert(Bitmap.Height > 0);
  RowSize := GetBitmapScanlineSize(Bitmap);
  PPixel1Start := Bitmap.Scanline[0];
  PPixel2Start := Bitmap.Scanline[Bitmap.Height - 1];
  Inc(PPixel2Start, Bitmap.Width - 1);
  for I := 1 to (Bitmap.Height div 2) do {Ignore center row for now}
  begin
    PPixel1 := PPixel1Start;
    PPixel2 := PPixel2Start;
    for J := 1 to Bitmap.Width do
    begin
      Buffer := PPixel1^;
      PPixel1^ := PPixel2^;
      PPixel2^ := Buffer;
      Inc(PPixel1);
      Dec(PPixel2);
    end;
    Inc(LongInt(PPixel1Start), RowSize);
    Dec(LongInt(PPixel2Start), RowSize);
  end;
  if (Odd(Bitmap.Height)) then {Process center row}
  begin
    PPixel1 := PPixel1Start;
    PPixel2 := PPixel2Start;
    for J := 1 to (Bitmap.Width div 2) do {Ignore center pixel}
    begin
      Buffer := PPixel1^;
      PPixel1^ := PPixel2^;
      PPixel2^ := Buffer;
      Inc(PPixel1);
      Dec(PPixel2);
    end;
  end;
end;

procedure RotateBitmap180_24(const Bitmap: TBitmap);
type
  TPixel = TPixel24; {Dependent on PixelFormat}
  PPixel = ^TPixel;
var
  PPixel1: PPixel;
  PPixel2: PPixel;
  Buffer: TPixel;
  PPixel1Start: PPixel;
  PPixel2Start: PPixel;
  I: Integer;
  J: Integer;
  RowSize: Integer;
begin
  Assert(GetBitmapPixelSize(Bitmap) = SizeOf(TPixel));
  Assert(Bitmap.Height > 0);
  RowSize := GetBitmapScanlineSize(Bitmap);
  PPixel1Start := Bitmap.Scanline[0];
  PPixel2Start := Bitmap.Scanline[Bitmap.Height - 1];
  Inc(PPixel2Start, Bitmap.Width - 1);
  for I := 1 to (Bitmap.Height div 2) do {Ignore center row for now}
  begin
    PPixel1 := PPixel1Start;
    PPixel2 := PPixel2Start;
    for J := 1 to Bitmap.Width do
    begin
      Buffer := PPixel1^;
      PPixel1^ := PPixel2^;
      PPixel2^ := Buffer;
      Inc(PPixel1);
      Dec(PPixel2);
    end;
    Inc(LongInt(PPixel1Start), RowSize);
    Dec(LongInt(PPixel2Start), RowSize);
  end;
  if (Odd(Bitmap.Height)) then {Process center row}
  begin
    PPixel1 := PPixel1Start;
    PPixel2 := PPixel2Start;
    for J := 1 to (Bitmap.Width div 2) do {Ignore center pixel}
    begin
      Buffer := PPixel1^;
      PPixel1^ := PPixel2^;
      PPixel2^ := Buffer;
      Inc(PPixel1);
      Dec(PPixel2);
    end;
  end;
end;

procedure RotateBitmap180_32(const Bitmap: TBitmap);
type
  TPixel = TPixel32; {Dependent on PixelFormat}
  PPixel = ^TPixel;
var
  PPixel1: PPixel;
  PPixel2: PPixel;
  Buffer: TPixel;
  PPixel1Start: PPixel;
  PPixel2Start: PPixel;
  I: Integer;
  J: Integer;
  RowSize: Integer;
begin
  Assert(GetBitmapPixelSize(Bitmap) = SizeOf(TPixel));
  Assert(Bitmap.Height > 0);
  RowSize := GetBitmapScanlineSize(Bitmap);
  PPixel1Start := Bitmap.Scanline[0];
  PPixel2Start := Bitmap.Scanline[Bitmap.Height - 1];
  Inc(PPixel2Start, Bitmap.Width - 1);
  for I := 1 to (Bitmap.Height div 2) do {Ignore center row for now}
  begin
    PPixel1 := PPixel1Start;
    PPixel2 := PPixel2Start;
    for J := 1 to Bitmap.Width do
    begin
      Buffer := PPixel1^;
      PPixel1^ := PPixel2^;
      PPixel2^ := Buffer;
      Inc(PPixel1);
      Dec(PPixel2);
    end;
    Inc(LongInt(PPixel1Start), RowSize);
    Dec(LongInt(PPixel2Start), RowSize);
  end;
  if (Odd(Bitmap.Height)) then {Process center row}
  begin
    PPixel1 := PPixel1Start;
    PPixel2 := PPixel2Start;
    for J := 1 to (Bitmap.Width div 2) do {Ignore center pixel}
    begin
      Buffer := PPixel1^;
      PPixel1^ := PPixel2^;
      PPixel2^ := Buffer;
      Inc(PPixel1);
      Dec(PPixel2);
    end;
  end;
end;

procedure RotateBitmapCW_32(const Bitmap: TBitmap);
type
  TPixel = TPixel32; {Dependent on Bitmap.PixelFormat}
  PPixel = ^TPixel;
var
  NewBitmap: TBitmap;
  PPixel1: PPixel;
  PPixel2: PPixel;
  PPixel1Start: PPixel;
  PPixel2Start: PPixel;
  I: Integer;
  J: Integer;
  BitmapRowSize: Integer;
  NewBitmapRowSize: Integer;
begin
  Assert(GetBitmapPixelSize(Bitmap) = SizeOf(TPixel));
  Assert(Bitmap.Height > 0);
  Assert(Bitmap.Width > 0);
  NewBitmap := TBitmap.Create;
  try
    NewBitmap.PixelFormat := Bitmap.PixelFormat;
    NewBitmap.Height := Bitmap.Width;
    NewBitmap.Width := Bitmap.Height;
    BitmapRowSize := GetBitmapScanlineSize(Bitmap);
    NewBitmapRowSize := GetBitmapScanlineSize(NewBitmap);
    PPixel1Start := Bitmap.Scanline[0];
    PPixel2Start := NewBitmap.Scanline[0];
    Inc(PPixel2Start, NewBitmap.Width - 1);
    for I := 0 to (Bitmap.Height - 1) do
    begin
      PPixel1 := PPixel1Start;
      PPixel2 := PPixel2Start;
      for J := 0 to (Bitmap.Width - 1) do
      begin
        PPixel2^ := PPixel1^;
        Inc(PPixel1);
        Inc(Integer(PPixel2), NewBitmapRowSize);
      end;
      Inc(Integer(PPixel1Start), BitmapRowSize);
      Dec(PPixel2Start);
    end;
    Bitmap.Assign(NewBitmap);
  finally
    NewBitmap.Free;
  end;
end;

procedure FlipBitmap(const Bitmap: TBitmap);
begin
  case Bitmap.PixelFormat of
    pf8Bit:
      FlipBitmap_8(Bitmap);
    pf16Bit:
      FlipBitmap_16(Bitmap);
    pf24Bit:
      FlipBitmap_24(Bitmap);
    pf32Bit:
      FlipBitmap_32(Bitmap);
  else
    Assert(False);
  end;
end;

procedure MirrorBitmap(const Bitmap: TBitmap);
begin
  case Bitmap.PixelFormat of
    pf8Bit:
      MirrorBitmap_8(Bitmap);
    pf16Bit:
      MirrorBitmap_16(Bitmap);
    pf24Bit:
      MirrorBitmap_24(Bitmap);
    pf32Bit:
      MirrorBitmap_32(Bitmap);
  else
    Assert(False);
  end;
end;

procedure RotateBitmap180(const Bitmap: TBitmap);
begin
  case Bitmap.PixelFormat of
    pf8Bit:
      RotateBitmap180_8(Bitmap);
    pf16Bit:
      RotateBitmap180_16(Bitmap);
    pf24Bit:
      RotateBitmap180_24(Bitmap);
    pf32Bit:
      RotateBitmap180_32(Bitmap);
  else
    Assert(False);
  end;
end;

procedure RotateBitmapCW(const Bitmap: TBitmap);
begin
  case Bitmap.PixelFormat of
    pf8Bit:
      ;
    pf16Bit:
      ;
    pf24Bit:
      ;
    pf32Bit:
      RotateBitmapCW_32(Bitmap);
  else
    Assert(False);
  end;
end;

procedure RotateBitmapCCW(const Bitmap: TBitmap);
begin
  case Bitmap.PixelFormat of
    pf8Bit:
      ;
    pf16Bit:
      ;
    pf24Bit:
      ;
    pf32Bit:
      ;
  else
    Assert(False);
  end;
end;

Nincsenek megjegyzések:

Megjegyzés küldése