Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
[gelöst] Rahmen ins BitmapImage setzen
dennisspohr
myCSharp.de - Member

Avatar #avatar-2982.jpg


Dabei seit:
Beiträge: 420
Herkunft: Westerwald

Themenstarter:

[gelöst] Rahmen ins BitmapImage setzen

beantworten | zitieren | melden

Hallo zusammen,

ich hatte vor einer Weile mal ein kleines Bildbearbeitungsprogramm in .NET 2.0 geschrieben. Nun bin ich gerade dran, dieses in .NET 4.0 - in einer WPF-Anwendung - zu entwickeln.

Es gibt eine Methode, die ein BitmapImage übergeben bekommt und auch ein solches zurückliefert. In der Methode soll in (!) dem BitmapImage ein Rahmen mit bestimmter Farbe/Größe gesetzt werden.

Weiß jemand, wie ich das am besten lösen könnte? Im Internet finde ich leider nichts dazu.
Vielen Dank für eure Hilfe.

Grüße
Dennis
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von dennisspohr am .
private Nachricht | Beiträge des Benutzers
Ayke
myCSharp.de - Member

Avatar #avatar-2293.gif


Dabei seit:
Beiträge: 643
Herkunft: Hamburg

beantworten | zitieren | melden

Zeichne eine Rechteck um dein Bild.

Graphics.DrawRectangle...

Achte darauf das der Startpunkt zum zeichenen mit +(Lienenbreite / 2) beginnt und -(Lienenbreite / 2) am Endpunkt.
private Nachricht | Beiträge des Benutzers
dennisspohr
myCSharp.de - Member

Avatar #avatar-2982.jpg


Dabei seit:
Beiträge: 420
Herkunft: Westerwald

Themenstarter:

beantworten | zitieren | melden

Graphics ist im Namespace System.Drawing drin. Ist dieses überhaupt zu einer BitmapImage (!= Bitmap) kompatibel? Bzw. wäre das denn sauber?
private Nachricht | Beiträge des Benutzers
Ayke
myCSharp.de - Member

Avatar #avatar-2293.gif


Dabei seit:
Beiträge: 643
Herkunft: Hamburg

beantworten | zitieren | melden

Die Image Klasse hat die Eigenschaft Source dort kanst du deine BitmapImage zuweisen.

Image image = new Image();    
image.Width = 200;

BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri(@"/sample/myimage.jpg",UriKind.RelativeOrAbsolute);
bi.EndInit();

image.Source = bi;
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von Ayke am .
private Nachricht | Beiträge des Benutzers
dennisspohr
myCSharp.de - Member

Avatar #avatar-2982.jpg


Dabei seit:
Beiträge: 420
Herkunft: Westerwald

Themenstarter:

beantworten | zitieren | melden

Ich weiß, wie ich ein BitmapImage einem Image zuweise :-)

Ein Image ist doch ein Control, was eigentlich nur zum Anzeigen auf einer Oberfläche gedacht ist, oder?

Und damit hätte ich ja immernoch das Problem, einen Rahmen ums Bild zu setzen. Am liebsten würde ich das ohne die Verwendung von System.Drawing machen, was glaube ich sinnvoller ist.
private Nachricht | Beiträge des Benutzers
Lector
myCSharp.de - Member



Dabei seit:
Beiträge: 862

beantworten | zitieren | melden

Möglichkeit 1:
Ein Border-Control um das Image-Control herumlegen. Das verändert natürlich nicht das Bild sondern nur die Ansicht.
Möglichkeit 2:
Einen DrawingContext verwenden um ein Rechteck darüberzumalen so wie Ayke das bereits genannt hat.
Möglichkeit 3:
Du verwendest eine WritableBitmap und schreibst auf Low-Level-Ebene die Pixel am Rand so um dass sie einen Rahmen ergeben.
private Nachricht | Beiträge des Benutzers
dennisspohr
myCSharp.de - Member

Avatar #avatar-2982.jpg


Dabei seit:
Beiträge: 420
Herkunft: Westerwald

Themenstarter:

beantworten | zitieren | melden

zu Möglichkeit 1:
Nützt mir nichts, weil ich eben nicht anzeigen möchte, sondern als neue Datei speichern möchte.

zu Möglichkeit 2:
Nochmal meine Frage: Ist das ganze mit dem BitmapImage kompatibel?

zu Möglichkeit 3:
Wäre eine Möglichkeit, hört sich aber langsam an.
private Nachricht | Beiträge des Benutzers
Lector
myCSharp.de - Member



Dabei seit:
Beiträge: 862

beantworten | zitieren | melden

Mit Möglichkeit 2 habe ich mich selbst noch nicht wirklich beschäftigt. Das war eher eine Idee. Darum kann ich leider nicht mehr dazu sagen.

