Wie geht das (C#)?

3 Antworten

Vom Fragesteller als hilfreich ausgezeichnet

So einfach wie es sich meine Vorredener gemacht haben ist die Nummer leider nicht

Du willst alle Monitore erfassen ist zwar relativ billig, aber physische Tücken, wenn der Hauptmonitor in der Mitte oder rechts ist:

var vScreen = SystemInformation.VirtualScreen;

die Linke obere Ecke kann sich unterhalb 0 befinden:

meine Konfig:

vScreen Properties:
Location : {X=-1920,Y=0}
Size   : {Width=5520, Height=1080}
X    : -1920
Y    : 0
Width  : 5520
Height  : 1080
Left   : -1920
Top   : 0
Right  : 3600
Bottom  : 1080
IsEmpty : False

...das wiederum dürfte wohl Lookbits nicht unbedingt schmecken. Arrays mit negativem Index?. 😱

Erstmal einen ganz banalen Screenshot, der hat dann auch als Basis 0,0

Den kann man schön übersichtlich zerlegen, denn das dauert wertvolle Millisekunden, welche einem laufenden Screen fehlen könnten und Lookbits sperrt nunmal den Zugriff auf eine Datenquelle für andere Threads. (den Screen) ein NoGo!!!

Ein Screenshot sind 5 Zeilen Code... ein wahrlich großes Opfer.😉

Aus den Bitmap (Screenshot) dann einen eine 2DArray zu bauen ist banal.

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;


class Prog{


    private static Bitmap Screenshot(){
         //äußerste Begrenzung aller aktiven Screens ermitteln
        var vScreen = SystemInformation.VirtualScreen;
         //neues Bitmap mit der errechneten Größe bereitstellen
        Bitmap bmpScreenshot = new Bitmap(vScreen.Width, vScreen.Height);
         // die gesamte berechnete Screenfläche in unser neues  Bitmap übertragen
         //(x und  Y im Ziel sind 0)
        Graphics g = Graphics.FromImage(bmpScreenshot);
        g.CopyFromScreen(vScreen.X,vScreen.Y, 0, 0, vScreen.Size);
        return bmpScreenshot;
    }


    public static Color[,] ImageTo2DByteArray(Bitmap bmp){
        int width = bmp.Width;
        int height = bmp.Height;
         //Rohe 32bit-Farbdaten ermitteln in RGB-ByteArray speichern
        BitmapData data = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
         //einfach nur Bytes ohne Ende
        byte[] bytes = new byte[height * data.Stride];
        Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);
        bmp.UnlockBits(data);
         //plump unser lineares Array per x-y-Loops in ein 2D_Array of Color umverteilen
         //...wir haben  nur  einen lange Reihe Bytes, von den jeweils 4 zusammengehören
         //...die  müssen wir schön  umverteilen
        Color[,] result = new Color[height, width];
        int currentRowOffs = 0;
        for (int y = 0; y < bmp.Height; y++){
             // Startoffset der aktuellen Spalte
            int currentOffs = currentRowOffs;
            for (int x = 0; x < bmp.Width; x++){
                 // ARGB = bytes [B,G,R,A] , !!!Byteorder auf x86-kompatiblen!!!
                Byte b = bytes[currentOffs];
                Byte g = bytes[currentOffs + 1];
                Byte r = bytes[currentOffs + 2];
                Byte a = bytes[currentOffs + 3];
                Color col = Color.FromArgb(a, r, g, b);
                 //aktuellen Offset im linearen Array "bytes" um 4 erhöhen
                currentOffs += 4; 
                result[y,x] = col;
            }
             // ganze Zeile Brite*4Bytes weiter
            currentRowOffs += data.Stride;
        }
        return result;
    }


    public static void Main(string[] args){
         //einfach  einen billigen Screnshot von allen Bildschirmen  machen
        Bitmap screenCopy = Screenshot();
        screenCopy.Save("test.bmp",ImageFormat.Bmp); //mal speichern damit  was sieht
        
        var my_2D_RGBarray = ImageTo2DByteArray(screenCopy);
         
        Console.WriteLine("Drücke J wenn die X_Y-Koortinaten und deren farbcode  angezeigt werden sollen");
        var keyInfo =  Console.ReadKey(true);
        if (keyInfo.Key.ToString() == "J"){
             // mal  jede einzelne Punktinformation des Bildes anzeigen.
             //Kannst Du  wenn Du Bock hast, auch so in eine Datei schreiben
             //kann  Dauern 😴
            for(int y = 0; y < my_2D_RGBarray.GetLength(0); y++)
                for(int x = 0; x < my_2D_RGBarray.GetLength(1); x++){
                    Color color = my_2D_RGBarray[y,x];
                    String HtmlColorCode = string.Format("#{0:X2}{1:X2}{2:X2}{3:X2}", color.A, color.R, color.G, color.B);
                    Console.WriteLine("X={0} Y={1}  Colorcode={2}  {3}", x, y, HtmlColorCode, my_2D_RGBarray[y,x]) ;
                }
        }

        Console.WriteLine("fertich...");
        Console.ReadKey();
    }
}

ich habe drauf verzichtet das Fenster auch noch auszublenden ist ne Demo aus der Hüfte, zum weiterbasteln

Bild zum Beitrag

Bild zum Beitrag

 - (Software, Programmiersprache, C Sharp)  - (Software, Programmiersprache, C Sharp)
raleD 
Fragesteller
 05.09.2023, 15:06

Ich kann die System.Drawing.Graphics Klasse nicht benutzen, weil alles crossplatform laufen soll und es unterstützt nur windows

0
Erzesel  05.09.2023, 16:10
@raleD

Crossplattform bei einer Handvoll Zeilen?

Im übrigen kann es bei solchem Minicode nicht Problem sein um über native APIs entsprechende Funktionen zu implementieren.

Eine all-in Bibliothek, welche jedes System befriedigt wirst Du wohl kaum finden.

Gegebenenfalls musst Du eben darüber nachdenken das Projekt in Java (Swing) anzufassen.

Eine Programmiersprache ist ein Werkzeug. Und man nutzt jenes, welches am besten passt.

(die Demo hätte ich ebenso in Powershell, Java, Delphi, Python ... schreiben können. -hätte lediglich etwas Recherche bezüglich nötiger Bibliotheken gekostet)

0
raleD 
Fragesteller
 05.09.2023, 16:15
@Erzesel

Java 💀‼️🙏😨

0

Du kannst dir mit Hilfe der Windows API (BitBlt) die Farbe eines Pixels in ein Bild kopieren.

using (var destination = Graphics.FromImage(new Bitmap(1, 1, PixelFormat.Format32bppArgb)))
{
  using (var source = Graphics.FromHwnd(IntPtr.Zero))
  {
    var hdcSrc = source.GetHdc();
    var hdc = destination.GetHdc();
    var result = BitBlt(hdc, 0, 0, 1, 1, hdcSrc, x, y, (int)CopyPixelOperation.SourceCopy);
    destination.ReleaseHdc();
    source.ReleaseHdc();
  }
}

Die aktuellen Bildschirmkoordinaten könntest du via GetCursorPos erfragen.

Falls du noch nie Funktionen der Windows API in einem C#-Projekt eingebunden hast, findest du hier einen kurzen Artikel dazu.

raleD 
Fragesteller
 04.09.2023, 14:34

Dankeschön

0
Erzesel  05.09.2023, 08:05

mit Graphics.FromHwnd erwischt man leider nicht mehrere Monitore...

inspiziere mal (quick&dirty) das von Graphics.FromHwnd(IntPtr.Zero) zurückgelieferte Object. in der Powershell:

PS C:\Users\Erzesel Secure\Desktop> Add-Type -a  System.Drawing
PS C:\Users\Erzesel Secure\Desktop> [Drawing.Graphics]::FromHwnd([IntPtr]::Zero)


CompositingMode    : SourceOver
RenderingOrigin    : {X=0,Y=0}
CompositingQuality : Default
TextRenderingHint  : SystemDefault
TextContrast       : 4
SmoothingMode      : None
PixelOffsetMode    : Default
InterpolationMode  : Bilinear
Transform          : System.Drawing.Drawing2D.Matrix
PageUnit           : Display
PageScale          : 1
DpiX               : 96
DpiY               : 96
Clip               : System.Drawing.Region
ClipBounds         : {X=-4194304,Y=-4194304,Width=8388608,Height=8388608}
IsClipEmpty        : False
VisibleClipBounds  : {X=0,Y=0,Width=1920,Height=1080}
IsVisibleClipEmpty : False

Die erfassbaren Grenzen beschränken sich allen auf den Hauptmonitor (VisibleClipBounds) .

Ein MultiomonitorDesktop arbeitet mit einem Virtuellen Screen, welcher die Grenzen aller Displays hat. (System.Windows.Forms.Screen.AllScreens)

0

Du könntest die Graphics-Klasse verwenden, um auf die Bildschirme zuzugreifen, und dann mit einer Schleife über die Pixel iterieren, um Positionen und Farben auszulesen.

Woher ich das weiß:eigene Erfahrung
raleD 
Fragesteller
 04.09.2023, 14:42

Windows Forms?

0
Charmin  04.09.2023, 14:47
@raleD

In diesem Fall könntest du die Screen-Klasse verwenden, um auf die Bildschirme zuzugreifen, und dann Schleifen verwenden, um die Pixel auf jedem Bildschirm zu durchlaufen und ihre Positionen und Farben auszulesen.

0
raleD 
Fragesteller
 04.09.2023, 14:53
@Charmin

ne ich meine ob die Graphics Klasse bei Windows forms vorhanden ist.. weil bei System.Drawing finde ich nichts

0
Charmin  04.09.2023, 15:13
@raleD

Achso, sollte vorhanden sein.
Bin erst Abend wieder am Rechner zum schauen.
gehört auch zum System.Drawing.

Wenn du sie nicht finden kannst, schau nach, ob die System.Drawing Bibliothek richtig eingebunden ist. Du kannst using System.Drawing; am Anfang deiner Datei hinzufügen, um sie zu verwenden. Aber denke mal das weißt du von alleine :-).

ich schaue Abend nochmal nach.

0
raleD 
Fragesteller
 04.09.2023, 16:09
@Charmin

Ja ich hab die Bibliothek richtig eingebunden aber irgendwie existiert die Klasse Graphics nicht

0
regex9  04.09.2023, 20:10
@raleD

Graphics ist ab NET 6 ausschließlich für Windows OS verfügbar. In cross-platform Projekten kannst du daher nicht auf diesen Typ zurückgreifen. Weiteres (Assembly, Namespace, etc.) steht in der Dokumentation.

1
raleD 
Fragesteller
 04.09.2023, 20:13
@regex9

‼️🙅‍♂️🤯

0
Charmin  04.09.2023, 20:35
@raleD

So, grad nochmal geschaut. Ich habe System.Drawing über NuGet installiert und funktioniert

0
raleD 
Fragesteller
 04.09.2023, 21:28
@Charmin

Egal ich brauche es eh nicht mehr, da alles cross platform laufen soll 💯‼️🤷‍♂️ Trotzdem danke

1