PsdBinaryWriter.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Photoshop PSD FileType Plugin for Paint.NET
  4. // http://psdplugin.codeplex.com/
  5. //
  6. // This software is provided under the MIT License:
  7. // Copyright (c) 2006-2007 Frank Blumenberg
  8. // Copyright (c) 2010-2016 Tao Yue
  9. //
  10. // Portions of this file are provided under the BSD 3-clause License:
  11. // Copyright (c) 2006, Jonas Beckeman
  12. //
  13. // See LICENSE.txt for complete licensing and attribution information.
  14. //
  15. /////////////////////////////////////////////////////////////////////////////////
  16. using System;
  17. using System.Drawing;
  18. using System.IO;
  19. using System.Text;
  20. namespace PhotoshopFile
  21. {
  22. /// <summary>
  23. /// Writes PSD data types in big-endian byte order.
  24. /// </summary>
  25. public class PsdBinaryWriter : IDisposable
  26. {
  27. private BinaryWriter writer;
  28. private Encoding encoding;
  29. internal Stream BaseStream
  30. {
  31. get
  32. {
  33. // Flush the writer so that the Stream.Position is correct.
  34. Flush();
  35. return writer.BaseStream;
  36. }
  37. }
  38. public PsdBinaryWriter(Stream stream, Encoding encoding)
  39. {
  40. this.encoding = encoding;
  41. // Specifying ASCII encoding will help catch any accidental calls to
  42. // BinaryWriter.Write(String). Since we do not own the Stream, the
  43. // constructor is called with leaveOpen = true.
  44. writer = new BinaryWriter(stream, Encoding.ASCII);
  45. }
  46. public void Flush()
  47. {
  48. writer.Flush();
  49. }
  50. public void Write(Rectangle rect)
  51. {
  52. Write(rect.Top);
  53. Write(rect.Left);
  54. Write(rect.Bottom);
  55. Write(rect.Right);
  56. }
  57. /// <summary>
  58. /// Pad the length of a block to a multiple.
  59. /// </summary>
  60. /// <param name="startPosition">Starting position of the padded block.</param>
  61. /// <param name="padMultiple">Byte multiple to pad to.</param>
  62. public void WritePadding(long startPosition, int padMultiple)
  63. {
  64. var length = writer.BaseStream.Position - startPosition;
  65. var padBytes = Util.GetPadding((int)length, padMultiple);
  66. for (long i = 0; i < padBytes; i++)
  67. {
  68. writer.Write((byte)0);
  69. }
  70. }
  71. /// <summary>
  72. /// Write string as ASCII characters, without a length prefix.
  73. /// </summary>
  74. public void WriteAsciiChars(string s)
  75. {
  76. var bytes = Encoding.ASCII.GetBytes(s);
  77. writer.Write(bytes);
  78. }
  79. /// <summary>
  80. /// Writes a Pascal string using the specified encoding.
  81. /// </summary>
  82. /// <param name="s">Unicode string to convert to the encoding.</param>
  83. /// <param name="padMultiple">Byte multiple that the Pascal string is padded to.</param>
  84. /// <param name="maxBytes">Maximum number of bytes to write.</param>
  85. public void WritePascalString(string s, int padMultiple, byte maxBytes = 255)
  86. {
  87. var startPosition = writer.BaseStream.Position;
  88. byte[] bytesArray = encoding.GetBytes(s);
  89. if (bytesArray.Length > maxBytes)
  90. {
  91. var tempArray = new byte[maxBytes];
  92. Array.Copy(bytesArray, tempArray, maxBytes);
  93. bytesArray = tempArray;
  94. }
  95. writer.Write((byte)bytesArray.Length);
  96. writer.Write(bytesArray);
  97. WritePadding(startPosition, padMultiple);
  98. }
  99. /// <summary>
  100. /// Write a Unicode string to the stream.
  101. /// </summary>
  102. public void WriteUnicodeString(string s)
  103. {
  104. Write(s.Length);
  105. var data = Encoding.BigEndianUnicode.GetBytes(s);
  106. Write(data);
  107. }
  108. public void Write(bool value)
  109. {
  110. writer.Write(value);
  111. }
  112. public void Write(byte[] value)
  113. {
  114. writer.Write(value);
  115. }
  116. public void Write(byte value)
  117. {
  118. writer.Write(value);
  119. }
  120. public void Write(Int16 value)
  121. {
  122. unsafe
  123. {
  124. Util.SwapBytes2((byte*)&value);
  125. }
  126. writer.Write(value);
  127. }
  128. public void Write(Int32 value)
  129. {
  130. unsafe
  131. {
  132. Util.SwapBytes4((byte*)&value);
  133. }
  134. writer.Write(value);
  135. }
  136. public void Write(Int64 value)
  137. {
  138. unsafe
  139. {
  140. Util.SwapBytes((byte*)&value, 8);
  141. }
  142. writer.Write(value);
  143. }
  144. public void Write(UInt16 value)
  145. {
  146. unsafe
  147. {
  148. Util.SwapBytes2((byte*)&value);
  149. }
  150. writer.Write(value);
  151. }
  152. public void Write(UInt32 value)
  153. {
  154. unsafe
  155. {
  156. Util.SwapBytes4((byte*)&value);
  157. }
  158. writer.Write(value);
  159. }
  160. public void Write(UInt64 value)
  161. {
  162. unsafe
  163. {
  164. Util.SwapBytes((byte*)&value, 8);
  165. }
  166. writer.Write(value);
  167. }
  168. //////////////////////////////////////////////////////////////////
  169. # region IDisposable
  170. private bool disposed = false;
  171. public void Dispose()
  172. {
  173. Dispose(true);
  174. GC.SuppressFinalize(this);
  175. }
  176. protected virtual void Dispose(bool disposing)
  177. {
  178. // Check to see if Dispose has already been called.
  179. if (disposed)
  180. {
  181. return;
  182. }
  183. if (disposing)
  184. {
  185. if (writer != null)
  186. {
  187. // BinaryWriter.Dispose() is protected, so we have to call Close.
  188. // The BinaryWriter will be automatically flushed on close.
  189. writer.Close();
  190. writer = null;
  191. }
  192. }
  193. disposed = true;
  194. }
  195. #endregion
  196. }
  197. }