Avatar billede koppelgaard Praktikant
17. november 2007 - 21:27 Der er 23 kommentarer og
1 løsning

Imagebrowser, find 5 fejl

Eller forhåbentlig kun.
Jeg arbejder stadig med en billedbrowser som jeg er ved at konstruere.

Jeg kan rotere billeder og men IKKE slette dem.

Koden er nedenfor men jeg tror man for at finde fejlen blive nødt til at have HELE PROJEKTET for at kunne finde fejlen.

FØRST BILLEDKLASSEN SOM INDEHOLDER ET IMAGE OG EN FILEINFO.
ENDVIDERE EN BOOL FREMKALDELSE, SOM HVIS SAND LÆGGER BILLEDET I "c:\fremkaldelse\"

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace PictureBrowser
{   
    public class PictureClass
    {
        private System.Drawing.Image image;
        private FileInfo fi;
        private bool fremkaldelse;
        public PictureClass(System.Drawing.Image image, FileInfo fi)
        {
            this.image =image;
            this.fi= fi;
            this.fremkaldelse = false;
        }
        public FileInfo FileInfo
        {
            get { return fi; }
            set { fi = value; }
           
        }
        public System.Drawing.Image Image
        {
            get { return image; }
            set { image = value; }
        }

        public bool Fremkaldelse
        {
            get { return fremkaldelse; }
            set { fremkaldelse = value; }

        }

        public void RotateImg(bool clockwise)
        {                   
            if (clockwise)
                Image.RotateFlip(System.Drawing.RotateFlipType.Rotate90FlipNone);

            else
                Image.RotateFlip(System.Drawing.RotateFlipType.Rotate270FlipNone);
            Save();
        }
        public void fremkald(bool Fremkald)
        {
            if (Fremkald)
            {
                File.Copy(fi.FullName, @"c:\fremkaldelse\" + fi.Name, true);
                fremkaldelse = true;
            }
            else
            {
                if (File.Exists(@"c:\fremkaldelse\" + fi.Name))
                    File.Delete(@"c:\fremkaldelse\" + fi.Name);
                fremkaldelse = false;
            }

        }
        public void Save()
        {
            Encoding enc = new ASCIIEncoding();
            string timeStr=null;
            foreach (PropertyItem pi in image.PropertyItems)// If the PropertyItem is a timestamp...               
                if (pi.Type == 2 /* text */ && pi.Id == 306 /* date and time */)                   
                    timeStr = enc.GetString(pi.Value).Replace(" ",":");// get the timestamp.
            string[] a=new string[6];
            a = timeStr.Substring(0, timeStr.Length - 1).Split(':')              ;

            DateTime time = new DateTime(Convert.ToInt32(a[0]), Convert.ToInt32(a[1]), Convert.ToInt32(a[2]), Convert.ToInt32(a[3]), Convert.ToInt32(a[4]), Convert.ToInt32(a[5]));

            Image.Save(fi.FullName, System.Drawing.Imaging.ImageFormat.Jpeg);
            File.SetLastWriteTime(fi.FullName,time);
        }
    }
}


DERNÆST EN CONTAINER TIL BILLEDEKLASSEN:
using System;
using System.Collections.Generic;
using System.IO;
using System.Drawing;
using System.Windows.Forms;

namespace PictureBrowser
{
    public class ConPicture
    {

        private Form1 f;
        List<PictureClass> PictureList = null;
        private string path;
        private int pic1_Number; 

        public ConPicture(Form1 f, string path)
        {           
            this.f = f;
            this.path = path;           
            PictureList = new List<PictureClass>();           
         
        }
        public int Pic1_Number
        {
            get { return pic1_Number; }
            set { pic1_Number = value; }
        }

        public void RotateImg(int imagebox, int x_korr)
        {
            int picNbr = imagebox + pic1_Number - 1;
            bool clockwise = false;
            switch (imagebox)
            {
                case 1:
                    if (x_korr < f.picBox1.Width / 2)
                        clockwise = true;
                    break;
                case 2:
                    if (x_korr < f.picBox2.Width / 2)
                        clockwise = true;
                    break;
                case 3:
                    if (x_korr < f.picBox3.Width / 2)
                        clockwise = true;
                    break;
                case 4:
                    if (x_korr < f.picBox4.Width / 2)
                        clockwise = true;
                    break;
            }
           


            PictureList[picNbr].RotateImg(clockwise);

            f.picBox1.Refresh();
            f.picBox2.Refresh();
            f.picBox3.Refresh();
            f.picBox4.Refresh();

        }
        public int Count()
        {
            return PictureList.Count;
        }

        public void Fremkaldelse(int imageBox,bool fremkald)
        {
            int picNbr = imageBox + pic1_Number - 1;
            PictureList[picNbr].fremkald(fremkald);
        }       
       
        public void Add(PictureClass pic)
        {       
            PictureList.Add(pic);
        }

        public System.Drawing.Image AddAndGet(int i)  {
            DirectoryInfo d = new DirectoryInfo(path);
            FileInfo[] fiList = d.GetFiles("*.jpg");
            System.Drawing.Image image = null;
            if (i >= 0 && i < fiList.Length)//hvis i er ikke på disken
            {
                //hvis i ikke er i picturelisten             
                if (i >= PictureList.Count)
                {
                    image = Image.FromFile(fiList[i].FullName);//så hent det fra disk
                    PictureList.Add(new PictureClass(image, fiList[i]));//tilføj det til listen
                }
                else
                    image = PictureList[i].Image;
            }
           
            return image;//retuner det
           
        }
        public string ImageName(int nbrInFileInfoArr)
        {
            string result;
            DirectoryInfo d = new DirectoryInfo(path);
            FileInfo[] fiList = d.GetFiles("*.jpg");
           
            result= fiList[nbrInFileInfoArr].Name;
         

            return result;
        }
        public string ImageLastWrite(int nbrInFileInfoArr)
        {
            string result;
            DirectoryInfo d = new DirectoryInfo(path);
            FileInfo[] fiList = d.GetFiles("*.jpg");
            result = Convert.ToString( fiList[nbrInFileInfoArr].LastWriteTime);

            return result;
           
        }
        public bool satTilFremkald(int nbrInFileInfoArr)
        {
         
            DirectoryInfo d = new DirectoryInfo(path);
            FileInfo[] fiList = d.GetFiles("*.jpg");
            if(File.Exists(@"c:\fremkaldelse\" +  fiList[nbrInFileInfoArr].Name))
                return true;
            else
            return false;           
           
        }

        public void DeletePicture(int imagebox)       
        {           
            try
            {
                //the pointer pic1_Number describes what is the image in box 1 and therefor also the image i box2,box3,box4
                //the argument of this metode 
                int picToRemove = pic1_Number + imagebox - 1; 
                string fil=PictureList[picToRemove].FileInfo.FullName;
                int l = 0;
                l = PictureList.Count;
                PictureList.RemoveAt(picToRemove);
                l = PictureList.Count;
                File.Delete(fil);

                f.picBox1.Image = AddAndGet(Pic1_Number + 0);
                f.picBox1.Image = AddAndGet(Pic1_Number + 1);
                f.picBox1.Image = AddAndGet(Pic1_Number + 2);
                f.picBox1.Image = AddAndGet(Pic1_Number + 3);
               
             
            }
            catch (Exception e)
            {
                MessageBox.Show("E!: " + e.Message);
                return;
            }
        }     
    }
}



X_korr kommer fra en clickevent. Hvis man klikker i højre side af billeder vendes det mod højre side op.
Klikker man i venstre vendes venstre side op.


JEG ER BARE KØRT FAST OG GAV GERNE 500 POINT HVIS JEG MÅTTE.

Michael
Avatar billede nielle Nybegynder
17. november 2007 - 22:04 #1
Du skriver at du ikke kan slette billeder, men kan du ikke lige fortælle lidt mere om hvad det er du prøver at gøre (hvordan kaldes DeletePicture) og hvilke fejl du oplever?

PS: Et billede kan ikke slettes så længe at der er en PictureBox som "holder fast" i det.
Avatar billede koppelgaard Praktikant
17. november 2007 - 22:22 #2
Jeg har en form med 4 billeder på een gang

Jeg har billederne i en container med fileinfo og selve billedet.
Efterhånden som jeg browser gennnem billederne lægger jeg dem i containenen for hurtigere at kunne have adgang til dem, hvis jeg bladre tilbage gemmen billederne.

Når jeg skal slette en billdet sletter jeg det på disk og i containeren ved

int picToRemove = pic1_Number + imagebox - 1;  (nummer i containeren)
string fil=PictureList[picToRemove].FileInfo.FullName;
                PictureList.RemoveAt(picToRemove);
                File.Delete(fil);

Pic1_Number henviser til hvadfor et nummer i containern, som picturebox 1 pejer på.

Herefter vil jeg gerne opdatere de 4 picturebokse.
Det gør jeg ved at hente billedet i containeneren med
                f.picBox1.Image = AddAndGet(Pic1_Number + 0);
                f.picBox2.Image = AddAndGet(Pic1_Number + 1);
                f.picBox3.Image = AddAndGet(Pic1_Number + 2);
                f.picBox4.Image = AddAndGet(Pic1_Number + 3);
Men her går det galt.
Argumentexception er beskeden.

Jeg kan ikke finde ud af hvorfor.


Men det ville nok være nemmere, hvis du havde projektet.
Jeg kunne maile det.

Michael
Avatar billede koppelgaard Praktikant
17. november 2007 - 23:06 #3
f.picBox1.Image = AddAndGet(Pic1_Number + 0);
                f.picBox1.Image = AddAndGet(Pic1_Number + 1);
                f.picBox1.Image = AddAndGet(Pic1_Number + 2);
                f.picBox1.Image = AddAndGet(Pic1_Number + 3);
er en fejl.
Der skulle stå
                f.picBox1.Image = AddAndGet(Pic1_Number + 0);
                f.picBox2.Image = AddAndGet(Pic1_Number + 1);
                f.picBox3.Image = AddAndGet(Pic1_Number + 2);
                f.picBox4.Image = AddAndGet(Pic1_Number + 3);
Avatar billede nielle Nybegynder
17. november 2007 - 23:10 #4
Du kan sende det til

nkh snaple get2net punktum dk

Forresten, en nemmer måde at slette filen på er ved at bruge FileInfo's delete:

int picToRemove = pic1_Number + imagebox - 1;  (nummer i containeren)
string fil = PictureList[picToRemove].FileInfo.FullName;
PictureList.RemoveAt(picToRemove);
File.Delete(fil);

rettes til:

int picToRemove = pic1_Number + imagebox - 1;  (nummer i containeren)
PictureList[picToRemove].FileInfo.Delete();
PictureList.RemoveAt(picToRemove);
Avatar billede koppelgaard Praktikant
18. november 2007 - 14:03 #5
Hej Nielle.
Jeg har sendt projektet.

MICHAEL
Avatar billede nielle Nybegynder
19. november 2007 - 22:17 #6
Har kigget på den ... endeligt fandt jeg ud af hvorfor at du fik en exception når du forsøget at slette (det er det eneste jeg har kigget på). Det sker fordi at du i:

DeletePicture.DeletePicture()

kalder Dispose på de billeder der er indlæst i de fire PictureBox'e fra starten af.

Problemet med dette er at det faktisk disposer billederne, som du har gemt i din ConPicture-liste - de peger jo på det samme Image. Dermed får du en exception når du forsøger at assigne de nu disposede billeder til PictureBox'ene i den nye rækkefølge.

Koden skal se sådan her ud hvis du skal undgå dette:

        public void DeletePicture(int imageBox)
        {
            // (af nielle) f.picBox1.Image.Dispose();
            f.picBox1.Image = null;

            // (af nielle) f.picBox2.Image.Dispose();
            f.picBox2.Image = null;

            // (af nielle) f.picBox3.Image.Dispose();
            f.picBox3.Image = null;

            // (af nielle) f.picBox4.Image.Dispose();
            f.picBox4.Image = null;

            conPicture.DeletePicture(imageBox);
        }
Avatar billede nielle Nybegynder
19. november 2007 - 22:19 #7
Derudover har jeg leget lidt med din kode:

namespace PictureBrowser
{
    public class PictureClass
    {
        private Image image = null;
        private FileInfo fi;
        private bool fremkaldelse = false;

        public PictureClass(FileInfo fi)
        {
            this.fi = fi;
        }

        internal void Delete()
        {
            this.image.Dispose();
            this.image = null;

            this.fi.Delete();
        }

        public FileInfo FileInfo
        {
            get { return fi; }
            set { fi = value; }
        }

        public Image Image
        {
            get
            {
                if (image == null) image = Image.FromFile(fi.FullName);
                return image;
            }
            set { image = value; }
        }

        public bool Fremkaldelse
        {
            get { return fremkaldelse; }
            set { fremkaldelse = value; }
        }

        public void RotateImg(bool clockwise)
        {
            if (clockwise)
                Image.RotateFlip(RotateFlipType.Rotate90FlipNone);
            else
                Image.RotateFlip(RotateFlipType.Rotate270FlipNone);

            Save();
        }

        public void Fremkald(bool fremkald)
        {
            if (fremkald)
            {
                File.Copy(fi.FullName, @"c:\fremkaldelse\" + fi.Name, true);
                fremkaldelse = true;
            }
            else
            {
                if (File.Exists(@"c:\fremkaldelse\" + fi.Name))
                    File.Delete(@"c:\fremkaldelse\" + fi.Name);

                fremkaldelse = false;
            }
        }

        public void Save()
        {
            Encoding enc = new ASCIIEncoding();
            string timeStr = null;
            foreach (PropertyItem pi in image.PropertyItems)// If the PropertyItem is a timestamp...
                if (pi.Type == 2 /* text */ && pi.Id == 306 /* date and time */)
                    timeStr = enc.GetString(pi.Value).Replace(" ", ":");// get the timestamp.

            string[] a = new string[6];
            a = timeStr.Substring(0, timeStr.Length - 1).Split(':');

            DateTime time = new DateTime(Convert.ToInt32(a[0]), Convert.ToInt32(a[1]), Convert.ToInt32(a[2]), Convert.ToInt32(a[3]), Convert.ToInt32(a[4]), Convert.ToInt32(a[5]));

            Image.Save(fi.FullName, System.Drawing.Imaging.ImageFormat.Jpeg);
            File.SetLastWriteTime(fi.FullName, time);
        }
    }
}

// ---------------------------------------------------------------------------------

namespace PictureBrowser
{
    public class Controller
    {
        private Form1 f;
        private ConPicture conPicture;
        private int pic1_Number;

        public Controller(Form1 f, ConPicture conPicture)
        {
            this.conPicture = conPicture;
            this.f = f;
            pic1_Number = 0;
        }

        public int Pic1_Number
        {
            get { return pic1_Number; }
            set
            {
                pic1_Number = value;
                conPicture.Pic1_Number = value;//husk at opdatere i conpic så rotate-metoden og fremkald metoden har det korrekte pic1_Number
            }
        }

        public void PushPicture(int jump)
        {
            Pic1_Number = Pic1_Number + jump;//husk at bruge propertyen
            UpdateImageBoxes();

        }

        public void SetStartPictures()
        {
            UpdateImageBoxes();
        }

        public void UpdateImageBoxes()
        {
            Image pic1 = conPicture.AddAndGet(pic1_Number + 0);
            Image pic2 = conPicture.AddAndGet(pic1_Number + 1);
            Image pic3 = conPicture.AddAndGet(pic1_Number + 2);
            Image pic4 = conPicture.AddAndGet(pic1_Number + 3);

            if (pic1 != null)
            {
                f.picBox1.Image = pic1;
                f.Label_navn1.Text = conPicture.ImageName(pic1_Number + 0);
                f.Label_tid1.Text = conPicture.ImageLastWrite(pic1_Number + 0);
                f.Chk_fremkald1.Checked = conPicture.satTilFremkald(pic1_Number + 0);
            }
            else
            {
                f.picBox1.Image = null;
                f.Label_navn1.Text = null;
                f.Label_tid1.Text = null;
                f.Chk_fremkald1.Checked = false;
            }

            if (pic2 != null)
            {
                f.picBox2.Image = pic2;
                f.Label_navn2.Text = conPicture.ImageName(pic1_Number + 1);
                f.Label_tid2.Text = conPicture.ImageLastWrite(pic1_Number + 1);
                f.Chk_fremkald2.Checked = conPicture.satTilFremkald(pic1_Number + 1);
            }
            else
            {

                f.picBox2.Image = null;
                f.Label_navn2.Text = null;
                f.Label_tid2.Text = null;
                f.Chk_fremkald2.Checked = false;
            }

            if (pic3 != null)
            {
                f.picBox3.Image = pic3;
                f.Label_navn3.Text = conPicture.ImageName(pic1_Number + 2);
                f.Label_tid3.Text = conPicture.ImageLastWrite(pic1_Number + 2);
                f.Chk_fremkald3.Checked = conPicture.satTilFremkald(pic1_Number + 2);
            }
            else
            {
                f.picBox3.Image = null;
                f.Label_navn3.Text = null;
                f.Label_tid3.Text = null;
                f.Chk_fremkald3.Checked = false;
            }

            if (pic4 != null)
            {
                f.picBox4.Image = pic4;
                f.Label_navn4.Text = conPicture.ImageName(pic1_Number + 3);
                f.Label_tid4.Text = conPicture.ImageLastWrite(pic1_Number + 3);
                f.Chk_fremkald4.Checked = conPicture.satTilFremkald(pic1_Number + 3);
            }
            else
            {
                f.picBox4.Image = null;
                f.Label_navn4.Text = null;
                f.Label_tid4.Text = null;
                f.Chk_fremkald4.Checked = false;
            }

            f.picBox1.Refresh();
            f.picBox2.Refresh();
            f.picBox3.Refresh();
            f.picBox4.Refresh();
        }

        public void DeletePicture(int imageBox)
        {
            // f.picBox1.Image.Dispose();
            f.picBox1.Image = null;

            // f.picBox2.Image.Dispose();
            f.picBox2.Image = null;

            // f.picBox3.Image.Dispose();
            f.picBox3.Image = null;

            // f.picBox4.Image.Dispose();
            f.picBox4.Image = null;

            conPicture.DeletePicture(imageBox);
        }

        public void RotateImg(int imagebox, int x_korr)
        {
            conPicture.RotateImg(imagebox, x_korr);
        }

        public void Fremkaldelse(int imageBox, bool fremkald)
        {
            conPicture.Fremkaldelse(imageBox, fremkald);
        }
    }
}

// ---------------------------------------------------------------------------------

namespace PictureBrowser
{
    public class ConPicture
    {
        private Form1 f;
        private string path;

        List<PictureClass> PictureList = new List<PictureClass>();

        public ConPicture(Form1 f, string path)
        {
            this.f = f;
            this.path = path;

            DirectoryInfo d = new DirectoryInfo(path);
            FileInfo[] fiList = d.GetFiles("*.jpg");

            foreach (FileInfo fi in fiList)
            {
                PictureList.Add(new PictureClass(fi));  //Hent fra disk, og tilføj det til listen
            }
        }

        private int pic1_Number;
        public int Pic1_Number
        {
            get { return pic1_Number; }
            set { pic1_Number = value; }
        }

        public void RotateImg(int imagebox, int x_korr)
        {
            int picNbr = imagebox + Pic1_Number - 1;
            bool clockwise = false;

            switch (imagebox)
            {
                case 1:
                    if (x_korr < f.picBox1.Width / 2) clockwise = true;
                    break;
                case 2:
                    if (x_korr < f.picBox2.Width / 2) clockwise = true;
                    break;
                case 3:
                    if (x_korr < f.picBox3.Width / 2) clockwise = true;
                    break;
                case 4:
                    if (x_korr < f.picBox4.Width / 2) clockwise = true;
                    break;
            }

            PictureList[picNbr].RotateImg(clockwise);

            f.picBox1.Refresh();
            f.picBox2.Refresh();
            f.picBox3.Refresh();
            f.picBox4.Refresh();
        }

        public int Count()
        {
            return PictureList.Count;
        }

        public void Fremkaldelse(int imageBox, bool fremkald)
        {
            int picNbr = imageBox + Pic1_Number - 1;
            PictureList[picNbr].Fremkald(fremkald);
        }

        //public void Add(PictureClass pic)
        //{
        //    PictureList.Add(pic);
        //}

        public void Delete(int i)
        {
            PictureList[i].Delete();
            PictureList.RemoveAt(i);
        }

        public Image AddAndGet(int i)
        {
            try
            {
                return PictureList[i].Image;
            }
            catch (System.ArgumentOutOfRangeException)
            {
                return null;
            }
        }

        public string ImageName(int nbrInFileInfoArr)
        {
            string result;
            DirectoryInfo d = new DirectoryInfo(path);
            FileInfo[] fiList = d.GetFiles("*.jpg");

            result = fiList[nbrInFileInfoArr].Name;

            return result;
        }

        public string ImageLastWrite(int nbrInFileInfoArr)
        {
            string result;
            DirectoryInfo d = new DirectoryInfo(path);
            FileInfo[] fiList = d.GetFiles("*.jpg");
            result = Convert.ToString(fiList[nbrInFileInfoArr].LastWriteTime);

            return result;
        }

        public bool satTilFremkald(int nbrInFileInfoArr)
        {
            DirectoryInfo d = new DirectoryInfo(path);
            FileInfo[] fiList = d.GetFiles("*.jpg");

            if (File.Exists(@"c:\fremkaldelse\" + fiList[nbrInFileInfoArr].Name))
                return true;
            else
                return false;

        }

        public void DeletePicture(int imagebox)
        {
            //try
            //{
            // the pointer pic1_Number describes what is the image in box 1 and
            // therefor also the image i box2, box3, box4
            // the argument of this metode
            int picToRemove = Pic1_Number + imagebox - 1;

            Delete(picToRemove);

            f.picBox1.Image = AddAndGet(Pic1_Number + 0);
            f.picBox2.Image = AddAndGet(Pic1_Number + 1);
            f.picBox3.Image = AddAndGet(Pic1_Number + 2);
            f.picBox4.Image = AddAndGet(Pic1_Number + 3);
            //}
            //catch (Exception e)
            //{
            //    MessageBox.Show("E!: " + e.Message);
            //}
        }
    }
}
Avatar billede nielle Nybegynder
19. november 2007 - 22:31 #8
1) Jeg har først og fremmest tilrettet din PictureClass sådan at den nu selv laver lazy-loading.
2) Dette er altså fjernet fra ConPicture.AddAndGet() - som nu nok burde hedde noget andet.
3) Desuden har jeg ændret ConPicture's constructor sådan at den populere hele PictureList-listen allerede ved start.

Du har flere steder, hvor at du er nede og læse hele biblioteket hver gang at du gør noget - det gjorde du f.eks. i din originale AddAndGet() funktion. Det bør du prøve at undgå - find i stedet for filerne i PictureList-listen.

Endeligt synes jeg slet ikke at du bør have en Form i din ConPicture-klasse. Denne klasse burde udelukkende koncentrere sig om at administrer en liste af PictureClass-objekter. I stedet burde din Form1 have en instans af ConPicture og kalde passende metoder i denne for at udtrække de relevante værdier.
Avatar billede koppelgaard Praktikant
20. november 2007 - 18:18 #9
Jeg er taknemmelig for alle gode råd.
Det er også det jeg gerne vil lære.
Ikke kun at få dette her til at fungere, men også at lære hvordan man opbygger et progrsm korrekt.
Jeg prøver at studere den tilrettede kode. Desværre er jeg på vej ud af døren så det må vente til i morgen.
Jeg vender tilbage!

Men send et svar.
Du fortjener pointene !!
Michael
Avatar billede nielle Nybegynder
20. november 2007 - 18:25 #10
Svar :^)
Avatar billede koppelgaard Praktikant
23. november 2007 - 11:21 #11
Så nu har jeg kikket på din kode og rettet til præcist som du sagde.
OG DET VIRKER, SELVFØLGELIG!
Virkelig dejligt.

Det jeg så lige skal have tjek på er :

1) det du mener med lazy loading er denne bid kode
public Image Image
        {
            get
            {
                if (image == null) image = Image.FromFile(fi.FullName);
                return image;
            }
            set { image = value; }
        }
Altså man ser efter om image peger på noget, og gør det ikke det henter man fra disk.
Har jeg ret?

2) det overrasker mig at man slet ikke mærker at alle billeder fra biblioteket loades ind i memory når conpic's constructor køres? Jeg troede, at det ville sluge masser af kræfter fra systemet.

3) jeg har ikke helt styr på hvad der sker her:
internal void Delete()
        {
            this.image.Dispose();
            this.image = null;

            this.fi.Delete();
        }

For det første hvad forstås med internal ?
Og hvorfor skal : "this.image.Dispose()" med. Hvad sker der med dispose?

4)
Hvad mener du om min controller ?
Er den et unødvendigt led ?


Jeg kan godt se at jeg i conpic som du skrive ikke skal have en ref. op til formen.
Det må jeg gå luet væk.

Og tak for hjælpen igen.
Det var lærerigt!
Michael
Avatar billede koppelgaard Praktikant
23. november 2007 - 11:39 #12
Jeg har lige prøvet at pudse picturebrowseren på et bibliotek med 130 billder.
Det var altså nok lige over hvad der kunne være i memory.
Så går det rigtig langsomt.
Måske jeg alligevel må opgive ideen om at gemme billederne i conpic ?

Michael
Avatar billede nielle Nybegynder
25. november 2007 - 12:30 #13
Det er da vist nogle store billeder?!

Måske skulle du overveje at lave thumbnails af dem (der findes direkte et metode kald til dette) og så nøjes med at gemme thumbs'ene i arrayet.

Alternativt kan du overveje om du skulle fjerne de ælste billeder fra arrayet efterhånden som at der er brug for plads.
Avatar billede koppelgaard Praktikant
25. november 2007 - 20:16 #14
Jeg vil prøve at lave thumbnails - tak for tippet.
Har du set mine 4 spørgsmål til din kode 23/11 11:21?
Avatar billede nielle Nybegynder
25. november 2007 - 21:22 #15
Næe, dem havde jeg da vist overset :^|

Ad 1) Ja, dén kode.

Vi loader først selve billedet når der rent faktisk spørges efter det.

Ad 2) Det er der lazy loading kommer ind. Billederne bliver jo slet ikke loadet - det er kun en masse FileInfo'er der bliver indlæst til at starte med.

Ad 3) "internal" er en access-modifier akkurat som "public" eller "private". Jeg har valgt internal fordi der ikke er brug for mere end det.

Delete() bruges til at slette billedet med:

Billedet består af et Image-objekt og en FileInfo-objekt. Det er ikke strengt taget nødvendig at kalde Dispose(), det burde grabage collectoren klare af sig selv efter at den er sat til null. På den anden side kan det næppe skade at frigøre den del af hukomnmelsen der har været brugt til at gemme billedet så hurtig som muligt. Det er det Dispose() gør.

Du havde selv akkurart den samme Dispose() i din DeletePicture() funktion (se 19/11-2007 22:17:32). Men der ledte det til en fejl fordi at du ikke var færdig med at bruge billedet.

Ad 4) En klasse bør have et veldefineret mål og helst kun eet.