Möglichkeit 3:
Wenn das was du machst ein 'Bildbearbeitungsprogramm' sein soll wird dir eh nichts anderes übrig bleiben. Das schreiben auf die Bitmap selbst kann man durchaus performant umsetzen. Was hier ausbremst ist eher der Bildschirm-Aktualisierungs-Mechanismus von WPF und die Tatsache dass managed C#-Code eben doch langsamer ist als nativer Code.
Ich glaube jedoch nicht dass du das bei der Erzeugung eines Bildrahmens merken wirst (Ich weis ja nicht was dein Bildbearbeitungsprogramm sonst so macht). Es ist IMHO die performanteste Variante unter WPF ein Bild zu manipulieren. Abspeichern ist damit auch überhaupt kein Problem da WritableBitmap von ImageSource ableitet.
private Nachricht | Beiträge des Benutzers
dennisspohr
myCSharp.de - Member

Avatar #avatar-2982.jpg


Dabei seit:
Beiträge: 420
Herkunft: Westerwald

Themenstarter:

beantworten | zitieren | melden

Das Programm soll viele einzelne Bildbearbeitungsschritte auf einen Bilderstapel machen. Das heißt, es geht in einer Schleife alle Bilder durch und wendet die einzelnen Bearbeitungsschritte (z.B. Rahmen setzen, Größe ändern, S/W, ...) an. Deshalb versuche ich sehr auf Geschwindigkeit zu achten, auch wegen der Erstellung eines Vorschaubildes.

Schade ist, dass es im Internet kaum Beispiele gibt, wie man BitmapImages bearbeiten kann.
private Nachricht | Beiträge des Benutzers
Lector
myCSharp.de - Member



Dabei seit:
Beiträge: 862

beantworten | zitieren | melden

Vermutlich weil niemand soetwas mit WPF macht...

Ich rate dir zu einer WritableBitmap. Der Performance-Flaschenhals in WPF ist hier lediglich die Bildschirmaktualisierung. Wenn du während des Bearbeitens der Bitmap, diese nicht am Bildschirm aktualisierst wirst du es relativ performant hinbekommen. Nachteil (ode Vorteil?) der WritableBitmap ist natürlich dass du mit absoluten Low-Level-Operationen arbeitest. Aber wenn ich mir deine Anwendungsgebiete (S/W=Schwarz-Weis-Filter?) ansehe wirst du eh alle Pixel als Byte-Array durchschleifen müssen. Zum anzeigen der Bilder kannst du einfach die Writable-Bitmap in ein Image-Control stecken. Für Thumbnails gibt es auch eine Klasse Transformed-Bitmap. Hier muss ich dich allerdings warnen. Unter .NET 3.5 kannst du leicht ein Speicherleck erzeugen wenn du eine TransformedBitmap in ein Image-Control packst. Wie es unter .NET 4.0 ist kann ich dir leider nicht sagen aber teste das am besten mal selbst. Wenn du die Writable-Bitmap direkt anzeigen willst kannst du noch einen Aktualisierungsmechanismus steuern mit dem du angibst wann die GUI aktualisiert werden soll (wenn du während der Anzeige das Bild verändern willst).
private Nachricht | Beiträge des Benutzers
dennisspohr
myCSharp.de - Member

Avatar #avatar-2982.jpg


Dabei seit:
Beiträge: 420
Herkunft: Westerwald

Themenstarter:

beantworten | zitieren | melden

Warum macht das niemand mit WPF? Wenn ich mit System.Drawing mehr Vorteile habe, kann ich das auch damit machen. Ich dachte nur, dass mir WPF (bzw. .NET 4.0) mehr Funktionalität und Performance bietet.

Das Vorschaubild soll erst am Ende angezeigt werden. Es können sich beliebig viele PlugIns einschalten und einen Bearbeitungsschritt zur Verfügung stellen. Ist die Frage, ob ich den PlugIns eine System.Drawing.Bitmap oder ein System.Windows.Media.Imaging.BitmapImage übergebe.

Eventuell könnten die einzelnen Bearbeitungsschritte mit einer Bitmap arbeiten und ganz am Ende wird diese zur Anzeige in ein BitmapImage umwandelt.
private Nachricht | Beiträge des Benutzers
Lector
myCSharp.de - Member



Dabei seit:
Beiträge: 862

beantworten | zitieren | melden

Nunja... WPF bietet dir einfach verwendbare Hardwareunterstützung. Damit kannst du einfach eine GUI designen ohne dass die Controls im Winows-Style sind.
Du kannst einfach Animationen integrieren. Die GUI ist schnell da hardware gestützt.
Du hast eine nette Default-Architektur die du leicht erweitern kannst. (Behaviors, Panels...)
Du hast eine tolle Command- und Binding-Unterstützung mit denen du super schnell irgendwelche Business-Anwendungen mit MVVM implementieren kannst.
Allerdings ist WPF nicht wirklich als Grafik-Library zu gebrauchen. Du kannst zwar mithilfe von PixelShadern tolle Bild-Filter implementieren die dann auch auf der Grafikkarte laufen und verdammt schnell sind allerdings ist das eher für Effekte vorgesehen. Wenn du damit eine Bitmap bearbeiten willst müsstest du einen solchen Shader auf ein ImageControl anwenden und dieses dann mit einer RenderTargetBitmap 'fotografieren'.

