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
GetPixel und SetPixel um Längen geschlagen. 800 mal schneller
Robertico
myCSharp.de - Member



Dabei seit:
Beiträge: 345

Themenstarter:

GetPixel und SetPixel um Längen geschlagen. 800 mal schneller

beantworten | zitieren | melden

Mittlerweile in Form einer DLL von janismac


Hallo alle,
Die Geschwindigkeit von GetPixel und SetPixel ging mir schon längst auf die Nerven.

Da ich jetzt beim Lernen etwas weiter bin, habe ich eine Klasse gemacht, die dies weit in den Schatten stellt. Fast 800 mal schneller.

Die Klasse ist noch nicht fertig, aber für meine Bedürfnisse reicht es. Sollte Interesse bestehen, mache ich natürlich weiter.

Da ich noch Frischling bin in CSharp bind ich für jede Kritik und Anregung sehr dankbar.

Zunächst: So habe ich die Geschwindigkeit getestet:

        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog of = new OpenFileDialog();
            of.Filter = "Bilder (*.BMP;*.JPG;*.GIF;*.PNG)|*.BMP;*.JPG;*.GIF;*.PNG|All files (*.*)|*.*";
            if (of.ShowDialog() == DialogResult.OK)
            {
// Vorbereitungen
                Bitmap test = (Bitmap)Image.FromFile(of.FileName); // Eine Bitmap laden Size: (755 x 666)
                RoBitmap rob = new RoBitmap(test); // RoBitmap davon erzeugen
                Bitmap test2 = new Bitmap(test.Width, test.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                // leere Bitmap gleicher Größe erstellen
                RoBitmap rob2 = new RoBitmap(test2); // RoBitmap davon erzeugen
// Test 1 mit Orginal GetPixel/SetPixel Die Bitmap test wird Pixel für Pixel in test2 kopiert

                DateTime now = DateTime.Now; // Zeit nehmen

                for (int x = 0; x < test.Width; x++)
                    for (int y = 0; y < test.Height; y++)
                        test2.SetPixel(x, y, test.GetPixel(x, y));

                TimeSpan usedTime = DateTime.Now - now;
                MessageBox.Show(usedTime.ToString()); // 35,5 Sekunden

// Test 2 mit Orginal SetPixel und RoBitmap GetPixel 
                test2 = new Bitmap(test.Width, test.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

                now = DateTime.Now;
                for (int x = 0; x < test.Width; x++)
                    for (int y = 0; y < test.Height; y++)
                        test2.SetPixel(x, y, rob.GetPixel(x, y));

                usedTime = DateTime.Now - now;
                MessageBox.Show(usedTime.ToString()); // 22,14 Sekunden

// Test 3 mit RoBitmap SetPixel / GetPixel 
                test2 = new Bitmap(test.Width, test.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                now = DateTime.Now;

                for (int x = 0; x < test.Width; x++)
                    for (int y = 0; y < test.Height; y++)
                        rob2.SetPixel(x, y, rob.GetPixel(x, y));

                usedTime = DateTime.Now - now;
                MessageBox.Show(usedTime.ToString()); // 4,45 Sekunden

// Test 4 mit RoBitmap SetPixel / GetPixel und Width/Height
                test2 = new Bitmap(test.Width, test.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                now = DateTime.Now;

                for (int x = 0; x < rob.Width; x++)
                    for (int y = 0; y < rob.Height; y++)
                        rob2.SetPixel(x, y, rob.GetPixel(x, y));

                usedTime = DateTime.Now - now;
                MessageBox.Show(usedTime.ToString()); // 0,047 Sekunden


                pictureBox1.Image = rob2.Image; // kommt das Richtige Bild heraus?
            }
        }

Und nun die noch nicht fertige Klasse:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace BildMischer
{
    class RoBitmap
    {
        private byte[] bildDaten;
        private Color[,] color;
        private int width;
        private int height;
        Bitmap Bild;
        Rectangle rect;
        bool modified;
        int bytes;
        int stride;
        System.Drawing.Imaging.PixelFormat pixelFormat;
        System.Drawing.Imaging.ColorPalette colorPalette;
        public RoBitmap(Bitmap bld)
        {
            Bild = bld;
            SetzeWerte();
        }
        void SetzeWerte()
        {
            colorPalette = Bild.Palette;
            pixelFormat = Bild.PixelFormat;
            width = Bild.Width;
            height = Bild.Height;
            rect = new Rectangle(0, 0, width, height);
            System.Drawing.Imaging.BitmapData bmpData =
                Bild.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly,
                Bild.PixelFormat);

            IntPtr ptr = bmpData.Scan0;
            stride = bmpData.Stride;
            bytes = stride * height;
            bildDaten = new byte[bytes];
            System.Runtime.InteropServices.Marshal.Copy(ptr, bildDaten, 0, bytes);
            Bild.UnlockBits(bmpData);
            color = new Color[width, height];
            switch (pixelFormat)
            {
                case System.Drawing.Imaging.PixelFormat.Format32bppArgb:
                    Format32BppArgb();
                    break;
                case System.Drawing.Imaging.PixelFormat.Format24bppRgb:
                    Format24BppRgb();
                    break;
                case System.Drawing.Imaging.PixelFormat.Format8bppIndexed:
                    Format8BppIndexed();
                    break;
                case System.Drawing.Imaging.PixelFormat.Format4bppIndexed:
                    Format4BppIndexed();
                    break;
                case System.Drawing.Imaging.PixelFormat.Format1bppIndexed:
                    Format1BppIndexed();
                    break;
            }
             modified = false;
       }
        void Format32BppArgb()
        {
            for (int y = 0; y < height; y++)
                for (int x = 0; x < width; x++)
                    color[x, y] = Color.FromArgb(bildDaten[y * stride + x * 4 + 3], bildDaten[y * stride + x * 4 + 2], bildDaten[y * stride + x * 4 + 1], bildDaten[y * stride + x * 4]);
        }
        void Format24BppRgb()
        {
            for (int y = 0; y < height; y++)
                for (int x = 0; x < width; x++)
                    color[x, y] = Color.FromArgb(bildDaten[y * stride + x * 3 + 2], bildDaten[y * stride + x * 3 + 1], bildDaten[y * stride + x * 3]);
        }
        void Format8BppIndexed()
        {
             for (int y = 0; y < height; y++)
                for (int x = 0; x < width; x++)
                    color[x, y] = colorPalette.Entries[bildDaten[y * stride + x]];
        }
        void Format4BppIndexed()
        {
            for (int y = 0; y < height; y++)
                for (int x = 0; x < width; x++)
                    if (x % 2 == 0)
                        color[x, y] = colorPalette.Entries[LowByte(bildDaten[y * stride + x / 2])];
                    else
                        color[x, y] = colorPalette.Entries[HighByte(bildDaten[y * stride + x / 2])];
        }
        void Format1BppIndexed()
        {
            int rest = width % 8;
            byte bits;
            int x, y;
            for (y = 0; y < height; y++)
            {
                for (x = 0; x < width - 8; x += 8)
                {
                    bits = bildDaten[y * stride + x / 8];
                    color[x, y] = colorPalette.Entries[(bits & 128) / 128];
                    color[x + 1, y] = colorPalette.Entries[(bits & 64) / 64];
                    color[x + 2, y] = colorPalette.Entries[(bits & 32) / 32];
                    color[x + 3, y] = colorPalette.Entries[(bits & 16) / 16];
                    color[x + 4, y] = colorPalette.Entries[(bits & 8) / 8];
                    color[x + 5, y] = colorPalette.Entries[(bits & 4) / 4];
                    color[x + 6, y] = colorPalette.Entries[(bits & 2) / 2];
                    color[x + 7, y] = colorPalette.Entries[bits & 1];
                }
                bits = bildDaten[y * stride + x / 8];
                int teiler = 128;
                for (int i = 0; i < rest; i++)
                {
                    color[x + i, y] = colorPalette.Entries[(bits & teiler) / teiler];
                    teiler /= 2;
                }
            }
        }
        int HighByte(byte zahl)
        {
            return zahl >> 4;
        }
        int LowByte(byte zahl)
        {

            return zahl & 15;
        }
        public Color GetPixel(int x, int y)
        {
            return color[x, y];
        }
        public void SetPixel(int x, int y, Color col)
        {
            color[x, y] = col;
            modified = true;
        }
        public int Width
        {
            get { return width; }
        }
        public int Height
        {
            get { return height; }
        }
        public Bitmap Image
        {
            set
            {
                Bild = value;
                SetzeWerte();
            }
            get
            {
                if (!modified) return Bild;
                switch (pixelFormat)
                {
                    case System.Drawing.Imaging.PixelFormat.Format32bppArgb:
                        return ReturnFormat32BppArgb();
                    case System.Drawing.Imaging.PixelFormat.Format24bppRgb:
                        return ReturnFormat24BppRgb();
                    case System.Drawing.Imaging.PixelFormat.Format8bppIndexed:
                        //ReturnFormat8BppIndexed();
                        break;
                    case System.Drawing.Imaging.PixelFormat.Format4bppIndexed:
                        //ReturnFormat4BppIndexed();
                        break;
                    case System.Drawing.Imaging.PixelFormat.Format1bppIndexed:
                        //ReturnFormat1BppIndexed();
                        break;
                }
                return null;
            }
        }
        Bitmap ReturnFormat24BppRgb()
        {
            for (int y = 0; y < height; y++)
                for (int x = 0; x < width; x++)
                {
                    bildDaten[y * stride + x * 3 + 2] = color[x, y].R;
                    bildDaten[y * stride + x * 3 + 1] = color[x, y].G;
                    bildDaten[y * stride + x * 3] = color[x, y].B;
                }
            System.Drawing.Imaging.BitmapData bmpData =
               Bild.LockBits(rect, System.Drawing.Imaging.ImageLockMode.WriteOnly,
               Bild.PixelFormat);
            IntPtr ptr = bmpData.Scan0;
            System.Runtime.InteropServices.Marshal.Copy(bildDaten, 0, ptr, bytes);
            Bild.UnlockBits(bmpData);
            modified = false;
            return Bild;
        }
         Bitmap ReturnFormat32BppArgb()
        {
            for (int y = 0; y < height; y++)
                for (int x = 0; x < width; x++)
                {
                    bildDaten[y * stride + x * 4 + 3] = color[x, y].A;
                    bildDaten[y * stride + x * 4 + 2] = color[x, y].R;
                    bildDaten[y * stride + x * 4 + 1] = color[x, y].G;
                    bildDaten[y * stride + x * 4] = color[x, y].B;
                }
            System.Drawing.Imaging.BitmapData bmpData =
               Bild.LockBits(rect, System.Drawing.Imaging.ImageLockMode.WriteOnly,
               Bild.PixelFormat);
            IntPtr ptr = bmpData.Scan0;
            System.Runtime.InteropServices.Marshal.Copy(bildDaten, 0, ptr, bytes);
            Bild.UnlockBits(bmpData);
            modified = false;
            return Bild;
        }
   }
}

Gruß Robert
Dieser Beitrag wurde 6 mal editiert, zum letzten Mal von Robertico am .
private Nachricht | Beiträge des Benutzers
Borg
myCSharp.de - Member



Dabei seit:
Beiträge: 1548
Herkunft: Berlin, Germany

beantworten | zitieren | melden

Der Ansatz ist prinzipiell nicht schlecht.
Allerdings musst du beim jedem Lesen/Zuweisen einer Bitmap immer den Speicher kopieren. Zumindest das Kopieren beim Lesen ließe sich durch Benutzung eines Dirty-Flags (bzw. modified) umgehen.
Der nächste Evolutionsschritt wäre direkt in den Speicher der Bitmap zu schreiben.

EDIT: Und der übernächste ist, das ganze von Bitmap abzuleiten um diesen ersetzen zu können...
private Nachricht | Beiträge des Benutzers
Robertico
myCSharp.de - Member



Dabei seit:
Beiträge: 345

Themenstarter:

beantworten | zitieren | melden

Hallo Borg,

Punkt 1 (gute Idee) habe ich umgesetzt. Mit den anderen werde ich mich befassen.

Gruß Robert
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo Borg,

meinst du jetzt das Marshal.Copy? Das ist doch sinnvoll, damit man nicht unsafe verwenden muss. Gerade für eine Bibliothek ist es aus meiner Sicht wünschenswert, unsafe zu vermeiden.

Und der Vorschlag, von Bitmap abzuleiten, scheitert daran, dass Bitmap sealed ist :-)

herbivore

PS: Verschoben nach .NET-Komponentensammlung
private Nachricht | Beiträge des Benutzers
Borg
myCSharp.de - Member



Dabei seit:
Beiträge: 1548
Herkunft: Berlin, Germany

beantworten | zitieren | melden

Ist es doch sealed? Verdammt. Ich hatte gestern gehofft, dass es das nicht ist; war jedoch zu faul nachzuschauen, da ich wusste, dass mich schon jemand korrigieren würde, falls es nicht stimmt...

Desweiteren ist mir der Bitmap-ctor public Bitmap ( int width, int height, int stride, PixelFormat format, IntPtr scan0 ) aufgefallen.

Zur Umsetzung von IntPtr in Byte[] bietet sich public static Object PtrToStructure ( IntPtr ptr, Type structureType ) an.
Für die Umwandlung des Byte[] in IntPtr bietet sich public static IntPtr UnsafeAddrOfPinnedArrayElement ( Array arr, int index ) an.

Ich habe das nicht ausprobiert, aber wenn es so funktioniert, wie ich mir das erhoffe und denke, kann man mit den Pointern arbeiten, ohne einen unsafe Kontext zu benutzen.

Eine zusätzliche Frage:
Mittels Reflection ist es doch möglich, protected und private Methoden aufzurufen. Kann man denn darüber nicht auch eine Ableitung einer sealed-Klasse erzeugen?
private Nachricht | Beiträge des Benutzers
Robertico
myCSharp.de - Member



Dabei seit:
Beiträge: 345

Themenstarter:

beantworten | zitieren | melden

Habe noch etwas probiert und es klappte.

Da ich nicht weis, ob es sinnvoll ist zunächt mal hier:

        public Bitmap GetTransparent(Color transparentColor)
        {
            return GetTransparent(transparentColor, 0);
        }
        public Bitmap GetTransparent(Color transparentColor, byte tranparenz)
        {
            // vorerst nur für zwei Formate
            int newStride;
            if (pixelFormat == System.Drawing.Imaging.PixelFormat.Format24bppRgb)
                newStride = stride / 3 * 4;
            else if (pixelFormat != System.Drawing.Imaging.PixelFormat.Format32bppArgb)
                newStride = stride;
            else
                return Bild;

            Bitmap F32 = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            byte[] f32 = new byte[height * newStride];
            for (int y = 0; y < height; y++)
                for (int x = 0; x < width; x++)
                {
                    if (color[x, y].ToArgb() != transparentColor.ToArgb())
                        f32[y * width * 4 + x * 4 + 3] = color[x, y].A;
                    else
                        f32[y * width * 4 + x * 4 + 3] = tranparenz;
                    f32[y * width * 4 + x * 4 + 2] = color[x, y].R;
                    f32[y * width * 4 + x * 4 + 1] = color[x, y].G;
                    f32[y * width * 4 + x * 4] = color[x, y].B;
                }
            System.Drawing.Imaging.BitmapData bmpData =
               F32.LockBits(rect, System.Drawing.Imaging.ImageLockMode.WriteOnly,
               F32.PixelFormat);
            IntPtr ptr = bmpData.Scan0;
            System.Runtime.InteropServices.Marshal.Copy(f32, 0, ptr, height * newStride);
            F32.UnlockBits(bmpData);
            return F32;
        }

private Nachricht | Beiträge des Benutzers
Borg
myCSharp.de - Member



Dabei seit:
Beiträge: 1548
Herkunft: Berlin, Germany

beantworten | zitieren | melden

Zitat
Habe noch etwas probiert und es klappte.
Was hast du probiert und was hat geklappt?
private Nachricht | Beiträge des Benutzers
Robertico
myCSharp.de - Member



Dabei seit:
Beiträge: 345

Themenstarter:

beantworten | zitieren | melden

Dachte Bitmap GetTransparent(Color transparentColor) sagt alles aus.

Die Funktion gibt die Bitmap zurück in der die Farbe transparentColor transparent ist.
private Nachricht | Beiträge des Benutzers
Borg
myCSharp.de - Member



Dabei seit:
Beiträge: 1548
Herkunft: Berlin, Germany

beantworten | zitieren | melden

Was die Methode tut, habe ich gesehen.
Nur brachte mich der zweite Satz
Zitat
Da ich nicht weis, ob es sinnvoll ist zunächt mal hier:
auf die Idee, dass der erste Satz sich nicht auf diese Methode bezieht...

EDIT: spellcheck
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo Borg,
Zitat
Mittels Reflection ist es doch möglich, protected und private Methoden aufzurufen. Kann man denn darüber nicht auch eine Ableitung einer sealed-Klasse erzeugen?
Reflection ist eine Laufzeitgeschichte. Die Definition einer Klasse ist Compilezeit. Natürlich könnte man zur Laufzeit Emit verwenden, aber das ist nichts anderes als ein Compileraufruf zur Laufzeit, d.h. man kann nur syntaktisch Korrektes emitieren. Also ich sehe keine Weg, sealed zu umgehen.

herbivore
private Nachricht | Beiträge des Benutzers
Robertico
myCSharp.de - Member



Dabei seit:
Beiträge: 345

Themenstarter:

Umwandlung in 8bpp (1280 x 998 < 1Sek.)

beantworten | zitieren | melden

Angesprochen auf die Möglichkeit dies einzubauen, habe ich es versucht.

Hier das Ergebnis:

//
        #region 8bpp
        Color ColorFuer8bpp(Color col)
        {
            int r = col.R - col.R % 51;
            int g = col.G - col.G % 51;
            int b = col.B - col.B % 51;
            return Color.FromArgb(r, b, g);
        }
        static Color ColorFuer8bpp(Color col, int zusatz)
        {
            int r = (col.R + zusatz) - (col.R + zusatz) % 51;
            int g = (col.G + zusatz) - (col.G + zusatz) % 51;
            int b = (col.B + zusatz) - (col.B + zusatz) % 51;
            return Color.FromArgb(r, b, g);
        }
        static ColorPalette AddSystemColor(ColorPalette palette)
        {
            int counter = 16;
            palette.Entries[counter++] = SystemColors.ActiveBorder;
            palette.Entries[counter++] = SystemColors.ActiveCaption;
            palette.Entries[counter++] = SystemColors.ButtonFace;
            palette.Entries[counter++] = SystemColors.ButtonShadow;
            palette.Entries[counter++] = SystemColors.Control;
            palette.Entries[counter++] = SystemColors.ControlDark;
            palette.Entries[counter++] = SystemColors.ControlDarkDark;
            palette.Entries[counter++] = SystemColors.ControlLight;
            palette.Entries[counter++] = SystemColors.Desktop;
            palette.Entries[counter++] = SystemColors.GradientActiveCaption;
            palette.Entries[counter++] = SystemColors.GradientInactiveCaption;
            palette.Entries[counter++] = SystemColors.GrayText;
            palette.Entries[counter++] = SystemColors.HotTrack;
            palette.Entries[counter++] = SystemColors.InactiveBorder;
            palette.Entries[counter++] = SystemColors.InactiveCaption;
            palette.Entries[counter++] = SystemColors.InactiveCaptionText;
            palette.Entries[counter++] = SystemColors.MenuBar;
            palette.Entries[counter++] = SystemColors.MenuHighlight;
            palette.Entries[counter++] = SystemColors.ScrollBar;
            //hier können noch 5 weitere Farben hinzu
            return palette;
        }
        public static void InitializeColor()
        {
            ColorPalette tmp = Color8bppPalette;
            Hashtable hash = PalettenFarben;
        }
        static ColorPalette color8bppPalette;
        static ColorPalette Color8bppPalette
        {
            get
            {
                if (color8bppPalette == null)
                {
                    Bitmap tmpImage = new Bitmap(1, 1, PixelFormat.Format8bppIndexed);
                    color8bppPalette = tmpImage.Palette;
                    color8bppPalette = AddSystemColor(color8bppPalette);

                }
                return color8bppPalette;
            }
        }
        static Hashtable palettenFarben;
        static Hashtable PalettenFarben
        {
            get
            {
                if (palettenFarben == null)
                {
                    palettenFarben = new Hashtable();
                    int r1, g1, b1, r1min, g1min, b1min;
                    Color tmpColor;
                    ColorPalette tmpPal = Color8bppPalette;
                    for (int i = 0; i < tmpPal.Entries.Length; i++)
                    {
                        tmpColor = tmpPal.Entries[i];
                        r1min = Math.Max(tmpColor.R - 5, 0);
                        g1min = Math.Max(tmpColor.G - 5, 0);
                        b1min = Math.Max(tmpColor.B - 5, 0);
                        r1 = Math.Min(r1min + 10, 255);
                        g1 = Math.Min(g1min + 10, 255);
                        b1 = Math.Min(b1min + 10, 255);

                        for (int r = r1min; r < r1; r++)
                            for (int g = g1min; g < g1; g++)
                                for (int b = b1min; b < b1; b++)
                                {
                                    if (!palettenFarben.ContainsKey(Color.FromArgb(r, g, b)))
                                    {
                                        palettenFarben[Color.FromArgb(r, g, b)] = (byte)i;
                                    }
                                }

                    }
                }
                return palettenFarben;
            }
        }
        public Bitmap ConvertTo8Bpp()
        {
            // mit dieser 15 habe ich das beste Ergebnis erzielt.
            return ConvertTo8Bpp(15);
        }
        public Bitmap ConvertTo8Bpp(int zusatz)
        {
            DateTime now = DateTime.Now;
            Bitmap destImage = new Bitmap( width, height, PixelFormat.Format8bppIndexed );
            BitmapData bitmapData = destImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
            int tmpStride = bitmapData.Stride;
            destImage.Palette = Color8bppPalette;
            Hashtable colNummer = new Hashtable();
            Color tmpColor;
            byte offset = 40;
            for (int r = 0; r < 256; r += 51)
                for (int g = 0; g < 256; g += 51)
                    for (int b = 0; b < 256; b += 51)
                    {
                        colNummer[Color.FromArgb(r, b, g)] = offset++;
                    }
            int tmpBytes = height * tmpStride;
            byte[] tmpBildDaten = new byte[tmpBytes];
            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    tmpColor = color[x, y];
                    int offset2 = (y * tmpStride) + x;
                    if (PalettenFarben.ContainsKey(tmpColor))
                        tmpBildDaten[offset2] = (byte)PalettenFarben[tmpColor];
                    else
                        tmpBildDaten[offset2] = (byte)colNummer[ColorFuer8bpp(tmpColor, zusatz)];
                }
            }
            IntPtr ptr = bitmapData.Scan0;
            System.Runtime.InteropServices.Marshal.Copy(tmpBildDaten, 0, ptr, tmpBytes);
            destImage.UnlockBits(bitmapData);
            TimeSpan verbr = DateTime.Now - now;
            MessageBox.Show(verbr.ToString());
            return destImage;
        }
        #endregion