PictureClass-klassen holder styr på et Image og dets associerede FileInfo.

ConPicture-klassen holder styr på en liste af PictureClass-objekter, og derfor bør den helst ikke også have form-relateret kode med. Jeg ville selv vælge at gøre den lidt mere tynd på netop det område. Endvidre ville jeg overveje om ConPicture endda skulle nedarve direkte fra List<PictureClass> klassen.

Jeg ville også give den et andet navn som siger lidt mere om den formål - f.eks. "PictureClassList".

Form1-klassen holder styr på formen og dens kontroller.

Et godt design vil forsøge at holde presentations-laget (Form1) så adskildt fra logikken som muligt. Det er her at ConPicture-klassen kommer ind:

Den fungere som en bro mellem formen og logikken omkring hvordan man manipulere med en liste af billeder. Jeg ville nok gøre den lidt slankere og vurdere hvilken del af den kode som mest høre til i Form1 og hvilken del som mest høre til i ConPicture.
Avatar billede koppelgaard Praktikant
30. november 2007 - 17:20 #16
Hej Nielle
Jeg har lavet flere problemer.
Nu har jeg tilføjet metoder til pictureClass i håb om at kunne skrive og læse  EXIF-data.
Metoderne er under linien--------------------

Det kan jeg men så virker rotering ikke. Jeg får alle mulige fejl.
Kan du umiddelbart se noget forkert ?


