質問

first i have made an desktop AIR app with drag and drop functions to view the tiles image, but because of some issues, i've tryed to make the same in C#. what do you think is the better choice ? ( i know for this little programm performance is not the question, but i mean the dufficulty and complexity of both )

I was building a simple TileViewer, so a picture is selected in openFileDialog and set as tiled BackgroundImage of the Form.

My problem is:

  1. I've been using a timer ( interval = 500 ) to reload the image, so if i edit the image in photoshop, the TileViewer will automaticaly reload the updated image ( as i save it in photoshop ).

    BUT the problem is that photoshop doesnt have premissions to do so, cuz the image is opened in an other programm ( my TileViewer )

  2. I removed the Timer and made a refresh button instead. but its the same problem.

I thought of making a copy of the bitmap data, but then I get an error that I dont have enought memory for a 32px x 32px img.

My code :

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

So guys, if you have any suggestions or solutions, let me know.

役に立ちましたか?

解決

Update 2:

Another issue was is in line Rectangle rect = new Rectangle(0, 0, 100, 100);

where in the constructor you should pass the width and heigth of the new image not an arbitary value like 100.

thats why the runtime says that you're out of memory !! (It did for me and I have a 18 GB monster machine)

Update:

your're leaking objects hence the out of memory exception

(Haans Already warned you about disposing objects thats.)

Try the following code

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

        }
}

OLD Answer

Like Jason said

you might need to do somethinglike this in your setimage method

Stream str = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read);
   this.BackgroundImage  = Bitmap.FromStream(str);
str.Close();

Note that you're better off closing any stream that you open after you use it.

instead of

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

他のヒント

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.

You will need to open the file manually with ReadOnly flags, and then load the payload of the file into the bitmap by hand.

an alternitive would be to copy the file and then open the copy.

See if you cna run the following code while photoshop has the file open

 FileStream s2 = new FileStream(name, FileMode.Open, FileAccess.Read, FileShare.Read);
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top