PropertyItem2.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. using System;
  2. using System.Drawing;
  3. using System.Drawing.Imaging;
  4. using System.Globalization;
  5. using System.IO;
  6. using System.Reflection;
  7. using System.Runtime.CompilerServices;
  8. using System.Runtime.Serialization.Formatters.Binary;
  9. namespace PaintDotNet.SystemLayer
  10. {
  11. /// <summary>
  12. /// Re-implements System.Drawing.PropertyItem so that the data is serializable.
  13. /// </summary>
  14. [Serializable]
  15. internal sealed class PropertyItem2
  16. {
  17. private const string piElementName = "exif";
  18. private const string idPropertyName = "id";
  19. private const string lenPropertyName = "len";
  20. private const string typePropertyName = "type";
  21. private const string valuePropertyName = "value";
  22. private int id;
  23. private int len;
  24. private short type;
  25. private byte[] value;
  26. public int Id
  27. {
  28. get
  29. {
  30. return id;
  31. }
  32. }
  33. public int Len
  34. {
  35. get
  36. {
  37. return len;
  38. }
  39. }
  40. public short Type
  41. {
  42. get
  43. {
  44. return type;
  45. }
  46. }
  47. public byte[] Value
  48. {
  49. get
  50. {
  51. return (byte[])value.Clone();
  52. }
  53. }
  54. public PropertyItem2(int id, int len, short type, byte[] value)
  55. {
  56. this.id = id;
  57. this.len = len;
  58. this.type = type;
  59. if (value == null)
  60. {
  61. this.value = new byte[0];
  62. }
  63. else
  64. {
  65. this.value = (byte[])value.Clone();
  66. }
  67. if (len != this.value.Length)
  68. {
  69. Tracing.Ping("len != value.Length: id=" + id + ", type=" + type);
  70. }
  71. }
  72. public string ToBlob()
  73. {
  74. string blob = string.Format("<{0} {1}=\"{2}\" {3}=\"{4}\" {5}=\"{6}\" {7}=\"{8}\" />",
  75. piElementName,
  76. idPropertyName, this.id.ToString(CultureInfo.InvariantCulture),
  77. lenPropertyName, this.len.ToString(CultureInfo.InvariantCulture),
  78. typePropertyName, this.type.ToString(CultureInfo.InvariantCulture),
  79. valuePropertyName, Convert.ToBase64String(this.value));
  80. return blob;
  81. }
  82. [MethodImpl(MethodImplOptions.Synchronized)]
  83. public PropertyItem ToPropertyItem()
  84. {
  85. PropertyItem pi = GetPropertyItem();
  86. pi.Id = this.Id;
  87. pi.Len = this.Len;
  88. pi.Type = this.Type;
  89. pi.Value = this.Value;
  90. return pi;
  91. }
  92. public static PropertyItem2 FromPropertyItem(PropertyItem pi)
  93. {
  94. return new PropertyItem2(pi.Id, pi.Len, pi.Type, pi.Value);
  95. }
  96. private static string GetProperty(string blob, string propertyName)
  97. {
  98. string findMe = propertyName + "=\"";
  99. int startIndex = blob.IndexOf(findMe) + findMe.Length;
  100. int endIndex = blob.IndexOf("\"", startIndex);
  101. string propertyValue = blob.Substring(startIndex, endIndex - startIndex);
  102. return propertyValue;
  103. }
  104. public static PropertyItem2 FromBlob(string blob)
  105. {
  106. PropertyItem2 pi2;
  107. if (blob.Length > 0 && blob[0] == '<')
  108. {
  109. string idStr = GetProperty(blob, idPropertyName);
  110. string lenStr = GetProperty(blob, lenPropertyName);
  111. string typeStr = GetProperty(blob, typePropertyName);
  112. string valueStr = GetProperty(blob, valuePropertyName);
  113. int id = int.Parse(idStr, CultureInfo.InvariantCulture);
  114. int len = int.Parse(lenStr, CultureInfo.InvariantCulture);
  115. short type = short.Parse(typeStr, CultureInfo.InvariantCulture);
  116. byte[] value = Convert.FromBase64String(valueStr);
  117. pi2 = new PropertyItem2(id, len, type, value);
  118. }
  119. else
  120. {
  121. // Old way of serializing: .NET serialized!
  122. byte[] bytes = Convert.FromBase64String(blob);
  123. MemoryStream ms = new MemoryStream(bytes);
  124. BinaryFormatter bf = new BinaryFormatter();
  125. SerializationFallbackBinder sfb = new SerializationFallbackBinder();
  126. sfb.AddAssembly(Assembly.GetExecutingAssembly());
  127. bf.Binder = sfb;
  128. pi2 = (PropertyItem2)bf.Deserialize(ms);
  129. }
  130. return pi2;
  131. }
  132. // System.Drawing.Imaging.PropertyItem does not have a public constructor
  133. // So, as per the documentation, we have to "steal" one.
  134. // Quite ridiculous.
  135. // This depends on PropertyItem.png being an embedded resource in this assembly.
  136. private static Image propertyItemImage;
  137. [MethodImpl(MethodImplOptions.Synchronized)]
  138. private static PropertyItem GetPropertyItem()
  139. {
  140. if (propertyItemImage == null)
  141. {
  142. Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("PaintDotNet.SystemLayer.PropertyItem.png");
  143. propertyItemImage = Image.FromStream(stream);
  144. }
  145. PropertyItem pi = propertyItemImage.PropertyItems[0];
  146. pi.Id = 0;
  147. pi.Len = 0;
  148. pi.Type = 0;
  149. pi.Value = new byte[0];
  150. return pi;
  151. }
  152. }
  153. }