将红衣主教打包并打包成四个字节

Rob*_*ank 2 delphi bit-manipulation delphi-2010

我必须将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;
Run Code Online (Sandbox Code Playgroud)

Dis*_*ned 7

我建议不要使用函数,只需使用变体记录.

type
  TCardinalRec = packed record
    case Integer of
      0: (Value: Cardinal;);
      1: (Bytes: array[0..3] of Byte;);
    end;
Run Code Online (Sandbox Code Playgroud)

然后,您可以轻松地使用它来获取单个字节.

var
  LPixel: TCardinalRec;
...
  LPixel.Value := 123455;
  //Then read each of the bytes using
  B1 := LPixel.Bytes[0];
  B2 := LPixel.Bytes[1];
  //etc.
Run Code Online (Sandbox Code Playgroud)

如果你绝对必须,你可以把它放到一个函数中,但是它不足以打扰函数调用的开销.


编辑
为了说明变体记录方法的效率,请考虑以下内容(假设您正在从Stream中读取图像).

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;
Run Code Online (Sandbox Code Playgroud)

PS:不是任意的通用字节数组,你可以明确地命名的变体记录为红,绿,蓝,(不管其第四个字节表示)的每个字节.

  • 他们不是被称为VARIANT RECORDS吗?(不是变量,变体) (2认同)

And*_*and 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;
Run Code Online (Sandbox Code Playgroud)

略微复杂(但不一定更快)

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;
Run Code Online (Sandbox Code Playgroud)

如果您不需要将字节作为字节变量,那么您甚至可以执行更复杂的操作,例如声明

type
  PCardinalRec = ^TCardinalRec;
  TCardinalRec = packed record
    Byte1,
    Byte2,
    Byte3,
    Byte4: byte;
  end;
Run Code Online (Sandbox Code Playgroud)

然后只是施放:

var
  c: cardinal;
begin
  c := $12345678;
  PCardinalRec(@c)^.Byte3 // get or set byte 3 in c
Run Code Online (Sandbox Code Playgroud)


Joh*_*ica 6

如果你想要快速,你需要考虑80x86架构.

速度在很大程度上取决于您对字节的处理方式.使用AL和AH寄存器(32位EAX寄存器中的最低有效字节), x86可以非常快速地访问底部的2个字节

如果要获得更高阶的两个字节,则不希望直接访问它们.因为您将获得未对齐的内存访问,浪费CPU周期并搞乱缓存.

让它变得更快
所有这些混乱单个字节的东西真的不需要.如果你想要非常快,一次使用4个字节.

NewPixel:= OldPixel or $0f0f0f0f;
Run Code Online (Sandbox Code Playgroud)

如果你想快速处理像素,请使用内联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.