using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace PictureBrowser
{
    public class PictureClass
    {
        private Image image = null;
        private FileInfo fi;
        private bool fremkaldelse = false;

        public PictureClass(FileInfo fi)
        {
            this.fi = fi;
        }

        internal void Delete()
        {
            this.image.Dispose();
            this.image = null;

            this.fi.Delete();
        }

        public FileInfo FileInfo
        {
            get { return fi; }
            set { fi = value; }
        }

        public Image Image
        {
            get
            {
                if (image == null) image = Image.FromFile(fi.FullName);
                return image;
            }
            set { image = value; }
        }

        public bool Fremkaldelse
        {
            get { return fremkaldelse; }
            set { fremkaldelse = value; }
        }

        public void RotateImg(bool clockwise)
        {
            if (clockwise)
                Image.RotateFlip(RotateFlipType.Rotate90FlipNone);
            else
                Image.RotateFlip(RotateFlipType.Rotate270FlipNone);

            Save();
        }

        public void Fremkald(bool fremkald)
        {
            if (fremkald)
            {
                File.Copy(fi.FullName, @"c:\fremkaldelse\" + fi.Name, true);
                fremkaldelse = true;
            }
            else
            {
                if (File.Exists(@"c:\fremkaldelse\" + fi.Name))
                    File.Delete(@"c:\fremkaldelse\" + fi.Name);

                fremkaldelse = false;
            }
        }

        public void Save()
        {
            Encoding enc = new ASCIIEncoding();
            string timeStr = null;
            foreach (PropertyItem pi in image.PropertyItems)// If the PropertyItem is a timestamp...
                if (pi.Type == 2 /* text */ && pi.Id == 306 /* date and time */)
                    timeStr = enc.GetString(pi.Value).Replace(" ", ":");// get the timestamp.

            string[] a = new string[6];
            a = timeStr.Substring(0, timeStr.Length - 1).Split(':');

            DateTime time = new DateTime(Convert.ToInt32(a[0]), Convert.ToInt32(a[1]), Convert.ToInt32(a[2]), Convert.ToInt32(a[3]), Convert.ToInt32(a[4]), Convert.ToInt32(a[5]));

            Image.Save(fi.FullName, System.Drawing.Imaging.ImageFormat.Jpeg);
            File.SetLastWriteTime(fi.FullName, time);
        }


//-----------------------------------------------------------------------------
        public void WriteNewDescriptionInImage(string NewDescription)
        {
           
            Image Pic;
            PropertyItem[] PropertyItems;
            byte[] bDescription = new Byte[NewDescription.Length];
            int i;
            string FilenameTemp;
            System.Drawing.Imaging.Encoder Enc = System.Drawing.Imaging.Encoder.Transformation;
            EncoderParameters EncParms = new EncoderParameters(1);
            EncoderParameter EncParm;
            ImageCodecInfo CodecInfo = GetEncoderInfo("image/jpeg");

            // copy description into byte array
            for (i = 0; i < NewDescription.Length; i++) bDescription[i] = (byte)NewDescription[i];

            // load the image to change
            string Filename = fi.FullName;
            Pic = Image; //Image.FromFile(Filename);

            // put the new description into the right property item
            PropertyItems = Pic.PropertyItems;
            PropertyItems[0].Id = 0x010e; // 0x010e as specified in EXIF standard
            PropertyItems[0].Type = 2;
            PropertyItems[0].Len = NewDescription.Length;
            PropertyItems[0].Value = bDescription;
            Pic.SetPropertyItem(PropertyItems[0]);

            // we cannot store in the same image, so use a temporary image instead
            FilenameTemp = Filename + ".temp";

            // for lossless rewriting must rotate the image by 90 degrees!
            EncParm = new EncoderParameter(Enc, (long)EncoderValue.TransformRotate90);
            EncParms.Param[0] = EncParm;

            // now write the rotated image with new description
            Pic.Save(FilenameTemp, CodecInfo, EncParms);

            // for computers with low memory and large pictures: release memory now
            Pic.Dispose(); 
            Pic = null;
            GC.Collect();

            // delete the original file, will be replaced later
            System.IO.File.Delete(Filename);

            // now must rotate back the written picture
            Image = Image.FromFile(FilenameTemp);
            EncParm = new EncoderParameter(Enc, (long)EncoderValue.TransformRotate270);
            EncParms.Param[0] = EncParm;
            Image.Save(Filename, CodecInfo, EncParms);

           
            // release memory now
          Image.Dispose();
            Image = null;
          GC.Collect();

            // delete the temporary picture
            System.IO.File.Delete(FilenameTemp);
            Image = Image.FromFile(fi.FullName);
        }
        private static ImageCodecInfo GetEncoderInfo(String mimeType)
        {
            int j;
            ImageCodecInfo[] encoders;
            encoders = ImageCodecInfo.GetImageEncoders();
            for (j = 0; j < encoders.Length; ++j)
            {
                if (encoders[j].MimeType == mimeType)
                    return encoders[j];
            }
            return null;
        }

        public string ReadRemark()
        {
            string result=null;
            Encoding enc = new ASCIIEncoding();           
           
            try
            {
                foreach (PropertyItem pi in this.Image.PropertyItems)
                {
                    if (pi.Id == 0x010e){
                        result =enc.GetString(pi.Value);
                    }
                }
                   
            }
            catch (Exception e)
            {
                return null;// MessageBox.Show(e.Message);
            }
            return result;           
           
        }

    }
}
Avatar billede nielle Nybegynder
01. december 2007 - 10:05 #17
Et par almene råd (i ingen speciel orden).

1) Dit program basere sig på (mindst) to directories:

C:\pic
C:\fremkaldelse\

Disse er hardkodet ind i koden, hvilket betyder at denne skal rekompileres hvis du ønsker at ændre dem. Du bør overveje hvordan du kan trække dem ud af koden sådan at den er lettere at konfigurere

2) Lige nu styrter programmet med en unhandled exeption hvis man forsøger at starte det uden at C:\pic eksistere. Du bør have noget fejlhåndtering.

3) EXIF-funktionaliteten er så omfattende og kompliceret i sin egen ret, at den burde trækkes ud af PictureClass-klassen og samles i sin egen class. Denne kan PictureClass så bruge når den skal lave EXIF ting.

4) Tilføj en app.config fil til dit projekt, og med følgende indhold:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.windows.forms jitDebugging="true" />
</configuration>