Damit das erste Bild nicht etwas länger braucht, sollte man :

            RoBitmap.InitializeColor();
vor Gebrauch machen.

Bin zwar noch nicht ganz zufrieden, aber man kann damit schon leben.

Gruß Robert.

PS. Wie gesagt: Kritik gerne gesehen.
private Nachricht | Beiträge des Benutzers
Robertico
myCSharp.de - Member



Dabei seit:
Beiträge: 345

Themenstarter:

beantworten | zitieren | melden

Erweiterte Version:

Auf Anregung von nils in eine txt-Datei gepackt und angehängt.

Die Endung cs ist komischerweise in myCSharp.de nicht erlaubt

Gruß Robert

PS: Als Admin ohne Probleme änderbar

public RoBitmap(Bitmap bld)
public RoBitmap(string fileName)

public Color[,] GetColorArray()

public Color GetPixel(int x, int y)
public void SetPixel(int x, int y, Color col)

public int Width
public int Height
public Bitmap Image
public Bitmap ConvertTo8Bpp()
public Bitmap ConvertTo8Bpp(int zusatz)
public Bitmap ConvertToGrayScale24bppBitmap()
public Bitmap ConvertToGrayScale8bppBitmap()
public Bitmap GetNegativ()
public Bitmap GetTransparent(Color transparentColor)
public Bitmap GetAllTransparent(byte tranparenz)
public Bitmap GetTransparent(Color transparentColor, byte tranparenz)
public Bitmap GetContrastedImage(float _contrastFactor)
public Bitmap GetFormat1BppIndexed()
public Bitmap GetFormat1BppIndexed(float brightness)
public Bitmap GetFormat1BppIndexed(float brightness, Color _color1, Color _color2)
public Hashtable ZaehleFarben()
public void Save(string fileName)
Attachments
private Nachricht | Beiträge des Benutzers
nils
myCSharp.de - Experte



