The purpose of this program, FlipReverseRotate.EXE, is to demonstrate how to
flip (top-to-bottom) and/or
reverse (left-to-right)a bitmap in memory and display the results on the screen.
Three methods to flip/reverse are compared:Scanline, CopyRect, StretchBlt.
In addition, a bitmap can be rotated any multiple of 90 degrees,
namely 0, 90, 180, or 270 degrees counterclockwise, but only with the Scanline method. View Code
// The FlipReverseRotate Library provides three functions to flip and/or// reverse a bitmap. You can choose which approach you'd like to use from the// three methods to flip or reverse a bitmap: ScanLine, CopyRect, StretchBlt.//// A "Flip" operation takes the top of an image to the bottom and the bottom of// the image to the top. It is a reflection along a horizontal line in the// middle of an image.//// A "Reverse" operation takes the left of an image to the right and the right// of the image to the left. It is a reflection along a vertical line in the// middle of an image.//// Any Flip/Reverse operation is commutative, i.e., the flip and reverse can// be performed in any order to get the same result. A flip followed by a// reverse is the same as a reverse followed by a flip.//// A "rotate" operation spins an image 0, 90, 180 or 270 degrees around an// axis in the center of the image.//// A flip/reverse operation along with a rotation is not commutative in general.// A flip followed by a rotation will not always result in the same image as a// rotation followed by a flip. The rotation here ALWAYS follows any flip and/or// reversal.//// The examples here are intended for use with bitmaps that have 24 bits/pixel.// Palettes may be lost on 256-color bitmaps.//// Copyright (C) 1998, Earl F. Glynn. All Rights Reserved.// May be used freely for non-comercial use.unit FlipReverseRotateLibrary;interfaceuses Dialogs, Windows, // TRGBTriple (put here to avoid TBitmap conflict in Implementation) Graphics; // TBitmap// Flip/Reverse functions by Methodfunction FlipReverseScanLine( const Flip, Reverse : BOOLEAN; const Bitmap : TBitmap ) : TBitmap;function FlipReverseCopyRect( const Flip, Reverse : BOOLEAN; const Bitmap : TBitmap ) : TBitmap;function FlipReverseStretchBlt( const Flip, Reverse : BOOLEAN; const Bitmap : TBitmap ) : TBitmap;// The Rotation function is only for the Scanline Method.// Note: Windows NT supports a "plgblt" API call that can be used to rotate// images.function RotateScanline90( const angle : INTEGER; const Bitmap : TBitmap ) : TBitmap;implementationuses Classes, // Rect SysUtils; // Exceptionconst MaxPixelCount = 65536; // or some other arbitrarily large valuetype EBitmapError = class( Exception ); TRGBArray = array [ 0 .. MaxPixelCount - 1 ] of TRGBTriple; pRGBArray = ^TRGBArray; /// ///function FlipReverseScanLine( const Flip, Reverse : BOOLEAN; const Bitmap : TBitmap ) : TBitmap;var i : INTEGER; j : INTEGER; RowIn : pRGBArray; RowOut : pRGBArray;begin if Bitmap.PixelFormat <> pf24bit then raise EBitmapError.Create( 'Can Flip/Reverse only 24-bit bitmap' ); RESULT := TBitmap.Create; RESULT.Width := Bitmap.Width; RESULT.Height := Bitmap.Height; RESULT.PixelFormat := Bitmap.PixelFormat; for j := 0 to Bitmap.Height - 1 do begin RowIn := Bitmap.Scanline[ j ]; if Flip then RowOut := RESULT.Scanline[ Bitmap.Height - 1 - j ] else RowOut := RESULT.Scanline[ j ]; // Optimization technique: Use two FOR loops so IF is outside of inner loop if Reverse then begin for i := 0 to Bitmap.Width - 1 do RowOut[ i ] := RowIn[ Bitmap.Width - 1 - i ] end else begin for i := 0 to Bitmap.Width - 1 do RowOut[ i ] := RowIn[ i ] end endend { FlipReverseScanLine };/// ///// This function implements a suggestion by David Ullrich in a July 25, 1997// post to comp.lang.pascal.delphi.misc.//// The Graphics.PAS unit shows that CopyRect calls the Windows StretchBlt API// function.function FlipReverseCopyRect( const Flip, Reverse : BOOLEAN; const Bitmap : TBitmap ) : TBitmap;var Bottom : INTEGER; Left : INTEGER; Right : INTEGER; Top : INTEGER;begin RESULT := TBitmap.Create; RESULT.Width := Bitmap.Width; RESULT.Height := Bitmap.Height; RESULT.PixelFormat := Bitmap.PixelFormat; // Flip Top to Bottom if Flip then begin // Unclear why extra "-1" is needed here. Top := Bitmap.Height - 1; Bottom := -1 end else begin Top := 0; Bottom := Bitmap.Height end; // Reverse Left to Right if Reverse then begin // Unclear why extra "-1" is needed here. Left := Bitmap.Width - 1; Right := -1; end else begin Left := 0; Right := Bitmap.Width; end; RESULT.Canvas.CopyRect( Rect( Left, Top, Right, Bottom ), Bitmap.Canvas, Rect( 0, 0, Bitmap.Width, Bitmap.Height ) );end { FlipReverseCopyRect };/// ///function FlipReverseStretchBlt( const Flip, Reverse : BOOLEAN; const Bitmap : TBitmap ) : TBitmap;var Bottom : INTEGER; Left : INTEGER; Right : INTEGER; Top : INTEGER;begin RESULT := TBitmap.Create; RESULT.Width := Bitmap.Width; RESULT.Height := Bitmap.Height; RESULT.PixelFormat := Bitmap.PixelFormat; // Flip Top to Bottom if Flip then begin // Unclear why extra "-1" is needed here. Top := Bitmap.Height - 1; Bottom := -1 end else begin Top := 0; Bottom := Bitmap.Height end; // Reverse Left to Right if Reverse then begin // Unclear why extra "-1" is needed here. Left := Bitmap.Width - 1; Right := -1; end else begin Left := 0; Right := Bitmap.Width; end; StretchBlt( RESULT.Canvas.Handle, Left, Top, Right - Left, Bottom - Top, Bitmap.Canvas.Handle, 0, 0, Bitmap.Width, Bitmap.Height, cmSrcCopy );end { FlipReverseStretchBlt };/// ///// Rotate 24-bits/pixel Bitmap any multiple of 90 degrees.function RotateScanline90( const angle : INTEGER; const Bitmap : TBitmap ) : TBitmap;// These four internal functions parallel the four cases in rotating a// bitmap using the Pixels property. See the RotatePixels example on// the Image Processing page of efg's Computer Lab for an example of the// use of the Pixels property (which is very slow).// A Bitmap.Assign could be used for a simple copy. A complete example// using ScanLine is included here to help explain the other three cases. function SimpleCopy : TBitmap; var i : INTEGER; j : INTEGER; RowIn : pRGBArray; RowOut : pRGBArray; begin RESULT := TBitmap.Create; RESULT.Width := Bitmap.Width; RESULT.Height := Bitmap.Height; RESULT.PixelFormat := Bitmap.PixelFormat; // only pf24bit for now // Out[i, j] = In[i, j] for j := 0 to Bitmap.Height - 1 do begin RowIn := Bitmap.Scanline[ j ]; RowOut := RESULT.Scanline[ j ]; // Could optimize the following by using a function like CopyMemory // from the Windows unit. for i := 0 to Bitmap.Width - 1 do begin // Why does this crash with RowOut[i] := RowIn[i]? Alignment? // Use this longer form as workaround. with RowOut[ i ] do begin rgbtRed := RowIn[ i ].rgbtRed; rgbtGreen := RowIn[ i ].rgbtGreen; rgbtBlue := RowIn[ i ].rgbtBlue; end end end end { SimpleCopy }; function Rotate90DegreesCounterClockwise : TBitmap; var i : INTEGER; j : INTEGER; RowIn : pRGBArray; begin RESULT := TBitmap.Create; RESULT.Width := Bitmap.Height; RESULT.Height := Bitmap.Width; RESULT.PixelFormat := Bitmap.PixelFormat; // only pf24bit for now // Out[j, Right - i - 1] = In[i, j] for j := 0 to Bitmap.Height - 1 do begin RowIn := Bitmap.Scanline[ j ]; for i := 0 to Bitmap.Width - 1 do pRGBArray( RESULT.Scanline[ Bitmap.Width - i - 1 ] )[ j ] := RowIn[ i ] end end { Rotate90DegreesCounterClockwise };// Could use Rotate90DegreesCounterClockwise twice to get a// Rotate180DegreesCounterClockwise. Rotating 180 degrees is the same// as a Flip and Reverse function Rotate180DegreesCounterClockwise : TBitmap; var i : INTEGER; j : INTEGER; RowIn : pRGBArray; RowOut : pRGBArray; begin RESULT := TBitmap.Create; RESULT.Width := Bitmap.Width; RESULT.Height := Bitmap.Height; RESULT.PixelFormat := Bitmap.PixelFormat; // only pf24bit for now // Out[Right - i - 1, Bottom - j - 1] = In[i, j] for j := 0 to Bitmap.Height - 1 do begin RowIn := Bitmap.Scanline[ j ]; RowOut := RESULT.Scanline[ Bitmap.Height - j - 1 ]; for i := 0 to Bitmap.Width - 1 do RowOut[ Bitmap.Width - i - 1 ] := RowIn[ i ] end end { Rotate180DegreesCounterClockwise };// Could use Rotate90DegreesCounterClockwise three times to get a// Rotate270DegreesCounterClockwise function Rotate270DegreesCounterClockwise : TBitmap; var i : INTEGER; j : INTEGER; RowIn : pRGBArray; begin RESULT := TBitmap.Create; RESULT.Width := Bitmap.Height; RESULT.Height := Bitmap.Width; RESULT.PixelFormat := Bitmap.PixelFormat; // only pf24bit for now // Out[Bottom - j - 1, i] = In[i, j] for j := 0 to Bitmap.Height - 1 do begin RowIn := Bitmap.Scanline[ j ]; for i := 0 to Bitmap.Width - 1 do pRGBArray( RESULT.Scanline[ i ] )[ Bitmap.Height - j - 1 ] := RowIn[ i ] end end { Rotate270DegreesCounterClockwise };begin if Bitmap.PixelFormat <> pf24bit then raise EBitmapError.Create( 'Can Rotate90 only 24-bit bitmap' ); if ( angle >= 0 ) and ( angle mod 90 <> 0 ) then raise EBitmapError.Create ( 'Rotate90: Angle not positive multiple of 90 degrees' ); case ( angle div 90 ) mod 4 of 0 : RESULT := SimpleCopy; 1 : RESULT := Rotate90DegreesCounterClockwise; // Anticlockwise for the Brits 2 : RESULT := Rotate180DegreesCounterClockwise; 3 : RESULT := Rotate270DegreesCounterClockwise else RESULT := nil // avoid compiler warning end;end { RotateScanline90 };end.