我必须将Cardinal打包并解压缩为四个单字节字段(在Delphi 2010中 )。
我在大图像的所有像素上执行此操作,因此我需要它快速!
谁能告诉我如何编写这两个功能? (const和out关键字只是为了清楚。如果它们干扰内联汇编,那么我可以删除它们。)
procedure FromCardinalToBytes( const aInput: Cardinal;
out aByte1: Byte;
out aByte2: Byte;
out aByte3: Byte;
out aByte4: Byte); inline;
function FromBytesToCardinal( const aByte1: Byte;
const aByte2: Byte;
const aByte3: Byte;
const aByte4: Byte):Cardinal; inline;
答案 0 :(得分:7)
我建议不要使用函数,只需使用变体记录。
type
TCardinalRec = packed record
case Integer of
0: (Value: Cardinal;);
1: (Bytes: array[0..3] of Byte;);
end;
然后您可以轻松地使用它来获取单个字节。
var
LPixel: TCardinalRec;
...
LPixel.Value := 123455;
//Then read each of the bytes using
B1 := LPixel.Bytes[0];
B2 := LPixel.Bytes[1];
//etc.
如果你绝对必须,你可以把它放到一个函数中,但是它不足以打扰函数调用的开销。
EDIT
为了说明变量记录方法的效率,请考虑以下内容(假设您正在从流中读取图像)。
var
LPixelBuffer: array[0..1023] of TCardinalRec;
...
ImageStream.Read(LPixelBuffer, SizeOf(LPixelBuffer));
for I := Low(LPixelBuffer) to High(LPixelBuffer) do
begin
//Here each byte is accessible by:
LPixelBuffer[I].Bytes[0]
LPixelBuffer[I].Bytes[1]
LPixelBuffer[I].Bytes[2]
LPixelBuffer[I].Bytes[3]
end;
PS:您可以将变体记录中的每个字节明确命名为红色,绿色,蓝色(以及第四个字节的含义),而不是任意通用的字节数组。
答案 1 :(得分:6)
有很多方法。最简单的是
function FromBytesToCardinal(const AByte1, AByte2, AByte3,
AByte4: byte): cardinal; inline;
begin
result := AByte1 + (AByte2 shl 8) + (AByte3 shl 16) + (AByte4 shl 24);
end;
procedure FromCardinalToBytes(const AInput: cardinal; out AByte1,
AByte2, AByte3, AByte4: byte); inline;
begin
AByte1 := byte(AInput);
AByte2 := byte(AInput shr 8);
AByte3 := byte(AInput shr 16);
AByte4 := byte(AInput shr 24);
end;
稍微复杂(但不一定更快)
function FromBytesToCardinal2(const AByte1, AByte2, AByte3,
AByte4: byte): cardinal; inline;
begin
PByte(@result)^ := AByte1;
PByte(NativeUInt(@result) + 1)^ := AByte2;
PByte(NativeUInt(@result) + 2)^ := AByte3;
PByte(NativeUInt(@result) + 3)^ := AByte4;
end;
procedure FromCardinalToBytes2(const AInput: cardinal; out AByte1,
AByte2, AByte3, AByte4: byte); inline;
begin
AByte1 := PByte(@AInput)^;
AByte2 := PByte(NativeUInt(@AInput) + 1)^;
AByte3 := PByte(NativeUInt(@AInput) + 2)^;
AByte4 := PByte(NativeUInt(@AInput) + 3)^;
end;
如果你不需要字节是字节变量,你甚至可以做更棘手的事情,比如声明
type
PCardinalRec = ^TCardinalRec;
TCardinalRec = packed record
Byte1,
Byte2,
Byte3,
Byte4: byte;
end;
然后只是演员:
var
c: cardinal;
begin
c := $12345678;
PCardinalRec(@c)^.Byte3 // get or set byte 3 in c
答案 2 :(得分:6)
如果您想要快速,则需要考虑80x86架构。
速度在很大程度上取决于你对字节做了什么。 使用AL和AH寄存器,x86可以非常快速地访问底部的2个字节 (32位EAX寄存器中的最低有效字节)
如果您想要获得更高的两个字节,那么不想要直接访问它们。因为你将获得一个未对齐的内存访问,浪费CPU周期并弄乱缓存。
加快速度
实际上不需要所有这些混乱单个字节的东西。
如果你想要非常快,一次使用4个字节。
NewPixel:= OldPixel or $0f0f0f0f;
如果您想快速处理像素,请使用内联MMX程序集并一次使用8个字节。
链接:
维基百科:http://en.wikipedia.org/wiki/MMX_%28instruction_set%29
MMX指令集的说明:http://webster.cs.ucr.edu/AoA/Windows/HTML/TheMMXInstructionSet.html
或者在SO上重新询问你的问题:我如何在MMX中进行这种位图操作。
真的很快
如果你真的想要它真的很快,比MMX快100或1000倍,你的显卡可以做到这一点。谷歌的CUDA或GPGPU。