Dabei seit:
Beiträge: 908
Herkunft: Nähe von Kassel

beantworten | zitieren | melden

hallo Robertico,

was ein ellenlanger quellcode.... 8o
vielleicht doch das nächste mal einfach als dateianhang gemacht, das erspart einem das viele scrollen

danke!




nils
?( wer suchet, der findet auch! :]
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo Robertico,
Zitat
Die Endung cs ist komischerweise in myCSharp.de nicht erlaubt
weil es in der Regel sinnvoller und sicherer ist, Code in Zip-Dateien zu packen, aber ich habe cs mal als erlaubte Dateiendung hinzugefügt.

herbivore
private Nachricht | Beiträge des Benutzers
Robertico
myCSharp.de - Member



Dabei seit:
Beiträge: 345

Themenstarter:

beantworten | zitieren | melden

Hallo herbivore,

Danke, ich denke, das ist für dieses Forum auch sinnvoll.

Nach meinem "kleinen" Veständnis ist ja nur eine Gefahr denkbar, wenn der Browser etwas anderes damit anstellen kann als herunter laden. (ausführen)

Denke nicht, dass ein Browser bei cs dies anbietet.

Gruß Robert
private Nachricht | Beiträge des Benutzers
tom-essen
myCSharp.de - Experte

Avatar #avatar-2140.png


