12
votes

Comment obtenir le bitmap / image d'un objet graphique en C #?

Je veux savoir quel est l'état intermédiaire du tampon où l'objet graphique dessine des trucs. Comment puis-je obtenir la maintien du bitmap ou de l'image qu'il contient?


2 commentaires

n'oubliez pas de le marquer comme accepté si cela fonctionne pour vous ..........


@Pranayrana: Aucune des réponses ne donne à l'astucher ce qu'ils veulent; Plutôt, tout le contraire.


7 Réponses :



2
votes

Pas à 100% sûr de ce que vous voulez ici, mais si vous souhaitez utiliser la classe graphique pour dessiner, puis enregistrer dans le fichier, vous devez obtenir l'objet graphique dans un fichier bitmap, puis enregistrer le bitmap après que vous soyez terminé. Vous pouvez faire cela comme ceci: xxx


0 commentaires

8
votes

Je ne suis pas vraiment sûr si je comprends ce que vous demandez, comme votre question est très peu claire.

Si vous voulez savoir comment enregistrer le contenu d'un objet code> graphique code> dans un bitmap, la réponse est qu'il n'y a pas d'approche directe pour le faire. Dessin sur un graphique code> est une opération à sens unique. P>

L'option meilleure est de créer un nouvel objet bitmap code>, obtenez un objet code> graphique code> pour ce bitmap et dessinez-le directement sur celui-ci. Le code suivant est un exemple de la façon dont vous pourriez faire cela: P>

// Create a new bitmap object
using (Bitmap bmp = new Bitmap(200, 300))
{
    // Obtain a Graphics object from that bitmap
    using (Graphics g = Graphics.FromImage(bmp))
    {
        // Draw onto the bitmap here
        // ....
        g.DrawRectangle(Pens.Red, 10, 10, 50, 50);
    }

    // Save the bitmap to a file on disk, or do whatever else with it
    // ...
    bmp.Save("C:\\MyImage.bmp");
}


0 commentaires

3
votes

Ce code travaillant pour moi où je suis convertit Image >> Bitmap >> Byte >> Base64 String. XXX


2 commentaires

Je ne sais pas vraiment pourquoi vous avez converti l'image en une chaîne de base64? Je vais accorder que la question n'est pas particulièrement claire, mais je ne vois pas cela mentionné n'importe où dedans.


Oui, bien sûr, nous pouvons obtenir l'objet graphique à partir d'un bitmap à l'aide de la méthode graphique.fromImage (). Ce que je cherchais était une API qui me donnerait l'image du bitmap !!



0
votes

Vous pouvez obtenir son HDC qui est un pointeur sur le tampon de surface et copier éventuellement copier son contenu à un autre HDC avec la fonction BitBlt. De cette façon, vous pouvez créer une copie de la surface de dessin sur un bitmap.

enum TernaryRasterOperations : uint
{
    /// <summary>dest = source</summary>
    SRCCOPY = 0x00CC0020,
    /// <summary>dest = source OR dest</summary>
    SRCPAINT = 0x00EE0086,
    /// <summary>dest = source AND dest</summary>
    SRCAND = 0x008800C6,
    /// <summary>dest = source XOR dest</summary>
    SRCINVERT = 0x00660046,
    /// <summary>dest = source AND (NOT dest)</summary>
    SRCERASE = 0x00440328,
    /// <summary>dest = (NOT source)</summary>
    NOTSRCCOPY = 0x00330008,
    /// <summary>dest = (NOT src) AND (NOT dest)</summary>
    NOTSRCERASE = 0x001100A6,
    /// <summary>dest = (source AND pattern)</summary>
    MERGECOPY = 0x00C000CA,
    /// <summary>dest = (NOT source) OR dest</summary>
    MERGEPAINT = 0x00BB0226,
    /// <summary>dest = pattern</summary>
    PATCOPY = 0x00F00021,
    /// <summary>dest = DPSnoo</summary>
    PATPAINT = 0x00FB0A09,
    /// <summary>dest = pattern XOR dest</summary>
    PATINVERT = 0x005A0049,
    /// <summary>dest = (NOT dest)</summary>
    DSTINVERT = 0x00550009,
    /// <summary>dest = BLACK</summary>
    BLACKNESS = 0x00000042,
    /// <summary>dest = WHITE</summary>
    WHITENESS = 0x00FF0062,
    /// <summary>
    /// Capture window as seen on screen.  This includes layered windows 
    /// such as WPF windows with AllowsTransparency="true"
    /// </summary>
    CAPTUREBLT = 0x40000000
}

