[Dll] PixelLib

    Publicités

Users Who Are Viewing This Thread (Total: 0, Members: 0, Guests: 0)

ragnarock

Membre actif
Mar 22, 2010
194
0
917
Salut !

J'ai fais une petite dll pour la recherche de pixel, alors je la partage ici.

Pourquoi ?
Tout simplement parce que la fonction GetPixel est la plus utilisée des méthodes et elle est affreusement lente.

La dll est écrite en c++, donc utilisable dans (presque) tous les languages, j'ai fais un wrapper en C# pour le .net et si ça intéresse du monde, je peux aussi en faire un en AutoIt.


Les fonction :
Code:
HBITMAP Screenshot(HWND hWnd, bool entireWindow);
[I]Bah... ça prend un screenshot. le entireWindow définit si c'est la fenêtre entière qui est capturée, ou seulement la zone client[/I]

COLORREF PixelGet(HWND hWnd, int x, int y, bool entireWindow);
[I]C'est comme le GetPixel, sauf en plus rapide et avec un autre nom (impossible de l'exporter si je laisse le même nom...)[/I]

BOOL PixelSearch(HWND hWnd, unsigned int color, int variation, LPPOINT lpPoint, bool entireWindow);
[I]Ça ça retourne la pos' du premier pixel trouvé qui correspond à la couleur[/I]

BOOL PixelSearchAll(HWND hWnd, unsigned int color, int variation, PointFoundCallback callback, bool entireWindow);
[I]Pareil, sauf que ça retourne tous les pixel[/I]

BOOL PixelSearchCenter(HWND hWnd, unsigned int color, int variation, LPPOINT lpPoint, bool entireWindow);
[I]Comme dessus, sauf que pour chercher ça part du centre de la fenêtre tourne en spirale pour chercher les pixels[/I]