Dabei seit:
Beiträge: 1928
Herkunft: NRW

beantworten | zitieren | melden

Hallo!

Habe die Klasse mittlerweile ebenfalls in Benutzung, und bin über die Zeitersparnis wirklich erstaunt.

Beim Durchlesen der Beiträge kam auch der Wunsch/Vorschlag, die Klasse von Bitmap abzuleiten, was aber nicht möglich ist.

Aber es sollte doch möglich sein, von Image abzuleiten, oder?
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von tom-essen am .
Nobody is perfect. I'm sad, i'm not nobody
private Nachricht | Beiträge des Benutzers
kleines_eichhoernchen
myCSharp.de - Member

Avatar #avatar-2079.jpg


Dabei seit:
Beiträge: 4055
Herkunft: Ursprünglich Vogtland, jetzt Much

beantworten | zitieren | melden

Ja von Image ableiten ist ja möglich, nur dann hast du die Funktionen von Bitmap nicht
Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...
private Nachricht | Beiträge des Benutzers
tom-essen
myCSharp.de - Experte

Avatar #avatar-2140.png


Dabei seit:
Beiträge: 1928
Herkunft: NRW

beantworten | zitieren | melden

Hallo!
Zitat
Original von kleines_eichhoernchen
Ja von Image ableiten ist ja möglich, nur dann hast du die Funktionen von Bitmap nicht

