2017-10-16 134 views
-2

我正在將圖像存儲在位圖中。當我調整我的對象時,我的圖像也需要調整大小。我已經做了一個調整我的圖像到所需大小的功能。降低C中繪圖的內存成本

當我絕對需要調整圖像大小時,我已經只調用了這個函數,但是我的內存開銷不斷隨着這個圖像的大小迅速從50 MB跳到1 GB以上。 (當我的鼠標按鈕被按下時,這個方法需要在每毫秒調用一次。)

我有我的Graphicsusing但這在這種情況下似乎沒有什麼幫助。 如果我打電話GC.Collect(2)當然有幫助,但它會極大地減慢GUI,如果我將它設置爲非阻塞,那麼它根本沒有幫助。

有沒有一種方法來釋放被調用的此函數的最後一個實例仍未使用的內存,或者是否需要更改我的代碼並以另一種方式執行此操作?如果有更好的方法,我會很感激一些幫助,因爲看起來GDI有漏洞,或者我的方法效率很低。

我的代碼:

public int getWidth() 
{ 
    return width; 
} 

public int getHeight() 
{ 
    return height; 
} 

public void createScaledImage() 
{ 
    var cr = new c_returnGraphicSettings(); 
    if (getWidth() > 20 && getHeight() > 20) 
    { 
     scaledImage = new Bitmap(getWidth(), getHeight()); 
     using (Graphics g = Graphics.FromImage(scaledImage)) 
     { 
      /* 
      g.InterpolationMode = cr.getIM(); 
      g.PixelOffsetMode = cr.getPOM(); 
      g.SmoothingMode = cr.getSM(); 
      /*--*/ 

      g.DrawImage(image, new Rectangle(new Point(0, 0), scaledImage.Size), new Rectangle(new Point(0, 0), image.Size), GraphicsUnit.Pixel); 
      g.Dispose(); 
     } 

     //GC.Collect(2, GCCollectionMode.Forced, true); 

    } 
} 

public Bitmap getScaledImage() 
{ 
    //createScaledImage(); 
    return scaledImage; 
} 

public void resizeImage() 
{ 
    if(image != null) 
    { 
     createScaledImage(); 
    } 
} 

典論主要形式有:

protected override void OnPaint(PaintEventArgs e) 
{ 
    base.OnPaint(e); 

    //TODO: PAINT!! 
    organizeImageList(); 
    foreach (c_ImageHolder c in Limages) 
    { 
     if (c != null) 
     { 
      e.Graphics.DrawImage(c.getScaledImage(), c.Position); 
      ... 
     } 
    } 
} 


private void f_Screen_MouseDown(object sender, MouseEventArgs e) 
{ 
    Limages.Sort(new intComparerDesc()); 
    foreach (c_ImageHolder c in Limages) 
    { 
     if (renhan.pointInPosition(e.Location, new Rectangle(c.Position, c.Size))) 
     { 
      c.select(); 
      selectedImage = c; 
      imageDragPoint = new Point(e.X - c.Left, e.Y - c.Top); 
      if (!c.isOverAnEdge(imageDragPoint) && !c.isOverACorner(imageDragPoint)) 
      { 
       resize = false; 
       cResizer = null; 
       ed = edges.none; 
       cor = corners.none; 
      } 
      else 
      { 
       resize = true; 
       cResizer = c; 
       if (c.isOverAnEdge(imageDragPoint)) 
       { 
        ed = c.overWhichEdge(imageDragPoint); 
        cor = corners.none; 
       } 
       else 
       { 
        cor = c.overWhichCorner(imageDragPoint); 
        ed = edges.none; 
       } 
      } 
      mdown = true; 
      break; 
     } 
    } 
    Invalidate(); 
} 

enter image description here


說明:

我使用I類到發存儲一個位圖圖像與一些關於它的大小和位置的數據,然後我使用它將該圖像繪製到存儲該類的實例的屏幕上。

由於透明度問題,我沒有使用控件(picturebox等)。

每個實例包含不同的圖像。我還需要能夠調整這些圖像的大小。由於這個原因,我有第二個位圖,用於存儲原始位圖的大小調整後的版本。

我使用不同的位圖存儲調整大小的圖像,以便如果我需要再次調整大小,我不調整已經修改的圖像,但原來的大小。 (保留質量)

調整大小的方式如下: 我按住鼠標左鍵在圖像的邊緣。當我每次調整大小時按住按鈕的同時移動鼠標時,該類會生成一張新圖像,以將原始圖像拉伸至新尺寸。該圖像返回到無效的主屏幕,並在繪圖時將新圖像繪製到屏幕的背景上。

問題是,因爲我需要將這個圖像繪製到背景上,所以我不能處理它。我可以複製並處理原文,但我認爲,那時我會遇到同樣的問題。

當我按住鼠標按鈕並不斷重新繪製圖像時,內存快速閃爍。完成後我可以處理,但只是調整圖像足夠長的時間會導致程序崩潰。

我已經做了更小更簡單的程序,證明了我的問題,以及一個簡短的視頻,你可以找到兩個位置:Video and link to program

還有就是要根據存儲在Dropbox的一個RAR文件我的演示程序的鏈接視頻。

我希望這個解釋和視頻/演示可以更好地解釋我的問題。

謝謝,給所有想嘗試幫助的人!

+1

你在左右漏東西。在舊的位圖上調用'Dispose()'。 ''''已經在'g'上調用'Dispose()',不需要手動完成。如果你的代碼是正確的,那麼根本不需要調用GC.Collect()。 – xxbbcc

+0

結果會怎樣?您正在爲(顯然)較小的圖像創建一個* new *位圖,因此您將在某個點處處理2個總圖像('image'和'scaledImage') – Plutonix

+1

爲什麼要手動調整位圖大小?在視圖上讓控件進行調整大小,當您完成調整大小(釋放鼠標單擊後)時,生成並存儲新的位圖。 –

回答

0

謝謝大家誰試圖幫助。我finalyl意識到我出錯的地方。

當我在控件中管理圖像時,我保留了原始代碼的功能。

使用我的新代碼,我可以管理調整大小而不寫入新的位圖。

我不知道爲什麼我不明白,在5人之後告訴我同樣的事情。

再次感謝。