using System; using System.Collections.Generic; using System.Text; using System.IO; namespace Orvid.Graphics.ImageFormats { public class XpmImage : ImageFormat { public override void Save(Image i, Stream dest) { XpmInternals.Save(i, dest); } public override Image Load(Stream s) { return XpmInternals.Load(s); } // Please note, everything below this // point was originally from a plugin // for Paint.Net, the plugin is available here: // http://forums.getpaint.net/index.php?/topic/14512-xpm-file-type-plugin/ // // // The source has been modified for use in this library. // // This disclaimer was last // modified on August 9, 2011. #region Internals private static class XpmInternals { #region Support Methods private static int ColorHash(Pixel colour) { int num = 0; if (colour.A > 0) { num = (((((0xff - colour.R) * 0x100) * 0x100) + ((0xff - colour.G) * 0x100)) + (0xff - colour.B)) + 1; } return num; } private static void IncrementChars(byte[] ascii) { ascii[0] = (byte)(ascii[0] + 1); for (int i = 0; i < ascii.Length; i++) { if (ascii[i] > 0x7e) { ascii[i + 1] = (byte)(ascii[i + 1] + 1); ascii[i] = 0x20; } } for (int j = 0; j < ascii.Length; j++) { if ((ascii[j] == 0x22) || (ascii[j] == 0x5c)) { ascii[j] = (byte)(ascii[j] + 1); } } } private static bool ReadLine(Stream input, out string line) { byte[] bytes = new byte[512]; for (int i = 0; i < 512; i++) { int num2 = input.ReadByte(); switch (num2) { case -1: line = ""; return true; case 10: case 13: line = Encoding.ASCII.GetString(bytes); return false; } bytes[i] = (byte)num2; } line = Encoding.ASCII.GetString(bytes); return false; } private static void WriteASCII(string text, Stream output) { byte[] bytes = Encoding.ASCII.GetBytes(text); output.Write(bytes, 0, bytes.Length); output.Flush(); } #endregion #region Load public static Image Load(Stream input) { string str; if (ReadLine(input, out str) || (str.Trim().Substring(0, 6).CompareTo("/* XPM") != 0)) { throw new Exception("No valid XPM header found"); } do { if (ReadLine(input, out str)) { throw new Exception("Cannot find the values section of the file"); } } while (str.Trim().Substring(0, 1).CompareTo("\"") != 0); char[] separator = new char[] { ' ', '\t', '"' }; string[] strArray = str.Split(separator); if (strArray.Length < 6) { throw new Exception("Invalid values section of the file"); } int width = Convert.ToInt32(strArray[1]); int height = Convert.ToInt32(strArray[2]); int num3 = Convert.ToInt32(strArray[3]); int length = Convert.ToInt32(strArray[4]); Image image = new Image(width, height); do { if (ReadLine(input, out str)) { throw new Exception("Cannot find the color section of the file"); } } while (str.Trim().Substring(0, 1).CompareTo("\"") != 0); Dictionary dictionary = new Dictionary(); for (int i = 0; i < num3; i++) { string str2 = str.Trim(); string key = str2.Substring(1, length); strArray = str2.Substring(length + 1).Split(separator); if (strArray.Length < 4) { throw new Exception("Invalid color entry"); } if (strArray[1].CompareTo("c") != 0) { throw new Exception("Non color type found, unhandled"); } if (strArray[2].CompareTo("None") == 0) { Pixel color = new Pixel(true); dictionary.Add(key, color); } else { if (strArray[2].Substring(0, 1).CompareTo("#") != 0) { throw new Exception("Non RGB color type found, unhandled"); } byte red = (byte)Convert.ToInt32(strArray[2].Substring(1, 2), 0x10); byte green = (byte)Convert.ToInt32(strArray[2].Substring(3, 2), 0x10); byte blue = (byte)Convert.ToInt32(strArray[2].Substring(5, 2), 0x10); Pixel color2 = new Pixel(red, green, blue, 255); dictionary.Add(key, color2); } if (ReadLine(input, out str)) { throw new Exception("Corrupt color section in the file"); } } do { if (ReadLine(input, out str)) { throw new Exception("Cannot find the pixel section of the file"); } } while (str.Trim().Substring(0, 1).CompareTo("\"") != 0); for (int j = 0; j < height; j++) { string str4 = str.Trim(); if (str4.Substring(1).IndexOf('"') != (width * length)) { throw new Exception("Corrupt pixel entry in the file"); } int startIndex = 1; int x = 0; while (x < width) { Pixel color3; string str5 = str4.Substring(startIndex, length); if (!dictionary.TryGetValue(str5, out color3)) { throw new Exception("Unknown pixel value - weird"); } image.SetPixel((uint)x, (uint)j, color3); x++; startIndex += length; } if (ReadLine(input, out str)) { throw new Exception("Corrupt pixel section in the file"); } } return image; } #endregion #region Save public static void Save(Image img, Stream dest) { WriteASCII("/* XPM */\nstatic char * pixmap[] = {\n", dest); int height = img.Height; int width = img.Width; SortedList list = new SortedList(); int num3 = 0; for (int i = 0; i < width; i++) { for (int m = 0; m < width; m++) { Pixel pixel = img.GetPixel((uint)i, (uint)m); int key = ColorHash(pixel); if (!list.ContainsKey(key)) { list.Add(key, pixel); num3++; } } } int num7 = 0; int num8 = 0; while (num8 < list.Count) { num8 += 93; num7++; } WriteASCII("/* width height num_colors chars_per_pixel */\n", dest); WriteASCII("\"" + width.ToString() + " " + height.ToString() + " " + num3.ToString() + " " + num7.ToString() + "\",\n", dest); Dictionary dictionary = new Dictionary(); byte[] ascii = new byte[num7]; for (int j = 0; j < num7; j++) { ascii[j] = 0x20; } ascii[0] = 0x1f; WriteASCII("/* colors */\n", dest); foreach (KeyValuePair pair in list) { IncrementChars(ascii); string str2 = Encoding.ASCII.GetString(ascii); Pixel color2 = pair.Value; if (color2.A > 0) { WriteASCII("\"" + str2 + " c #" + color2.R.ToString("x").PadLeft(2, '0') + color2.G.ToString("x").PadLeft(2, '0') + color2.B.ToString("x").PadLeft(2, '0') + "\",\n", dest); } else { WriteASCII("\"" + str2 + " c None\",\n", dest); } dictionary.Add(pair.Key, str2); } WriteASCII("/* pixels */\n", dest); for (int k = 0; k < height; k++) { string str5 = "\""; for (int n = 0; n < width; n++) { string str6; int num13 = ColorHash(img.GetPixel((uint)n, (uint)k)); if (!dictionary.TryGetValue(num13, out str6)) { throw new Exception("Colour missing from the stringList, weird"); } str5 = str5 + str6; } if (k == (height - 1)) { str5 = str5 + "\"\n"; } else { str5 = str5 + "\",\n"; } WriteASCII(str5, dest); } WriteASCII("};\n", dest); } #endregion } #endregion } }