1

首先,我制作了一个具有拖放功能的桌面 AIR 应用程序来查看磁贴图像,但由于一些问题,我尝试在 C# 中制作相同的内容。你认为什么是更好的选择?(我知道这个小程序的性能不是问题,但我的意思是两者的难度和复杂性)

我正在构建一个简单的 TileViewer,因此在 openFileDialog 中选择了一张图片并将其设置为 Form 的平铺 BackgroundImage。

我的问题是:

  1. 我一直在使用计时器(interval = 500)来重新加载图像,所以如果我在 Photoshop 中编辑图像,TileViewer 将自动重新加载更新的图像(因为我将其保存在 Photoshop 中)。

    但问题是 Photoshop 没有这样做的权限,因为图像是在其他程序(我的 TileViewer)中打开的

  2. 我删除了计时器并制作了一个刷新按钮。但它是同样的问题。

我想制作一个位图数据的副本,但后来我得到一个错误,我没有足够的内存用于 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 );
    }

所以小伙伴们,如果你有任何建议或解决方案,请告诉我。

4

3 回答 3

2

更新 2:

另一个问题是 Rectangle rect = new Rectangle(0, 0, 100, 100);

在构造函数中,您应该传递新图像的宽度和高度,而不是像 100 这样的任意值。

这就是为什么运行时说你内存不足!(它对我有用,我有一台 18 GB 的怪物机器)

更新:

您正在泄漏对象,因此出现内存不足异常

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

请注意,您最好关闭使用后打开的任何流。

代替

私人无效setImage(){
位图tempImg =新位图(文件名);<--- 矩形 rect = new Rectangle(0, 0, 100, 100);
PixelFormat 格式 = tempImg.PixelFormat;

    this.BackgroundImage = new Bitmap( FileName ).Clone( rect, format );  
}  
于 2012-09-11T18:17:48.767 回答
2

The Bitmap.Clone() method doesn't do what you hope it does. It creates a "shallow" copy. You get a new Bitmap object but it still uses the underlying pixel buffer. Including the memory-mapped file that GDI+ uses to keep the pixel data out of the swap file. Which in turn puts a lock on the file.

You'll need to make a "deep" copy, do so with the Bitmap(Image) constructor. Like this:

private void setImage() {
    using (var tempImg = new Bitmap(FileName)) {
        this.BackgroundImage = new Bitmap(tempImg);
    }
}

The using statement ensures the original image is disposed and the lock gets released.

于 2012-09-11T18:21:39.717 回答
0

您将需要使用 ReadOnly 标志手动打开文件,然后手动将文件的有效负载加载到位图中。

另一种方法是复制文件,然后打开副本。

看看您是否在 Photoshop 打开文件时运行以下代码

 FileStream s2 = new FileStream(name, FileMode.Open, FileAccess.Read, FileShare.Read);
于 2012-09-11T18:04:26.043 回答