Så får du mulighed for at få debuggeren op mens at du afprøver dit program.

5) Du har fire ens billed-kontroller i din form. Overvej om du ikke på et eller andet tidspunkt skulle oprette et Windows Control Library hvor at du samler funktionaliteten for sådan en dims som en selv indeholdt kontrol.

6) Tilbage til punkt 2) - du bør i det hele taget være lidt mere omhyggelig med fejl håndtering; lige nu fejler din PictureClass.Save() med en null-exception hvis blot en af pi'erne i EXIF-headeren ikke er et timestamp.

7) Læg dig fat på en navngivnings-konvention. Enten skriver du engelske funktions-navne eller også skriver du danske. Lige nu har du begge: SkrivBemærkning() og RotateImg(). Desuden bør dine fuktions-navne altid begynde mesd stort (Microsofts efen anbefaling). Du har f.eks. læsBemærkning().
Avatar billede nielle Nybegynder
01. december 2007 - 10:11 #18
Og så til selve problemet.

Svj. kan se skyldes den at du godt nok sætter Image til null i WriteNewDescriptionInImage() kodem, men siden at du også Disposer den så har PictureBox'en stadig en reference til filen. Dermed kan filen ikke slettes og det giver så fejlen.

Den anden fejl som forhindrede at man ikke kunne rotere et billede blev løst med punkt 6 ovenfor.

