将 Cardinal 打包和解包为四个字节

发布于 2024-11-03 07:16:59 字数 691 浏览 0 评论 0原文

我必须将 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;

I have to pack and unpack a Cardinal into four one-byte fields (in Delphi 2010).

I'm doing this across all the pixels of a large image, so I need it to be fast!

Can anyone show me how to write these two functions? (The const and out keywords are just for clarity. If they interfere with inline assembly, then I can remove them.)

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;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

2024-11-10 07:16:59

我建议不要使用函数,而只使用变体记录。

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.

如果绝对必要,您可以将其放入函数中,但这很简单,无需担心函数调用的开销。


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

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:您可以将变体记录中的每个字节明确命名为红色、绿色、蓝色(以及第四个字节的含义),而不是任意通用的字节数组。

I'd recommed not using a function, just use a variant record.

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

Then you can easily use this to obtain the individual bytes.

var
  LPixel: TCardinalRec;
...
  LPixel.Value := 123455;
  //Then read each of the bytes using
  B1 := LPixel.Bytes[0];
  B2 := LPixel.Bytes[1];
  //etc.

If you absolutely must, you can put this into a function, but it's trivial enough not to bother with the overhead of a function call.


EDIT
To illustrate the efficiency of the variant record approach consider the following (assuming you're reading your image from a 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;

PS: Instead of an arbitrarily generic Bytes array, you could explicitly name each Byte in the variant record as Red, Green, Blue, (and whatever the fourth Byte means).

我乃一代侩神 2024-11-10 07:16:59

有很多方法。最简单的是

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

There are many ways. The simplest is

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;

Slightly more sophisticated (but not necessarily faster) is

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;

If you don't need the bytes to be byte variables, you can do even trickier things, like declaring

type
  PCardinalRec = ^TCardinalRec;
  TCardinalRec = packed record
    Byte1,
    Byte2,
    Byte3,
    Byte4: byte;
  end;

and then just cast:

var
  c: cardinal;
begin
  c := $12345678;
  PCardinalRec(@c)^.Byte3 // get or set byte 3 in c
少跟Wǒ拽 2024-11-10 07:16:59

如果您想要快速,则需要考虑 80x86 架构。

速度在很大程度上取决于您对字节的处理方式。
x86 可以使用 AL 和 AH 寄存器非常快速地访问底部 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

或者重新询问您的问题:如何在 MMX 中进行位图操作...。

真的非常快
如果您希望它非常非常快,例如比 MMX 快 100 或 1000 倍,您的显卡可以做到。谷歌搜索 CUDA 或 GPGPU。

If you want fast you need to consider the 80x86 architecture.

The speed depends heavily on what you are doing with the bytes.
The x86 can access the bottom 2 bytes really fast, using the AL and AH registers
(least significant bytes in the 32-bit EAX register)

If you want to get at the higher order two bytes, you do not want to access those directly. Because you'll get an unaligned memory access, wasting CPU-cycles and messing up with the cache.

Making it faster
All this stuff messing with individual bytes is really not needed.
If you want to be really fast, work with 4 bytes at a time.

NewPixel:= OldPixel or $0f0f0f0f;

If you want to process your pixels really fast use inline MMX assembly and work with 8 bytes at a time.

Links:
Wikipedia: http://en.wikipedia.org/wiki/MMX_%28instruction_set%29
Explanation of the MMX instruction set: http://webster.cs.ucr.edu/AoA/Windows/HTML/TheMMXInstructionSet.html

Or re-ask your question on SO: How do I do this bitmap manipulation ... in MMX.

Really really fast
If you want it really really fast, like 100 or 1000x faster than MMX can, your videocard can do that. Google for CUDA or GPGPU.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文