Einzelnen Beitrag anzeigen

Trinity.dp

Registriert seit: 27. Nov 2009
8 Beiträge
 
#1

bitmap32 and xor

  Alt 17. Sep 2011, 13:28
Hallo liebe "Praxler"!

Gestern habe ich eine neue "Rückgängig"-Funktion für mein Bildbearbeitungsprogramm geschrieben. Dabei bin ich auf eine interessantes Phänomen gestoßen, welches mir schon viel Kopfzerbrechen bereitet hat.

Ich benutze xor um die Differenz von zwei Bitmap32 Bildern zu ermitteln. Das funktioniert auch wunderbar, falls diese Bilder nicht 1x1 Pixel große sind (dann funktioniert xor nämlich nicht). Ich habe eine kleines Testprogramm geschrieben, welches den Fehler verdeutlicht. Auf der Form befinden sich ein Button und ein Memo. Weitere Anmerkungen stehen unten beim Output.

Bitte helft mir! Ich habe schon sehr viel Zeit investiert diese Verhalten zu verstehen, aber es ist mir immer noch unerklärlich und für mein Programm leider zentral.

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, gr32;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

 // xor two memory blocks
 procedure MemBlockXOR(const Source1, Source2, Destination: Pointer;
                            Blocksize: Integer); assembler;
    asm
      push edi
      push esi
      push ebx
      mov esi,eax
      mov edi,ecx
      mov ecx,Blocksize;
      mov eax,[esi]
      and eax,[edx]
      mov [edi],eax
      mov eax,[esi+4]
      and eax,[edx+4]
      mov [edi+4],eax
      add esi,ecx
      add edx,ecx
      add edi,ecx
      shr ecx,3
      test ecx,ecx
      jz @@ending
      neg ecx
    @@doit:
      mov eax,[esi+ecx*8]
      mov ebx,[esi+ecx*8+4]
      xor eax,[edx+ecx*8]
      xor ebx,[edx+ecx*8+4]
      mov [edi+ecx*8],eax
      mov [edi+ecx*8+4],ebx
      inc ecx
      jnz @@doit
    @@ending:
      pop ebx
      pop esi
      pop edi
 end;

 // helper function for testing only
 function IntToBin ( value: LongInt; digits: integer ): string;
  begin
    result := StringOfChar ( '0', digits ) ;
    while value > 0 do begin
      if ( value and 1 ) = 1 then
        result [ digits ] := '1';
      dec ( digits ) ;
      value := value shr 1;
    end;
  end;
  

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
  var bmp1, bmp2, xbmp : TBitmap32;
begin
// create bitmaps
bmp1 := TBitmap32.Create;
bmp2 := TBitmap32.create;
xbmp := TBitmap32.create;

// FIRST test, everything works
bmp1.SetSize(2,2);
bmp1.Clear(tcolor32($124423213));
bmp2.SetSize(2,2);
bmp2.Clear(tcolor32(clblue));
xbmp.setSize(2,2);

// check what we get
memo1.Lines.Add('TEST 1: ');

// xbmp := bmp1 xor bmp2;
MemBlockXOR(@bmp1.Bits[0], @bmp2.Bits[0], @xbmp.bits[0], sizeof(tcolor32) * (bmp1.width * bmp1.height));

memo1.lines.add(inttobin(bmp1.Pixels[0,0],32) + ' xor');
memo1.lines.add(inttobin(bmp2.Pixels[0,0],32) + ' =');
memo1.lines.add(inttobin(xbmp.Pixels[0,0],32));

// SECOND test, fail
bmp1.SetSize(1,1);
bmp1.Clear(tcolor32($124423213));
bmp2.SetSize(1,1);
bmp2.Clear(tcolor32(clblue));
xbmp.setSize(1,1);

// check what we get
memo1.Lines.Add('TEST 2: ');

// xbmp := bmp1 xor bmp2;
MemBlockXOR(bmp1.ScanLine[0], bmp2.ScanLine[0], xbmp.ScanLine[0], sizeof(tcolor32) * (bmp1.width * bmp1.height));

memo1.lines.add(inttobin(bmp1.Pixels[0,0],32) + ' xor');
memo1.lines.add(inttobin(bmp2.Pixels[0,0],32) + ' =');
memo1.lines.add(inttobin(xbmp.Pixels[0,0],32));

// free bitmaps
bmp1.free;
bmp2.free;
xbmp.free;

end;

end.
Output:
Code:
TEST 1:
00100100010000100011001000010011 xor
00000000111111110000000000000000 =
00100100101111010011001000010011
TEST 2:
00100100010000100011001000010011 xor
00000000111111110000000000000000 =
00000000010000100000000000000000
Man sieht, dass die xor Funktion im zweiten Fall nicht richtig funktioniert.

Geändert von Trinity.dp (17. Sep 2011 um 14:41 Uhr)
  Mit Zitat antworten Zitat