暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  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. // See LICENSE.txt for complete licensing and attribution information.
  11. //
  12. /////////////////////////////////////////////////////////////////////////////////
  13. using System;
  14. using System.Collections.Generic;
  15. using System.Diagnostics;
  16. using PDNWrapper;
  17. using System.IO;
  18. using System.Linq;
  19. using System.Text;
  20. using Unity.Collections;
  21. namespace PhotoshopFile
  22. {
  23. internal static class Util
  24. {
  25. [DebuggerDisplay("Top = {Top}, Bottom = {Bottom}, Left = {Left}, Right = {Right}")]
  26. internal struct RectanglePosition
  27. {
  28. public int Top { get; set; }
  29. public int Bottom { get; set; }
  30. public int Left { get; set; }
  31. public int Right { get; set; }
  32. }
  33. public static Rectangle IntersectWith(
  34. this Rectangle thisRect, Rectangle rect)
  35. {
  36. thisRect.Intersect(rect);
  37. return thisRect;
  38. }
  39. ///////////////////////////////////////////////////////////////////////////
  40. /// <summary>
  41. /// Fills a buffer with a byte value.
  42. /// </summary>
  43. static public void Fill(byte[] ptr, int start, int end, byte value)
  44. {
  45. while (start < end)
  46. {
  47. ptr[start] = value;
  48. start++;
  49. }
  50. }
  51. static public void Invert(byte[] ptr, int ptrStart, int ptrEnd)
  52. {
  53. while (ptrStart < ptrEnd)
  54. {
  55. ptr[ptrStart] = (byte)(ptr[ptrStart] ^ 0xff);
  56. ptrStart++;
  57. }
  58. }
  59. /// <summary>
  60. /// Fills a buffer with a byte value.
  61. /// </summary>
  62. static public void Fill(NativeArray<byte> ptr, int start, int end, byte value)
  63. {
  64. while (start < end)
  65. {
  66. ptr[start] = value;
  67. start++;
  68. }
  69. }
  70. static public void Invert(NativeArray<byte> ptr, int ptrStart, int ptrEnd)
  71. {
  72. while (ptrStart < ptrEnd)
  73. {
  74. ptr[ptrStart] = (byte)(ptr[ptrStart] ^ 0xff);
  75. ptrStart++;
  76. }
  77. }
  78. ///////////////////////////////////////////////////////////////////////////
  79. /// <summary>
  80. /// Reverses the endianness of a 2-byte word.
  81. /// </summary>
  82. static public void SwapBytes2(byte[] ptr, int start)
  83. {
  84. byte byte0 = ptr[start];
  85. ptr[start] = ptr[start + 1];
  86. ptr[start + 1] = byte0;
  87. }
  88. ///////////////////////////////////////////////////////////////////////////
  89. /// <summary>
  90. /// Reverses the endianness of a 4-byte word.
  91. /// </summary>
  92. static public void SwapBytes4(byte[] ptr, int start)
  93. {
  94. byte byte0 = ptr[start];
  95. byte byte1 = ptr[start + 1];
  96. ptr[start] = ptr[start + 3];
  97. ptr[start + 1] = ptr[start + 2];
  98. ptr[start + 2] = byte1;
  99. ptr[start + 3] = byte0;
  100. }
  101. /// <summary>
  102. /// Reverses the endianness of a word of arbitrary length.
  103. /// </summary>
  104. static public void SwapBytes(byte[] ptr, int start, int nLength)
  105. {
  106. for (long i = 0; i < nLength / 2; ++i)
  107. {
  108. byte t = ptr[start + i];
  109. ptr[start + i] = ptr[start + nLength - i - 1];
  110. ptr[start + nLength - i - 1] = t;
  111. }
  112. }
  113. ///////////////////////////////////////////////////////////////////////////
  114. public static void SwapByteArray(int bitDepth,
  115. byte[] byteArray, int startIdx, int count)
  116. {
  117. switch (bitDepth)
  118. {
  119. case 1:
  120. case 8:
  121. break;
  122. case 16:
  123. SwapByteArray2(byteArray, startIdx, count);
  124. break;
  125. case 32:
  126. SwapByteArray4(byteArray, startIdx, count);
  127. break;
  128. default:
  129. throw new Exception(
  130. "Byte-swapping implemented only for 16-bit and 32-bit depths.");
  131. }
  132. }
  133. /// <summary>
  134. /// Reverses the endianness of 2-byte words in a byte array.
  135. /// </summary>
  136. /// <param name="byteArray">Byte array containing the sequence on which to swap endianness</param>
  137. /// <param name="startIdx">Byte index of the first word to swap</param>
  138. /// <param name="count">Number of words to swap</param>
  139. public static void SwapByteArray2(byte[] byteArray, int startIdx, int count)
  140. {
  141. int endIdx = startIdx + count * 2;
  142. if (byteArray.Length < endIdx)
  143. throw new IndexOutOfRangeException();
  144. {
  145. //fixed (byte* arrayPtr = &byteArray[0])
  146. {
  147. //byte* ptr = arrayPtr + startIdx;
  148. //byte* endPtr = arrayPtr + endIdx;
  149. while (startIdx < endIdx)
  150. {
  151. SwapBytes2(byteArray, startIdx);
  152. startIdx += 2;
  153. }
  154. }
  155. }
  156. }
  157. /// <summary>
  158. /// Reverses the endianness of 4-byte words in a byte array.
  159. /// </summary>
  160. /// <param name="byteArray">Byte array containing the sequence on which to swap endianness</param>
  161. /// <param name="startIdx">Byte index of the first word to swap</param>
  162. /// <param name="count">Number of words to swap</param>
  163. public static void SwapByteArray4(byte[] byteArray, int startIdx, int count)
  164. {
  165. int endIdx = startIdx + count * 4;
  166. if (byteArray.Length < endIdx)
  167. throw new IndexOutOfRangeException();
  168. {
  169. //fixed (byte* arrayPtr = &byteArray[0])
  170. {
  171. //byte* ptr = arrayPtr + startIdx;
  172. //byte* endPtr = arrayPtr + endIdx;
  173. while (startIdx < endIdx)
  174. {
  175. SwapBytes4(byteArray, startIdx);
  176. startIdx += 4;
  177. }
  178. }
  179. }
  180. }
  181. ///////////////////////////////////////////////////////////////////////////
  182. /// <summary>
  183. /// Calculates the number of bytes required to store a row of an image
  184. /// with the specified bit depth.
  185. /// </summary>
  186. /// <param name="size">The size of the image in pixels.</param>
  187. /// <param name="bitDepth">The bit depth of the image.</param>
  188. /// <returns>The number of bytes needed to store a row of the image.</returns>
  189. public static int BytesPerRow(Size size, int bitDepth)
  190. {
  191. switch (bitDepth)
  192. {
  193. case 1:
  194. return (size.Width + 7) / 8;
  195. default:
  196. return size.Width * BytesFromBitDepth(bitDepth);
  197. }
  198. }
  199. /// <summary>
  200. /// Round the integer to a multiple.
  201. /// </summary>
  202. public static int RoundUp(int value, int multiple)
  203. {
  204. if (value == 0)
  205. return 0;
  206. if (Math.Sign(value) != Math.Sign(multiple))
  207. {
  208. throw new ArgumentException(
  209. "value and multiple cannot have opposite signs.");
  210. }
  211. var remainder = value % multiple;
  212. if (remainder > 0)
  213. {
  214. value += (multiple - remainder);
  215. }
  216. return value;
  217. }
  218. /// <summary>
  219. /// Get number of bytes required to pad to the specified multiple.
  220. /// </summary>
  221. public static int GetPadding(int length, int padMultiple)
  222. {
  223. if ((length < 0) || (padMultiple < 0))
  224. throw new ArgumentException();
  225. var remainder = length % padMultiple;
  226. if (remainder == 0)
  227. return 0;
  228. var padding = padMultiple - remainder;
  229. return padding;
  230. }
  231. /// <summary>
  232. /// Returns the number of bytes needed to store a single pixel of the
  233. /// specified bit depth.
  234. /// </summary>
  235. public static int BytesFromBitDepth(int depth)
  236. {
  237. switch (depth)
  238. {
  239. case 1:
  240. case 8:
  241. return 1;
  242. case 16:
  243. return 2;
  244. case 32:
  245. return 4;
  246. default:
  247. throw new ArgumentException("Invalid bit depth.");
  248. }
  249. }
  250. public static short MinChannelCount(this PsdColorMode colorMode)
  251. {
  252. switch (colorMode)
  253. {
  254. case PsdColorMode.Bitmap:
  255. case PsdColorMode.Duotone:
  256. case PsdColorMode.Grayscale:
  257. case PsdColorMode.Indexed:
  258. case PsdColorMode.Multichannel:
  259. return 1;
  260. case PsdColorMode.Lab:
  261. case PsdColorMode.RGB:
  262. return 3;
  263. case PsdColorMode.CMYK:
  264. return 4;
  265. }
  266. throw new ArgumentException("Unknown color mode.");
  267. }
  268. /// <summary>
  269. /// Verify that the offset and count will remain within the bounds of the
  270. /// buffer.
  271. /// </summary>
  272. /// <returns>True if in bounds, false if out of bounds.</returns>
  273. public static bool CheckBufferBounds(byte[] data, int offset, int count)
  274. {
  275. if (offset < 0)
  276. return false;
  277. if (count < 0)
  278. return false;
  279. if (offset + count > data.Length)
  280. return false;
  281. return true;
  282. }
  283. public static void CheckByteArrayLength(long length)
  284. {
  285. if (length < 0)
  286. {
  287. throw new Exception("Byte array cannot have a negative length.");
  288. }
  289. if (length > 0x7fffffc7)
  290. {
  291. throw new OutOfMemoryException(
  292. "Byte array cannot exceed 2,147,483,591 in length.");
  293. }
  294. }
  295. /// <summary>
  296. /// Writes a message to the debug console, indicating the current position
  297. /// in the stream in both decimal and hexadecimal formats.
  298. /// </summary>
  299. [Conditional("DEBUG")]
  300. public static void DebugMessage(Stream stream, string message,
  301. params object[] args)
  302. {
  303. //var formattedMessage = String.Format(message, args);
  304. //Debug.WriteLine("0x{0:x}, {0}, {1}",
  305. //stream.Position, formattedMessage);
  306. }
  307. }
  308. /// <summary>
  309. /// Fixed-point decimal, with 16-bit integer and 16-bit fraction.
  310. /// </summary>
  311. internal class UFixed16_16
  312. {
  313. public UInt16 Integer { get; set; }
  314. public UInt16 Fraction { get; set; }
  315. public UFixed16_16(UInt16 integer, UInt16 fraction)
  316. {
  317. Integer = integer;
  318. Fraction = fraction;
  319. }
  320. /// <summary>
  321. /// Split the high and low words of a 32-bit unsigned integer into a
  322. /// fixed-point number.
  323. /// </summary>
  324. public UFixed16_16(UInt32 value)
  325. {
  326. Integer = (UInt16)(value >> 16);
  327. Fraction = (UInt16)(value & 0x0000ffff);
  328. }
  329. public UFixed16_16(double value)
  330. {
  331. if (value >= 65536.0) throw new OverflowException();
  332. if (value < 0) throw new OverflowException();
  333. Integer = (UInt16)value;
  334. // Round instead of truncate, because doubles may not represent the
  335. // fraction exactly.
  336. Fraction = (UInt16)((value - Integer) * 65536 + 0.5);
  337. }
  338. public static implicit operator double(UFixed16_16 value)
  339. {
  340. return (double)value.Integer + value.Fraction / 65536.0;
  341. }
  342. }
  343. }