MLibraryV2.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Drawing.Drawing2D;
  5. using System.Drawing.Imaging;
  6. using System.IO;
  7. using System.IO.Compression;
  8. using System.Runtime.InteropServices;
  9. using System.Text;
  10. using System.Windows.Forms;
  11. namespace LibraryEditor
  12. {
  13. /// <summary>
  14. /// V2 Library
  15. /// Uses DXT5 Images
  16. /// Supports Frames (When at LibVersion 3)
  17. /// </summary>
  18. public sealed class MLibraryV2
  19. {
  20. public const int LibVersion = 3;
  21. public static bool Load = true;
  22. public string FileName;
  23. public List<MImage> Images = new List<MImage>();
  24. public FrameSet Frames = new FrameSet();
  25. public List<int> IndexList = new List<int>();
  26. public int Count;
  27. private bool _initialized;
  28. private BinaryReader _reader;
  29. private FileStream _stream;
  30. public MLibraryV2(string filename)
  31. {
  32. FileName = filename;
  33. Initialize();
  34. Close();
  35. }
  36. public void Initialize()
  37. {
  38. int CurrentVersion;
  39. _initialized = true;
  40. if (!File.Exists(FileName))
  41. return;
  42. _stream = new FileStream(FileName, FileMode.Open, FileAccess.ReadWrite);
  43. _reader = new BinaryReader(_stream);
  44. CurrentVersion = _reader.ReadInt32();
  45. if (CurrentVersion < 2)
  46. {
  47. MessageBox.Show("Wrong version, expecting lib version: " + LibVersion.ToString() + " found version: " + CurrentVersion.ToString() + ".", "Failed to open", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
  48. return;
  49. }
  50. Count = _reader.ReadInt32();
  51. Images = new List<MImage>();
  52. IndexList = new List<int>();
  53. int frameSeek = 0;
  54. if (CurrentVersion >= 3)
  55. {
  56. frameSeek = _reader.ReadInt32();
  57. }
  58. for (int i = 0; i < Count; i++)
  59. IndexList.Add(_reader.ReadInt32());
  60. for (int i = 0; i < Count; i++)
  61. Images.Add(null);
  62. for (int i = 0; i < Count; i++)
  63. CheckImage(i);
  64. if (CurrentVersion >= 3)
  65. {
  66. _stream.Seek(frameSeek, SeekOrigin.Begin);
  67. var frameCount = _reader.ReadInt32();
  68. for (int i = 0; i < frameCount; i++)
  69. {
  70. Frames.Add((MirAction)_reader.ReadByte(), new Frame(_reader));
  71. }
  72. }
  73. }
  74. public void Close()
  75. {
  76. if (_stream != null)
  77. _stream.Dispose();
  78. }
  79. public void Save()
  80. {
  81. Close();
  82. MemoryStream stream = new MemoryStream();
  83. BinaryWriter writer = new BinaryWriter(stream);
  84. Count = Images.Count;
  85. IndexList.Clear();
  86. int offSet = (4 + 4 + 4) + (Count * 4);
  87. for (int i = 0; i < Count; i++)
  88. {
  89. IndexList.Add((int)stream.Length + offSet);
  90. Images[i].Save(writer);
  91. }
  92. var frameSeek = (int)stream.Length + offSet;
  93. writer.Flush();
  94. byte[] fBytes = stream.ToArray();
  95. _stream = File.Create(FileName);
  96. writer = new BinaryWriter(_stream);
  97. writer.Write(LibVersion);
  98. writer.Write(Count);
  99. writer.Write(frameSeek);
  100. for (int i = 0; i < Count; i++)
  101. writer.Write(IndexList[i]);
  102. writer.Write(fBytes);
  103. writer.Write(Frames.Keys.Count);
  104. foreach (var action in Frames.Keys)
  105. {
  106. writer.Write((byte)action);
  107. Frames[action].Save(writer);
  108. }
  109. writer.Flush();
  110. writer.Close();
  111. writer.Dispose();
  112. Close();
  113. }
  114. private void CheckImage(int index)
  115. {
  116. if (!_initialized)
  117. Initialize();
  118. if (Images == null || index < 0 || index >= Images.Count)
  119. return;
  120. if (Images[index] == null)
  121. {
  122. _stream.Position = IndexList[index];
  123. Images[index] = new MImage(_reader);
  124. }
  125. if (!Load) return;
  126. MImage mi = Images[index];
  127. if (!mi.TextureValid)
  128. {
  129. _stream.Seek(IndexList[index] + 12, SeekOrigin.Begin);
  130. mi.CreateTexture(_reader);
  131. }
  132. }
  133. public Point GetOffSet(int index)
  134. {
  135. if (!_initialized)
  136. Initialize();
  137. if (Images == null || index < 0 || index >= Images.Count)
  138. return Point.Empty;
  139. if (Images[index] == null)
  140. {
  141. _stream.Seek(IndexList[index], SeekOrigin.Begin);
  142. Images[index] = new MImage(_reader);
  143. }
  144. return new Point(Images[index].X, Images[index].Y);
  145. }
  146. public Size GetSize(int index)
  147. {
  148. if (!_initialized)
  149. Initialize();
  150. if (Images == null || index < 0 || index >= Images.Count)
  151. return Size.Empty;
  152. if (Images[index] == null)
  153. {
  154. _stream.Seek(IndexList[index], SeekOrigin.Begin);
  155. Images[index] = new MImage(_reader);
  156. }
  157. return new Size(Images[index].Width, Images[index].Height);
  158. }
  159. public MImage GetMImage(int index)
  160. {
  161. if (index < 0 || index >= Images.Count)
  162. return null;
  163. return Images[index];
  164. }
  165. public Bitmap GetPreview(int index)
  166. {
  167. if (index < 0 || index >= Images.Count)
  168. return new Bitmap(1, 1);
  169. MImage image = Images[index];
  170. if (image == null || image.Image == null)
  171. return new Bitmap(1, 1);
  172. if (image.Preview == null)
  173. image.CreatePreview();
  174. return image.Preview;
  175. }
  176. public void AddImage(Bitmap image, short x, short y, bool removeBlack = true)
  177. {
  178. MImage mImage = new MImage(image, removeBlack) { X = x, Y = y };
  179. Count++;
  180. Images.Add(mImage);
  181. }
  182. public void AddImage(Bitmap image, Bitmap maskImage, short x, short y, bool removeBlack = true)
  183. {
  184. MImage mImage = new MImage(image, maskImage, removeBlack) { X = x, Y = y };
  185. Count++;
  186. Images.Add(mImage);
  187. }
  188. public void ReplaceImage(int Index, Bitmap image, short x, short y, bool removeBlack = true)
  189. {
  190. MImage mImage = new MImage(image, removeBlack) { X = x, Y = y };
  191. Images[Index] = mImage;
  192. }
  193. public void InsertImage(int index, Bitmap image, short x, short y, bool removeBlack = true)
  194. {
  195. MImage mImage = new MImage(image, removeBlack) { X = x, Y = y };
  196. Count++;
  197. Images.Insert(index, mImage);
  198. }
  199. public void RemoveImage(int index)
  200. {
  201. if (Images == null || Count <= 1)
  202. {
  203. Count = 0;
  204. Images = new List<MImage>();
  205. return;
  206. }
  207. Count--;
  208. Images.RemoveAt(index);
  209. }
  210. public static bool CompareBytes(byte[] a, byte[] b)
  211. {
  212. if (a == b) return true;
  213. if (a == null || b == null || a.Length != b.Length) return false;
  214. for (int i = 0; i < a.Length; i++) if (a[i] != b[i]) return false;
  215. return true;
  216. }
  217. public void RemoveBlanks(bool safe = false)
  218. {
  219. for (int i = Count - 1; i >= 0; i--)
  220. {
  221. if (Images[i].FBytes == null || Images[i].FBytes.Length <= 24)
  222. {
  223. if (!safe)
  224. RemoveImage(i);
  225. else if (Images[i].X == 0 && Images[i].Y == 0)
  226. RemoveImage(i);
  227. }
  228. }
  229. }
  230. public sealed class MImage
  231. {
  232. public short Width, Height, X, Y, ShadowX, ShadowY;
  233. public byte Shadow;
  234. public int Length;
  235. public byte[] FBytes;
  236. public bool TextureValid;
  237. public Bitmap Image, Preview;
  238. //layer 2:
  239. public short MaskWidth, MaskHeight, MaskX, MaskY;
  240. public int MaskLength;
  241. public byte[] MaskFBytes;
  242. public Bitmap MaskImage;
  243. public Boolean HasMask;
  244. public MImage(BinaryReader reader)
  245. {
  246. //read layer 1
  247. Width = reader.ReadInt16();
  248. Height = reader.ReadInt16();
  249. X = reader.ReadInt16();
  250. Y = reader.ReadInt16();
  251. ShadowX = reader.ReadInt16();
  252. ShadowY = reader.ReadInt16();
  253. Shadow = reader.ReadByte();
  254. Length = reader.ReadInt32();
  255. FBytes = reader.ReadBytes(Length);
  256. //check if there's a second layer and read it
  257. HasMask = ((Shadow >> 7) == 1) ? true : false;
  258. if (HasMask)
  259. {
  260. MaskWidth = reader.ReadInt16();
  261. MaskHeight = reader.ReadInt16();
  262. MaskX = reader.ReadInt16();
  263. MaskY = reader.ReadInt16();
  264. MaskLength = reader.ReadInt32();
  265. MaskFBytes = reader.ReadBytes(MaskLength);
  266. }
  267. }
  268. public MImage(byte[] image, short Width, short Height)//only use this when converting from old to new type!
  269. {
  270. FBytes = image;
  271. this.Width = Width;
  272. this.Height = Height;
  273. }
  274. public MImage(Bitmap image, bool removeBlack = true)
  275. {
  276. if (image == null)
  277. {
  278. FBytes = new byte[0];
  279. return;
  280. }
  281. Width = (short)image.Width;
  282. Height = (short)image.Height;
  283. Image = image;// FixImageSize(image);
  284. FBytes = ConvertBitmapToArray(Image, removeBlack);
  285. }
  286. public MImage(Bitmap image, Bitmap Maskimage, bool removeBlack = true)
  287. {
  288. if (image == null)
  289. {
  290. FBytes = new byte[0];
  291. return;
  292. }
  293. Width = (short)image.Width;
  294. Height = (short)image.Height;
  295. Image = image;// FixImageSize(image);
  296. FBytes = ConvertBitmapToArray(Image, removeBlack);
  297. if (Maskimage == null)
  298. {
  299. MaskFBytes = new byte[0];
  300. return;
  301. }
  302. HasMask = true;
  303. MaskWidth = (short)Maskimage.Width;
  304. MaskHeight = (short)Maskimage.Height;
  305. MaskImage = Maskimage;// FixImageSize(Maskimage);
  306. MaskFBytes = ConvertBitmapToArray(MaskImage, removeBlack);
  307. }
  308. private Bitmap FixImageSize(Bitmap input)
  309. {
  310. int w = input.Width + (4 - input.Width % 4) % 4;
  311. int h = input.Height + (4 - input.Height % 4) % 4;
  312. if (input.Width != w || input.Height != h)
  313. {
  314. Bitmap temp = new Bitmap(w, h);
  315. using (Graphics g = Graphics.FromImage(temp))
  316. {
  317. g.Clear(Color.Transparent);
  318. g.InterpolationMode = InterpolationMode.NearestNeighbor;
  319. g.DrawImage(input, 0, 0);
  320. g.Save();
  321. }
  322. input.Dispose();
  323. input = temp;
  324. }
  325. return input;
  326. }
  327. private unsafe byte[] ConvertBitmapToArray(Bitmap input, bool removeBlack = true)
  328. {
  329. BitmapData data = input.LockBits(new Rectangle(0, 0, input.Width, input.Height), ImageLockMode.ReadOnly,
  330. PixelFormat.Format32bppArgb);
  331. byte[] pixels = new byte[input.Width * input.Height * 4];
  332. Marshal.Copy(data.Scan0, pixels, 0, pixels.Length);
  333. input.UnlockBits(data);
  334. if (removeBlack)
  335. {
  336. for (int i = 0; i < pixels.Length; i += 4)
  337. {
  338. if (pixels[i] == 0 && pixels[i + 1] == 0 && pixels[i + 2] == 0)
  339. pixels[i + 3] = 0; //Make Transparent
  340. }
  341. }
  342. byte[] compressedBytes;
  343. compressedBytes = Compress(pixels);
  344. return compressedBytes;
  345. }
  346. public unsafe void CreateTexture(BinaryReader reader)
  347. {
  348. int w = Width;// +(4 - Width % 4) % 4;
  349. int h = Height;// +(4 - Height % 4) % 4;
  350. if (w < 2 || h < 2) return;
  351. Image = new Bitmap(w, h);
  352. BitmapData data = Image.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite,
  353. PixelFormat.Format32bppArgb);
  354. byte[] dest = Decompress(FBytes);
  355. Marshal.Copy(dest, 0, data.Scan0, dest.Length);
  356. Image.UnlockBits(data);
  357. dest = null;
  358. if (HasMask)
  359. {
  360. w = MaskWidth;// +(4 - MaskWidth % 4) % 4;
  361. h = MaskHeight;// +(4 - MaskHeight % 4) % 4;
  362. if (w == 0 || h == 0)
  363. {
  364. return;
  365. }
  366. try
  367. {
  368. MaskImage = new Bitmap(w, h);
  369. data = MaskImage.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite,
  370. PixelFormat.Format32bppArgb);
  371. dest = Decompress(MaskFBytes);
  372. Marshal.Copy(dest, 0, data.Scan0, dest.Length);
  373. MaskImage.UnlockBits(data);
  374. }
  375. catch (Exception ex)
  376. {
  377. File.AppendAllText(@".\Error.txt",
  378. string.Format("[{0}] {1}{2}", DateTime.Now, ex, Environment.NewLine));
  379. }
  380. }
  381. dest = null;
  382. }
  383. public void Save(BinaryWriter writer)
  384. {
  385. writer.Write(Width);
  386. writer.Write(Height);
  387. writer.Write(X);
  388. writer.Write(Y);
  389. writer.Write(ShadowX);
  390. writer.Write(ShadowY);
  391. writer.Write(HasMask ? (byte)(Shadow | 0x80) : (byte)Shadow);
  392. writer.Write(FBytes.Length);
  393. writer.Write(FBytes);
  394. if (HasMask)
  395. {
  396. writer.Write(MaskWidth);
  397. writer.Write(MaskHeight);
  398. writer.Write(MaskX);
  399. writer.Write(MaskY);
  400. writer.Write(MaskFBytes.Length);
  401. writer.Write(MaskFBytes);
  402. }
  403. }
  404. public static byte[] Compress(byte[] raw)
  405. {
  406. using (MemoryStream memory = new MemoryStream())
  407. {
  408. using (GZipStream gzip = new GZipStream(memory,
  409. CompressionMode.Compress, true))
  410. {
  411. gzip.Write(raw, 0, raw.Length);
  412. }
  413. return memory.ToArray();
  414. }
  415. }
  416. static byte[] Decompress(byte[] gzip)
  417. {
  418. // Create a GZIP stream with decompression mode.
  419. // ... Then create a buffer and write into while reading from the GZIP stream.
  420. using (GZipStream stream = new GZipStream(new MemoryStream(gzip), CompressionMode.Decompress))
  421. {
  422. const int size = 4096;
  423. byte[] buffer = new byte[size];
  424. using (MemoryStream memory = new MemoryStream())
  425. {
  426. int count = 0;
  427. do
  428. {
  429. count = stream.Read(buffer, 0, size);
  430. if (count > 0)
  431. {
  432. memory.Write(buffer, 0, count);
  433. }
  434. }
  435. while (count > 0);
  436. return memory.ToArray();
  437. }
  438. }
  439. }
  440. public void CreatePreview()
  441. {
  442. if (Image == null)
  443. {
  444. Preview = new Bitmap(1, 1);
  445. return;
  446. }
  447. Preview = new Bitmap(64, 64);
  448. using (Graphics g = Graphics.FromImage(Preview))
  449. {
  450. g.InterpolationMode = InterpolationMode.Low;//HighQualityBicubic
  451. g.Clear(Color.Transparent);
  452. int w = Math.Min((int)Width, 64);
  453. int h = Math.Min((int)Height, 64);
  454. g.DrawImage(Image, new Rectangle((64 - w) / 2, (64 - h) / 2, w, h), new Rectangle(0, 0, Width, Height), GraphicsUnit.Pixel);
  455. g.Save();
  456. }
  457. }
  458. }
  459. }
  460. }