Frage

Ich bin mit einem GDI+ - Grafik zu zeichnen, 4000*3000 Bild auf dem Bildschirm, aber es ist wirklich langsam.Es dauert ungefähr 300ms.Ich wünschte, es nur nehmen weniger als 10ms.

Bitmap *bitmap = Bitmap::FromFile("XXXX",...);

//-------------------------------------------- // dieser Teil dauert etwa 300ms, schrecklich!

int width = bitmap->GetWidth();
int height = bitmap->GetHeight();
DrawImage(bitmap,0,0,width,height);

//------------------------------------------

Ich kann CachedBitmap, weil ich wollen, Bearbeiten Sie die bitmap später.

Wie kann ich es verbessern?Oder ist irgend etwas falsch?

Dieses native GDI-Funktion zeichnet ebenfalls die Bild in die Bildschirm, und es nur nehmen Sie 1 ms:

SetStretchBltMode(hDC, COLORONCOLOR);   
StretchDIBits(hDC, rcDest.left, rcDest.top, 
        rcDest.right-rcDest.left, rcDest.bottom-rcDest.top, 
        0, 0, width, height,
        BYTE* dib, dibinfo, DIB_RGB_COLORS, SRCCOPY);

//--------------------------------------------------------------

Wenn ich verwenden möchten, StretchDIBits, muss ich weiterleiten BITMAPINFO, Aber wie bekomme ich BITMAPINFO von Gdi+ - Bitmap-Objekt?Ich habe das experiment von FreeImage lib, ich nenne StretchDIBits mit FreeImageplus Objekt, es ziehen auch wirklich schnell.Aber jetzt brauche ich zu zeichnen-Bitmap, und schreiben Sie einen Algorithmus, der auf Bitmap ' s bits, array, wie kann ich BITMAPINFO, wenn ich ein Bitmap-Objekt?Es ist wirklich ärgerlich -___________-|

War es hilfreich?

Lösung

Sie haben einen Bildschirm von 4000 x 3000 resolution?Wow!

Wenn nicht, zeichnen Sie nur den sichtbaren Teil des Bildes, es wäre viel schneller...

[EDIT nach den ersten Kommentar] Meine Bemerkung ist in der Tat ein bisschen dumm, nehme ich an DrawImage Maske/überspringen Sie nicht benötigte Pixel.

Nach der Bearbeitung (mit StretchDIBits), ich denke, eine mögliche Quelle der speed-Unterschied könnte die Tatsache, dass StretchDIBits ist die hardware-beschleunigte ("Wenn der Treiber keine Unterstützung für die JPEG-oder PNG-Datei-Bild"ein kleiner Tipp,...), während DrawImage sein könnte (ich habe keinen Beweis dafür!) coded in C, die sich auf die Leistung der CPU anstelle der GPU ist eines...

Wenn ich mich Recht erinnere -, DIB-Bilder sind schneller (trotz des "device independent").Finden High-Speed-Win32-Animation: "verwenden CreateDIBSection zu tun, high-speed-animation".OK, es gilt für DIB vs.GDI, in alten Windows-version (1996!) aber ich denke, es ist immer noch wahr.

[EDIT] Vielleicht Bitmap::GetHBITMAP Funktion könnte helfen Sie mit StretchDIBits (nicht getestet...).

Andere Tipps

Wenn Sie GDI + verwenden, ist die TextureBrush Klasse, was Sie brauchen, um Bilder schnell zu machen. Ich habe ein paar von 2D-Spielen mit ihm geschrieben, immer um 30 FPS oder so.

Ich habe .NET-Code nie in C ++ geschrieben, also hier ist ein C # -ish Beispiel:

Bitmap bmp = new Bitmap(...)
TextureBrush myBrush = new TextureBrush(bmp)

private void Paint(object sender, PaintEventArgs e):
{
    //Don't draw the bitmap directly. 
    //Only draw TextureBrush inside the Paint event.
    e.Graphics.FillRectangle(myBrush, ...)
}

Nur ein Gedanke; statt die Breite und Höhe des Bildes vor dem Ziehen Abrufen, warum diese Werte nicht zwischenspeichern, wenn Sie das Bild laden?

Entdecken Sie die Auswirkungen der explizit den Interpolationsmodus zu NearestNeighbor Einstellung (wo, in Ihrem Beispiel, es ist wie Interpolation sieht nicht wirklich nötig! Aber 300ms ist die Art von Kosten zu tun, qualitativ hochwertige Interpolation, wenn keine Interpolation erforderlich ist, so sein einen Versuch wert)

Eine andere Sache zu erforschen, um die Farbtiefe des Bitmap zu ändern.

Leider, wenn ich ein ähnliches Problem hatte, fand ich, dass GDI + bekannt ist viel langsamer als GDI und nicht im Allgemeinen Hardware beschleunigt, aber jetzt Microsoft haben sich weiterentwickelt, um WPF werden sie nicht zurückkommen GDI zu verbessern +!

