/// <summary> /// Crops image to given size /// </summary> /// <param name="startX"></param> /// <param name="startY"></param> /// <param name="endX"></param> /// <param name="endY"></param> public void Crop(int startX, int startY, int endX, int endY) { if (startX > endX || startY > endY || startX < 0 || startY < 0 || endX > data.GetLength(0) || endY > data.GetLength(1)) { throw new ArgumentException("Invalid input"); } Pixel[,] temp = new Pixel[endX - startX, endY - startY]; int xcount = startX; int ycount = startY; for (int i = 0; i < temp.GetLength(0); i++) { for (int j = 0; j < temp.GetLength(1); j++) { temp[i, j] = data[xcount, ycount]; ycount++; } ycount = startY; xcount++; } data = temp; }
/// <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)); }