用FireMonkey Delphi XE3创建固定为32位像素格式的屏幕外位图的替代方案?

gtlvzcf8  于 2022-10-16  发布在  其他
关注(0)|答案(1)|浏览(355)

由于FMX TBitmap实现将PixelFormat设置为只读属性,因此我不能像以前使用VCL TBitmap那样,在创建空的TBitmap之后将其设置为32位。此示例说明如何使用FMX rutines GetPixel,SetPixel:http://members.adug.org.au/2012/10/05/read-write-image-bitmap-pixels-in-delphi-xe3/访问独立于PixelFormat的像素
使用FMX TBitmap.Map()方法,我可以访问指向像素数据的指针,但我不能假定它的PixelFormat为32位。
我的目的是访问32位位图、纹理或32位固定格式的表面,这样我的2D图形库就可以直接在屏幕外使用这些内存;而不需要每次都在像素格式之间进行检查和转换。在图像处理结束时,它可以复制到任何可见的表面、纹理或图像上,以便在表格中显示。
感谢您的帮助!

zkure5ic

zkure5ic1#

若要定位位图扫描线的像素,可以使用属性TBitMap.ScanLine[0],该属性提供指向图像第一行的指针。要了解扫描线是如何在24位位图中构造的,您可以查看David Heffernan和TLama在以下位置的文章:
How to use ScanLine property for 24-bit bitmaps?
我已经创建了在Delphi下运行的汇编语言函数,允许您从/向32位/像素位图读取/写入像素(对于24位/像素位图,还有2个以上)。
下面是我的GetPixelBMp32()和PutPixelBMp32()函数的原型和功能:

type T_RGB_Temp=record {RGB color RECORD type}
      Blue, {BLUE component from 0 to 255}
      Green, {GREEN component from 0 to 255}
      Red, {RED component from 0 to 255}
      Mask {ALPHA channel from 0 to 255} :byte;
     end;

     T_Coord_XY=record {X and Y position RECORD type}
      X, {X position}
      Y {Y position} :smallint;
     end;

     T_Dim_XY=record {Width and height of bitmap RECORD type}
      DimX, {Width}
      DimY {Height} :word;
     end;

function GetPixelBMp32(XY:T_Coord_XY;
                       BMp32_Dim_XY:T_Dim_XY;
                       ScanLine0:pointer):T_RGB_Temp;

procedure PutPixelBMp32(XY:T_Coord_XY;
                        BMp32_Dim_XY:T_Dim_XY;
                        ScanLine0:pointer;Pix:T_RGB_Temp);

给定使用PixelFormat=(pf32Bit,pfCustom)定义的BitMap32:TBitMap,ScanLine0参数必须始终为BitMap32.ScanLine[0];如果ScanLine0=Nil,则不会发生任何情况。
BMp32_Dim_XY.DimX和BMp32_Dim_XY.DimY是给定图像的尺寸;如果使用类型强制转换BMp32_Dim_XY.DimX:=Word(Width:SmallInt)或BMp32_Dim_XY.DimX:=Word(Height:SmallInt),并且宽度或高度为负值,则不会发生任何事情。
XY.X和XY.Y是Pixel的坐标;它们可以是负数,也可以大于给定图像的大小,但在这种情况下,不会发生任何事情。
Pix.Red、Pix.Green、Pix.Blue、Pix.MASK是像素的8位颜色分量。PIX是T_RGB_TEMP类型的​​;GetPixelBMp32()的结果也是相同类型的。
位图扫描线的组织顺序是相反的,就好像内存中的图像是相对于X轴镜像的;因此,在内存中,TBitMap.ScanLine[0]之后的所有扫描线都位于较低的地址位置,就好像TBitMap.ScanLine[0]是最后一个扫描线,而不是第一个扫描线。
此外,如果扫描线的字节数不是4的倍数(对齐到DWord),如在24位/像素格式中,则在扫描线的末尾添加0到3个字节(对齐)。
24位位图的对齐方式为:A:=(TBitMap.Width+3),而不是3。
以下是上述函数(32位/像素图像)的定义:

procedure PutPixelBMp32(XY:T_Coord_XY;
                        BMp32_Dim_XY:T_Dim_XY;
                        ScanLine0:pointer;Pix:T_RGB_Temp); assembler;
{ eax edx ecx are 1°, 2° and 3° parameters.
  Can freely modify the eax, ecx, and edx registers. }