Og koden:

    public class PictureClass
    {
        private Image image = null;
        private FileInfo fi;
        private bool fremkaldelse = false;

        public PictureClass(FileInfo fi)
        {
            this.fi = fi;
        }

        internal void Delete()
        {
            this.image.Dispose();
            this.image = null;

            this.fi.Delete();
        }

        public FileInfo FileInfo
        {
            get { return fi; }
            set { fi = value; }
        }

        public Image Image
        {
            get
            {
                if (image == null) image = Image.FromFile(fi.FullName);
                return image;
            }
            set { image = value; }
        }

        public bool Fremkaldelse
        {
            get { return fremkaldelse; }
            set { fremkaldelse = value; }
        }

        public void RotateImg(bool clockwise)
        {
            if (clockwise)
                Image.RotateFlip(RotateFlipType.Rotate90FlipNone);
            else
                Image.RotateFlip(RotateFlipType.Rotate270FlipNone);

            Save();
        }

        public void Fremkald(bool fremkald)
        {
            if (fremkald)
            {
                File.Copy(fi.FullName, @"c:\fremkaldelse\" + fi.Name, true);
                fremkaldelse = true;
            }
            else
            {
                if (File.Exists(@"c:\fremkaldelse\" + fi.Name))
                    File.Delete(@"c:\fremkaldelse\" + fi.Name);

                fremkaldelse = false;
            }
        }

        public void Save()
        {
            foreach (PropertyItem pi in image.PropertyItems)  // If the PropertyItem is a timestamp...
                if (pi.Type == 2 &&  // text
                    pi.Id == 306) // date and time
                {
                    Encoding enc = new ASCIIEncoding();
                    string timeStr = enc.GetString(pi.Value).Replace(" ", ":");  // get the timestamp.

                    string[] a = new string[6];
                    a = timeStr.Substring(0, timeStr.Length - 1).Split(':');

                    DateTime time = new DateTime(Convert.ToInt32(a[0]), Convert.ToInt32(a[1]), Convert.ToInt32(a[2]), Convert.ToInt32(a[3]), Convert.ToInt32(a[4]), Convert.ToInt32(a[5]));

                    Image.Save(fi.FullName, System.Drawing.Imaging.ImageFormat.Jpeg);
                    File.SetLastWriteTime(fi.FullName, time);
                }
        }

        //-----------------------------------------------------------------------------

        public void WriteNewDescriptionInImage(string newDescription)
        {
            this.Image.Dispose();
            this.Image = null;
            GC.Collect();

            WriteNewDescriptionInImage(this.fi.FullName, newDescription);
        }

        // Koden tilpasset fra http://www.eggheadcafe.com/articles/20030706.asp
        private void WriteNewDescriptionInImage(string filename, string newDescription)
        {
            byte[] bDescription = new Byte[newDescription.Length];

            // copy description into byte array
            for (int i = 0; i < newDescription.Length; i++)
                bDescription[i] = (byte)newDescription[i];

            // load the image to change
            Image pic = Image.FromFile(filename);

            // put the new description into the right property item
            PropertyItem[] propertyItems = pic.PropertyItems;
            propertyItems[0].Id = 0x010e; // 0x010e as specified in EXIF standard
            propertyItems[0].Type = 2;
            propertyItems[0].Len = newDescription.Length;
            propertyItems[0].Value = bDescription;
            pic.SetPropertyItem(propertyItems[0]);

            // we cannot store in the same image, so use a temporary image instead
            string filenameTemp = filename + ".temp";

            // for lossless rewriting must rotate the image by 90 degrees!
            System.Drawing.Imaging.Encoder enc = System.Drawing.Imaging.Encoder.Transformation;

            EncoderParameter encParm = new EncoderParameter(enc, (long)EncoderValue.TransformRotate90);

            EncoderParameters encParms = new EncoderParameters(1);
            encParms.Param[0] = encParm;

            // now write the rotated image with new description
            ImageCodecInfo codecInfo = GetEncoderInfo("image/jpeg");
            pic.Save(filenameTemp, codecInfo, encParms);

            // for computers with low memory and large pictures: release memory now
            pic.Dispose();
            pic = null;
            GC.Collect();

            // delete the original file, will be replaced later
            System.IO.File.Delete(filename);

            // now must rotate back the written picture
            pic = Image.FromFile(filenameTemp);
            encParm = new EncoderParameter(enc, (long)EncoderValue.TransformRotate270);
            encParms.Param[0] = encParm;
            pic.Save(filename, codecInfo, encParms);

            // release memory now
            pic.Dispose();
            pic = null;
            GC.Collect();

            // delete the temporary picture
            System.IO.File.Delete(filenameTemp);
        }

        private static ImageCodecInfo GetEncoderInfo(String mimeType)
        {
            ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();

            for (int j = 0; j < encoders.Length; ++j)
            {
                if (encoders[j].MimeType == mimeType)
                    return encoders[j];
            }
            return null;
        }

        public string ReadRemark()
        {
            string result = null;
            Encoding enc = new ASCIIEncoding();

            try
            {
                foreach (PropertyItem pi in this.Image.PropertyItems)
                {
                    if (pi.Id == 0x010e)
                    {
                        result = enc.GetString(pi.Value);
                    }
                }
            }
            catch (Exception)
            {
                return null; // MessageBox.Show(e.Message);
            }

            return result;
        }
    }
Avatar billede nielle Nybegynder
01. december 2007 - 10:13 #19
Jeg har i øvrigt omstruktureret WriteNewDescriptionInImage() kden - ved godt at det var mig selv som gav linket til koden, men jeg synes nu alligevel ikke at den oprindelige form var specielt pænt stillet op. ;^)
Avatar billede koppelgaard Praktikant
01. december 2007 - 20:04 #20
Jeg har lige prøvet din kode og det virker - selvfølgelig :-) Dejlig.
Men nu til det svære.
Jeg skal forsøge at rette koden som efter dine råd(som lyder meget fornuftige!).

Til dine råd:
ad 1)
Mon ikke jeg skal gemme biblioteker i en ini-fil?
Og visualisere dem i en form med settlings ?

ad 2)
Du bør have noget fejlhåndtering.
JA helt sikker !

