How to flip, rotate and mirror bitmaps (Views: 300)
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; |