Stimmt. Aber die Kompatibilität wäre zumindest ein wenig erhöht worden.
Wichtig wären natürlich GetPixel und SetPixel gewesen. Keine Ahnung, warum die in der Image-Klasse fehlen.

Genauso wenig kann ich nachvollziehen, warum Bitmap sealed ist...
Nobody is perfect. I'm sad, i'm not nobody
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo ihr beiden,

bitte das Thema nicht hier ausdiskutieren, weil wir in ".NET-Komponentensammlung" sind. Der Vorschlag ist da und Robertico kann ihn prüfen.

Nur der kurze Hinweis: In Image fehlt Get- und SetPixel, weil ein Image keine Pixelgrafik sein muss, sondern auch eine Vektorgrafik sein kann.

herbivore
private Nachricht | Beiträge des Benutzers
tom-essen
myCSharp.de - Experte

Avatar #avatar-2140.png


Dabei seit:
Beiträge: 1928
Herkunft: NRW

RoBitmap noch schneller machen

beantworten | zitieren | melden

Hallo!

An sich fand ich die Idee und die Umsetzung schon ganz interessant, allerdings hat mich die Verzögerung beim Erstellen der Klasse gestört (z.B. 300dpi A4-Seite).

Man kann das Ganze noch weiter beschleunigen, indem man bei GetPixel und SetPixel direkt auf die Bilddaten zugreift. Neben der Vermeidung der anfänglichen Verzögerung kann man zumindest GetPixel bei entsprechender Optimierung nochmal um einiges beschleunigen, bei SetPixel hab' ich's noch nicht getestet. Und ausserdem wird der Speicher radikal entlastet.
Nobody is perfect. I'm sad, i'm not nobody
private Nachricht | Beiträge des Benutzers
Robertico
myCSharp.de - Member