3)
Ja det er vel egetlig en god ide.
Så kan jeg også bruge klassen en anden gang.

4)
Tilføj en app.config fil til dit projekt.

Her er jeg nok på glat is.
Hvor lægges den kode og hvad betyder den ?
Jeg får mulighed for at få debuggeren op mens jeg afprøver programmet.
Og hvad kan jeg se her ?

5)
Windows Control Library
MERE GLAT IS
Det lyder smart, men lyder kombliceret. Vil det sige at jeg kan bruge denne control i andre sammehænge? Eller hvad ?
Kan du give et hint ?


6) Tilbage til punkt 2) - du bør i det hele taget være lidt mere omhyggelig med fejl håndtering; lige nu fejler din PictureClass.Save() med en null-exception hvis blot en af pi'erne i EXIF-headeren ikke er et timestamp.

Ja! Jeg er ikke helt stiv i fejlhåndtering  - endnu.
Men pi-erne er det det kun timestamps? Er det ikke alle mulige informationer om billedet ?

7) Læg dig fat på en navngivnings-konvention.
ENDNU MERE JA!.
jeg er god klar over det. Jeg ville lave det om men var mere fokuseret på at få koden til at virke i første omgang!



Din løsning:
"Svj. kan se skyldes den at du godt nok sætter Image til null i WriteNewDescriptionInImage() kodem, men siden at du også Disposer den så har PictureBox'en stadig en reference til filen. Dermed kan filen ikke slettes og det giver så fejlen."

