// Spludlow Software // Copyright © Samuel P. Ludlow 2020 All Rights Reserved // Distributed under the terms of the GNU General Public License version 3 // Distributed WITHOUT ANY WARRANTY; without implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE // https://www.spludlow.co.uk/LICENCE.TXT // The Spludlow logo is a registered trademark of Samuel P. Ludlow and may not be used without permission // v1.14 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; using System.Data; using System.Drawing; using System.Drawing.Imaging; namespace Spludlow.Drawing { public class PGM { // P1 Portable bitmap ASCII // P2 Portable graymap ASCII // P3 Portable pixmap ASCII // P4 Portable bitmap Binary // P5 Portable graymap Binary // P6 Portable pixmap Binary // PBM uses 1 bit per pixel // PGM uses 8 bits per pixel // PPM uses 24 bits per pixel, swap round RGB-BGR // only currently support binary with Format24bppRgb private static DataTable FileTypeTable; static PGM() { FileTypeTable = Spludlow.Data.TextTable.ReadText(new string[] { "Magic Mode Heads Format", "Char* Char Int32 String", "1 A 2 Format1bppIndexed", "2 A 3 Format8bppIndexed", "3 A 3 Format24bppRgb", "4 B 2 Format1bppIndexed", "5 B 3 Format8bppIndexed", "6 B 3 Format24bppRgb", }); } /// /// Convert PGM bitmap to specified ImageFormat /// Only supports Binary 24 bit at moment /// public static void Convert(string sourceFilename, string targetFilename, ImageFormat imageFormat, int dpi) { byte[] data = File.ReadAllBytes(sourceFilename); if ((char)data[0] != 'P') throw new ApplicationException("PGM; Exmpected 'P' in first byte."); char magicVersion = (char)data[1]; DataRow row = FileTypeTable.Rows.Find(magicVersion); if (row == null) throw new ApplicationException("Bad magic number version:\t" + magicVersion); bool binary = false; if ((char)row["Mode"] == 'B') binary = true; int headLineCount = (int)row["Heads"]; string[] headlines = ReadLines(data, headLineCount); if (headLineCount != headlines.Length) throw new ApplicationException("Did not read all header lines."); string[] widthHeight = headlines[1].Split(new char[] { ' ' }); int width = Int32.Parse(widthHeight[0]); int height = Int32.Parse(widthHeight[1]); int maxValue = 1; if (headLineCount >= 3) maxValue = Int32.Parse(headlines[2]); if (width <= 0 || height <= 0) throw new ApplicationException("PGM, Bad size:\t" + width + "x" + height + "@" + maxValue + " head:" + headlines[1]); PixelFormat pixelFormat = (PixelFormat)Enum.Parse(typeof(PixelFormat), (string)row["Format"]); if (pixelFormat != PixelFormat.Format24bppRgb) throw new ApplicationException("PGM only supports Format24bppRgb"); using (Bitmap bitmap = new Bitmap(width, height, pixelFormat)) { bitmap.SetResolution(dpi, dpi); byte[] bitmapData = Spludlow.Drawing.Bitmaps.ReadBitmapData(bitmap, pixelFormat); if (binary == true) { int startIndex = data.Length - (width * height * 3); int oddBytesOnEnd = (bitmapData.Length / height) - (width * 3); for (int y = 0; y < height; ++y) { int sourceIndex = startIndex + (y * (width * 3)); int targetIndex = (y * (width * 3)) + (y * oddBytesOnEnd); for (int x = 0; x < width; ++x) { bitmapData[targetIndex + (x * 3) + 0] = data[sourceIndex + (x * 3) + 2]; bitmapData[targetIndex + (x * 3) + 1] = data[sourceIndex + (x * 3) + 1]; bitmapData[targetIndex + (x * 3) + 2] = data[sourceIndex + (x * 3) + 0]; } } } else { throw new ApplicationException("PGM; Text format not currently supported."); } Spludlow.Drawing.Bitmaps.WriteBitmapData(bitmap, bitmapData, pixelFormat); bitmap.Save(targetFilename, imageFormat); } } private static string[] ReadLines(byte[] data, int lineCount) { List items = new List(); using (MemoryStream memoryStream = new MemoryStream(data)) { using (StreamReader reader = new StreamReader(memoryStream)) { do { string line = reader.ReadLine().Trim(); if (line.Length == 0 || line.StartsWith("#") == true) continue; items.Add(line); } while (items.Count < lineCount); } } return items.ToArray(); } } }