Dabei seit:
Beiträge: 345

Themenstarter:

beantworten | zitieren | melden

Hallo tom-essen,

Weiss nicht genau was du meinst.

Das erste was ich tue ist, die Bilddaten aus dem Bild zu holen. Dann damit arbeiten und erst wieder bei Gebrauch in das Bild zu schreiben.
Daher ist das so schnell.

Eine Verzögerung ist nur beim ersten Gebrauch der Klasse da durch:
Zitat
Damit das erste Bild nicht etwas länger braucht, sollte man :

C#-Code:
RoBitmap.InitializeColor();

vor Gebrauch machen.
Sonst sollte es schnell gehen.

Gruß Robert
private Nachricht | Beiträge des Benutzers
tom-essen
myCSharp.de - Experte

Avatar #avatar-2140.png


Dabei seit:
Beiträge: 1928
Herkunft: NRW

beantworten | zitieren | melden

Hallo!

@Robertico:
Du holst die Daten aus dem Bitmap mittels Marshal.Copy in ein eigenes Byte-Array.
Wenn du nun anstatt einer neuen Matrix mit x*y Color-Einträgen die entsprechende Farbe immer erst bei Bedarf in GetPixel aus dem Byte-Array berechnest, sparst du dir die Matrix und kannst je nach Pixelformat noch ein wenig schneller werden. Besonders die Color-Klasse hat noch einige Überprüfungen, die man übergehen kann (z.B. kann aufgund des Byte-Arrays kein Wert über 255 sein).