Det jeg forsøge er at fjerne alle referencer til filen og derfor disposer jeg og sætter til null.
Men du siger, at siden jeg disposer den har pictureboxen stadig en reference til filen.
Jeg trodede at dispose netop fjernede alle forbindelser mellem billede og fil.
Er det forkert ??
Avatar billede nielle Nybegynder
01. december 2007 - 20:40 #21
Ad "ad 1)" ;^)

".NET måden" er ikke at bruge .ini filer, men at bruge .config filer. Config-filer er egentlig blot almindelige XML-filer hvor alle opsætningsoplysningerne ligger. Det fede ved at bruge dem er at .NET kommer med en del biblioteker til at læse og arbejde med sådan nogle.

Jeg synes dog at du skal vente med denne del af dit program og koncentrere dig om billeddelen lige nu. For at holde lidt fokus.

Ad 4) Ude i højre side af VS, i Solution Exploren, højreklikker du på dit projekt. Det bringer kontekstmenuen frem. Vælg "Add", vælg derefter "New Item...". Det bringer "Add New Item" dialogen frem. I denne er der en masse ikoner. Klik på den der hedder "Application Configuration File" og læg mærke til at der i "Name" feltet nu står "App.config" (det er forresten denne fil som du senere skal bruge til punkt 1) ovenfor). Tryk på "Add" knappen. Du får nu en ny fane i VS (App.config). Tilret den som vist ovenfor i 01/12-2007 10:05:40.

