using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using System.IO; using System.Drawing; namespace VisualIntelligentScissors { public delegate void ProgressCallback(int percent); public class GrayBitmap { public GrayBitmap() { gradient = new GradientBitmap(this); } public GrayBitmap Clone() { GrayBitmap clone = new GrayBitmap(); if (bitmap != null) clone.bitmap = (Bitmap)bitmap.Clone(); if (gradient != null) clone.gradient = gradient.Clone(clone); clone.maximumGrayValue = maximumGrayValue; return clone; } private Bitmap bitmap; public Bitmap Bitmap { get { return bitmap; } } private GradientBitmap gradient; public GradientBitmap Gradient { get { return gradient; } /*------------------------------------------------------------------------------*/ set { gradient = value; } // This line wasn't here before /*------------------------------------------------------------------------------*/ } private int maximumGrayValue; #region Loading support /// /// place holder for image loader which comes in text and binary flavors. /// /// name of file containing image /// public void Load(Stream file, out string segmentationPoints, ProgressCallback callback) { Gradient.Reset(); loadBinary(file, out segmentationPoints, callback); } private int parseANumber(BinaryReader b) { StringBuilder number = new StringBuilder(byte.MaxValue.ToString().Length); number.Append(b.ReadChar()); // spin through white space prefix while (number[0] == ' ' || number[0] == '\n') number[0] = b.ReadChar(); // get some digits. ASSUME nothing but digits and white space char ch; while ((ch = b.ReadChar()) != ' ' && ch != '\n') number.Append(ch); return Int32.Parse(number.ToString()); } /// /// load a binary pgm file. /// /// file containing the image to load /// string private void loadBinary(Stream file, out string segmentationPoints, ProgressCallback callback) { // Create the reader for data. using (BinaryReader r = new BinaryReader(file)) { // read in a line. char[] chars = new char[255]; chars = r.ReadChars(2); if (chars[1] != '5') { file.Position = 0; // reset to starting position of stream. loadAscii(file, out segmentationPoints, callback); return; } //spin through the comments. while (chars[0] != '\n') chars[0] = r.ReadChar(); chars[0] = (char)r.PeekChar(); while (chars[0] == '#') { while (chars[0] != '\n') chars[0] = r.ReadChar(); chars[0] = (char)r.PeekChar(); } segmentationPoints = string.Empty; // TODO: read segment points from binary file // next up: width height and max gray value. int imgCols = parseANumber(r); int imgRows = parseANumber(r); maximumGrayValue = parseANumber(r); // now read in the image all at once (can do this with binary images). bitmap = new Bitmap(imgCols, imgRows); byte[] imageRaw = new byte[imgRows * imgCols]; imageRaw = r.ReadBytes(imgRows * imgCols); int rr = 0; while (rr < imgRows) { callback(rr * 100 / imgRows); int cc = 0; while (cc < imgCols) { byte pixelValue = imageRaw[(imgCols * rr) + cc]; bitmap.SetPixel(cc, rr, Color.FromArgb(pixelValue, pixelValue, pixelValue)); cc++; } rr++; } } } /// /// ascii version of the image loader. works fine. /// but is dog-slow (when debugging only). Would go faster if it read the whole file in at once instead /// of line by line? /// /// file containing the image to load. /// string private void loadAscii(Stream file, out string segmentationPoints, ProgressCallback callback) { using (StreamReader sr = new StreamReader(file)) { // grok out the magic number etc, which are in plain text. String line = sr.ReadLine(); if (line != "P2") throw new ApplicationException("unsupported PGM filetype, try type P2 or P5 only."); // spin through comments if any. segmentationPoints = string.Empty; while ((line = sr.ReadLine()).StartsWith("#")) if (Regex.IsMatch(line, frmMain.SegmentPointRegex)) segmentationPoints = line.Substring(line.IndexOf("(")); // parse out the width and height. string[] pieces; pieces = line.Split(' '); int imgCols = Int32.Parse(pieces[0]); int imgRows = Int32.Parse(pieces[1]); // Initialize the image with the size just read in. bitmap = new Bitmap(imgCols, imgRows); using (DirectBitmapWriter dba = new DirectBitmapWriter(bitmap)) { // get the max gray value. maximumGrayValue = Int32.Parse(sr.ReadLine()); // Prepare to receive pixels: first row, first column int pixelRow = 0, pixelColumn = 0; while (pixelRow < imgRows) { // Each line will contain only a few of the pixels on a single row of the image. line = sr.ReadLine(); string[] colEntries = line.Split(' '); for (int ii = 0; ii < colEntries.Length; ii++) { if (colEntries[ii].Length == 0) continue; // skip " " double spaces byte thisColor = byte.Parse(colEntries[ii]); dba.SetGrayPixel(pixelColumn, pixelRow, thisColor); if (++pixelColumn == imgCols) { pixelColumn = 0; pixelRow++; callback(pixelRow * 100 / imgRows); } } } } } } #endregion } }