ScanLine的优化问题!(50分)

  • 主题发起人 主题发起人 lance2000
  • 开始时间 开始时间
L

lance2000

Unregistered / Unconfirmed
GUEST, unregistred user!
//反色,即:底片效果
procedure NotColor(SrcBmp:Tbitmap);
var
i, j: integer;
SrcRow: pRGBArray;
ScanlineBytes:integer;
begin
ScanlineBytes:=SrcBmp.Width*3;

SrcRow := SrcBmp.ScanLine[0];

for i := 0 to SrcBmp.Height - 1 do
begin
for j := 0 to SrcBmp.Width - 1 do
begin
SrcRow[j].rgbtRed :=not SrcRow[j].rgbtRed ;
SrcRow[j].rgbtGreen :=not SrcRow[j].rgbtGreen;
SrcRow[j].rgbtBlue :=not SrcRow[j].rgbtBlue;
end;

dec(integer(SrcRow), ScanlineBytes); //老外写的是inc!!!
end;
end;

那个老外是Tjpegimage的作者.偶不太懂何时用inc何时用dec,与dib有关?
与os有关?与bmp有关?
 
是啊,你要计算下一行的数据,所以要用inc。
如果你用dec,肯定会出错的。
 
你的代码中:
...
SrcRow := SrcBmp.ScanLine[0]; // 老外也是这样吗?
...

请看 VCL 源码:

function TBitmap.GetScanLine(Row: Integer): Pointer;
begin
Changing(Self);
with FImage.FDIB, dsbm, dsbmih do
begin
if (Row < 0) or (Row > bmHeight) then
InvalidOperation(@SScanLine);
DIBNeeded;
GDIFlush;
if biHeight > 0 then // bottom-up DIB --- 这行
Row := biHeight - Row - 1;
Integer(Result) := Integer(bmBits) +
Row * BytesPerScanline(biWidth, biBitCount, 32);
end;
end;

Windows 下的 dib 本身就是倒序存储每行的;
ScanLine[0] 对应的是最后一行,当然应该 dec,
若第一行为 SrcRow := SrcBmp.ScanLine[SrcBmp.Height - 1];
则应为 inc;

愚见:)
 
procedure InvertImage(const AnImage:TImage);
var
BytesPorScan: integer;
vi_width, vi_height: integer;
p: pByteArray;
begin
//仅在24位或32位色下有效
If not (AnImage.Picture.Bitmap.PixelFormat in[pf24Bit, pf32Bit])then
raise exception.create(''Error, Format File not soported!'');

try
BytesPorScan := Abs(Integer(AnImage.Picture.Bitmap.ScanLine[1])-
Integer(AnImage.Picture.Bitmap.ScanLine[0]));
except
raise exception.create(''Error'');
end;

//翻转每个像素的RGB数值
for vi_height := 0 to AnImage.Picture.Bitmap.Height - 1 do
begin
P := AnImage.Picture.Bitmap.ScanLine[vi_height];
for vi_width := 0 to BytesPorScan - 1 do
P^[vi_width] := 255-P^[vi_width];
end;
AnImage.Refresh
 
DIB位图数据存放方式有两种:bottom-up方式和top-down方式。
前者数据存储格式为(低地址到高地址):
ScanLine n
ScanLine n-1
...
ScanLine 1
ScanLine 0
后者格式为:
ScanLine 0
ScanLine 1
...
ScanLine n
这两种方式由位图的 BITMAPINFOHEADER 结构中的 biHeight 决定,为正时是由下到上,
为负时是由上到下,TBitmap中默认是为正,故行数大的扫描线地址在前面。

ScanlineBytes:=SrcBmp.Width*3;
的用法是不对的,每行扫描线的实际存储长度是按4字节对齐的,应该是:
ScanLineBytes := (SrcBmp.Width * 3 + 3) div 4 * 4
建议你使用
ScanLineBytes := SrcBmp.ScanLine[1] - SrcBmp.ScanLine[0];
这样不管是什么顺序,都可以用 Inc 来修改指针。
 
:)

又学到一招
 
多人接受答案了。
 
和我猜的一样,与bmp有关.
ScanlineBytes:=SrcBmp.Width*3;
我这样用没错啊!!!
 
系统要求一行扫描线的实际存储长度按4字节对齐,如果SrcBmp.Width刚好能被4整除,
用ScanlineBytes:=SrcBmp.Width*3;碰巧不会出错,你试试把Width设为101看看:)
 

Similar threads

I
回复
0
查看
452
import
I
I
回复
0
查看
569
import
I
I
回复
0
查看
504
import
I
后退
顶部