Alle Grafikkartenhersteller haben auf 3D-Leistung bewegt und scheinen nicht interessiert in 2D-Beschleunigung, und es gibt keine klare Quelle von Informationen darüber, welche Funktionen oder Hardware beschleunigt oder nicht. Sehr frustrierend, weil eine App in .NET geschrieben zu haben mit GDI +, ich bin nicht glücklich auf eine ganz andere Technologie zu ändern, um ihn zu beschleunigen zu einem vernünftigen Niveau.

Ich glaube nicht, dass sie viel von einem anderen machen werde, aber da Sie nicht wirklich sind, um die Größe des Bildes, versuchen Sie die Überlastung von DrawImage , die nicht (Versuch) tut, um die Größe:

DrawImage(bitmap,0,0);

Wie gesagt, ich bezweifle es wird keinen Unterschied machen, weil i bin sicher, dass , die DrawImage prüft die Breite und Höhe der Bitmap, und wenn es keine Größenänderung ist erforderlich, ruft nur diese Überlastung. (Ich würde hoffen, dass es nicht stört alle 12 Millionen Pixel durchlaufen keine eigentliche Arbeit durchführen).

Update: Mein ponderings falsch sind. Ich hatte herausgefunden, da, aber Jungs Kommentar erinnerte mich an meine alte Antwort: Sie wollen die Zielgröße angeben; obwohl es die Quelle Größe entspricht:

DrawImage(bitmap, 0, 0, bitmap.GetWidth, bitmap.GetHeight);

Der Grund ist wegen dpi Unterschiede zwischen der dpi-Wert von bitmap und die dpi des Ziels. GDI + wird die Skalierung durchführt um das Bild zu bekommen die richtige „Größe“ zu kommen (das heißt in Zoll)


Was ich auf meinen eigenen seit Oktober letzten Jahres gelernt haben, ist, dass Sie wirklich ein „Cache“ Version Ihrer Bitmap zeichnen möchten. Es gibt eine CachedBitmap Klasse in GDI +. Es gibt einige Tricks, um es zu benutzen. Aber es Ende habe ich eine Funktion Bit (Delphi) Code, der es tut.

Der Nachteil ist, dass der CachedBitmap ungültig werden kann - was bedeutet, es kann nicht zeichnen verwendet werden. Dies geschieht, wenn der Benutzer ändert Auflösungen oder Farbtiefen (z Remote Desktop). In diesem Fall wird die DrawImage fehl, und Sie müssen die CachedBitmap neu erstellt:

class procedure TGDIPlusHelper.DrawCachedBitmap(image: TGPImage;
      var cachedBitmap: TGPCachedBitmap;
      Graphics: TGPGraphics; x, y: Integer; width, height: Integer);
var
   b: TGPBitmap;
begin
   if (image = nil) then
   begin
      //i've chosen to not throw exceptions during paint code - it gets very nasty
      Exit;
   end;

   if (graphics = nil) then
   begin
      //i've chosen to not throw exceptions during paint code - it gets very nasty
      Exit;
   end;

   //Check if we have to invalidate the cached image because of size mismatch
   //i.e. if the user has "zoomed" the UI
   if (CachedBitmap <> nil) then
   begin
      if (CachedBitmap.BitmapWidth <> width) or (CachedBitmap.BitmapHeight <> height) then
         FreeAndNil(CachedBitmap); //nil'ing it will force it to be re-created down below
   end;

   //Check if we need to create the "cached" version of the bitmap
   if CachedBitmap = nil then
   begin
      b := TGDIPlusHelper.ResizeImage(image, width, height);
      try
         CachedBitmap := TGPCachedBitmap.Create(b, graphics);
      finally
         b.Free;
      end;
end;

    if (graphics.DrawCachedBitmap(cachedBitmap, x, y) <> Ok) then
begin
       //The calls to DrawCachedBitmap failed
       //The API is telling us we have to recreate the cached bitmap
       FreeAndNil(cachedBitmap);
       b := TGDIPlusHelper.ResizeImage(image, width, height);
       try
          CachedBitmap := TGPCachedBitmap.Create(b, graphics);
       finally
          b.Free;
       end;

       graphics.DrawCachedBitmap(cachedBitmap, x, y);
    end;
 end;

Die cachedBitmap wird unter Bezugnahme eingeleitet. Der erste Anruf es DrawCachedBitmap im Cache Version erstellt. Sie geben es dann in nachfolgenden Aufrufen, z.

Image imgPrintInvoice = new Image.FromFile("printer.png");
CachedBitmap imgPrintInvoiceCached = null;

...

int glyphSize = 16 * (GetCurrentDpi() / 96);

DrawCachedBitmap(imgPrintInvoice , ref imgPrintInvoiceCached , graphics, 
      0, 0, glyphSize, glyphSize);

i verwenden, um die Routine Glyphen auf Tasten zu ziehen, unter Berücksichtigung der aktuellen DPI. Das gleiche vom Internet Explorer-Team hätte verwendet werden können Bilder zu zeichnen, wenn der Benutzer hohe dpi ausgeführt wird (dh sehr langsam Zeichnung Bilder gezoomt, weil sie GDI + verwenden).