Ad 5)

Måske var det også noget du skulle vente lidt med til senere. Det der med at holde fokus. ;^)

Men lidt forklaring allerede nu: Når du opretter et nyt projekt i VS er dette en af de projekttyper man kan vælge imellem. Groft sagt bruger man det til at lave nye kontroller som man kan sætte ind på sin side. Sådan en kontrol kan godt bestå af mange af de "almindelige" kontroller - og i dit tilfælde kan du jo bruge sådan en til at danne en samle-kontrol bestående af en PictureBox, en Label og en Checkboxs (din "fremkald"). Jeg kan ikke lige huske hvad du har på din form, men du har jo i hvertfald 4 grupper af kontroller som høre logisk sammen - en for hvert billede.

Ja, du kan godt genbruge sådan en "super-kontrol" i andre applikationer. Men det skal jo være en speciel type kontrol hvis den lige skal have brug for en ontrol som ser sådan ud. ;^)

Ja det er smart ... nej det er egentlig ikke særligt kompliceret.

Ad 6) For de billede filer jeg prøvede med var der i hvert fald nogle hvor at Save() smed en null-pointer exception fordi at der var et pi som ikke var en timestamp og at din timeStr-variabel derfor forblev med at værre null selv om koden senere forsægte at hendte en substring ud af denne.

Jeg er lidt nysgerrig efter at vide hvorfor du troede at alle pi'er skulle være timestamps? Selvfølgelig indeholder en EXIF header andet end timestamps - den description du forsøger at tilføje er et eksempel på dette.

Ad X)

Dispose() forcere frigivelsen af hukommelse. Normalt er dette gjort ved at sætte noget lig med null, men ikke altid (eller også sker det bare ikke hurtigt nok for programet). Eftersom at hukommelsen ikke var disposet holdt PictureBox'sn stadig fast på filen og den kunne derfor ikke slettes. Dette var katastrofalt i dette tilfælde - algoritmen er baseret på at den kan slette filen og oprette den ændrede fil under samme navn.
Avatar billede koppelgaard Praktikant
03. december 2007 - 08:59 #22
1000 TAK for dine svar.
Ligeså snart jeg har et time smøger jeg ærmerne op og går i gang :-)

Michael
Avatar billede koppelgaard Praktikant
17. december 2007 - 20:46 #23
Hej Nielle
Jeg har sendt dig en mail!!

Til ekspert-brugere : forklaring følger.
Avatar billede nielle Nybegynder
17. december 2007 - 21:05 #24
Den er modtaget. Jeg kigger på den lige så hurtig jeg får tid; jeg er lige travlt opatget af at skrive (endnu) en artikel til Eksperten om regexp: :^)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester