以下代码取自uddf, 可将bmp旋转90度:
procedure RotateBitmap90Degrees(ABitmap: TBitmap);
const
BITMAP_HEADER_SIZE = SizeOf(TBitmapFileHeader) +
SizeOf(TBitmapInfoHeader);
var
{ Things that end in R are for the rotated image. }
PbmpInfoR: PBitmapInfoHeader;
bmpBuffer, bmpBufferR: PByte;
MemoryStream, MemoryStreamR: TMemoryStream;
PbmpBuffer, PbmpBufferR: PByte;
PbmpBufferRFirstScanLine, PbmpBufferColumnZero: PByte;
BytesPerPixel, BytesPerScanLine, BytesPerScanLineR: Integer;
X, Y, T: Integer;
begin
{
Don't *ever* call GetDIBSizes! It screws up your bitmap.
I'll be posting about that shortly.
}
MemoryStream := TMemoryStream.Create;
{
To do: Put in a SetSize, which will eliminate any reallocation
overhead.
}
ABitmap.SaveToStream(MemoryStream);
{
Don't need you anymore. We'll make a new one when the time comes.
}
ABitmap.Free;
bmpBuffer := MemoryStream.Memory;
{ Set PbmpInfoR to point to the source bitmap's info header. }
{ Boy, these headers are getting annoying. }
Inc( bmpBuffer, SizeOf(TBitmapFileHeader) );
PbmpInfoR := PBitmapInfoHeader(bmpBuffer);
{ Set bmpBuffer to point to the original bitmap bits. }
Inc(bmpBuffer, SizeOf(PbmpInfoR^));
{ Set the ColumnZero pointer to point to, uh, column zero. }
PbmpBufferColumnZero := bmpBuffer;
with PbmpInfoR^ do
begin
BytesPerPixel := biBitCount shr 3;
{ ScanLines are DWORD aligned. }
BytesPerScanLine := ((((biWidth * biBitCount) + 31) div 32) * SizeOf(DWORD));
BytesPerScanLineR := ((((biHeight * biBitCount) + 31) div 32) * SizeOf(DWORD));
{ The TMemoryStream that will hold the rotated bits. }
MemoryStreamR := TMemoryStream.Create;
{
Set size for rotated bitmap. Might be different from source size
due to DWORD aligning.
}
MemoryStreamR.SetSize(BITMAP_HEADER_SIZE + BytesPerScanLineR * biWidth);
end;
{ Copy the headers from the source bitmap. }
MemoryStream.Seek(0, soFromBeginning);
MemoryStreamR.CopyFrom(MemoryStream, BITMAP_HEADER_SIZE);
{ Here's the buffer we're going to rotate. }
bmpBufferR := MemoryStreamR.Memory;
{ Skip the headers, yadda yadda yadda... }
Inc(bmpBufferR, BITMAP_HEADER_SIZE);
{
Set up PbmpBufferRFirstScanLine and advance it to end of the first scan
line of bmpBufferR.
}
PbmpBufferRFirstScanLine := bmpBufferR;
Inc(PbmpBufferRFirstScanLine, (PbmpInfoR^.biHeight - 1) * BytesPerPixel);
{ Here's the meat. Loop through the pixels and rotate appropriately. }
{ Remember that DIBs have their origins opposite from DDBs. }
for Y := 1 to PbmpInfoR^.biHeight do
begin
PbmpBuffer := PbmpBufferColumnZero;
PbmpBufferR := PbmpBufferRFirstScanLine;
for X := 1 to PbmpInfoR^.biWidth do
begin
for T := 1 to BytesPerPixel do
begin
PbmpBufferR^ := PbmpBuffer^;
Inc(PbmpBufferR);
Inc(PbmpBuffer);
end;
Dec(PbmpBufferR, BytesPerPixel);
Inc(PbmpBufferR, BytesPerScanLineR);
end;
Inc(PbmpBufferColumnZero, BytesPerScanLine);
Dec(PbmpBufferRFirstScanLine, BytesPerPixel);
end;
{ Done with the source bits. }
MemoryStream.Free;
{ Now set PbmpInfoR to point to the rotated bitmap's info header. }
PbmpBufferR := MemoryStreamR.Memory;
Inc( PbmpBufferR, SizeOf(TBitmapFileHeader) );
PbmpInfoR := PBitmapInfoHeader(PbmpBufferR);
{ Swap the width and height of the rotated bitmap's info header. }
with PbmpInfoR^ do
begin
T := biHeight;
biHeight := biWidth;
biWidth := T;
end;
ABitmap := TBitmap.Create;
{ Spin back to the very beginning. }
MemoryStreamR.Seek(0, soFromBeginning);
ABitmap.LoadFromStream(MemoryStreamR);
MemoryStreamR.Free;
end;