/// <summary> /// parses image and write arrays to output file /// </summary> /// <param name="options">parsed command line args</param> /// <returns>error code</returns> static int ParseFontImage(ParseOptions options) { try { var bitmap = new Bitmap(Image.FromFile(options.InputFileName)); var settings = PixelSettings.FromFile(options.PixelSettingsPath); var mapper = new PixelMapper(bitmap, settings); var map = mapper.MapPixels(); OutputFileFormatter.WriteOutput(map, options.OutputFileName, options.SingleArray); } catch (Exception e) { if (e is FileNotFoundException) { ConsoleLogger.WriteMessage($"File not found or invalid file name \"{e.Message}\"", MessageType.Error); return((int)ErrorCode.FileNotFound); } ConsoleLogger.WriteMessage(e.Message + "\n" + e.InnerException?.Message, MessageType.Error); if (e is ArgumentException) { return((int)ErrorCode.FileParsingError); } return((int)ErrorCode.UknownError); } return((int)ErrorCode.NoError); }
/// <summary> /// Fills bitmap with solid color and draws a grid on it /// </summary> /// <param name="patternWidthCount">width of grid in symbols (cells)</param> /// <param name="patternHeightCount">height of grid in symbols (cells)</param> /// <returns>production ready bitmap</returns> public Bitmap GeneratePattern(int patternWidthCount, int patternHeightCount, EnumerationStyle enumerationStyle, byte[] sampleData = null) { if (enumerationStyle != EnumerationStyle.None) { patternHeightCount++; patternWidthCount++; } var pattentWidth = patternWidthCount * _settings.SymbolWidth + (patternWidthCount - 1) * _settings.DelimeterWidth; var patternHeight = patternHeightCount * _settings.SymbolHeight + (patternHeightCount - 1) * _settings.DelimeterHeight; var pattern = new Bitmap(pattentWidth, patternHeight); ConsoleLogger.WriteMessage($"Generating pattern\nBitmap size {pattentWidth} x {patternHeight} px", MessageType.Info); FillBackground(pattern); DrawVerticalLines(pattern); DrawHorizontalLines(pattern); Enumerate(pattern, enumerationStyle); if (sampleData != null) { FillSampleData(pattern, sampleData, enumerationStyle); } return(pattern); }
static int Main(string[] args) { var options = new CommandLineOptions(); if (!Parser.Default.ParseArguments(args, options, (verb, suboptions) => { _invokedVerb = verb; _suboptions = (CommonOptions)suboptions; })) { Environment.Exit((int)ErrorCode.ArgumentsMismatch); } int errorCode = (int)ErrorCode.NoError; if (_invokedVerb == "generate") { errorCode = GeneratePattern((GenerateOptions)_suboptions); } if (_invokedVerb == "parse") { errorCode = ParseFontImage((ParseOptions)_suboptions); } if (errorCode == (int)ErrorCode.NoError) { ConsoleLogger.WriteMessage($"SUCCESS! \nFile written: \"{_suboptions.OutputFileName}\"", MessageType.Info); } return(errorCode); }
static int Main(string[] args) { // Parse command-line arguments try { Parser.Default.ParseArguments <GenerateOptions, ParseOptions>(args) .MapResult( (GenerateOptions options) => GeneratePattern(options), (ParseOptions options) => ParseFontImage(options), // just exit, this usually means that no arguments were given (errs) => { System.Environment.Exit(1); return(null); }); } catch (Exception e) { NotifyError(e); return(1); } ConsoleLogger.WriteMessage($"SUCCESS! \nFile written: \"{_outputFileName}\"", MessageType.Info); return(0); }
// Notifies user about error details private static void NotifyError(ErrorCode errorCode) { // todo: add more details switch (errorCode) { case ErrorCode.UknownError: ConsoleLogger.WriteMessage("There was error, but we have no idea why.", MessageType.Error); break; case ErrorCode.ArgumentsMismatch: ConsoleLogger.WriteMessage("Error parsing arguments. Check command line.", MessageType.Error); break; case ErrorCode.FileNotFound: ConsoleLogger.WriteMessage("File was not found", MessageType.Error); break; case ErrorCode.FileParsingError: ConsoleLogger.WriteMessage("Error parsing file", MessageType.Error); break; case ErrorCode.ArgumentsNotParsed: //do nothings as this usually means that no arguments were passed to command line break; } }
/// <summary> /// Fills bitmap with solid color and draws a grid on it /// </summary> /// <param name="patternWidthCount">width of grid in symbols (cells)</param> /// <param name="patternHeightCount">height of grid in symbols (cells)</param> /// <returns>production ready bitmap</returns> public Bitmap GeneratePattern(int patternWidthCount, int patternHeightCount) { var pattentWidth = patternWidthCount * _settings.SymbolWidth + (patternWidthCount - 1) * _settings.DelimeterWidth; var patternHeight = patternHeightCount * _settings.SymbolHeight + (patternHeightCount - 1) * _settings.DelimeterHeight; var pattern = new Bitmap(pattentWidth, patternHeight); ConsoleLogger.WriteMessage($"Generating pattern\nBitmap size {pattentWidth} x {patternHeight} px", MessageType.Info); FillBackground(pattern); DrawVerticalLines(pattern); DrawHorizontalLines(pattern); return(pattern); }
// Notifies user about error details private static void NotifyError(Exception e) { switch (e) { case FileNotFoundException _: ConsoleLogger.WriteMessage($"File not found: {e.Message}", MessageType.Error); return; case ArgumentException _: ConsoleLogger.WriteMessage($"Error parsing file: {e.Message}", MessageType.Error); return; default: ConsoleLogger.WriteMessage($"Unexpected error: {e.Message}", MessageType.Error); return; } }
static int Main(string[] args) { // Parse command-line arguments var errorCode = Parser.Default.ParseArguments <GenerateOptions, ParseOptions>(args) .MapResult( (GenerateOptions options) => GeneratePattern(options), (ParseOptions options) => ParseFontImage(options), errs => ErrorCode.ArgumentsNotParsed); if (errorCode == ErrorCode.NoError) { ConsoleLogger.WriteMessage($"SUCCESS! \nFile written: \"{_outputFileName}\"", MessageType.Info); } else { NotifyError(errorCode); } return((int)errorCode); }
/// <summary> /// Grid pattern generation and writing to file /// </summary> /// <param name="options">parsed command line args</param> /// <returns>error code</returns> static int GeneratePattern(GenerateOptions options) { try { var settings = PixelSettings.FromFile(options.PixelSettingsPath); var generator = new PatternGenerator(settings); var pattern = generator.GeneratePattern(options.PatternWidth, options.PatternHeight); pattern.Save(options.OutputFileName); } catch (Exception e) { ConsoleLogger.WriteMessage(e.Message + "\n" + e.InnerException?.Message, MessageType.Error); if (e is FileNotFoundException) { return((int)ErrorCode.FileNotFound); } return((int)ErrorCode.UknownError); } return((int)ErrorCode.NoError); }
/// <summary> /// map all cells in grid to byte arrays /// </summary> /// <returns>list of mapped arrays</returns> public List <byte[]> MapPixels() { ConsoleLogger.WriteMessage($"Parsing bitmap to byte array", MessageType.Info); if (_settings.SymbolWidth * _settings.SymbolHeight * _settings.BitsPerPixel % 8 != 0) { ConsoleLogger.WriteMessage("Number of bits per symbol is not a multiple of 8. Output values will be padded", MessageType.Warning); } var symbols = new List <byte[]>(); for (int j = 0; j < _bitmap.Height; j += _settings.SymbolHeight + _settings.DelimeterHeight) { for (int i = 0; i < _bitmap.Width; i += _settings.SymbolWidth + _settings.DelimeterWidth) { symbols.Add(ProcessSymbol(i, i + _settings.SymbolWidth, j, j + _settings.SymbolHeight)); } } return(symbols); }
/// <summary> /// Opens a filestream and deserialize JSON formatted <see cref="PixelSettings"/> /// </summary> /// <param name="fileName">Path to file</param> /// <returns><see cref="PixelSettings"/> isntance</returns> public static PixelSettings FromFile(string fileName) { try { using (var stream = File.OpenRead(fileName)) { var serializer = new DataContractJsonSerializer(typeof(PixelSettings), new DataContractJsonSerializerSettings() { UseSimpleDictionaryFormat = true }); ConsoleLogger.WriteMessage($"Loaded configuration from {stream.Name}", MessageType.Info); return(serializer.ReadObject(stream) as PixelSettings); } } catch (IOException e) { ConsoleLogger.WriteMessage("Error reading from config file", MessageType.Error); ConsoleLogger.WriteMessage(e.Message, MessageType.Error); throw; } }
/// <summary> /// map all cells in grid to byte arrays /// </summary> /// <param name="skipHeaders">will skip first row and first column</param> /// <returns>list of mapped arrays</returns> public List <byte[]> MapPixels(bool skipHeaders) { ConsoleLogger.WriteMessage($"Parsing bitmap to byte array", MessageType.Info); if (_settings.SymbolWidth * _settings.SymbolHeight * _settings.BitsPerPixel % 8 != 0) { ConsoleLogger.WriteMessage("Number of bits per symbol is not a multiple of 8. Output values will be padded", MessageType.Warning); } var symbols = new List <byte[]>(); var columnCount = (_bitmap.Width + _settings.DelimeterWidth) / (_settings.SymbolWidth + _settings.DelimeterWidth); var rowCount = (_bitmap.Height + _settings.DelimeterHeight) / (_settings.SymbolHeight + _settings.DelimeterHeight); var pixelTracker = new BitmapPixelTracker(_settings.CellsLookupDirection) { // Skip first row and columnt if they were used for rows/columns numbers XStart = skipHeaders ? 1 : 0, XEnd = columnCount, XDelta = 1, // Skip first row and columnt if they were used for rows/columns numbers YStart = skipHeaders ? 1 : 0, YEnd = rowCount, YDelta = 1 }; // Process cells (symbols) // in this case pixel coords will correspond to cell foreach (var pixel in pixelTracker) { // get symbol top leftPoint var symbolX = pixel.X * (_settings.DelimeterWidth + _settings.SymbolWidth); var symbolY = pixel.Y * (_settings.DelimeterHeight + _settings.SymbolHeight); symbols.Add(ProcessSymbol(symbolX, symbolX + _settings.SymbolWidth, symbolY, symbolY + _settings.SymbolHeight)); } return(symbols); }
/// <summary> /// Grid pattern generation and writing to file /// </summary> /// <param name="options">parsed command line args</param> /// <returns>error code</returns> static ErrorCode GeneratePattern(GenerateOptions options) { try { if (options.ExcessValue != null) { return(ErrorCode.ArgumentsMismatch); } Settings = PixelSettings.FromFile(options.PixelSettingsPath); _outputFileName = options.OutputFileName; var generator = new PatternGenerator(Settings); byte[] sampleData = null; if (options.InputFileName != null) { sampleData = ParseDataFile(options.InputFileName); } var pattern = generator.GeneratePattern(options.PatternWidth, options.PatternHeight, options.EnumerationStyle, sampleData); pattern.Save(options.OutputFileName); } catch (Exception e) { switch (e) { case PixelProcessingException _: ConsoleLogger.WriteMessage(e.Message, MessageType.Error); return(ErrorCode.FileParsingError); case FileNotFoundException _: return(ErrorCode.FileNotFound); default: return(ErrorCode.UknownError); } } return(ErrorCode.NoError); }
/// <summary> /// Writes formatted output of symbols parser's result /// </summary> /// <param name="symbols">byte[] representation of symbols</param> /// <param name="fileName">path to the file to create</param> /// <param name="singleArray">shall output be written to single array or one array per symbol</param> public static void WriteOutput(List <byte[]> symbols, string fileName, bool singleArray = false) { try { using (var stream = File.Open(fileName, FileMode.Create)) using (var writer = new StreamWriter(stream)) { // Make header writer.WriteLine("//"); writer.WriteLine("//"); writer.WriteLine("// Generated with PixelPixie (c) 2016"); writer.WriteLine("//"); writer.WriteLine("//"); writer.WriteLine(); writer.WriteLine(); // Write array(s) if (singleArray) { var totalLength = (from s in symbols select s.Length).Sum(); writer.Write($"unsigned char c[{totalLength}] = \n"); writer.Write("{\n "); int elementCounter = 0; for (int i = 0; i < symbols.Count; i++) { for (int j = 0; j < symbols[i].Length; j++) { writer.Write($"0x{symbols[i][j]:X2}"); elementCounter++; if (j + 1 < symbols[i].Length || i < symbols.Count - 1) { writer.Write(", "); if (elementCounter % ElementsPerLine == ElementsPerLine - 1) { writer.Write("\n "); } } } } writer.Write("\n};"); writer.WriteLine("\n"); } else { for (int i = 0; i < symbols.Count; i++) { writer.WriteLine($"//symbol {i + 1}"); writer.Write($"unsigned char c{i + 1}[{symbols[i].Length}] = \n"); writer.Write("{\n "); for (int j = 0; j < symbols[i].Length; j++) { writer.Write($"0x{symbols[i][j]:X2}"); if (j + 1 < symbols[i].Length) { writer.Write(", "); if (j % ElementsPerLine == ElementsPerLine - 1) { writer.Write("\n "); } } } writer.Write("\n};"); writer.WriteLine("\n"); } } } } catch (IOException) { ConsoleLogger.WriteMessage("Failed writing output", MessageType.Error); throw; } }
/// <summary> /// Writes formatted output of symbols parser's result /// </summary> /// <param name="symbols">byte[] representation of symbols</param> /// <param name="fileName">path to the file to create</param> /// <param name="singleArray">shall output be written to single array or one array per symbol</param> /// <param name="contentOnly">for single array: output will be just array contents, without name or curly braces</param> public static void WriteOutput(List <byte[]> symbols, string fileName, bool singleArray = false, bool contentOnly = false) { try { using (var stream = File.Open(fileName, FileMode.Create)) using (var writer = new StreamWriter(stream)) { var fileVersionInfo = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location); var copyRight = fileVersionInfo.LegalCopyright; var version = fileVersionInfo.ProductVersion; // Make header writer.WriteLine("//"); writer.WriteLine("//"); writer.WriteLine($"// Generated with PixelPixie v.{version} {copyRight}"); writer.WriteLine("//"); writer.WriteLine("//"); writer.WriteLine(); writer.WriteLine(); // Write array(s) if (singleArray) { var totalLength = (from s in symbols select s.Length).Sum(); if (contentOnly == false) { writer.Write($"unsigned char c[{totalLength}] = \n"); writer.Write("{\n "); } else { writer.Write(" "); } int elementCounter = 0; for (int i = 0; i < symbols.Count; i++) { for (int j = 0; j < symbols[i].Length; j++) { writer.Write($"0x{symbols[i][j]:X2}"); elementCounter++; if (j + 1 < symbols[i].Length || i < symbols.Count - 1) { writer.Write(", "); if (elementCounter % ElementsPerLine == ElementsPerLine - 1) { writer.Write("\n "); } } } } if (contentOnly == false) { writer.Write("\n};"); } writer.WriteLine("\n"); } else { for (int i = 0; i < symbols.Count; i++) { writer.WriteLine($"//symbol {i + 1}"); writer.Write($"unsigned char c{i + 1}[{symbols[i].Length}] = \n"); writer.Write("{\n "); for (int j = 0; j < symbols[i].Length; j++) { writer.Write($"0x{symbols[i][j]:X2}"); if (j + 1 < symbols[i].Length) { writer.Write(", "); if (j % ElementsPerLine == ElementsPerLine - 1) { writer.Write("\n "); } } } writer.Write("\n};"); writer.WriteLine("\n"); } } } } catch (IOException) { ConsoleLogger.WriteMessage("Failed writing output", MessageType.Error); throw; } }