سؤال

أنا أستخدم GDI+ Graphic لرسم صورة بحجم 4000*3000 على الشاشة، لكنها بطيئة حقًا.يستغرق حوالي 300 مللي ثانية.أتمنى أن تشغل أقل من 10 مللي ثانية.

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

//-------------------------------------------- // هذا الجزء يستغرق حوالي 300 مللي ثانية ، فظيع!

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

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

لا يمكنني استخدام CachedBitmap، لأنني أريد تحرير الصورة النقطية لاحقًا.

كيف يمكنني تحسينه؟أو هل هناك أي شيء خاطئ؟

تقوم وظيفة GDI الأصلية أيضًا برسم الصورة إلى الشاشة، ويستغرق الأمر 1 مللي ثانية فقط:

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);

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

إذا كنت أرغب في استخدام StretchDIBits، فأنا بحاجة إلى تمرير BITMAPINFO، ولكن كيف يمكنني الحصول على BITMAPINFO من كائن Gdi+ Bitmap؟لقد أجريت التجربة بواسطة FreeImage lib، وقمت باستدعاء StretchDIBits باستخدام كائن FreeImageplus، وهو يرسم بسرعة كبيرة.لكنني الآن بحاجة إلى رسم صورة نقطية، وكتابة بعض الخوارزميات على مصفوفة البتات الخاصة بالصورة النقطية، كيف يمكنني الحصول على BITMAPINFO إذا كان لدي كائن صورة نقطية؟إنه أمر مزعج حقًا -__________-|

هل كانت مفيدة؟

المحلول

لديك شاشة من 4000 x 3000 قرار؟ نجاح باهر!

إذا لم يكن كذلك، يجب أن يوجه فقط الجزء المرئي من الصورة، فإنه سيكون أسرع بكثير ...

[تحرير بعد التعليق الأول] وملاحظتي هي في الواقع غبي بعض الشيء، وأعتقد سوف DrawImage قناع / تخطي بكسل لزوم لها.

وبعد تحرير الخاص بك (تظهر StretchDIBits)، أعتقد مصدرا محتملا للفرق السرعة قد تأتي من حقيقة أن <لأ href = "http://msdn.microsoft.com/en-us/library/ms532289.aspx" يختلط = "نوفولو noreferrer" عنوان = "StretchDIBits"> StretchDIBits والأجهزة تسارع ( "<م> إذا كان السائق لا يمكن أن تدعم صورة JPEG أو PNG " هو تلميح ...) في حين DrawImage قد يكون (ليس لدي أي دليل على ذلك!) مشفرة في C، والاعتماد على قوة وحدة المعالجة المركزية بدلا من واحدة GPU في ...

إذا لم تخني والصور DIB سريعة (على الرغم من كونه "جهاز مستقل"). انظر السامي سرعة Win32 والرسوم المتحركة : "< م> استخدام CreateDIBSection للقيام ارتفاع سرعة الحركة ". OK، فإنه ينطبق على بنك دبي الإسلامي مقابل GDI، في نسخة ويندوز القديمة (1996!) ولكن اعتقد انه لا يزال صحيحا.

[تحرير] ربما نقطية :: GetHBITMAP وظيفة قد تساعدك على استخدام StretchDIBits (لم تختبر ...).

نصائح أخرى

إذا كنت تستخدم GDI +، الطبقة TextureBrush هي ما تحتاجه لجعل الصور بسرعة. لقد كتبت بضع مباريات 2D ومعها، والحصول على حوالي 30 FPS أو نحو ذلك.

ولقد كتبت أبدا. رمز NET في C ++، حتى هنا مثال C # -ish:

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, ...)
}

ومجرد التفكير. بدلا من استرجاع وعرض وارتفاع الصورة قبل الرسم، لماذا لا تخزين هذه القيم عند تحميل الصورة؟

واستكشاف أثر بشكل صريح إعداد وضع الاستيفاء لNearestNeighbor (حيث، في سبيل المثال، فإنه يبدو وكأنه ليست هناك حاجة فعلا الاستيفاء! لكن 300mS وهو نوع من تكلفة القيام عالية الجودة الاستيفاء عند الحاجة لا الاستيفاء، لذلك لها يستحق المحاولة)

وشيء آخر لاستكشاف يتغير عمق الألوان من الصورة النقطية.

وللأسف عندما كان لي مشكلة مماثلة، وجدت أن GDI + هو معروف أن تكون أبطأ بكثير من GDI وليس عادة الأجهزة تسارع، ولكن الآن مايكروسوفت قد انتقلت إلى WPF فإنها لن أعود إلى تحسين GDI +!

