/// <summary>
        /// Converts a string (usually from file) to an Image object
        /// </summary>
        /// <param name="imgData">the image data in string format</param>
        /// <returns>the deserialized Image</returns>
        public Image Parse(string imgData)
        {
            string formatRgx  = '^' + formatSpec + '$';
            string commentRgx = '^' + commentTag + ".+$";
            string sizeRgx    = @"^\d+ \d+$";
            string rangeRgx   = @"^\d+$";
            string pixelRgx   = @"^(:?\d+ ?)+$";

            //each line in the "file"
            string[] lines = imgData.Split
                                 (new string[] { Environment.NewLine },
                                 StringSplitOptions.None);

            //the minimum length of any pgm file is 4 lines
            if (lines.Length < 4)
            {
                throw new InvalidDataException
                          ("Invalid number of lines " + lines.Length +
                          " is not enough");
            }

            //first line should be format specifier
            checkFormat(lines[0], true, 0, formatRgx);
            //second line should be either comment or size specifier
            checkOneFormat(lines[1], true, 1, commentRgx, sizeRgx);

            string[] metadata = lines.Skip(1)                                      //skip format specifier
                                .TakeWhile(line => checkFormat(line, false, -1, commentRgx))
                                                                                   //take only metadata lines, line numbering is irrelevant here
                                .Select(comment => comment = comment.Substring(1)) //remove #
                                .ToArray();

            //line after comments should be size specifier
            checkFormat(lines[metadata.Length + 1], true,
                        metadata.Length + 1, sizeRgx);

            int[] size = lines[metadata.Length + 1].Split(' ')
                         .Select(num => int.Parse(num))
                         .ToArray();

            //line after size specifier should be range
            checkFormat(lines[metadata.Length + 2], true,
                        metadata.Length + 2, rangeRgx);

            int maxRange = int.Parse(lines[metadata.Length + 2]);

            //the rest of the string should be filled with pixels
            for (int i = metadata.Length + 3; i < lines.Length; i++)
            {
                checkFormat(lines[i], true, i, pixelRgx);
            }

            int[] pixelsData = lines.Skip(metadata.Length + 3) //skip metadata and stuff
                               .Select(line => line.Split(' ').Select(num => int.Parse(num)))
                                                               //parse each collection of collection
                               .SelectMany(list => list.ToArray()).ToArray();
            //flatten the array

            //verify maxRange of each pixel
            for (int i = 0; i < pixelsData.Length; i++)
            {
                if (pixelsData[i] > maxRange)
                {
                    throw new InvalidDataException
                              ("Pixel " + i + " expected at most : " +
                              maxRange + Environment.NewLine + "Actual : " +
                              pixelsData[i]);
                }
            }

            //checking amount of pixel corresponds to specified size
            if (pixelsData.Length != size[0] * size[1])
            {
                throw new InvalidDataException("Expected size : " +
                                               size[0] * size[1] + ", Actual size : "
                                               + pixelsData.Length);
            }

            //filling the resulting Pixel rectangular array
            Pixel[,] pixels = new Pixel[size[0], size[1]];
            for (int i = 0; i < pixelsData.Length; i++)
            {
                pixels[i % pixels.GetLength(0),
                       i / pixels.GetLength(0)] =
                    new Pixel(pixelsData[i]);
            }

            return(new Image(string.Join(Environment.NewLine, metadata),
                             maxRange, pixels));
        }
Exemple #2
0
        public Image Parse(string imageData)
        {
            // Getting information from string

            string[] lines = imageData.Split(new string[] { System.Environment.NewLine }, StringSplitOptions.None);

            int currentLine = 1;

            string metadata = "";

            while (currentLine < lines.Length)
            {
                if (lines[currentLine].StartsWith("#"))
                {
                    metadata += lines[currentLine].Substring(2) + System.Environment.NewLine;
                }
                else
                {
                    break;
                }

                currentLine++;
            }
            metadata = metadata.Trim();

            string[] widthHeight    = lines[currentLine].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            string   widthInString  = widthHeight[0].Trim();
            string   heightInString = widthHeight[1].Trim();

            currentLine++;

            string maxRangeInString = lines[currentLine].Trim();

            currentLine++;

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

            while (currentLine < lines.Length)
            {
                string[] numbersOnLine = lines[currentLine].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (string number in numbersOnLine)
                {
                    numbersInStrings.Add(number);
                }

                currentLine++;
            }

            // Validating the information and parsing it into the right type

            int width;
            int height;

            if (int.TryParse(widthInString, out width) == false)
            {
                throw new InvalidDataException();
            }
            if (int.TryParse(heightInString, out height) == false)
            {
                throw new InvalidDataException();
            }
            if (width <= 0 || height <= 0)
            {
                throw new InvalidDataException();
            }

            int maxRange;

            if (int.TryParse(maxRangeInString, out maxRange) == false)
            {
                throw new InvalidDataException();
            }
            if (maxRange <= 0)
            {
                throw new InvalidDataException();
            }

            if (numbersInStrings.Count / 3.0 != height * width)
            {
                throw new InvalidDataException();
            }

            int[] numbers = new int[numbersInStrings.Count];
            for (int i = 0; i < numbersInStrings.Count; i++)
            {
                int number;
                if (int.TryParse(numbersInStrings[i], out number) == false)
                {
                    throw new InvalidDataException();
                }
                if (number > maxRange)
                {
                    throw new InvalidDataException();
                }

                numbers[i] = number;
            }

            // Creating image object

            int red   = 0;
            int green = 0;
            int blue  = 0;

            List <Pixel> pixels = new List <Pixel>();

            for (int i = 0; i < numbers.Length; i++)
            {
                if (i % 3 == 0)
                {
                    red = numbers[i];
                }
                else if ((i - 1) % 3 == 0)
                {
                    green = numbers[i];
                }
                else if ((i - 2) % 3 == 0)
                {
                    blue = numbers[i];
                    Pixel pixel = new Pixel(red, green, blue);
                    pixels.Add(pixel);
                }
            }

            // Putting all the values from pixels list (1D) into the image 2D array
            Pixel[,] image = new Pixel[height, width];
            for (int row = 0; row < height; row++)
            {
                for (int column = 0; column < width; column++)
                {
                    image[row, column] = pixels[row * width + column];
                }
            }

            return(new Image(metadata, maxRange, image));
        }