2017-10-16 121 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人之后告诉我同样的事情。

再次感谢。