انتقلت

وجميع الشركات المصنعة بطاقة الرسومات على أداء 3D ولا تبدو مهتمة تسارع 2D، وليس هناك مصدر واضح من المعلومات التي وظائف هي أو يمكن أن تكون الأجهزة تسارع أم لا. محبط للغاية لأنه كتب التطبيق في. NET باستخدام GDI +، وأنا لست سعيدا لتغيير تقنية مختلفة تماما أن يصل إلى سرعة إلى مستويات معقولة.

لا أعتقد أنها ستحدث فرقًا كبيرًا، ولكن نظرًا لأنك لا تحتاج فعليًا إلى تغيير حجم الصورة، فحاول استخدام التحميل الزائد DrawImage هذا لا (يحاول) تغيير الحجم:

DrawImage(bitmap,0,0);

كما قلت، أشك في أن هذا سيحدث أي فرق، لأنني كذلك بالتأكيد الذي - التي DrawImage يتحقق من عرض و ارتفاع للصورة النقطية، وإذا لم تكن هناك حاجة لتغيير الحجم، فما عليك سوى استدعاء هذا التحميل الزائد.(آمل ألا يزعجني الأمر من خلال 12 مليون بكسل لا تؤدي أي عمل فعلي).

تحديث:تأملاتي خاطئة.لقد اكتشفت ذلك منذ ذلك الحين، لكن تعليق الرجال ذكرني بإجابتي القديمة:أنت يريد لتحديد حجم الوجهة؛على الرغم من أنه يطابق حجم المصدر:

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

والسبب هو وجود اختلافات نقطة في البوصة بين نقطة في البوصة bitmap ونقطة في البوصة للوجهة.سيقوم GDI+ بإجراء القياس للحصول على الصورة بالحجم الصحيح (أي.بالبوصة)


ما تعلمته بنفسي منذ أكتوبر الماضي هو أنك تريد حقًا رسم "مخبأة" إصدار الصورة النقطية الخاصة بك.هناك CachedBitmap فئة في GDI+.هناك بعض الحيل لاستخدامه.ولكن في النهاية لدي جزء من كود (دلفي) يقوم بذلك.

التحذير هو أن CachedBitmap يمكن أن تصبح غير صالحة - مما يعني أنه لا يمكن استخدامها للرسم.يحدث هذا إذا قام المستخدم بتغيير الدقة أو عمق الألوان (على سبيل المثال.سطح المكتب البعيد).في هذه الحالة DrawImage سوف تفشل، ويجب عليك إعادة إنشاء CachedBitmap:

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;

ال cachedBitmap يتم تمريرها عن طريق المرجع.النداء الأول ل DrawCachedBitmap هو - هي مخبأة سيتم إنشاء الإصدار.ثم تقوم بتمريرها في مكالمات لاحقة، على سبيل المثال:

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

...

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

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

أستخدم الروتين لرسم الحروف الرسومية على الأزرار، مع مراعاة DPI الحالي.كان من الممكن أن يستخدم فريق Internet Explorer نفس الشيء لرسم الصور عندما يقوم المستخدم بتشغيل نقطة عالية في البوصة (أي رسم الصور المكبرة ببطء شديد، لأنهم يستخدمون GDI+).

وحاول استخدام نسخة من صورة نقطية من الملف. وظيفة FromFile على بعض الملفات ترجع "بطيء" صورة، ولكن نسخته رسم أسرع.

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

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

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

/* آسف أولاً على MA English ، والرمز باللغة البولندية جزئيًا ، ولكن من السهل فهمه.واجهت نفس المشكلة ووجدت الحل الأفضل.ها هو.

لا تستخدم:الرسومات الرسومات (HDC)؛graphics.DrawImage(gpBitmap, 0, 0);إنه بطيء.

يستخدم:GetHBITMAP(Gdiplus::Color(), &g_hBitmap) لـ HBITMAP والرسم باستخدام وظيفتي ShowBitmapStretch().

يمكنك تغيير حجمه وهو أسرع بكثير!أرتور تشيكالسكي / بولندا

*/

//--------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;

ولقد جعلت بعض البحث ولم يكن قادرا على ايجاد وسيلة لتقديم الصور مع GDI / GDI + أكثر سرعة من

Graphics.DrawImage/DrawImageUnscaled

و في نفس الوقت بسيطة مثل ذلك.

وحتى اكتشفت

ImageList.Draw(GFX,Point,Index)

وونعم انها حقا سريع جدا وبسيط.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top