Versuchen Kopie von Bitmap-Datei. Fromfile-Funktion auf einigen Dateien zurückgibt Bild „langsam“, aber seine Kopie schneller ziehen.

Bitmap *bitmap = Bitmap::FromFile("XXXX",...);

Bitmap *bitmap2 = new Bitmap(bitmap); // make copy

DrawImage(bitmap2,0,0,width,height);

/ * Erster leid ma Englisch, und der Code ist teilweise in der polnischen, aber es ist einfach zu verstehen. Ich hatte das gleiche Problem und ich fand die beste Lösung. Hier ist es.

Dont Verwendung: Grafik Grafik (hdc); Graphics.DrawImage (gpBitmap, 0, 0); Es ist langsam.

Verwendung: GetHBITMAP (Gdiplus :: Color (), & g_hBitmap) für HBITMAP und ziehe meine Funktion ShowBitmapStretch mit ()

.

Sie können die Größe ändern und es ist viel schneller! Artur Czekalski / Polen

* /

//--------Global-----------
Bitmap *g_pGDIBitmap; //for loading picture
int gRozXOkna, gRozYOkna; //size of working window
int gRozXObrazu, gRozYObrazu; //Size of picture X,Y
HBITMAP g_hBitmap = NULL; //for displaying on window
//------------------------------------------------------------------------------
int ShowBitmapStretch(HDC hdc, HBITMAP hBmp, int RozX, int RozY, int RozXSkal, int RozYSkal, int PozX, int PozY) 
{
    if (hBmp == NULL) return -1;
    HDC hdc_mem = CreateCompatibleDC(hdc); //utworzenie kontekstu pamięciowego
    if (NULL == hdc_mem) return -2;
    //Trzeba połączyć BMP z hdc_mem, tzn. umieścić bitmapę w naszym kontekście pamięciowym
    if (DeleteObject(SelectObject(hdc_mem, hBmp)) == NULL) return -3; 

    SetStretchBltMode(hdc, COLORONCOLOR); //important! for smoothness
    if (StretchBlt(hdc, PozX, PozY, RozXSkal, RozYSkal, hdc_mem, 0, 0, RozX, RozY, SRCCOPY) == 0) return -4;

    if (DeleteDC(hdc_mem) == 0) return -5;
    return 0; //OK
}
//---------------------------------------------------------------------------
void ClearBitmaps(void)
{
    if (g_hBitmap) { DeleteObject(g_hBitmap);  g_hBitmap = NULL; }
    if (g_pGDIBitmap) { delete g_pGDIBitmap;  g_pGDIBitmap = NULL; }
}
//---------------------------------------------------------------------------
void MyOpenFile(HWND hWnd, szFileName)
{
    ClearBitmaps(); //Important!
    g_pGDIBitmap = new Bitmap(szFileName); //load a picture from file

    if (g_pGDIBitmap == 0) return;
    //---Checking if picture was loaded
    gRozXObrazu = g_pGDIBitmap->GetWidth();
    gRozYObrazu = g_pGDIBitmap->GetHeight();
    if (gRozXObrazu == 0 || gRozYObrazu == 0) return;

    //---Uworzenie bitmapy do wyświatlaia; DO IT ONCE HERE!
    g_pGDIBitmap->GetHBITMAP(Gdiplus::Color(), &g_hBitmap); //creates a GDI bitmap from this Bitmap object
    if (g_hBitmap == 0) return;

    //---We need to force the window to redraw itself
    InvalidateRect(hWnd, NULL, TRUE);
    UpdateWindow(hWnd);
}
//---------------------------------------------------------------------------
void MyOnPaint(HDC hdc, HWND hWnd) //in case WM_PAINT; DO IT MANY TIMES
{
    if (g_hBitmap)
    {
        double SkalaX = 1.0, SkalaY = 1.0; //scale
        if (gRozXObrazu > gRozXOkna || gRozYObrazu > gRozYOkna || //too big picture, więc zmniejsz; 
           (gRozXObrazu < gRozXOkna && gRozYObrazu < gRozYOkna)) //too small picture, można powiększyć 
        {
            SkalaX = (double)gRozXOkna / (double)gRozXObrazu; //np. 0.7 dla zmniejszania; FOR DECREASE
            SkalaY = (double)gRozYOkna / (double)gRozYObrazu; //np. 1.7 dla powiększania; FOR INCREASE
            if (SkalaY < SkalaX) SkalaX = SkalaY; //ZAWSZE wybierz większe skalowanie, czyli mniejszą wartość i utaw w SkalaX
        }

    if (ShowBitmapStretch(hdc, g_hBitmap, gRozXObrazu, gRozYObrazu, (int)(gRozXObrazu*SkalaX), (int)(gRozYObrazu*SkalaX), 0, 0, msg) < 0) return;

Ich habe einige forsch gemacht und war, einen Weg finden machen Bilder mit GDI / GDI + schneller als

nicht in der Lage
Graphics.DrawImage/DrawImageUnscaled

und zugleich einfach wie es.

Bis ich entdeckte

ImageList.Draw(GFX,Point,Index)

und ja es ist wirklich so schnell und einfach.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top