Mit InitializeColor habe ich keine Geschwindigkeitssprünge bemerkt.

Wichtig war mir besonders die Vermeidung der anfänglichen Verzögerung, da ich mehrere Bilddateien der Reihe nach einlese, analysiere und dann die nächste nehme.
Die Barcode-Analyse z.B. benötigt nur ca. 1 Sekunde, aber das Einlesen mit RoBitmap dauert 2 Sekunden. Und das ist bei mehreren 100 Dateien (Rechnungszentrum) schon ein Unterschied.

Ich hoffe, ich konnte meine Gedanken diesmal verständlicher formulieren, evtl. krieg' ich auch den Code nochmal vernünftig zusammen.
Nobody is perfect. I'm sad, i'm not nobody
private Nachricht | Beiträge des Benutzers
Robertico
myCSharp.de - Member



Dabei seit:
Beiträge: 345

Themenstarter:

beantworten | zitieren | melden

Hallo tom-essen,

ich bin bei weitem kein C# Profi.
alles was ich hier produziere ist auf das wenige Wissen der Sprache, dass ich mir bisher angeeignet habe, aufgebaut.

Ich kenne noch lange nicht alle Möglichkeiten. Das einzige was ich gut kann, ist kombinieren.
Dann fummle ich mir daraus etwas zurecht.
Mein Wissen wird zwar täglich größer, aber wie hier bin ich immer sehr dankbar wenn mir jemand hilft, der mehr Ahnung hat.

Baue sie einfach um und hänge sie an. Mit der Zeit bekommen wir dann vielleicht eine super Klasse.

Gruß Robert
private Nachricht | Beiträge des Benutzers
rene.dh
myCSharp.de - Member



Dabei seit:
Beiträge: 2
Herkunft: Erlangen

beantworten | zitieren | melden

Hallo Robertico

mit großem Interesse habe ich deinen Beitrag gelesen.
Ich denke, dass ich mit deinen Überlegungen zu der Klasse der Lösung meines Problems näher komme.

Was habe ich gemacht:
Ich habe mir eine Klasse zum Konvertieren von Bildformaten geschrieben, wobei ich die gegebenen Möglichkeiten der Framework und hier der Image-Klasse ausnutze. Laut "Petzold" sollte man immer die Image-Klasse nutzen, wenn man seine Aufgaben damit lösen kann.

