首先,我制作了一个带有拖放功能的桌面AIR应用程序来查看瓷砖图像,但由于一些问题,我尝试在C#中制作同样的应用程序。你认为什么是更好的选择?(我知道这个小程序的性能不是问题,但我指的是两者的愚蠢和复杂性)
我正在构建一个简单的TileViewer,所以在openFileDialog中选择一张图片,并将其设置为Form的平铺BackgroundImage。
我的问题是:
-
我一直在使用计时器(间隔=500)来重新加载图像,所以如果我在photoshop中编辑图像,TileViewer将自动重新加载更新的图像(就像我在photohop中保存它一样)。
但问题是,photoshop没有这样做的前提,因为图像是在另一个程序(我的TileViewer)中打开的
-
我去掉了定时器,改为刷新按钮。但问题是一样的。
我想复制位图数据,但后来我得到一个错误,我没有足够的内存用于32px x 32px img。
我的代码:
private string FileName;
public Form1() {
InitializeComponent();
FileName = "";
}
// OPEN FILE btn
private void button1_Click( object sender, EventArgs e ) {
openFileDialog1.Filter = "PNG Files (*.png)|*.png|JPG Files (*.jpg)|*.jpg";
if(openFileDialog1.ShowDialog() == DialogResult.OK) {
button2.Enabled = true;
FileName = openFileDialog1.FileName;
setImage();
}
}
// REFRESH btn
private void button2_Click( object sender, EventArgs e ) {
if( FileName != "" ) {
setImage();
}
}
private void setImage() {
Bitmap tempImg = new Bitmap( FileName );
Rectangle rect = new Rectangle(0, 0, 100, 100);
PixelFormat format = tempImg.PixelFormat;
this.BackgroundImage = new Bitmap( FileName ).Clone( rect, format );
}
所以,伙计们,如果你们有任何建议或解决方案,请告诉我。
更新2:
另一个问题是矩形矩形rect=新矩形(0,0,100,100);
在构造函数中,应该传递新图像的宽度和高度,而不是像100这样的任意值。
这就是为什么运行时会说你内存不足!!(它为我做了,我有一台18GB的怪物机器)
更新:
您正在泄漏对象,因此出现内存不足异常
(Haans已经警告过你要处理那些东西了。)
尝试以下代码
private string FileName;
public Form1()
{
InitializeComponent();
FileName = "";
}
// OPEN FILE btn
private void button1_Click(object sender, EventArgs e)
{
openFileDialog1.Filter = "PNG Files (*.png)|*.png|JPG Files (*.jpg)|*.jpg";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
FileName = openFileDialog1.FileName;
setImage();
}
}
// REFRESH btn
private void button2_Click(object sender, EventArgs e)
{
if (FileName != "")
{
setImage();
}
}
private void setImage()
{
Stream str=new FileStream(FileName,FileMode.Open, FileAccess.Read,FileShare.Read);
Bitmap tempImg= new Bitmap(Bitmap.FromStream(str));
str.Close();
using( tempImg)
{
Rectangle rect = new Rectangle(0, 0, tempImg.Width, tempImg.Height);
PixelFormat format = tempImg.PixelFormat;
this.BackgroundImage = new Bitmap(tempImg);
}
}
旧答案
就像杰森说的
你可能需要在你的setimage方法中做一些类似的事情
Stream str = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read);
this.BackgroundImage = Bitmap.FromStream(str);
str.Close();
注意,你最好关闭你使用后打开的任何流。
而不是
private void setImage(){
位图tempImg=新位图(FileName)<---矩形rect=新矩形(0,0,100,100)
PixelFormat format=tempImg.PixelFormat;
this.BackgroundImage = new Bitmap( FileName ).Clone( rect, format );
}
Bitmap.Clone()方法并不能实现您所希望的效果。它创建了一个"浅"副本。您得到了一个新的位图对象,但它仍然使用底层像素缓冲区。包括GDI+用来将像素数据排除在交换文件之外的内存映射文件。这反过来又锁定了文件。
您需要制作一个"深度"副本,使用位图(图像)构造函数即可。像这样:
private void setImage() {
using (var tempImg = new Bitmap(FileName)) {
this.BackgroundImage = new Bitmap(tempImg);
}
}
using语句确保释放原始图像并释放锁。
您需要使用ReadOnly标志手动打开文件,然后手动将文件的有效负载加载到位图中。
一种替代方法是复制文件,然后打开副本。
看看你是否可以在photoshop打开文件时运行以下代码
FileStream s2 = new FileStream(name, FileMode.Open, FileAccess.Read, FileShare.Read);