C# Bilder überlagern

Nuuub

Lt. Junior Grade
Registriert
Aug. 2004
Beiträge
285
Morschn,

ich versuche 2 Bilder "live" zu überlagern. Man wählt 2 Bilder aus, die geladen werden, dazu kann man einen Wert zur Skalierung des 2. Bildes angeben und die gewünschte Position. Die Bilder werden dann wie angegeben übereinander gezeichnet.
Das Prinzip funktioniert soweit ohne Probleme, allerdings nur mit einem Zwischenspeicherschritt.
Erst mal der Code:

Code:
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows;
using System.Windows.Media;
using Image = System.Drawing.Image;
using MessageBox = System.Windows.MessageBox;
using Rectangle = System.Drawing.Rectangle;

namespace Convertilon
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();   
        }

        private void Changilon(object sender, RoutedEventArgs e)
        {
            var b = new ImageSourceConverter();
            var bild1 = Image.FromFile(file1.Text);
            var bild2 = SetImgOpacity(new Bitmap(file2.Text), (float)slider1.Value);
            var scaling = Math.Round(slider1.Value);
            var pos = 0;
            int xpos;
            int ypos;

            if (rbLinks.IsChecked == true)
                pos = 1;
            if (rbObenLinks.IsChecked == true)
                pos = 2;
            if (rbOben.IsChecked == true)
                pos = 3;
            if (rbObenRechts.IsChecked == true)
                pos = 4;
            if (rbRechts.IsChecked == true)
                pos = 5;
            if (rbUntenRechts.IsChecked == true)
                pos = 6;
            if (rbUnten.IsChecked == true)
                pos = 7;
            if (rbUntenLinks.IsChecked == true)
                pos = 8;

            switch (pos)
            {
                case 1:
                    xpos = 0;
                    ypos = (int)Math.Round(bild1.Height/2d) - (int)Math.Round(bild2.Height/(2*scaling));
                    break;
                case 2:
                    xpos = 0;
                    ypos = 0;
                    break;
                case 3:
                    xpos = (int) Math.Round(bild1.Width/2d) - (int) Math.Round(bild2.Width/(2*scaling));
                    ypos = 0;
                    break;
                case 4:
                    xpos = bild1.Width - (int) Math.Round(bild2.Width/scaling);
                    ypos = 0;
                    break;
                case 5:
                    xpos = bild1.Width - (int) Math.Round(bild2.Width/scaling);
                    ypos = (int) Math.Round(bild1.Height/2d) - (int) Math.Round(bild2.Height/(2*scaling));
                    break;
                case 6:
                    xpos = bild1.Width - (int) Math.Round(bild2.Width/scaling);
                    ypos = bild1.Height - (int) Math.Round(bild2.Height/scaling);
                    break;
                case 7:
                    xpos = (int) Math.Round(bild1.Width/2d) - (int) Math.Round(bild2.Width/(2*scaling));
                    ypos = bild1.Height - (int) Math.Round(bild2.Height/scaling);
                    break;
                case 8:
                    xpos = 0;
                    ypos = bild1.Height - (int) Math.Round(bild2.Height/scaling);
                    break;
                default:
                    xpos = 0;
                    ypos = 0;
                    break;
            }
            var cmxPic = new ColorMatrix { Matrix33 = 1 };
            ImageAttributes iaPic = new ImageAttributes();
            iaPic.SetColorMatrix(cmxPic, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
            var g = Graphics.FromImage(bild1); //background
            g.DrawImage(bild2, new Rectangle(xpos, ypos, (int)Math.Round(bild2.Width/scaling), (int)Math.Round(bild2.Height/scaling)), 0, 0, bild2.Width, bild2.Height, GraphicsUnit.Pixel, iaPic);

            try
            {
                var name1 = genName();
                bild1.Save(name1 + ".jpg");
                var bild = b.ConvertFromString(name1 + ".jpg");
                image3.Source = (ImageSource)bild;
                bild1.Dispose();
            }
            catch
            {
                MessageBox.Show("Zoooonk");
            }
            finally
            {
                bild1.Dispose();
            }

        }

        public string genName()
        {
            var b = new Random();
            var alphabet = new string[26]
                           {
                               "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r",
                               "s", "t", "u", "v", "w", "x", "y", "z"
                           };
            var name = "";

            for (var i = 0; i < 5; i++)
            {
                var c = b.Next(0, 25);
                name = name + alphabet[c];
            }
            return name;

        }

        private void LeOpen1(object sender, RoutedEventArgs e)
        {
            // Configure open file dialog box
            var dlg = new Microsoft.Win32.OpenFileDialog { FileName = "", DefaultExt = ".png", Filter = "PNG-Images (.png)|*.png|JPEG-Images (.jpg)|*.jpg|Bitmapscheisse (.bmp)|*.bmp|All files (*.*)|*.*" };

            // Show open file dialog box
            bool? result = dlg.ShowDialog();

            // Process open file dialog box results
            if (result == true)
            {
                // Open document
                string filename = dlg.FileName;
            }
            if (!string.IsNullOrEmpty(dlg.FileName))
            {
                file1.Text = dlg.FileName;
                var sr = new StreamReader(dlg.FileName);
                sr.Close();
                var b = new ImageSourceConverter();
                var f = b.ConvertFromString(dlg.FileName);
                image1.Source = (ImageSource) f;
            }
        }

        private void LeOpen2(object sender, RoutedEventArgs e)
        {
            // Configure open file dialog box
            var dlg = new Microsoft.Win32.OpenFileDialog { FileName = "", DefaultExt = ".png", Filter = "PNG-Images (.png)|*.png|JPEG-Images (.jpg)|*.jpg|Bitmapscheisse (.bmp)|*.bmp|All files (*.*)|*.*" };

            // Show open file dialog box
            bool? result = dlg.ShowDialog();

            // Process open file dialog box results
            if (result == true)
            {
                // Open document
                string filename = dlg.FileName;
            }
            if (!string.IsNullOrEmpty(dlg.FileName))
            {
                file2.Text = dlg.FileName;
                var sr = new StreamReader(dlg.FileName);
                sr.Close();
                var b = new ImageSourceConverter();
                var f = b.ConvertFromString(dlg.FileName);
                image2.Source = (ImageSource) f;
            }
        }
    }
}

