最近写的一个将图片旋转90度的函数,但是有一些细节不理解,该如何解决
最近写的一个将图片旋转90度的函数,但是有一些细节不理解
总的思想是把图像数据写入一个内存流中做备份,然后按照一定规则和算法写入BMP各个像素点中。
procedure PictureRotate270Degrees(BitMap:TBitMap);
var
aStream: TMemoryStream;
header: TBitMapInfo;
dc: HDC;//Device context的句柄,译作设备上下文的句柄
P: ^THelpRGB;
x, y, b, h:integer;
RowOut: pRGBArray;
begin
aStream:=TMemoryStream.Create;//创建内存流
aStream.SetSize(BitMap.Height*BitMap.Width*4);//根据图像尺寸指定内存流大小
with header.bmiHeader do
begin
biSize:= Sizeof(TBitMapInfoHeader);//TBitMapInfoHeader占用的存储空间,固定为40
biWidth:= BitMap.Width;
biHeight:= BitMap.Height;
biPlanes:= 1; //目标设备平面数
biBitCount:= 32;//颜色位数
biCompression:= 0;//不压缩
biSizeImage:= aStream.Size;
bixPelsPermeter:= 1;//水平分辨率
biyPelsPermeter:= 1;//垂直分辨率
biClrUsed:= 0;//位图使用颜色在颜色表中的变址数
biClrImportant:= 0;//重要颜色变址数,如果为0,指全部使用重要颜色
end;
dc:= GetDc(0);//获得某个设备的设备环境,0指显示器
p:= aStream.Memory;
//GetDiBits把图像中指定的行写入缓存,作为原图像文件的数据备份
GetDiBits(dc, BitMap.Handle, 0, BitMap.Height, p, header, dib_RGB_Colors);
//GetDiBits的header参数在TBitMpa中似乎没有定义
ReleaseDC(0, dc);//不再需要某个设备,释放
b:= BitMap.Width;
h:= BitMap.Height;
for y:= 0 to (h - 1) do
begin
rowOut:= BitMap.ScanLine[y];
p:= aStream.Memory;
//指针移动到某行像素的起始位置
inc(p, y);//指针移位,p为当前指针位置,y为移动位数,相当于指针移动到P+y
for x:= 0 to (b - 1) do
begin
//将写在内存流中的图像文件备份重新写入图片,问题:长宽不同,会不会写到指针数组的尽头,到空地址上去?
rowout[x]:= p.rgb;
//指针移动到某行像素中某个特定像素
inc(p, b);
end;
end;
aStream.Free;
end;
看标有“问题”的一行注释,当图片长宽不同的时候,将列数据写入原图片的行中是否可能由于原图片行上的像素数目少于列,而导致内存或指针方面的错误。
本人已经试过,不会发生问题,请高人解释原因,谢谢
------解决方案--------------------
1、看代码内容与标题相距太远:整个代码就写了将TBitmap写入一个流,然后又从流写回bmp
2、如果只是备份没必要这样写,直接定义一个临时TBitmap,将原对象拷贝过去就玩了,如:
var
tmp: TBitmap;
begin
tmp := TBitmap.Create;
tmp.Assign(BitMap);
...... // 这里对tmp操作就行了,不会影响BitMap
tmp.Free;
end;
------解决方案--------------------
32位的位图每扫描行没有padding字节,所以只要Width*Height相同的图片不管它们各自的Width和Height是多少,它们的大小是一样的。
总的思想是把图像数据写入一个内存流中做备份,然后按照一定规则和算法写入BMP各个像素点中。
procedure PictureRotate270Degrees(BitMap:TBitMap);
var
aStream: TMemoryStream;
header: TBitMapInfo;
dc: HDC;//Device context的句柄,译作设备上下文的句柄
P: ^THelpRGB;
x, y, b, h:integer;
RowOut: pRGBArray;
begin
aStream:=TMemoryStream.Create;//创建内存流
aStream.SetSize(BitMap.Height*BitMap.Width*4);//根据图像尺寸指定内存流大小
with header.bmiHeader do
begin
biSize:= Sizeof(TBitMapInfoHeader);//TBitMapInfoHeader占用的存储空间,固定为40
biWidth:= BitMap.Width;
biHeight:= BitMap.Height;
biPlanes:= 1; //目标设备平面数
biBitCount:= 32;//颜色位数
biCompression:= 0;//不压缩
biSizeImage:= aStream.Size;
bixPelsPermeter:= 1;//水平分辨率
biyPelsPermeter:= 1;//垂直分辨率
biClrUsed:= 0;//位图使用颜色在颜色表中的变址数
biClrImportant:= 0;//重要颜色变址数,如果为0,指全部使用重要颜色
end;
dc:= GetDc(0);//获得某个设备的设备环境,0指显示器
p:= aStream.Memory;
//GetDiBits把图像中指定的行写入缓存,作为原图像文件的数据备份
GetDiBits(dc, BitMap.Handle, 0, BitMap.Height, p, header, dib_RGB_Colors);
//GetDiBits的header参数在TBitMpa中似乎没有定义
ReleaseDC(0, dc);//不再需要某个设备,释放
b:= BitMap.Width;
h:= BitMap.Height;
for y:= 0 to (h - 1) do
begin
rowOut:= BitMap.ScanLine[y];
p:= aStream.Memory;
//指针移动到某行像素的起始位置
inc(p, y);//指针移位,p为当前指针位置,y为移动位数,相当于指针移动到P+y
for x:= 0 to (b - 1) do
begin
//将写在内存流中的图像文件备份重新写入图片,问题:长宽不同,会不会写到指针数组的尽头,到空地址上去?
rowout[x]:= p.rgb;
//指针移动到某行像素中某个特定像素
inc(p, b);
end;
end;
aStream.Free;
end;
看标有“问题”的一行注释,当图片长宽不同的时候,将列数据写入原图片的行中是否可能由于原图片行上的像素数目少于列,而导致内存或指针方面的错误。
本人已经试过,不会发生问题,请高人解释原因,谢谢
------解决方案--------------------
1、看代码内容与标题相距太远:整个代码就写了将TBitmap写入一个流,然后又从流写回bmp
2、如果只是备份没必要这样写,直接定义一个临时TBitmap,将原对象拷贝过去就玩了,如:
var
tmp: TBitmap;
begin
tmp := TBitmap.Create;
tmp.Assign(BitMap);
...... // 这里对tmp操作就行了,不会影响BitMap
tmp.Free;
end;
------解决方案--------------------
32位的位图每扫描行没有padding字节,所以只要Width*Height相同的图片不管它们各自的Width和Height是多少,它们的大小是一样的。