Soviel zur WPF-Unterstützung.

Ich weis nicht wie viel Unterstützung du von WinForms bekommst. War schon lange her als ich das letzte mal damit Programmiert habe. Ich kann mich allerdings noch grob daran erinnern dass ich damit Bilder mit DrawLine(), FillRect()... bearbeitet werden können. Die gleichen Methoden gibt es mit WPF im DrawingContext. Ob man damit Bitmaps bearbeiten kann kann ich dir leider nicht beantworten.

Fakt ist jedoch dass dir für einen S/W-Filter WinForms wohl genausowenig Unterstützung wie WPF bietet. Von daher ist es, unter diesen Gesichtspunkt betrachtet, egal auf welche Technologie du setzt.
private Nachricht | Beiträge des Benutzers
dennisspohr
myCSharp.de - Member

Avatar #avatar-2982.jpg


Dabei seit:
Beiträge: 420
Herkunft: Westerwald

Themenstarter:

beantworten | zitieren | melden

WPF kann ich ja trotzdem weiter benutzen, eben nur nicht für die eigentliche Bearbeitung. Diese könnte ich dann mit System.Drawing machen.

Auf die Pixelshader bin ich auch gestoßen, allerdings habe ich dort sehr wenige Tutorials gefunden, wie man diese genau anwendet. Für Filter wären diese aufgrund ihrer hohen Geschwindigkeit eigentlich sehr interessant.

Ich weiß, dass das mit System.Drawing alles relativ einfach funktioniert. Ich habe die einzelnen Bearbeitungsschritte damit ja alle schon mal so ähnlich gemacht.
private Nachricht | Beiträge des Benutzers
Lector
myCSharp.de - Member



Dabei seit:
Beiträge: 862

beantworten | zitieren | melden

Wenn du dich für die Shader interressierst kannst du dir mal das Tool Shazzam ansehen.

Damit solltest du einen groben Überblick bekommen was man damit alles machen kann. Bei solchen Effekten handelt es sich allerdings NICHT um Bitmap-Operationen auch wenn man diese per RenderTargetBitmap theoretisch dazu zwingen könnte eine Bitmap zu bearbeiten.

Ich habe selbst auch schon einige Shader implementiert um div. GUI-Effekte zu erzielen. Evtl. lässt sich dass ja auf Filter umbiegen. Vorteil ist wie gesagt dass die Grafikkarte Unterstützung anbietet (sofern diese das unterstützt). Wenn dieser Ansatz klappt hättest du sicher einen mörderschnellen Filter-Mechanismus ;).
private Nachricht | Beiträge des Benutzers
dennisspohr
myCSharp.de - Member

Avatar #avatar-2982.jpg


Dabei seit:
Beiträge: 420
Herkunft: Westerwald

Themenstarter:

beantworten | zitieren | melden

Vielen Dank für den Link. Ich werde mir das Tool heute Abend zu Hause mal anschauen.

Das mit man mit den Shaders sehr viel machen kann, habe ich schon bemerkt :-) Ich habe nur nichts gefunden, wie ich diese auf ein BitmapImage anwenden kann. Bei den Beispielen im Internet sind diese immer direkt an ein Image-Control gebunden, was mir an dieser Stelle ja nichts bringt.

Ich könnte ein PlugIn für Filter und ein PlugIn für Sonstiges (also bsp. Rahmen) anbieten. Das klingt gut :)
private Nachricht | Beiträge des Benutzers
dennisspohr
myCSharp.de - Member

Avatar #avatar-2982.jpg


Dabei seit:
Beiträge: 420
Herkunft: Westerwald

Themenstarter:

beantworten | zitieren | melden

So, hier kommt die Lösung :-) Nachdem ich tagelang gesucht und gesucht habe.. die Lösung ist so verdammt einfach. Folgender Quellcode-Schnispel sollte Erklärung genug sein:


        public BitmapSource Execute(BitmapSource bitmap)
        {
            double newWidth = bitmap.PixelWidth + config.Thickness * 2;
            double newHeight = bitmap.PixelHeight + config.Thickness * 2;

            RenderTargetBitmap renderTarget = new RenderTargetBitmap(
                (int)newWidth,
                (int)newHeight,
                bitmap.DpiX,
                bitmap.DpiY,
                PixelFormats.Default);

            DrawingVisual drawingVisual = new DrawingVisual();
            DrawingContext drawingContext = drawingVisual.RenderOpen();

            Rect imageRect = new Rect(config.Thickness, config.Thickness, bitmap.PixelWidth, bitmap.PixelHeight);
            Pen pen = new Pen(Brushes.Black, config.Thickness);

            using (drawingContext)
            {
                drawingContext.DrawRectangle(Brushes.Black, pen, new Rect(0, 0, newWidth, newHeight));
                drawingContext.DrawImage(bitmap, imageRect);
            }

            renderTarget.Render(drawingVisual);
            return renderTarget as BitmapSource;
        }
private Nachricht | Beiträge des Benutzers