Bild übertragen mit ScanLine?



  • Bin bei einem Versuch über ein Problem gestolpert, daß ich gern lösen möchte. Ich versuche, von einem Start-TImage ein Bild in eine Speicherbitmap zu übernehmen, es dann mit ScanLine abzuarbeiten und in ein Ziel-TImage zu übertragen.

    Das Ziel-TImage zeigt sich nur als schwarze Fläche. Wenn ich scrolle oder Refresh() einbaue, bekommt auch das Start-TImage einen senkrechten, zonig grauen Balken.

    Klar, ich hab immer wieder den Aufbau geändert und versucht, Checkmöglichkeiten mit einzubauen. Indes, es will sich kein Licht einstellen. Kann mir jemand weiterhelfen? Kann das sein, daß der Beispielcode für diese Verwendungsart gar nicht gedacht ist?

    void __fastcall TResa::ButtonEnter(TObject *Sender)
    {
     Ziel->Width = StrToInt(EditX->Text);
     Ziel->Height = StrToInt(EditY->Text);
    
     Graphics::TBitmap *pBitmap = new Graphics::TBitmap();
     Byte *ptr;
     try
     {
      pBitmap->Width = Start->Width;
      pBitmap->Height = Start->Height;
      pBitmap->Assign(Start->Picture->Graphic);
      for (int y = 0; y < pBitmap->Height; y++)
      {
       ptr = (Byte *)pBitmap->ScanLine[y];
       for (int x = 0; x < pBitmap->Width; x++)
        ptr[x] = (Byte)y;
       }
       Ziel->Canvas->StretchDraw(ClientRect,pBitmap);
      }
      catch (...) 
      { 
       ShowMessage("Bitmap konnte nicht geladen oder verändert werden");
      } 
    
     delete pBitmap;
     pBitmap = NULL;
     Ziel->Picture->SaveToFile("0DestBmp.BMP");
    }
    


  • Was willst du denn überhaupt mit pBitmap machen? Hier machst du nix anderes als: Jedes Pixel in einer Zeile hat die Farbe RGB(y,y,y), wobei y die Zeilennummer ist. Ich denke nicht, dass das dein Vorhaben ist.



  • Aaaaah, das ist der Fehler. Kein Wunder, daß ich keinen "Motor"-mechanismus erkenn. ScanLine ist also "nur" zum bitweisen Durcharbeiten verwendbar?

    Oder falsch angewendet? Ich will Pixel für Pixel ein Bild von einem Image ins andere übertragen. Ist dann sowas überhaupt machbar?



  • Klar. Hol dir die ScanLines von Bild und Image->Picture->Bitmap und setze die Bytes in der Image-ScanLine wie in der Bitmap-ScanLine. Line für Line bis zum Ende.



  • *Haue*, das versuch ich umzusetzen. Also dieser Beispielcode hat ein Bild geladen und dann eine schwarze Fläche gemalt. Na ja, bei sinnvollen Beispielen lernt man wohl zu schnell. 😡 😉 Die Straffung: Ich kann keinen vernünftigen Eindruck von ScanLine bekommen. Die Zeiger brauch ich sicher, aber nicht so, wie's jetzt ist...

    Logo, ich versteh die Zusammenhänge nicht. Könntest du mir zumindest mal den Ansatz zeigen? Dann müßte/sollte ich doch den Rest erkennen können, trotz der Zeiger. Denn bei denen steh ich ganz am Anfang.



  • Hi, hier mal ein Beispiel, um ein Bitmap in ein anderes mittels scanline + memcpy zu kopieren (schnell).

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
       if (OpenDialog1->Execute())
       {
          Image1->Picture->LoadFromFile(OpenDialog1->FileName);
          Image1->Width = Image1->Picture->Bitmap->Width;
          Image1->Height = Image1->Picture->Bitmap->Height;
          Image1->Picture->Bitmap->PixelFormat = pf32bit;
    
          Image2->Width = Image1->Width;
          Image2->Height = Image1->Height;
          Image2->Picture->Bitmap->Width = Image1->Picture->Bitmap->Width;
          Image2->Picture->Bitmap->Height = Image1->Picture->Bitmap->Height;
          Image2->Picture->Bitmap->PixelFormat = pf32bit;
    
          for (int row=0; row<Image1->Picture->Bitmap->Height; row++)
          {
              memcpy(Image2->Picture->Bitmap->ScanLine[row], Image1->Picture->Bitmap->ScanLine[row], 4 * Image1->Picture->Bitmap->Width);
          }
       }
    }
    


  • *super* danke, gleich die ganze Routine, @F98. Sie ließ sich problemlos integrieren. Ich mußte allerdings noch Pen->Widt von Image1 nach Image2 übernehmen, oder zumindest einen höheren Wert einstellen. Ohne bekam ich eine exeption, Zeilenüberlauf. Somit scheint nur 1:1 Übertragung möglich zu sein. Schade, ich wollte in der nächsten Stufe verschiedene +/-Vergrößerungen einstellen.

    Aber irgendwas fehlt noch. Ich bekomm als Ergebnis ein weißes, leeres TImage. Muß ich nicht doch den Byte Pointer benutzen, um die Werte der Bytes zu referenzieren?

    Am letzten memcpy-Parameter ( 4 * Image1->Picture->Bitmap->Width) hab ich ohne Versteh geknobelt. size_t n ist unsigned. Ja gut, aber... ?



  • Du musst irgendwas falsch gemacht haben. Bei mir funzt es prächtig (war auch nicht anders zu erwarten). Und das mit der PenWidth ist ja wohl absoluter Quatsch.



  • Stimmt. Genau dieser Code läuft einwandfrei, und ich kann auch die zweite Darstellung größer oder kleiner haben. Image2 in der größe ändern stretchdrawt automatisch.

    Da hab ich im Gesamtaufbau einen Fehler. Als einzigen Unterschied hab ich AutoSize=true für Image1 statt der direkten Wertzuweisung. Ansonsten muß ich den Code noch mal voll durchgehen. Gibts ja gar nicht, daß sich so ein edler Code nicht integrieren läßt.

    Habt großen dank für eure Hilfe. Jetz hab ich endlich ein starkes Beispiel, um mit ScanLine sinnvoll arbeiten zu können. 🕶



  • Na klar. Hatte in ner anderen Function noch alten falschen Code stehen gelassen. Das mußte kollidieren.

    Der "absolute Quatsch" hatte ich mich nachdenklich gemacht. Immerhin wurde damit eine Exeption vermieden. Hab mal gelesen, daß Überschreiben von Eigenschaften möglich sein soll. Das war der gaze Gag. So konnte ich aber nur einen Teil kompensieren. Sorry, das war von außerhalb natürlich nicht ersichtlich. Ich hatte es ja übersehen, trotz Quelltext vor der Nase. 🙄

    Hmmm, der letzte Parameter von memcpy ist interessant. Damit sind lustige Stauchungen und Abschneidungen möglich. Nicht übel als Effekt. Man muß dann innerhalb eines Wertebereiches variieren, um ein gewolltes Ziel zu erreichen. :p

    Mit manuellem Malen ist der Weg wohl nicht vergleichbar. Die Eigenschaften der Bildelemente scheinen nicht variierbar zu sein. Zumindest kann ich die Eigenschaften der Übertragung (Pen, Brush usw.) nicht steuern. Versuchen, Mausaktionen zu simulieren? Aber irgendwie glaub ich nicht dran. Zumindest zu komlex.



  • Der Code

    for (int row=0; row<Start->Picture->Bitmap->Height; row++)
     {
        memcpy(Ziel->Picture->Bitmap->ScanLine[row/2],
                Start->Picture->Bitmap->ScanLine[row],
                Start->Picture->Bitmap->Width*4);
        }
    

    staucht das übertragene Bild in der Höhe. Ist Stauchung auch in der Breite möglich?



  • Was du da machst ist keine Stauchung - du lässt einfach jede 2. Zeile aus. 😉



  • Hey, logisch denken ist alles. 🙂 Ich kann auch nicht wirklich rauslesen, daß ich zeilenweise arbeite. ...Scheint momentan noch nicht sinnvoll, an dem Punkt weiter zu studieren. Ich bring die Grundlagen nicht zusammen. - Dafür komm ich mit dem Maltool gut voran. Da beweg ich mich auf verstandenem Terrain.

    Habt nochmals Dank. Ein klein wenig Einblick hat es auf jeden Fall gebracht.



  • So langsam glaube ich, dass du überhaupt nicht weißt, was du da machst, wenn du codest.



  • Hier an dem Punkt ist das so. Hatte gehofft, durch Beispiele würde sich der Bereich erschließen. Etwas Licht ist schon mal reingekommen. Geduld und Augen offen halten. Es finden sich immer wieder Mosaiksteinchen.

    Anderes erschließt sich wesentlich leichter. Wenn ich 'ne Syntax versteh, kann ich auch Algors finden. Ich muß dazu sagen, ich hab noch recht wenig Praxis. 1/2 Jahr intensiv, dann in den letzten Jahren andere Sachen. HTML, Linux erkunden, ein Infoprojekt. Vor einem Jahr hab ich das Spielebauprojekt (RPG) entdeckt - es begann grad, sich zu formatieren. Nach den Vorarbeiten wird's jetzt Zeit, daß ich wieder intensiver code. Es wird mehr als genug gebraucht, und da sollte man fit sein.


Anmelden zum Antworten