Image 如何调整图片的大小?
我有图像(500x500),但我需要将其调整为200x200并在TImage上绘制。如何达到这样的效果Image 如何调整图片的大小?,image,delphi,resize,delphi-7,Image,Delphi,Resize,Delphi 7,我有图像(500x500),但我需要将其调整为200x200并在TImage上绘制。如何达到这样的效果 注意我知道TImage中的拉伸属性,但我想以编程方式调整图像大小。如果您知道新尺寸不大于原始尺寸,您只需执行以下操作即可 procedure ShrinkBitmap(Bitmap: TBitmap; const NewWidth, NewHeight: integer); begin Bitmap.Canvas.StretchDraw( Rect(0, 0, NewWidth,
注意
我知道TImage中的
拉伸
属性,但我想以编程方式调整图像大小。如果您知道新尺寸不大于原始尺寸,您只需执行以下操作即可
procedure ShrinkBitmap(Bitmap: TBitmap; const NewWidth, NewHeight: integer);
begin
Bitmap.Canvas.StretchDraw(
Rect(0, 0, NewWidth, NewHeight),
Bitmap);
Bitmap.SetSize(NewWidth, NewHeight);
end;
如果您知道新维度不小于原始维度,我将编写相应的代码作为练习
如果你想要一个通用函数,你可以这样做
procedure ResizeBitmap(Bitmap: TBitmap; const NewWidth, NewHeight: integer);
var
buffer: TBitmap;
begin
buffer := TBitmap.Create;
try
buffer.SetSize(NewWidth, NewHeight);
buffer.Canvas.StretchDraw(Rect(0, 0, NewWidth, NewHeight), Bitmap);
Bitmap.SetSize(NewWidth, NewHeight);
Bitmap.Canvas.Draw(0, 0, buffer);
finally
buffer.Free;
end;
end;
这种方法的缺点是执行两个像素的复制操作。我至少可以想出两种解决这个问题的办法。(哪个?我经常使用本页中的
SmoothResize
过程:
缩放比StretchDraw函数好得多
不要让标题欺骗你。页面演示了如何调整JPG的大小,但SmoothResize过程本身使用位图来调整大小。调整PNG的大小也可以在类似的情况下完成,但如果使用此过程,将失去透明度 良好的可用性和图片质量提供了下面单元1)中的
调整图像大小的功能。代码取决于,2)和2)
该函数采用两个文件名或两个流。输入是(自动检测为)BMP、PNG、GIF或JPG,输出总是JPG
unit AwResizeImage;
interface
uses
Windows, SysUtils, Classes, Graphics, Math, JPEG, GR32, GIFImage, PNGImage,
GR32_Resamplers;
type
TImageType = (itUnknown, itBMP, itGIF, itJPG, itPNG);
TImageInfo = record
ImgType: TImageType;
Width: Cardinal;
Height: Cardinal;
end;
function GetImageInfo(const AFilename: String): TImageInfo; overload;
function GetImageInfo(const AStream: TStream): TImageInfo; overload;
function ResizeImage(const ASource, ADest: String; const AWidth,
AHeight: Integer; const ABackColor: TColor;
const AType: TImageType = itUnknown): Boolean; overload;
function ResizeImage(const ASource, ADest: TStream; const AWidth,
AHeight: Integer; const ABackColor: TColor;
const AType: TImageType = itUnknown): Boolean; overload;
implementation
type
TGetDimensions = procedure(const ASource: TStream;
var AImageInfo: TImageInfo);
TCardinal = record
case Byte of
0: (Value: Cardinal);
1: (Byte1, Byte2, Byte3, Byte4: Byte);
end;
TWord = record
case Byte of
0: (Value: Word);
1: (Byte1, Byte2: Byte);
end;
TPNGIHDRChunk = packed record
Width: Cardinal;
Height: Cardinal;
Bitdepth: Byte;
Colortype: Byte;
Compression: Byte;
Filter: Byte;
Interlace: Byte;
end;
TGIFHeader = packed record
Signature: array[0..2] of Char;
Version: array[0..2] of Char;
Width: Word;
Height: Word;
end;
TJPGChunk = record
ID: Word;
Length: Word;
end;
TJPGHeader = packed record
Reserved: Byte;
Height: Word;
Width: Word;
end;
const
SIG_BMP: array[0..1] of Char = ('B', 'M');
SIG_GIF: array[0..2] of Char = ('G', 'I', 'F');
SIG_JPG: array[0..2] of Char = (#255, #216, #255);
SIG_PNG: array[0..7] of Char = (#137, #80, #78, #71, #13, #10, #26, #10);
function SwapBytes(const ASource: Cardinal): Cardinal; overload;
var
mwSource: TCardinal;
mwDest: TCardinal;
begin
mwSource.Value := ASource;
mwDest.Byte1 := mwSource.Byte4;
mwDest.Byte2 := mwSource.Byte3;
mwDest.Byte3 := mwSource.Byte2;
mwDest.Byte4 := mwSource.Byte1;
Result := mwDest.Value;
end;
function SwapBytes(const ASource: Word): Word; overload;
var
mwSource: TWord;
mwDest: TWord;
begin
mwSource.Value := ASource;
mwDest.Byte1 := mwSource.Byte2;
mwDest.Byte2 := mwSource.Byte1;
Result := mwDest.Value;
end;
procedure GetBMPDimensions(const ASource: TStream; var AImageInfo: TImageInfo);
var
bmpFileHeader: TBitmapFileHeader;
bmpInfoHeader: TBitmapInfoHeader;
begin
FillChar(bmpFileHeader, SizeOf(TBitmapFileHeader), #0);
FillChar(bmpInfoHeader, SizeOf(TBitmapInfoHeader), #0);
ASource.Read(bmpFileHeader, SizeOf(TBitmapFileHeader));
ASource.Read(bmpInfoHeader, SizeOf(TBitmapInfoHeader));
AImageInfo.Width := bmpInfoHeader.biWidth;
AImageInfo.Height := bmpInfoHeader.biHeight;
end;
procedure GetGIFDimensions(const ASource: TStream; var AImageInfo: TImageInfo);
var
gifHeader: TGIFHeader;
begin
FillChar(gifHeader, SizeOf(TGIFHeader), #0);
ASource.Read(gifHeader, SizeOf(TGIFHeader));
AImageInfo.Width := gifHeader.Width;
AImageInfo.Height := gifHeader.Height;
end;
procedure GetJPGDimensions(const ASource: TStream; var AImageInfo: TImageInfo);
var
cSig: array[0..1] of Char;
jpgChunk: TJPGChunk;
jpgHeader: TJPGHeader;
iSize: Integer;
iRead: Integer;
begin
FillChar(cSig, SizeOf(cSig), #0);
ASource.Read(cSig, SizeOf(cSig));
iSize := SizeOf(TJPGChunk);
repeat
FillChar(jpgChunk, iSize, #0);
iRead := ASource.Read(jpgChunk, iSize);
if iRead <> iSize then
Break;
if jpgChunk.ID = $C0FF then
begin
ASource.Read(jpgHeader, SizeOf(TJPGHeader));
AImageInfo.Width := SwapBytes(jpgHeader.Width);
AImageInfo.Height := SwapBytes(jpgHeader.Height);
Break;
end
else
ASource.Position := ASource.Position + (SwapBytes(jpgChunk.Length) - 2);
until False;
end;
procedure GetPNGDimensions(const ASource: TStream; var AImageInfo: TImageInfo);
var
cSig: array[0..7] of Char;
cChunkLen: Cardinal;
cChunkType: array[0..3] of Char;
ihdrData: TPNGIHDRChunk;
begin
FillChar(cSig, SizeOf(cSig), #0);
FillChar(cChunkType, SizeOf(cChunkType), #0);
ASource.Read(cSig, SizeOf(cSig));
cChunkLen := 0;
ASource.Read(cChunkLen, SizeOf(Cardinal));
cChunkLen := SwapBytes(cChunkLen);
if cChunkLen = SizeOf(TPNGIHDRChunk) then
begin
ASource.Read(cChunkType, SizeOf(cChunkType));
if AnsiUpperCase(cChunkType) = 'IHDR' then
begin
FillChar(ihdrData, SizeOf(TPNGIHDRChunk), #0);
ASource.Read(ihdrData, SizeOf(TPNGIHDRChunk));
AImageInfo.Width := SwapBytes(ihdrData.Width);
AImageInfo.Height := SwapBytes(ihdrData.Height);
end;
end;
end;
function GetImageInfo(const AFilename: String): TImageInfo;
var
fsImage: TFileStream;
begin
fsImage := TFileStream.Create(AFilename, fmOpenRead or fmShareDenyWrite);
try
Result := GetImageInfo(fsImage);
finally
FreeAndNil(fsImage);
end;
end;
function GetImageInfo(const AStream: TStream): TImageInfo;
var
iPos: Integer;
cBuffer: array[0..2] of Char;
cPNGBuffer: array[0..4] of Char;
GetDimensions: TGetDimensions;
begin
GetDimensions := nil;
Result.ImgType := itUnknown;
Result.Width := 0;
Result.Height := 0;
FillChar(cBuffer, SizeOf(cBuffer), #0);
FillChar(cPNGBuffer, SizeOf(cPNGBuffer), #0);
iPos := AStream.Position;
AStream.Read(cBuffer, SizeOf(cBuffer));
if cBuffer = SIG_GIF then
begin
Result.ImgType := itGIF;
GetDimensions := GetGIFDimensions;
end
else if cBuffer = SIG_JPG then
begin
Result.ImgType := itJPG;
GetDimensions := GetJPGDimensions;
end
else if cBuffer = Copy(SIG_PNG, 1, 3) then
begin
AStream.Read(cPNGBuffer, SizeOf(cPNGBuffer));
if cPNGBuffer = Copy(SIG_PNG, 4, 5) then
begin
Result.ImgType := itPNG;
GetDimensions := GetPNGDimensions;
end;
end
else if Copy(cBuffer, 1, 2) = SIG_BMP then
begin
Result.ImgType := itBMP;
GetDimensions := GetBMPDimensions;
end;
AStream.Position := iPos;
if Assigned(GetDimensions) then
begin
GetDimensions(AStream, Result);
AStream.Position := iPos;
end;
end;
procedure GIFToBMP(const ASource: TStream; const ADest: TBitmap);
var
imgSource: TGIFImage;
begin
imgSource := TGIFImage.Create();
try
imgSource.LoadFromStream(ASource);
ADest.Assign(imgSource);
finally
FreeAndNil(imgSource);
end;
end;
procedure JPGToBMP(const ASource: TStream; const ADest: TBitmap);
var
imgSource: TJPEGImage;
begin
imgSource := TJPEGImage.Create();
try
imgSource.LoadFromStream(ASource);
ADest.Assign(imgSource);
finally
FreeAndNil(imgSource);
end;
end;
procedure PNGToBMP(const ASource: TStream; const ADest: TBitmap);
var
imgSource: TPNGImage;
begin
imgSource := TPNGImage.Create();
try
imgSource.LoadFromStream(ASource);
ADest.Assign(imgSource);
finally
FreeAndNil(imgSource);
end;
end;
function ResizeImage(const ASource, ADest: String; const AWidth,
AHeight: Integer; const ABackColor: TColor;
const AType: TImageType = itUnknown): Boolean;
var
fsSource: TFileStream;
fsDest: TFileStream;
begin
Result := False;
fsSource := TFileStream.Create(ASource, fmOpenRead or fmShareDenyWrite);
try
fsDest := TFileStream.Create(ADest, fmCreate or fmShareExclusive);
try
Result := not Result; //hide compiler hint
Result := ResizeImage(fsSource, fsDest, AWidth, AHeight, ABackColor, AType);
finally
FreeAndNil(fsDest);
end;
finally
FreeAndNil(fsSource);
end;
end;
function ResizeImage(const ASource, ADest: TStream; const AWidth,
AHeight: Integer; const ABackColor: TColor;
const AType: TImageType = itUnknown): Boolean;
var
itImage: TImageType;
ifImage: TImageInfo;
bmpTemp: TBitmap;
bmpSource: TBitmap32;
bmpResized: TBitmap32;
cBackColor: TColor32;
rSource: TRect;
rDest: TRect;
dWFactor: Double;
dHFactor: Double;
dFactor: Double;
iSrcWidth: Integer;
iSrcHeight: Integer;
iWidth: Integer;
iHeight: Integer;
jpgTemp: TJPEGImage;
begin
Result := False;
itImage := AType;
if itImage = itUnknown then
begin
ifImage := GetImageInfo(ASource);
itImage := ifImage.ImgType;
if itImage = itUnknown then
Exit;
end;
bmpTemp := TBitmap.Create();
try
case itImage of
itBMP: bmpTemp.LoadFromStream(ASource);
itGIF: GIFToBMP(ASource, bmpTemp);
itJPG: JPGToBMP(ASource, bmpTemp);
itPNG: PNGToBMP(ASource, bmpTemp);
end;
bmpSource := TBitmap32.Create();
bmpResized := TBitmap32.Create();
try
cBackColor := Color32(ABackColor);
bmpSource.Assign(bmpTemp);
bmpResized.Width := AWidth;
bmpResized.Height := AHeight;
bmpResized.Clear(cBackColor);
iSrcWidth := bmpSource.Width;
iSrcHeight := bmpSource.Height;
iWidth := iSrcWidth;
iHeight := iSrcHeight;
with rSource do
begin
Left := 0;
Top := 0;
Right := iSrcWidth;
Bottom := iSrcHeight;
end;
if (iWidth > AWidth) or (iHeight > AHeight) then
begin
dWFactor := AWidth / iWidth;
dHFactor := AHeight / iHeight;
if (dWFactor > dHFactor) then
dFactor := dHFactor
else
dFactor := dWFactor;
iWidth := Floor(iWidth * dFactor);
iHeight := Floor(iHeight * dFactor);
end;
with rDest do
begin
Left := Floor((AWidth - iWidth) / 2);
Top := Floor((AHeight - iHeight) / 2);
Right := Left + iWidth;
Bottom := Top + iHeight;
end;
bmpSource.Resampler := TKernelResampler.Create;
TKernelResampler(bmpSource.Resampler).Kernel := TLanczosKernel.Create;
bmpSource.DrawMode := dmOpaque;
bmpResized.Draw(rDest, rSource, bmpSource);
bmpTemp.Assign(bmpResized);
jpgTemp := TJPEGImage.Create();
jpgTemp.CompressionQuality := 80;
try
jpgTemp.Assign(bmpTemp);
jpgTemp.SaveToStream(ADest);
Result := True;
finally
FreeAndNil(jpgTemp);
end;
finally
FreeAndNil(bmpResized);
FreeAndNil(bmpSource);
end;
finally
FreeAndNil(bmpTemp);
end;
end;
end.
unitawresizeimage;
接口
使用
Windows、SysUtils、类、图形、数学、JPEG、GR32、GIFImage、PNGImage、,
GR32_重采样器;
类型
TImageType=(itUnknown、itBMP、itGIF、itJPG、itPNG);
TImageInfo=记录
ImgType:TImageType;
宽度:基数;
身高:基数;
结束;
函数GetImageInfo(const AFilename:String):TImageInfo;超载;
函数GetImageInfo(const AStream:TStream):TImageInfo;超载;
函数ResizeImage(const ASource,ADest:String;const AWidth,
AHeight:整数;const-ABackColor:TColor;
常量AType:TImageType=itUnknown):布尔值;超载;
函数大小图像(const ASource,ADest:TStream;const AWidth,
AHeight:整数;const-ABackColor:TColor;
常量AType:TImageType=itUnknown):布尔值;超载;
实施
类型
TGetDimensions=程序(常量A来源:TStream;
var AImageInfo:TImageInfo);
TCardinal=记录
大小写字节
0:(值:基数);
1:(字节1,字节2,字节3,字节4:字节);
结束;
TWord=记录
大小写字节
0:(值:Word);
1:(字节1,字节2:字节);
结束;
TPNGIHDRChunk=打包记录
宽度:基数;
身高:基数;
位深度:字节;
颜色类型:字节;
压缩:字节;
过滤器:字节;
隔行扫描:字节;
结束;
TGIFHeader=打包记录
签名:字符的数组[0..2];
版本:字符的数组[0..2];
宽度:字;
高度:字;
结束;
TJPGChunk=记录
ID:单词;
长度:字;
结束;
TJPGHeader=打包记录
保留:字节;
高度:字;
宽度:字;
结束;
常数
SIG_BMP:Char=('B','M')的数组[0..1];
SIG_GIF:Char=('G','I','F')的数组[0..2];
SIG_JPG:Char=(#255,#216,#255)的数组[0..2];
SIG#u PNG:Char=(#137,#80,#78,#71,#13,#10,#26,#10)的数组[0..7];
函数交换字节(const ASource:Cardinal):Cardinal;超载;
变量
资料来源:TCardinal;
mwDest:TCardinal;
开始
mwSource.Value:=A来源;
mwDest.Byte1:=mwSource.Byte4;
mwDest.Byte2:=mwSource.Byte3;
mwDest.Byte3:=mwSource.Byte2;
mwDest.Byte4:=mwSource.Byte1;
结果:=mwDest.值;
结束;
函数交换字节(const-ASource:Word):Word;超载;
变量
资料来源:TWord;
MWDST:TWord;
开始
mwSource.Value:=A来源;
mwDest.Byte1:=mwSource.Byte2;
mwDest.Byte2:=mwSource.Byte1;
结果:=mwDest.值;
结束;
过程GetBMPDimensions(const ASource:TStream;var AImageInfo:TImageInfo);
变量
bmpFileHeader:TBitmapFileHeader;
bmpInfoHeader:TBitmapInfoHeader;
开始
FillChar(bmpFileHeader,SizeOf(TBitmapFileHeader),#0);
FillChar(bmpInfoHeader,SizeOf(TBitmapInfoHeader),#0);
ASource.Read(bmpFileHeader,SizeOf(TBitmapFileHeader));
ASource.Read(bmpInfoHeader,SizeOf(TBitmapInfoHeader));
AImageInfo.Width:=bmpInfoHeader.biWidth;
AImageInfo.Height:=bmpInfoHeader.biHeight;
结束;
过程GetGIFDimensions(const ASource:TStream;var AImageInfo:TImageInfo);
变量
gifiheader:TGIFHeader;
开始
FillChar(gifHeader,SizeOf(TGIFHeader),#0);
ASource.Read(gifHeader,SizeOf(TGIFHeader));
AImageInfo.Width:=gifHeader.Width;
AImageInfo.Height:=gifHeader.Height;
结束;
过程GetJPGDimensions(const ASource:TStream;var AImageInfo:TImageInfo);
变量
cSig:Char的数组[0..1];
jpgChunk:TJPGChunk;
jpgHeader:TJPGHeader;
iSize:整数;
iRead:整数;
开始
FillChar(cSig,SizeOf(cSig),#0);
ASource.Read(cSig,SizeOf(cSig));
iSize:=SizeOf(TJPGChunk);
重复
FillChar(jpgChunk,iSize,#0);
iRead:=ASource.Read(jpgChunk,iSize);
如果我是伊塞兹的话
打破
如果jpgChunk.ID=$C0FF,则
开始
ASource.Read(jpgHeader,SizeOf(TJPGHeader));
AImageInfo.Width:=交换字节(jpgHeader.Width);
AImageInfo.Height:=交换字节(jpgHeader.Height);
打破
结束
其他的
ASource.Position:=ASource.Position+(交换字节(jpgChunk.Length)-2);
直到错误;
结束;
过程GetPNGDimensions(const ASource:TStream;var AImageInfo:TImageInfo);
变量
cSig:Char的数组[0..7];
康克伦:红衣主教;
cChunkType:字符的数组[0..3];
ihdrData:TPNGIHDRChunk;
开始
FillChar(cSig,SizeOf(cSig),#0);
FillChar(cChunkType,SizeOf(cChunkType),#0);
ASource.Read(cSig,SizeOf(cSig));
cChunkLen:=0;
一个资源读取(cChunkLen,SizeOf(红衣主教));
cChunkLen:=交换字节(cChunkLen);
如果cChunkLen=SizeOf(TPNGIHDRChunk),则
开始
ASource.Read(cChunkType,SizeOf(cChunkType));
如果AnsiUpperCase(cChunkType)=“IHDR”,则
开始
FillChar(ihdrData,SizeOf(TPNGIHDRChunk),#0);
ASource.Read(ihdrData,SizeOf(TPNGIHDRChunk));
目标
img := TIMage.create(nil);
img.picture.loadfromfile('any_file_type');
Result:= TBitmap.Create;
result.Width := newWidth;
result.Height := newHeight;
Result.Canvas.Draw(0,0,img.Picture.Graphic);
uses
GR32, GR32_Resamplers;
procedure Resize(InputPicture: TBitmap; OutputImage: TImage; const DstWidth, DstHeigth: Integer);
var
Src, Dst: TBitmap32;
begin
Dst := nil;
try
Src := TBitmap32.Create;
try
Src.Assign(InputPicture);
SetHighQualityStretchFilter(Src);
Dst := TBitmap32.Create;
Dst.SetSize(DstWidth, DstHeigth);
Src.DrawTo(Dst, Rect(0, 0, DstWidth, DstHeigth), Rect(0, 0, Src.Width, Src.Height));
finally
FreeAndNil(Src);
end;
OutputImage.Assign(Dst);
finally
FreeAndNil(Dst);
end;
end;
// If you need to set a highest quality resampler, use this helper routine to configure it
procedure SetHighQualityStretchFilter(B: TBitmap32);
var
KR: TKernelResampler;
begin
if not (B.Resampler is TKernelResampler) then
begin
KR := TKernelResampler.Create(B);
KR.Kernel := TLanczosKernel.Create;
end
else
begin
KR := B.Resampler as TKernelResampler;
if not (KR.Kernel is TLanczosKernel) then
begin
KR.Kernel.Free;
KR.Kernel := TLanczosKernel.Create;
end;
end;
end;