Hi, ich portiere gerade ein altes Projekt. Dieses arbeitet mit BitBlt. Da DrawImage zu langsam ist, und mir die Zeit fehlt mich da reinzuarbeiten wollt ich die BitBlt Funktion wieder nehmen. Mein Problem ist egal was ich BitBlt gebe es kommt immer schwarz heraus!
private void button1_Click(object sender, EventArgs e)
{
Bitmap b = new Bitmap(m_strPath);
if (pictureBox1.Image == null)
{
pictureBox1.Image = new Bitmap(b.Width, b.Height, b.PixelFormat);
}
Graphics bmp = Graphics.FromImage(b);
Graphics pic = Graphics.FromImage(pictureBox1.Image);
Graphics form = this.CreateGraphics();
IntPtr bmpHdc = bmp.GetHdc();
IntPtr picHdc = pic.GetHdc();
IntPtr frmHdc = form.GetHdc();
IntPtr bmpDC = CreateCompatibleDC(bmpHdc);
IntPtr picDC = CreateCompatibleDC(picHdc);
IntPtr frmDC = CreateCompatibleDC(frmHdc);
IntPtr hbmOld = SelectObject(bmpDC, b.GetHbitmap());
// auf pic
bool bpic = BitBlt(picDC, 0, 0, b.Width, b.Height, bmpDC, 0, 0, TernaryRasterOperations.SRCCOPY);
// auf Form
bool bfrm = BitBlt(frmDC, 0, 0, b.Width, b.Height, bmpDC, 0, 0, TernaryRasterOperations.SRCCOPY);
SelectObject(bmpDC, hbmOld);
DeleteObject(bmpDC);
bmp.Dispose();
pic.Dispose();
form.Dispose();
Text = bpic.ToString() + " - " + bfrm.ToString();
}
Leider funktioniert das so nicht. Farbe ist 24Bit RGB, doch das kann es doch net sein. Das gleiche Ergebnis bekommt ich wenn ich einfach vom Graphics das Hdc übergebe. Bitblt bringt immer true zurück!
Der unterschied zwischen der obigen und er nur Hdc Version:
Ich hoffe Ihr habt auch das Problem, um mir zu helfen!
@Trivalik: Woher hast Du die P/Invoke-Signaturen? Von Pinvoke.net?
Poste diese doch bitte mal zusätzlich hier.
Die Signaturen sind hier aus dem Forum und von pinvoke.
/// <summary>
/// Performs a bit-block transfer of the color data corresponding to a
/// rectangle of pixels from the specified source device context into
/// a destination device context.
/// </summary>
/// <param name="hdc">Handle to the destination device context.</param>
/// <param name="nXDest">The leftmost x-coordinate of the destination rectangle (in pixels).</param>
/// <param name="nYDest">The topmost y-coordinate of the destination rectangle (in pixels).</param>
/// <param name="nWidth">The width of the source and destination rectangles (in pixels).</param>
/// <param name="nHeight">The height of the source and the destination rectangles (in pixels).</param>
/// <param name="hdcSrc">Handle to the source device context.</param>
/// <param name="nXSrc">The leftmost x-coordinate of the source rectangle (in pixels).</param>
/// <param name="nYSrc">The topmost y-coordinate of the source rectangle (in pixels).</param>
/// <param name="dwRop">A raster-operation code.</param>
/// <returns>
/// <c>true</c> if the operation succeeded, <c>false</c> otherwise.
/// </returns>
[DllImport("gdi32.dll")]
static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth,
int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);
public enum TernaryRasterOperations:uint
{
SRCCOPY = 0x00CC0020, /* dest = source*/
SRCPAINT = 0x00EE0086, /* dest = source OR dest*/
SRCAND = 0x008800C6, /* dest = source AND dest*/
SRCINVERT = 0x00660046, /* dest = source XOR dest*/
SRCERASE = 0x00440328, /* dest = source AND (NOT dest )*/
NOTSRCCOPY = 0x00330008, /* dest = (NOT source)*/
NOTSRCERASE = 0x001100A6, /* dest = (NOT src) AND (NOT dest) */
MERGECOPY = 0x00C000CA, /* dest = (source AND pattern)*/
MERGEPAINT = 0x00BB0226, /* dest = (NOT source) OR dest*/
PATCOPY = 0x00F00021, /* dest = pattern*/
PATPAINT = 0x00FB0A09, /* dest = DPSnoo*/
PATINVERT = 0x005A0049, /* dest = pattern XOR dest*/
DSTINVERT = 0x00550009, /* dest = (NOT dest)*/
BLACKNESS = 0x00000042, /* dest = BLACK*/
WHITENESS = 0x00FF0062, /* dest = WHITE*/
};
[DllImport("gdi32.dll", ExactSpelling = true)]
internal static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("gdi32.dll", ExactSpelling = true)]
internal static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
[DllImport("gdi32.dll", ExactSpelling=true)]
internal static extern bool DeleteObject( IntPtr hgdiobj);
Hab nun mal in dem Support Artikel von MS gestöbert. Diese Funktioniert auch nur ist mir nicht klar warum in bitblt hdcScreen und hdcCompatible benutzt werden obwohl doch beides vom Desktop Fenster abstammen!
IntPtr hdcScreen = GetDC(GetDesktopWindow());
IntPtr hdcCompatible = CreateCompatibleDC(hdcScreen);
Seh ich richtig das GetDC der Win32 das selbe ist wie GetHdc von Graphics?
Kann es sein das es ein Problem gibt wenn mein Bild 24 Bit RGB ist, da im Deskop Beispiel 32 BitRGB rausgekommen ist.
habe mal kurz selbst ein beispiel erstellt und in deinen Code eingefügt.
probiers mal bitte mit folgendem Code (diesen in deinen Event-Click einfügen):
public void Test()
{
// Get a Graphics object associated with the screen.
bm = new Bitmap(this.m_strPath);
Graphics grfxScreen = Graphics.FromImage(bm);
// Create a bitmap the size of the screen.
// Create a Graphics object associated with the bitmap.
Graphics grfxBitmap = Graphics.FromImage(bm);
// Get hdc's associated with the Graphics objects.
IntPtr hdcScreen = grfxScreen.GetHdc();
IntPtr hdcBitmap = grfxBitmap.GetHdc();
// Do the bitblt from the screen to the bitmap.
BitBlt(hdcBitmap, 0, 0, bm.Width, bm.Height,
hdcScreen, 0, 0, TernaryRasterOperations.SRCCOPY);
// Release the device contexts.
grfxBitmap.ReleaseHdc(hdcBitmap);
grfxScreen.ReleaseHdc(hdcScreen);
// Manually dispose of the Graphics objects.
grfxBitmap.Dispose();
grfxScreen.Dispose();
this.pictureBox1.Image = bm;
}
Der funktioniert bei mir.
EDIT: Bei mir wirkt sich dein Code übrigens nicht so aus, daß etwas schwarz wird, sondern es passiert schlicht und einfach überhaupt nichts.
Danke, das geht wirklich!
Edit:
Seh grad das da beschissen wurde, das geladene Bitmap wird einfach der PictureBox zugewiesen. Wenn ich BitBlt auskommentiere passiert das selbe! Also leider keine Lösung!
Wieso das Bild kommt doch in die PictureBox per BitBlt von meinem Beispiel?
Was möchtest Du denn jetzt wirklich haben? Auf die Form? Auf den Screen?
@dr4g0n76
Ich meine das zwei Zeilen das selbe tun.
public void Test()
{
// Get a Graphics object associated with the screen.
bm = new Bitmap(this.m_strPath);
this.pictureBox1.Image = bm;
}
Hab nun eine Lösung gefunden, die einzige im Netz🙂
public void CaptureControl(PictureBox dstPic,Bitmap srcBmp)
{
Bitmap dstBmp = new Bitmap(dstPic.Image);
// Src anpassen
Graphics gSrc;
Graphics clientDC = this.CreateGraphics();
IntPtr hdc = clientDC.GetHdc();
IntPtr memdc = CreateCompatibleDC(hdc);
SelectObject(memdc, srcBmp.GetHbitmap());
gSrc = Graphics.FromHdc(memdc);
clientDC.ReleaseHdc(hdc);
Graphics gDst = Graphics.FromImage(dstBmp);
// dst anpassen
IntPtr dcSrc = gSrc.GetHdc();
IntPtr dcDst = gDst.GetHdc();
BitBlt(dcDst, 0, 0, 100, 100, dcSrc, 0, 0, TernaryRasterOperations.SRCCOPY);
DeleteDC(memdc);
gSrc.ReleaseHdc(dcSrc);
gDst.ReleaseHdc(dcDst);
DeleteObject(hBmp)
pictureBox1.Image = dstBmp;
}
Ich finde es zwar komisch das man die PictureBox noch zuweisen muss, aber naja es geht so erstmal. Damit schein nun diese Funktion auch der Flaschenhals geworden zu sein, obwohl diese die schnellste sein sollte 😦
P.S. Ich benutze eine Funktion die wie oben und noch Argumente die ich an BitBlt weiterleite um weniger im Code ändern zu müssen.