[DllImport("gdi32.dll", EntryPoint = "BitBlt", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool BitBlt([In] IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, [In] IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);

public static Bitmap CopyGraphicsContent(Graphics source, Rectangle rect)
{
    Bitmap bmp = new Bitmap(rect.Width, rect.Height);

    using (Graphics dest = Graphics.FromImage(bmp))
    {
        IntPtr hdcSource = source.GetHdc();
        IntPtr hdcDest = dest.GetHdc();

        BitBlt(hdcDest, 0, 0, rect.Width, rect.Height, hdcSource, rect.X, rect.Y, TernaryRasterOperations.SRCCOPY);

        source.ReleaseHdc(hdcSource);
        dest.ReleaseHdc(hdcDest);
    }

    return bmp;
}


0 commentaires

3
votes

Puisque personne n'a répondu à la question réelle après 9 ans ... xxx

pour arriver aux bits de bitmap , vous devez savoir quelque chose à propos de GDI Bitmaps d'abord . Il y a soi-disant bitmaps dépendant du périphérique (DDB ou souvent simplement simplement "bitmap" dans l'API) et bitmaps indépendants de l'appareil (DIB). Une explication complète de la différence serait hors de portée de cette réponse.

si vous utilisez this.settyle (contrôletyle.optimizeddoublebuffer, true); , alors l'objet graphique dans < Code> Onpaint utilisera un DIB, sinon il utilisera un DDB.

si votre HBITMAP est un ddb < / Strong>, vous ne pouvez pas lire / écrire les données de pixels directement (même s'il est techniquement possible, Windows n'expose aucun moyen de le faire). Vous devez utiliser getdibits pour les copier sur un tampon indépendant de périphérique, à l'aide d'un format particulier, puis setdibits pour les copier.

Si votre HBITMAP est un dib , vous pouvez obtenir les bits de pixels réels (comme un pointeur) et lisez / écrivez-les directement en mémoire en utilisant < a href = "https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getobjecte" rel = "nofollow noreferrer"> getObject (Ne pas être confondu avec getcurrentObject ): xxx

bitmap.bmbits sera null S'il s'agissait d'un DDB, et ce sera une adresse mémoire valide si elle est une DIB. Si vous souhaitez simplement copier ces données, vous pouvez utiliser directement bmbits ; La longueur totale est bmheight * bmwidthbyltes .

Si vous souhaitez manipuler des données de pixels en mémoire, vous devez connaître le format de pixel exact du DIB afin de le manipuler correctement. . Il existe de nombreuses possibilités sur ce que le format de pixel peut être (nombre de bits par pixel 1/4/16/24/32, RVB VS BGR, Palesettes, etc.). C'est beaucoup de travail si vous voulez vraiment tout soutenir .

Pour ce faire, sachez que lorsque vous avez donné un HBITMAP , le , le GetObject la fonction acceptera un bitmap struct (comme indiqué dans l'exemple de code ci-dessus) ou un DIBSECTION STRIT. Notez que dibsection commence par un bitmap , cela rend les deux structures compatibles. Iff le HBITMAP est un dib, puis getObject remplira un indice valide (non null) BMBits Pointeur, et il remplira également la dibsection 's bitmapinfoheader struct, que vous pouvez ensuite utiliser pour inspecter le format de pixel du DIB. examiner le bitmapinfoheader sera douloureux.


0 commentaires

0
votes

@Dialer a la meilleure réponse dans ce fil jusqu'à présent. À titre d'exemple supplémentaire, voici comment obtenir des bits de graphiques ou de tout HWND dans EMGU.CV MAT en C #.

    struct BITMAP
    {
        public Int32 bmType;
        public Int32 bmWidth;
        public Int32 bmHeight;
        public Int32 bmWidthBytes;
        public Int16 bmPlanes;
        public Int16 bmBitsPixel;
        public IntPtr bmBits;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    struct BITMAPINFOHEADER
    {
        public int biSize;
        public int biWidth;
        public int biHeight;
        public Int16 biPlanes;
        public Int16 biBitCount;
        public int biCompression;
        public int biSizeImage;
        public int biXPelsPerMeter;
        public int biYPelsPerMeter;
        public int biClrUsed;
        public int bitClrImportant;
    }

    [DllImport("user32.dll", SetLastError=true)]
    static extern IntPtr GetDC(IntPtr hWnd);

    // System.Windows.Forms.Internal.IntUnsafeNativeMethods
    [DllImport("gdi32.dll", CharSet = CharSet.Auto, EntryPoint = "GetCurrentObject", ExactSpelling = true, SetLastError = true)]
    static extern IntPtr IntGetCurrentObject(HandleRef hDC, int uObjectType);
    
    [DllImport("gdi32.dll", CharSet = CharSet.Auto, EntryPoint = "GetObject")]
    static extern int GetObjectBitmap(IntPtr hObject, int nCount, ref BITMAP lpObject);

    [DllImport("gdi32.dll", EntryPoint = "GetDIBits")]
    static extern int GetDIBits(IntPtr hdc, IntPtr hbmp, int uStartScan, int cScanLines, 
                                IntPtr lpvBits, ref BITMAPINFOHEADER lpbi, int uUsage);

    /// <summary>Gets GDI HDC as an Emgu.CV.Mat image as BGRA</summary>
    /// <param name="hdc">GDI HDC</param>
    /// <param name="destination">Destination Mat which will receive the window contents image</param>
    /// <param name="verticalFlip">If TRUE, pixel will be flipped vertically</param>
    /// <returns>TRUE if image was copied successfully</returns>
    public static bool GetHdcAsMat(IntPtr hdc, ref Mat destination, bool verticalFlip)
    {
        try
        {
            // This is a HBITMAP, which is the actual buffer that is being drawn to by hdc.
            IntPtr hbitmap = IntGetCurrentObject(new HandleRef(null, hdc), 7 /*OBJ_BITMAP*/);

            // Get width, height and the address of the pixel data for the native HBitmap
            BITMAP info = new BITMAP();
            if (0 == GetObjectBitmap(hbitmap, Marshal.SizeOf(info), ref info))
                return false;

            // if the image is a DIB, we can copy the bits directly from bmBits
            if (info.bmBits != IntPtr.Zero)
            {
                // data view of the DIB bits, no allocations
                Mat view = new Mat(info.bmHeight, info.bmWidth, DepthType.Cv8U, 4, 
                                   info.bmBits, info.bmWidth * 4);

                if (verticalFlip) // copy flipped:
                    CvInvoke.Flip(view, destination, FlipType.Vertical);
                else // copy directly:
                    view.CopyTo(destination); // automatically resize destination
                return true;
            }

            // otherwise, use GetDIBits to get the bitmap from the GPU
            // a copy is always needed to get the data from GPU to system memory

            if (destination.Width != info.bmWidth ||
                destination.Height != info.bmHeight)
            {
                destination.Dispose();
                destination = new Mat(info.bmHeight, info.bmWidth, DepthType.Cv8U, 4);
            }

            var desired = new BITMAPINFOHEADER();
            desired.biSize = Marshal.SizeOf(desired);
            desired.biWidth = info.bmWidth;
            desired.biHeight = verticalFlip ? -info.bmHeight : info.bmHeight;
            desired.biPlanes = 1;
            desired.biBitCount = info.bmBitsPixel;

            // Copy bits into destination
            IntPtr dest = destination.DataPointer;
            return 0 != GetDIBits(hdc, hbitmap, 0, destination.Height, dest, ref desired, 0);
        }
        catch
        {
            return false;
        }
    }
    
    /// <summary>Gets window contents as an Emgu.CV.Mat image as BGRA</summary>
    /// <param name="hwnd">Handle to desired window</param>
    /// <param name="destination">Destination Mat which will receive the window contents image</param>
    /// <param name="verticalFlip">If TRUE, pixel will be flipped vertically</param>
    /// <returns>TRUE if image was copied successfully</returns>
    public static bool GetWindowAsMat(IntPtr hwnd, ref Mat destination, bool verticalFlip)
    {
        IntPtr hdc = GetDC(hwnd); // private DC does not need to be released
        return GetHdcAsMat(hdc, ref destination, verticalFlip);
    }

    /// <summary>Gets GDI Graphics contents as an Emgu.CV.Mat image as BGRA</summary>
    /// <param name="graphics">.NET GDI Graphics instance</param>
    /// <param name="destination">Destination Mat which will receive the window contents image</param>
    /// <param name="verticalFlip">If TRUE, pixel will be flipped vertically</param>
    /// <returns>TRUE if image was copied successfully</returns>
    public static bool GetGraphicsAsMat(Graphics graphics, ref Mat destination, bool verticalFlip)
    {
        IntPtr hdc = graphics.GetHdc();
        try
        {
            return GetHdcAsMat(hdc, ref destination, verticalFlip);
        }
        finally
        {
            // NOTE: You cannot use the graphics object before ReleaseHdc is called.
            graphics.ReleaseHdc(hdc);
        }
    }


0 commentaires