asm

     push  ebx
     push  esi
     push  edi

     mov   ebx,Pix        {ebx <- Pix}

     mov   edi,BMp32_Dim_XY {edi <- edx <- BMp32_Dim_XY}
     mov   esi,ScanLine0  {esi <- ecx <- ScanLine0}
     mov   edx,XY         {edx <- eax <- XY}

     or    esi,esi        {If ScanLine0=Nil, ...}
     je    @@00           {... Exit}

     movsx eax,di         {eax <- DimX}
     shr   edi,16
     movsx edi,di         {edi <- DimY}

     movsx ecx,dx         {ecx <- X}
     shr   edx,16
     movsx edx,dx         {edx <- Y}

     or    eax,eax        {If DimX<0, ...}
     js    @@00           {... Exit}

     cmp   ecx,eax        {If X<0 or if X>=DimX, ...}
     jae   @@00           {... Exit}

     or    edi,edi        {If DimY<0, ...}
     js    @@00           {... Exit}

     cmp   edx,edi        {If Y<0 or if Y>=DimY, ...}
     jae   @@00           {... Exit}

     lea   ecx,[4*ecx]    {ecx <- X position in byte}

     lea   esi,[esi+ecx]  {Update source pointer and free ecx}

     lea   eax,[4*eax]    {eax <- scanline size in byte}

     mul   edx            {eax <- Y * (scanline size in byte)}
     sub   esi,eax        {esi <- Pixel write target pointer}

     mov   [esi],ebx      {bl <- Blue; bh <- Green; byte2(ebx) <- Red; byte3(ebx) <- Mask}

@@00:pop   edi
     pop   esi
     pop   ebx

end;

function GetPixelBMp32(XY:T_Coord_XY;
                       BMp32_Dim_XY:T_Dim_XY;
                       ScanLine0:pointer):T_RGB_Temp; assembler;
{ eax edx ecx are 1°, 2° and 3° parameters.
  Can freely modify the eax, ecx, and edx registers. }
asm

     push  esi
     push  edi

     mov   edi,BMp32_Dim_XY {edi <- edx <- BMp32_Dim_XY}
     mov   esi,ScanLine0  {esi <- ecx <- ScanLine0}
     mov   edx,XY         {edx <- eax <- XY}

     xor   eax,eax        {Inizializza @Result a 0}

     or    esi,esi        {If ScanLine0=Nil, ...}
     je    @@00           {... Exit}

     movsx eax,di         {eax <- DimX}
     shr   edi,16
     movsx edi,di         {edi <- DimY}

     movsx ecx,dx         {ecx <- X}
     shr   edx,16
     movsx edx,dx         {edx <- Y}

     or    eax,eax        {If DimX<0, ...}
     js    @@00           {... Exit}

     cmp   ecx,eax        {If X<0 or if X>=DimX, ...}
     jae   @@00           {... Exit}

     or    edi,edi        {If DimY<0, ...}
     js    @@00           {... Exit}

     cmp   edx,edi        {If Y<0 or if Y>=DimY, ...}
     jae   @@00           {... Exit}

     lea   ecx,[4*ecx]    {ecx <- X position in byte}

     lea   esi,[esi+ecx]  {Update source pointer and free ecx}

     lea   eax,[4*eax]    {eax <- scanline size in byte}

     mul   edx            {eax <- Y * (scanline size in byte)}
     sub   esi,eax        {esi <- Pixel write target pointer}

     mov   eax,[esi]      {al <- Blue; ah <- Green; byte2(eax) <- Red; byte3(eax) <- Mask}

@@00:pop   edi
     pop   esi

end;

下面是已经定义了参数类型的函数的定义(24位/像素图像):

procedure PutPixelBMp24(XY:T_Coord_XY;
                        BMp24_Dim_XY:T_Dim_XY;
                        ScanLine0:pointer;Pix:T_RGB_Temp); assembler;
{ eax edx ecx are 1°, 2° and 3° parameters.
  Can freely modify the eax, ecx, and edx registers. }
asm

     push  ebx
     push  esi
     push  edi

     mov   ebx,Pix        {ebx <- Pix}

     mov   edi,BMp24_Dim_XY {edi <- edx <- BMp24_Dim_XY}
     mov   esi,ScanLine0  {esi <- ecx <- ScanLine0}
     mov   edx,XY         {edx <- eax <- XY}

     or    esi,esi        {If ScanLine0=Nil, ...}
     je    @@00           {... Exit}

     movsx eax,di         {eax <- DimX}
     shr   edi,16
     movsx edi,di         {edi <- DimY}

     movsx ecx,dx         {ecx <- X}
     shr   edx,16
     movsx edx,dx         {edx <- Y}

     or    eax,eax        {If DimX<0, ...}
     js    @@00           {... Exit}

     cmp   ecx,eax        {If X<0 or if X>=DimX, ...}
     jae   @@00           {... Exit}

     or    edi,edi        {If DimY<0, ...}
     js    @@00           {... Exit}

     cmp   edx,edi        {If Y<0 or if Y>=DimY, ...}
     jae   @@00           {... Exit}

     lea   ecx,[ecx+2*ecx]{ecx <- X position in byte}

     lea   esi,[esi+ecx]  {Update source pointer and free ecx}

     lea   eax,[eax+2*eax]{eax <- scanline size in byte}

     add   eax,3          {Process in eax ...}
     and   eax,0FFFFFFFCH {... The dword aligned scanline size in byte}

     mul   edx            {eax <- Y * (dword aligned scanline size in byte)}
     sub   esi,eax        {esi <- Pixel write target pointer}

     mov   [esi],bx       {bl <- Blue; bh <- Green}

     shr   ebx,8          {bh <- Red}

     mov   [esi+2],bh     {bh <- Red}

@@00:pop   edi
     pop   esi
     pop   ebx

end;

function GetPixelBMp24(XY:T_Coord_XY;
                       BMp24_Dim_XY:T_Dim_XY;
                       ScanLine0:pointer):T_RGB_Temp; assembler;
{ eax edx ecx are 1°, 2° and 3° parameters.
  Can freely modify the eax, ecx, and edx registers. }
asm

     push  esi
     push  edi

     mov   edi,BMp24_Dim_XY {edi <- edx <- BMp24_Dim_XY}
     mov   esi,ScanLine0  {esi <- ecx <- ScanLine0}
     mov   edx,XY         {edx <- eax <- XY}

     xor   eax,eax        {Inizializza @Result a 0}

     or    esi,esi        {If ScanLine0=Nil, ...}
     je    @@00           {... Exit}

     movsx eax,di         {eax <- DimX}
     shr   edi,16
     movsx edi,di         {edi <- DimY}

     movsx ecx,dx         {ecx <- X}
     shr   edx,16
     movsx edx,dx         {edx <- Y}

     or    eax,eax        {If DimX<0, ...}
     js    @@00           {... Exit}

     cmp   ecx,eax        {If X<0 or if X>=DimX, ...}
     jae   @@00           {... Exit}

     or    edi,edi        {If DimY<0, ...}
     js    @@00           {... Exit}

     cmp   edx,edi        {If Y<0 or if Y>=DimY, ...}
     jae   @@00           {... Exit}

     lea   ecx,[ecx+2*ecx]{ecx <- X position in byte}

     lea   esi,[esi+ecx]  {Update source pointer and free ecx}

     lea   eax,[eax+2*eax]{eax <- scanline size in byte}

     add   eax,3          {Process in eax ...}
     and   eax,0FFFFFFFCH {... The dword aligned scanline size in byte}

     mul   edx            {eax <- Y * (dword aligned scanline size in byte)}
     sub   esi,eax        {esi <- Pixel write target pointer}

     mov   ax,[esi+1]     {al -> Green; ah -> Red}

     shl   eax,8          {B2 -> Red; B1 -> Green}

     mov   al,[esi]       {B0 -> Blue}

@@00:pop   edi
     pop   esi

end;

如果您需要更高的传输速度,以下是GetPixelBMp32()和PutPixelBMp32()函数的简化版本,但不检查传入参数的正确性:

procedure PutPixelBMp32(XY:T_Coord_XY;
                        BMp24_Dim_XY:T_Dim_XY;
                        ScanLine0:pointer;Pix:T_RGB_Temp); assembler;
{ eax edx ecx are 1°, 2° and 3° parameters.
  Can freely modify the eax, ecx, and edx registers. }
asm

     push  ebx
     push  esi

     mov   ebx,Pix        {ebx <- Pix}

     mov   esi,ScanLine0  {esi <- ecx <- ScanLine0}
     mov   eax,XY         {eax <- eax <- XY}
     mov   edx,BMp32_Dim_XY {edx <- edx <- BMp32_Dim_XY}

     movzx edx,dx         {edx <- DimX}

     movzx ecx,ax         {ecx <- X}
     shr   eax,16
     movzx eax,ax         {eax <- Y}

     lea   ecx,[4*ecx]    {ecx <- X position in byte}
     lea   esi,[esi+ecx]  {Update source pointer and free ecx}
     lea   edx,[4*edx]    {edx <- scanline size in byte}

     mul   edx            {eax <- Y * (scanline size in byte)}
     sub   esi,eax        {esi <- Pixel write target pointer}

     mov   [esi],ebx      {bl <- Blue; bh <- Green; byte2(ebx) <- Red; byte3(ebx) <- Mask}

     pop   esi
     pop   ebx

end;

function GetPixelBMp32(XY:T_Coord_XY;
                       BMp24_Dim_XY:T_Dim_XY;
                       ScanLine0:pointer):T_RGB_Temp; assembler;
{ eax edx ecx are 1°, 2° and 3° parameters.
  Can freely modify the eax, ecx, and edx registers. }
asm

     push  esi

     mov   esi,ScanLine0  {esi <- ecx <- ScanLine0}
     mov   eax,XY         {eax <- eax <- XY}
     mov   edx,BMp32_Dim_XY {edx <- edx <- BMp32_Dim_XY}

     movzx edx,dx         {edx <- DimX}

     movzx ecx,ax         {ecx <- X}
     shr   eax,16
     movzx eax,ax         {eax <- Y}

     lea   ecx,[4*ecx]    {ecx <- X position in byte}
     lea   esi,[esi+ecx]  {Update source pointer and free ecx}
     lea   edx,[4*edx]    {edx <- scanline size in byte}

     mul   edx            {edx <- Y * (scanline size in byte)}
     sub   esi,eax        {esi <- Pixel write target pointer}

     mov   eax,[esi]      {al <- Blue; ah <- Green; byte2(eax) <- Red; byte3(eax) <- Mask}

     pop   esi

end;

相关问题