0

I have a TCP application where I can request images from a folder on the server from the client. If I request a small folder, it works fine. If its a big folder it will throw an out of memory exception. But then anything after that, even a folder with 1 file will throw the same out of memory exception.

I thought it might have been the thread that is out of memory, so I tried to put it on a separate thread and task but neither worked. Here is the code I'm using:

    public static void Images(string path)
    {
        new Task(() =>
        {
            try
            {
                string root = lookupDirectoryPath("Application data");
                string backupPath = root + @"\Apple Computer\MobileSync\";
                string imagePath = backupPath + path;

                if (Directory.Exists(imagePath))
                {
                    String[] allfiles = Directory.GetFiles(imagePath, "*.*", SearchOption.AllDirectories);
                    List<Image> allImages = new List<Image>();

                    foreach (string file in allfiles)
                    {
                        using (FileStream stream = new FileStream(file, FileMode.Open, FileAccess.Read))
                        {
                            if (IsImage(stream))
                            {
                                allImages.Add(Image.FromFile(file));
                            }
                        }
                    }

                    if (allImages.Count > 0)
                    {
                        byte[] data = imageListToByteArray(allImages);
                        serverSendByteArray(data, 12);
                    }
                    else
                    {
                        serverSendByteArray(Encoding.Default.GetBytes("backup contained no images"), 1);
                    }
                }
                else
                {
                    serverSendByteArray(Encoding.Default.GetBytes("iphone backup folder does not exist"), 1);
                }
            }
            catch (Exception ex)
            {
                if (ex.GetType().IsAssignableFrom(typeof(OutOfMemoryException)))
                {
                    serverSendByteArray(Encoding.Default.GetBytes("Out of memory, could not send iphone images"), 1);
                }
                else
                {
                    serverSendByteArray(Encoding.Default.GetBytes("Unknown error, could not send iphone images"), 1);
                }
            }
        }).Start();
    }

The exception gets thrown at allImages.Add(Image.FromFile(file));

this is the isImage() function:

        public static bool IsImage(Stream stream)
    {
        stream.Seek(0, SeekOrigin.Begin);

        List<string> jpg = new List<string> { "FF", "D8" };
        List<string> bmp = new List<string> { "42", "4D" };
        List<string> gif = new List<string> { "47", "49", "46" };
        List<string> png = new List<string> { "89", "50", "4E", "47", "0D", "0A", "1A", "0A" };
        List<List<string>> imgTypes = new List<List<string>> { jpg, bmp, gif, png };

        List<string> bytesIterated = new List<string>();

        for (int i = 0; i < 8; i++)
        {
            string bit = stream.ReadByte().ToString("X2");
            bytesIterated.Add(bit);

            bool isImage = imgTypes.Any(img => !img.Except(bytesIterated).Any());
            if (isImage)
            {
                return true;
            }
        }

        return false;
    }

Thanks for any help

Rachel Dockter
  • 946
  • 1
  • 8
  • 21

3 Answers3

0

Image.FromFile seem to cause the error. In the following question it was a corrupeted image file or running out of file handles, Image.FromStream() did it better. Worth a try cause you already have the stream open:

https://stackoverflow.com/a/2216338/7803013

Community
  • 1
  • 1
eMpTy
  • 30
  • 4
0

I tried and I can reproduce your problem. It is definitely out of memory and nothing like "It just seems to be" the memory usage increases to about 4 GB and then the error shows up. Console output is just to see what's happening there.

The Image object seems to be not the best way to save the data.

I tried this and got this to work with many many files. Maybe you can change the code to fit your needs:

            String[] allfiles = Directory.GetFiles(imagePath, "*.*", SearchOption.AllDirectories);
            //List<Image> allImages = new List<Image>();
            List<Byte[]> allImagesBytes = new List<Byte[]>();

            foreach (string file in allfiles)
            {
                using (FileStream stream = new FileStream(file, FileMode.Open, FileAccess.Read))
                {
                    if (IsImage(stream))
                    {
                        Console.Clear();
                        Console.Write(allImagesBytes.Count());
                        //allImages.Add(Image.FromStream(stream));
                        //allImages.Add(Image.FromFile(file));
                        allImagesBytes.Add(File.ReadAllBytes(file));

                    }
                }
            }
eMpTy
  • 30
  • 4
  • thanks, the problem would be converting it back into images, if you had an array of bytes with continuous image code, how would you seperate them? I could put a symbol inbetween like a # byte and do it like that but did you have anything in mind? – Rachel Dockter Apr 03 '17 at 18:58
  • convert the list/array of byte arrays in json format could be an approach – eMpTy Apr 03 '17 at 19:04
  • hmm yeh, well this was the only answer that helped really so ill accept this one, thanks – Rachel Dockter Apr 03 '17 at 19:07
-1

Try changing this

using (FileStream stream = new FileStream(file, FileMode.Open, FileAccess.Read))
{
    if (IsImage(stream))
    {
        allImages.Add(Image.FromFile(file));
    }
}
...
if (allImages.Count > 0)
{
    byte[] data = imageListToByteArray(allImages);
    serverSendByteArray(data, 12);
}

into this:

using (FileStream stream = new FileStream(file, FileMode.Open, FileAccess.Read))
{
    if (IsImage(stream))
    {
        allImages.Add(Image.FromFile(file));
    }
    stream.Close();
}
....
if (allImages.Count > 0)
{
    byte[] data = imageListToByteArray(allImages);
    foreach(Image img in allImages)
    {
        img.Dispose();
    }
    serverSendByteArray(data, 12);
}                    
Cleptus
  • 3,446
  • 4
  • 28
  • 34