Die Open-Funktionen sind hoffentlich selbst erklärend. In file1.Text bzw file2.Text sind die Pfade zu den gewählten Bildern. In der Oberfläche gibt es Radiobuttonse, um die Position vom 2. Bild anzugeben und einen Slider für dessen Skalierung. Bild1 ist der "Hintergrund" und Bild2 wird einfach davor geklatscht.

Nun das schon angesprochene Problem: Es geht immer nur, wenn ich das Bild zwischenspeichere. genName() baut dabei einen Zufallsstring, der als Name fungiert (sonst lässt sich das letzte Bild nicht überschreiben). Darunter wird das zusammengeklatschte Bild gespeichert und wird danach wieder geladen, weil ich es nicht hinbekomme, dass das ganze ohne diesen Schritt funktioniert. Und genau da brauch ich Eure Hilfe ;)

Anbei noch ein Bild:
http://imageshack.us/photo/my-images/7/schubidu.png/

MfG
 
Zuletzt bearbeitet:
Dieser Schritt ist doch nicht blöd. Dann kann nämlich auch bei einem Stromausfall nichts passieren, wenn das überlagerte Bild gespeichert wird. Ich würde es so lassen? Oder hat das alles Performance Gründe?
 
Es soll am Ende als eigene Funktion ablaufen, also 2 ImageSources rein, Skalierungs- und Positionsparameter und dann gibs nur ne ImageSource zurück. Da ist das zwischenspeichern suboptimal, zumal sich die Daten auch nur nach Beenden des jeweiligen Threads wieder löschen lassen.
 
Nuuub schrieb:
Nun das schon angesprochene Problem: Es geht immer nur, wenn ich das Bild zwischenspeichere. genName() baut dabei einen Zufallsstring, der als Name fungiert (sonst lässt sich das letzte Bild nicht überschreiben). Darunter wird das zusammengeklatschte Bild gespeichert und wird danach wieder geladen, weil ich es nicht hinbekomme, dass das ganze ohne diesen Schritt funktioniert. Und genau da brauch ich Eure Hilfe ;)
Was geht immer nur...?
Oder mit anderen Worten: Was genau willst Du erreichen?
Das "Ergebnisbild" unter dem Namen von "Bild1" abspeichern?
Das "Ergebnisbild" in Deinem Programm weiterverarbeiten?

bzgl.
Nuuub schrieb:
(sonst lässt sich das letzte Bild nicht überschreiben)
guckst Du http://msdn.microsoft.com/en-us/library/stf701f5.aspx
http://msdn.microsoft.com/en-us/library/stf701f5.aspx schrieb:
The file remains locked until the Image is disposed.


HTH

BigNum

Edit: Aha, Posting #3 erklärt es...
 
Zuletzt bearbeitet:
Ich möchte die Bilder zusammenführen (klappt ja), dann aber nicht speichern sondern "nur" anzeigen. Löschen geht leider nicht, auch mit Dispose(); nicht, aber vielleicht bin ich da wieder nur einfach zu doof für ;)
Deshalb der Ansatz das zusammengeführte Bild im Speicher zu haben, anzuzeigen und dann noch weiterverarbeiten zu können.
 
Hier ein simples "quick'n dirty" Beispiel wie's geht:

Code:
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;

public class MyPictureBox : Form
{
    public MyPictureBox()
    {
        Bitmap bm1 = new Bitmap("c:\\bild1.png");
        Bitmap bm2 = new Bitmap("c:\\bild2.jpg");
        Size = new Size(bm1.Width + 30, bm1.Height + 40);
        PictureBox pb = new PictureBox();
        pb.Parent = this;
        pb.Height = bm1.Height;
        pb.Width = bm1.Width;
        pb.BorderStyle = BorderStyle.FixedSingle;
        pb.SizeMode = PictureBoxSizeMode.AutoSize;

        var cmxPic = new ColorMatrix { Matrix33 = 1 };
        ImageAttributes iaPic = new ImageAttributes();
        iaPic.SetColorMatrix(cmxPic, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
        
        var g = Graphics.FromImage(bm1);
        g.DrawImage(bm2, new Rectangle(0, 0, bm2.Width, bm2.Height), 0, 0, bm2.Width, bm2.Height, GraphicsUnit.Pixel, iaPic);

        pb.Image = bm1;
    }

    static void Main()
    {
        Application.Run(new MyPictureBox());
    }
}


HTH

BigNum
 
Ok, dazu noch ne doofe Frage:
Wie zeig ich dann den Inhalt von pb an?

Bekome mit
var bla = new Window{ Content = pb } und bla.Show(); nur ein leeres Fenster...
 
Kann ich verstehen ;)
Den Code in WindowsForms finde ich sehr viel logischer aufgebaut. Habe nun eine Möglichkeit gefunden aus dem Bitmap-Type eine BitmapSource zu machen und die kann man gleich als ImageSource verwenden. Nun geht alles ohne Zwischenspeichern. Und das nur nach fast 4 Stunden Frustration ;)
 
WPF ist echt beschei.... Habe schon lange gebraucht, um rauszufinden, wie man zur Laufzeit die Position von Elementen ändern kann. Transform Group erstellen .... Nachdem alles so variabel geworden ist, und alle sich nur noch von der Object Klasse ableidet, wirds unübersichtlich. Gibt auch meistens midestens zwei Methoden um eine Sache zu machen.

Aber GZ, dass es nun funktioniert.
 

Ähnliche Themen

W
  • Geschlossen
  • Frage
2 3
Antworten
45
Aufrufe
2.681
Antworten
10
Aufrufe
765
Antworten
5
Aufrufe
868
Zurück
Oben