对不起,刚才分数给的有点小误差。
卷起千堆雪tyn给我的Code,花了我300分,我要公开它:
//----------
unit ImgFlp;
interface
uses Windows, Classes, SysUtils, Graphics;
type
EInvalidPixelFormat = class(Exception);
procedure ImageFlipH(aBitmap: TBitmap);
// flips the image along the center horizontal axis
procedure ImageFlipV(aBitmap: TBitmap);
// flips the image along the center vertical axis
procedure ImageRotate90(aBitmap: TBitmap);
// rotates the bitmap counterclockwise in increments of 90degrees
implementation
const
BitsPerByte = 8; // Assume there are 8 bits in one byte, this may not be true in the future. (JIC)
{ this functions returns the number of bytes needed to represent 1 pixel
in the current PixelFormat of the bitmap. }
function GetPixelSize(aBitmap: TBitmap): integer;
var
nBitCount, nMultiplier: integer;
begin
case aBitmap.PixelFormat of
pfDevice:
begin
nBitCount := GetDeviceCaps(aBitmap.Canvas.Handle, BITSPIXEL);
nMultiplier := nBitCount div BitsPerByte;
if (nBitCount mod BitsPerByte)>0 then
begin
Inc(nMultiplier);
end;
end;
pf1bit: nMultiplier := 1;
pf4bit: nMultiplier := 1;
pf8bit: nMultiplier := 1;
pf15bit: nMultiplier := 2;
pf16bit: nMultiplier := 2;
pf24bit: nMultiplier := 3;
pf32bit: nMultiplier := 4;
else raise EInvalidPixelFormat.Create('Bitmap pixelformat is unknown.');
end;
Result := nMultiplier;
end;
procedure ImageFlipH(aBitmap: TBitmap);
var
nMultiplier,
nMemSize, y, y2,
nHalfHeight, nFullHeight: integer;
aScanLine: PByteArray;
begin
nMultiplier := GetPixelSize(ABitmap);
nMemSize := aBitmap.Width * nMultiplier;
GetMem(aScanLine, nMemSize);
try
nFullHeight := aBitmap.Height;
nHalfHeight := nFullHeight div 2;
{
This FOR-LOOP basically swaps the top and the bottom lines converging
into the center lines.
}
for y := 0 to nHalfHeight do
begin
Move(aBitmap.ScanLine[y]^, aScanLine^, nMemSize);
y2 := nFullHeight - y - 1;
Move(aBitmap.ScanLine[y2]^, aBitmap.ScanLine[y]^, nMemSize);
Move(aScanLine^, aBitmap.ScanLine[y2]^, nMemSize);
end;
finally
FreeMem(aScanLine);
end;
end;
{
This procedure swaps the pixel information in a scanline, in other words, the
leftmost pixel is swapped with the rightmost pixel moving to the middle of the
scanline. nSize is the total byte size of the scanline. nElemWidth is the
number of bytes per pixel. (e.g. for 24bit, 1 pixel is 3 bytes)
}
procedure ReverseScanLine(AScanLine: PByteArray; nSize, nElemWidth: integer);
var
i, j, w, w2, x1, x2: integer;
aByte: Byte;
begin
w := nSize div nElemWidth;
w2 := w div 2;
for i := 0 to w2 do
begin
x1 := i * nElemWidth;
x2 := (w - i - 1) * nElemWidth;
for j := 0 to nElemWidth-1 do
begin
aByte := AScanLine[x1 + j];
AScanLine[x1 + j] := AScanLine[x2 + j];
AScanLine[x2 + j] := aByte;
end;
end;
end;
procedure ImageFlipV(aBitmap: TBitmap);
var
nMultiplier,
nMemSize, y,
nFullHeight: integer;
aScanLine: PByteArray;
begin
nMultiplier := GetPixelSize(ABitmap);
nMemSize := aBitmap.Width * nMultiplier;
GetMem(aScanLine, nMemSize);
try
nFullHeight := aBitmap.Height;
{ this FOR-LOOP read the scanlines into a buffer and swaps the pixels and
then writes it back into the bitmap scanlines. the buffer is necessary
because it is faster working with a copy of the scanline than using the
scanline itself }
for y := 0 to nFullHeight-1 do
begin
Move(aBitmap.ScanLine[y]^, aScanLine^, nMemSize);
ReverseScanLine(aScanLine, nMemSize, nMultiplier);
Move(aScanLine^, aBitmap.ScanLine[y]^, nMemSize);
end;
finally
FreeMem(aScanLine);
end;
end;
{ this procedure rotates the image counterclockwise by 90 degrees.
i could have made this routine rotate clockwise but doing it in
counter-clockwise is easier and thus less prone to bugs.
what we do here is grab the first scanline and distribute each pixel
along one column of the new image (or in this case new scanlines buffer)
we do this until we run out of scanlines then we are done.}
procedure ImageRotate90(aBitmap: TBitmap);
var
nIdx, nOfs,
x, y, i,
nMultiplier: integer;
nMemWidth, nMemHeight, nMemSize,
nScanLineSize: LongInt;
aScnLnBuffer: PChar;
aScanLine: PByteArray;
begin
nMultiplier := GetPixelSize(ABitmap);
nMemWidth := aBitmap.Height;
nMemHeight := aBitmap.Width;
nMemSize := nMemWidth * nMemHeight * nMultiplier;
GetMem(aScnLnBuffer, nMemSize);
try
nScanLineSize := aBitmap.Width * nMultiplier;
GetMem(aScanLine, nScanLineSize);
try
for y := 0 to aBitmap.Height-1 do
begin
Move(aBitmap.ScanLine[y]^, aScanLine^, nScanLineSize);
for x := 0 to aBitmap.Width-1 do
begin
nIdx := ((aBitmap.Width-1) - x) * nMultiplier;
nOfs := (x * nMemWidth * nMultiplier) + // y component of the dst
(y * nMultiplier); // x component of the dst
for i := 0 to nMultiplier-1 do
Byte(aScnLnBuffer[nOfs + i]) := aScanLine[nIdx+i];
end;
end;
aBitmap.Height := nMemHeight;
aBitmap.Width := nMemWidth;
for y := 0 to nMemHeight-1 do
begin
nOfs := y * nMemWidth * nMultiplier;
Move((@(aScnLnBuffer[nOfs]))^, aBitmap.ScanLine[y]^, nMemWidth * nMultiplier);
end;
finally
FreeMem(aScanLine, nScanLineSize);
end;
finally
FreeMem(aScnLnBuffer, nMemSize);
end;
end;
end.