Wo hab ich nun ein Problem? Wenn ich nach TIF oder GIF konvertieren lasse, dann wirft es mir immer eine Exception, wobei ich beim Debuggen festgestellt habe, dass das Pixelformat immer wieder auf PixelFormat.Format8bppIndexed zurückgesetzt wurde. Der resultierende Stream ist dann auch nur noch 2408 groß X(

Eine weitere Sache wäre noch die Speicherverwaltung? Da weiß ich auch noch nicht, ob das so alles optimal gelöst ist...

Vielleicht hat jemand noch eine Idee... ich komme hier jedenfalls nicht mehr weiter (nicht so richtig...).

Danke

Rene

Die vollständige Klasse ist im Anhang



        private Image ConvertImage(Image sourceImage, ImageFormat targetImageFormat)
        {
            if (sourceImage.RawFormat.Equals(targetImageFormat))
            {
                return sourceImage;
            }
            PixelFormat _pixelFormat = PixelFormat.Format32bppArgb;
            if (targetImageFormat.Equals(ImageFormat.Jpeg))
            {
                _pixelFormat = PixelFormat.Format24bppRgb;
            }
            else if (targetImageFormat.Equals(ImageFormat.Gif))
            {
                _pixelFormat = PixelFormat.Format32bppArgb;
            }
            else if (targetImageFormat.Equals(ImageFormat.Bmp))
            {
                _pixelFormat = PixelFormat.Format32bppArgb;
            }
            else if (targetImageFormat.Equals(ImageFormat.Png))
            {
                _pixelFormat = PixelFormat.Format32bppArgb;
            }
            else if (targetImageFormat.Equals(ImageFormat.Tiff))
            {
                _pixelFormat = PixelFormat.Format32bppArgb;
            }
            else if (targetImageFormat.Equals(ImageFormat.Wmf))
            {
                _pixelFormat = PixelFormat.Undefined;
            }
            else
            {
                _pixelFormat = PixelFormat.Format24bppRgb;
            }


            Bitmap bmp = new Bitmap(sourceImage.Size.Width,
                                          sourceImage.Size.Height,
                                          _pixelFormat);
            Graphics g1 = Graphics.FromImage(bmp);

            g1.DrawImage(bmp,
                         0,0,
                         bmp.Size.Width,
                         bmp.Size.Height);

            g1.CompositingQuality = CompositingQuality.HighQuality;
            g1.SmoothingMode = SmoothingMode.HighQuality;
            g1.InterpolationMode = InterpolationMode.HighQualityBicubic;

            g1.Dispose();
            
            using (Stream imgStream = new MemoryStream())
            {
                bmp.Save(imgStream, targetImageFormat);
                bmp.Dispose();
                imgStream.Seek(0, SeekOrigin.Begin);
                return GetImage(imgStream);
            }
            return null;
        }


        public Image GetImage(Stream imageSourceStream)
        {
            return Image.FromStream(imageSourceStream);
        }


Attachments
private Nachricht | Beiträge des Benutzers
S.H.-Teichhof
myCSharp.de - Member

Avatar #avatar-2460.jpg


Dabei seit:
Beiträge: 1552
Herkunft: Sindringen

beantworten | zitieren | melden

wäre http://www.fh-wedel.de/~si/seminare/ws06/Ausarbeitung/15.CSharp/c-sharp3.0.htm#extensions keine möglichleit um Bitmap zu erweitern
Wir Arbeiten eigendlich nicht wir nehmen nur das geld
private Nachricht | Beiträge des Benutzers
rene.dh
myCSharp.de - Member



Dabei seit:
Beiträge: 2
Herkunft: Erlangen

Could not load file or assembly 'IwagImages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'

beantworten | zitieren | melden

Erfordert Marshal.Copy im Zusammenhang mit einer ASP.NET Anwendung eine spezielle Berechtigung in der Anwendung?


Danke

Rene
private Nachricht | Beiträge des Benutzers
Robertico
myCSharp.de - Member



Dabei seit:
Beiträge: 345

Themenstarter:

beantworten | zitieren | melden

Hallo alle,

Habe Unterstützung bekommen.

janismac
hat sich bereit erklärt in der Klasse mal richtig Ordnung zu machen und Kommentare hinein zu schreiben.

Dann wird er es in eine DLL packen und hier zur Verfügung stellen.

Bei der Gelegenheit möchte ich noch ein Schnipselchen vorstellen, dass ich letztens gebraucht habe. Es tauscht im Bild eine Farbe gegen eine andere. Und das in gewohnter Schnelle.

public void TauscheFarbe(Color f1, Color f2)
        {
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    if (color[x, y] == f1)
                    {
                        color[x, y] = f2;
                    }
                }
            }
        }

Gruß Robert
private Nachricht | Beiträge des Benutzers
janismac
myCSharp.de - Member



Dabei seit:
Beiträge: 183

beantworten | zitieren | melden

hallo

habe wie (von Robertico) angekündigt, das ganze einwenig überarbeitet und in eine DLL gepackt

es ist erstmal nur ne beta

es fehlen leider immernoch die funktionen zum umrechnen in Drawing.Bitmap aus 1bpp, 4bpp und 8bpp (bpp = Bits per Pixel)

wenn jemand weiß wie das geht (und zeit hat) wär es schön wenn das noch wergänzt würde

MfG janismac
Attachments
private Nachricht | Beiträge des Benutzers
meli-m
myCSharp.de - Member



Dabei seit:
Beiträge: 8

Cf

beantworten | zitieren | melden

Hallo,

kann man diese Klasse auch im Compact Framework nutzen? In der MSDN steht ja das der Namespace Drawing komplett vorhanden ist. Aber die ColorPalette scheint nicht vorhanden zu sein. PixelFormat macht keine Probleme.
Könnte man sich die ColorPalette dann irgendwie nachbauen? Oder mache ich irgendwas anders falsch?

Viele Grüße,

Meli
private Nachricht | Beiträge des Benutzers
Kaji
myCSharp.de - Member



Dabei seit:
Beiträge: 602
Herkunft: Clausthal-Zellerfeld

beantworten | zitieren | melden

Hallo,

das ist nen ziemlich netter Code leider fehlte mir die rückwandlung in 8bpp. Deswegen hab ich sie mal nach implementiert und anscheinend funktioniert sie auch.


        Bitmap ReturnFormat8BppIndexed()
        {
            for (int y = 0; y < height; y++)
                for (int x = 0; x < width; x++)
                    bildDaten[y * stride + x] = color[x, y].R;
            System.Drawing.Imaging.BitmapData bmpData =
                Bild.LockBits(rect, System.Drawing.Imaging.ImageLockMode.WriteOnly,
                Bild.PixelFormat);
            IntPtr ptr = bmpData.Scan0;
            System.Runtime.InteropServices.Marshal.Copy(bildDaten, 0, ptr, bytes);
            Bild.UnlockBits(bmpData);
            modified = false;
            return Bild;
        }
private Nachricht | Beiträge des Benutzers