BOOL PixelSearchAllCenter(HWND hWnd, unsigned int color, int variation, PointFoundCallback callback, bool entireWindow);
[I]Comme dessus.[/I]
(L'algo pour parcourir le bmp en spirale je l'ai pompé ici : Ce lien n'est pas visible, veuillez vous connecter pour l'afficher. Je m'inscris!)


Le wrapper en C# :
Code:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;

namespace TestPixelLib
{
    internal static class PixelLibWrapper
    {
        private const string DllName = "PixelLib.dll";
        private static PointFoundCallback PixelSearchAllCallback, PixelSearchAllCenterCallback;

        #region Dll imports

        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        private delegate void PointFoundCallback(Point value);


        [DllImport(DllName, SetLastError = true, EntryPoint = "Screenshot", CallingConvention = CallingConvention.Cdecl)]
        private static extern IntPtr _Screenshot(IntPtr hWnd, bool entireWindow);


        [DllImport(DllName, SetLastError = true, EntryPoint = "PixelGet", CallingConvention = CallingConvention.Cdecl)]
        private static extern uint _GetPixel(IntPtr hWnd, int x, int y, bool entireWindow);


        [DllImport(DllName, SetLastError = true, EntryPoint = "PixelSearch", CallingConvention = CallingConvention.Cdecl)]
        private static extern bool _PixelSearch(IntPtr hWnd, uint color, int variation, out Point lpPoint, bool entireWindow);


        [DllImport(DllName, SetLastError = true, EntryPoint = "PixelSearchAll", CallingConvention = CallingConvention.Cdecl)]
        private static extern bool _PixelSearchAll(IntPtr hWnd, uint color, int variation, PointFoundCallback callback, bool entireWindow);


        [DllImport(DllName, SetLastError = true, EntryPoint = "PixelSearchCenter", CallingConvention = CallingConvention.Cdecl)]
        private static extern bool _PixelSearchCenter(IntPtr hWnd, uint color, int variation, out Point lpPoint, bool entireWindow);


        [DllImport(DllName, SetLastError = true, EntryPoint = "PixelSearchAllCenter", CallingConvention = CallingConvention.Cdecl)]
        private static extern bool _PixelSearchAllCenter(IntPtr hWnd, uint color, int variation, PointFoundCallback callback, bool entireWindow);


        [DllImport("gdi32.dll", SetLastError = true)]
        private static extern bool DeleteObject(IntPtr hObject);

        #endregion

        static PixelLibWrapper()
        {
            if (!File.Exists(DllName))
                throw new FileNotFoundException("Cannot find a required dll", DllName);
        }

        /// <summary>
        /// Takes a screenshot of the desired window.
        /// </summary>
        /// <param name="hWnd">Handle to the window, Intptr.Zero for desktop window.</param>
        /// <param name="entireWindow">True for entire window, false for client area.</param>
        internal static Bitmap Screenshot(IntPtr hWnd, bool entireWindow = false)
        {
            var hBmp = _Screenshot(hWnd, entireWindow);
            var bmp = Image.FromHbitmap(hBmp);
            DeleteObject(hBmp);
            return bmp;
        }

        /// <summary>
        /// Returns an 0xAARRGGBB uint (alpha is always 00 (disabled)).
        /// </summary>
        /// <param name="hWnd">Handle to the window, Intptr.Zero for desktop window.</param>
        /// <param name="x">X coord</param>
        /// <param name="y">Y coord</param>
        /// <param name="entireWindow">True for entire window, false for client area.</param>
        internal static uint GetPixel(IntPtr hWnd, int x, int y, bool entireWindow = false)
        {
            return _GetPixel(hWnd, x, y, entireWindow);
        }

        /// <summary>
        /// Returns the first point with the desired color or a (-1;-1) point in case of failure.
        /// </summary>
        /// <param name="hWnd">Handle to the window, Intptr.Zero for desktop window.</param>
        /// <param name="color">Wanted color, format 0x00RRGGBB.</param>
        /// <param name="variation">The margin of error for color match, default is 0</param>
        /// <param name="entireWindow">True for entire window, false for client area.</param>
        internal static Point PixelSearch(IntPtr hWnd, uint color, int variation = 0, bool entireWindow = false)
        {
            Point pt;
            return _PixelSearch(hWnd, color, variation, out pt, entireWindow) ? pt : new Point(-1, -1);
        }


        /// <summary>
        /// Returns a list of point with the desired color.
        /// </summary>
        /// <param name="hWnd">Handle to the window, Intptr.Zero for desktop window.</param>
        /// <param name="color">Wanted color, format 0x00RRGGBB.</param>
        /// <param name="variation">The margin of error for color match, default is 0</param>
        /// <param name="entireWindow">True for entire window, false for client area.</param>
        internal static List<Point> PixelSearchAll(IntPtr hWnd, uint color, int variation = 0, bool entireWindow = false)
        {
            var res = new List<Point>();
            PixelSearchAllCallback = res.Add;
            _PixelSearchAll(hWnd, color, variation, PixelSearchAllCallback, entireWindow);
            return res;
        }

        /// <summary>
        /// Returns the first centered point with the desired color or a (-1;-1) point in case of failure.
        /// </summary>
        /// <param name="hWnd">Handle to the window, Intptr.Zero for desktop window.</param>
        /// <param name="color">Wanted color, format 0x00RRGGBB.</param>
        /// <param name="variation">The margin of error for color match, default is 0</param>
        /// <param name="entireWindow">True for entire window, false for client area.</param>
        internal static Point PixelSearchCenter(IntPtr hWnd, uint color, int variation = 0, bool entireWindow = false)
        {
            Point pt;
            return _PixelSearchCenter(hWnd, color, variation, out pt, entireWindow) ? pt : new Point(-1, -1);
        }


        /// <summary>
        /// Returns a list of point with the desired color, starts at the center.
        /// </summary>
        /// <param name="hWnd">Handle to the window, Intptr.Zero for desktop window.</param>
        /// <param name="color">Wanted color, format 0x00RRGGBB.</param>
        /// <param name="variation">The margin of error for color match, default is 0</param>
        /// <param name="entireWindow">True for entire window, false for client area.</param>
        internal static List<Point> PixelSearchAllCenter(IntPtr hWnd, uint color, int variation = 0, bool entireWindow = false)
        {
            var res = new List<Point>();
            PixelSearchAllCenterCallback = res.Add;
            _PixelSearchAllCenter(hWnd, color, variation, PixelSearchAllCenterCallback, entireWindow);
            return res;
        }
    }
}
(le code est aussi dans le .rar)

Pour l'utiliser, faut soit l'ajouter à son projet et changer le namespace, soit le compiler en dll et inclure la dll.


Comparatif des différentes méthodes

En gros ça teste tous les pixel de la fenêtre (taille ~ 350x350) pour voir s'ils correspondent à une couleur prédéfinie.

dr6y.png

(J'ai pas eu le courage de laisser tourner plus longtemps avec le GetPixel, c'est teeeeellement leeent)

La méthode cool (Dedieu l'inspiration !!!) en C# est plus rapide, surement car ça ne passe pas par une dll et y'a pas tout le bordel de marshalling.
Pour me consoler je me dis que c'est moins portable que du c++ :snif1:


Download !!!

c'est en bas du post que ça s'passe ça.
Dans le .rar y'a la source de la dll + la dll compilée + un prog de test en C# & le wrapper


Et pour finir

J'suis pas bon en c++, donc si vous avez des conseils (surtout pour l'export des fonctions, j'suis une bouse) je suis preneur !

À vous de vous amuser avec la dll maintenant :)


À venir (un jour peut-être..)
  • Le wrapper AutoIt
  • Choix de la partie de la fenêtre dans laquelle on veut chercher les pixels
  • Bah.. j'ai pas trop d'idées en fait
 

Attachments

  • PixelLib.rar
    12.6 MB · Views: 17

Nayres

Membre Banni
Apr 15, 2012
3,431
0
341
Quelque part.
Ça te dérange si je modifie le code? J'ai quelques idées en tête que je voudrais tester pour diminuer le délai.
En tout cas merci du partage
 
Last edited:

ragnarock

Membre actif
Mar 22, 2010
194
0
917
Non du tout, tu peux y aller.

Mais je veux bien que tu partages si tu trouve comment améliorer ça :)
 

Evaelis

La Voix de la Sagesse
V
Ancien staff
Apr 28, 2010
22,949
468
1,699
Valhalla
Ce serait vraiment cool effectivement de partager si tu optimises :)
 

TheHardButcher

Programmeur C/C++
V
Dec 14, 2009
1,461
58
964
France
J'avais fait un projet du même style il y a un ou deux ans, j'essayerais de le retrouver, mais je ne me rappelais plus que c'étais si lent :/
 

ragnarock

Membre actif
Mar 22, 2010
194
0
917
Yop,

Déjà merci à vous^^

Je viens de voir que y'a des endroits ou j'utilise des DeleteDC à la place de ReleaseDC, ça fais peut-être des memory leaks, je changerai ça dans la prochaine version que je fais.

Et Ethnical, si c'est pour du .net (je discrédite un peu ma dll là en disant ça) c'est mieux de prendre la fonction que j'ai pris pour comparaison, c'est plus facilement modifiable et ça évite d'ajouter la dll et le wrapper, ça fait moins de bordel.

Code:
    var hdcSrc = GetDC(Handle);
    RECT rect;
    GetClientRect(Handle, out rect);

    var width = rect.Right - rect.Left;
    var height = rect.Bottom - rect.Top;
    var hdcDest = CreateCompatibleDC(hdcSrc);
    var hBitmap = CreateCompatibleBitmap(hdcSrc, width, height);
    var hOld = SelectObject(hdcDest, hBitmap);
    BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, 0x00CC0020 /*SRCCOPY*/);
    SelectObject(hdcDest, hOld);
    DeleteDC(hdcDest);
    ReleaseDC(hdcSrc);
    var bmp = Image.FromHbitmap(hBitmap);
    DeleteObject(hBitmap);

    var bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
        ImageLockMode.ReadOnly, bmp.PixelFormat);
    uint red = (color >> 16) & 0xFF,
          green = (color >> 8) & 0xFF,
          blue = color & 0xFF;

    for (int y = 0; y < rect.Bottom; y++)
    {
        var row = (byte*)bmpData.Scan0 + (y * bmpData.Stride);

        for (int x = 0; x < rect.Right; x++)
        {
            if (row[x * 4] == blue &&
                row[x * 4 + 1] == green &&
                row[x * 4 + 2] == red)
            {
                // bon pixel
            }
        }
    }
    bmp.UnlockBits(bmpData);

et les imports :
Code:
        [DllImport("user32.dll")]
        internal static extern IntPtr GetDC(IntPtr hwnd);

        [DllImport("user32.dll")]
        internal static extern Int32 ReleaseDC(IntPtr hwnd, IntPtr hdc);

        [DllImport("user32.dll")]
        private static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);

        [DllImport("gdi32.dll")]
        internal static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int nWidth, int nHeight);

        [DllImport("gdi32.dll")]
        internal static extern bool DeleteDC(IntPtr hDC);

        [DllImport("gdi32.dll")]
        internal static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest, int nWidth,
            int nHeight, IntPtr hObjSource, int nXSrc, int nYSrc, uint dwRop);

        [DllImport("gdi32.dll")]
        internal static extern IntPtr CreateCompatibleDC(IntPtr hdc);

        [DllImport("gdi32.dll")]
        internal static extern IntPtr SelectObject(IntPtr hdc, IntPtr h);
 
Last edited: