Mask.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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-2017 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.Collections.Specialized;
  18. using System.Diagnostics;
  19. using System.Drawing;
  20. using System.Globalization;
  21. namespace PhotoshopFile
  22. {
  23. public class Mask
  24. {
  25. /// <summary>
  26. /// The layer to which this mask belongs
  27. /// </summary>
  28. public Layer Layer { get; private set; }
  29. /// <summary>
  30. /// The rectangle enclosing the mask.
  31. /// </summary>
  32. public Rectangle Rect { get; set; }
  33. private byte backgroundColor;
  34. public byte BackgroundColor
  35. {
  36. get => backgroundColor;
  37. set
  38. {
  39. if ((value != 0) && (value != 255))
  40. throw new PsdInvalidException("Mask background must be fully-opaque or fully-transparent.");
  41. backgroundColor = value;
  42. }
  43. }
  44. private static int positionVsLayerBit = BitVector32.CreateMask();
  45. private static int disabledBit = BitVector32.CreateMask(positionVsLayerBit);
  46. private static int invertOnBlendBit = BitVector32.CreateMask(disabledBit);
  47. private BitVector32 flags;
  48. public BitVector32 Flags => flags;
  49. /// <summary>
  50. /// If true, the position of the mask is relative to the layer.
  51. /// </summary>
  52. public bool PositionVsLayer
  53. {
  54. get => flags[positionVsLayerBit];
  55. set => flags[positionVsLayerBit] = value;
  56. }
  57. public bool Disabled
  58. {
  59. get => flags[disabledBit];
  60. set => flags[disabledBit] = value;
  61. }
  62. /// <summary>
  63. /// if true, invert the mask when blending.
  64. /// </summary>
  65. public bool InvertOnBlend
  66. {
  67. get => flags[invertOnBlendBit];
  68. set => flags[invertOnBlendBit] = value;
  69. }
  70. /// <summary>
  71. /// Mask image data.
  72. /// </summary>
  73. public byte[] ImageData { get; set; }
  74. public Mask(Layer layer)
  75. {
  76. Layer = layer;
  77. this.flags = new BitVector32();
  78. }
  79. public Mask(Layer layer, Rectangle rect, byte color, BitVector32 flags)
  80. {
  81. Layer = layer;
  82. Rect = rect;
  83. BackgroundColor = color;
  84. this.flags = flags;
  85. }
  86. }
  87. /// <summary>
  88. /// Mask info for a layer. Contains both the layer and user masks.
  89. /// </summary>
  90. public class MaskInfo
  91. {
  92. public Mask LayerMask { get; set; }
  93. public Mask UserMask { get; set; }
  94. /// <summary>
  95. /// Construct MaskInfo with null masks.
  96. /// </summary>
  97. public MaskInfo()
  98. {
  99. }
  100. public MaskInfo(PsdBinaryReader reader, Layer layer)
  101. {
  102. Util.DebugMessage(reader.BaseStream, "Load, Begin, MaskInfo");
  103. var maskLength = reader.ReadUInt32();
  104. if (maskLength <= 0)
  105. return;
  106. var startPosition = reader.BaseStream.Position;
  107. var endPosition = startPosition + maskLength;
  108. // Read layer mask
  109. var rectangle = reader.ReadRectangle();
  110. var backgroundColor = reader.ReadByte();
  111. var flagsByte = reader.ReadByte();
  112. LayerMask = new Mask(layer, rectangle, backgroundColor, new BitVector32(flagsByte));
  113. // User mask is supplied separately when there is also a vector mask.
  114. if (maskLength == 36)
  115. {
  116. var userFlagsByte = reader.ReadByte();
  117. var userBackgroundColor = reader.ReadByte();
  118. var userRectangle = reader.ReadRectangle();
  119. UserMask = new Mask(layer, userRectangle, userBackgroundColor,
  120. new BitVector32(userFlagsByte));
  121. }
  122. // 20-byte mask data will end with padding.
  123. reader.BaseStream.Position = endPosition;
  124. Util.DebugMessage(reader.BaseStream, "Load, End, MaskInfo");
  125. }
  126. ///////////////////////////////////////////////////////////////////////////
  127. public void Save(PsdBinaryWriter writer)
  128. {
  129. Util.DebugMessage(writer.BaseStream, "Save, Begin, MaskInfo");
  130. if (LayerMask == null)
  131. {
  132. writer.Write((UInt32)0);
  133. return;
  134. }
  135. using (new PsdBlockLengthWriter(writer))
  136. {
  137. writer.Write(LayerMask.Rect);
  138. writer.Write(LayerMask.BackgroundColor);
  139. writer.Write((byte)LayerMask.Flags.Data);
  140. if (UserMask == null)
  141. {
  142. // Pad by 2 bytes to make the block length 20
  143. writer.Write((UInt16)0);
  144. }
  145. else
  146. {
  147. writer.Write((byte)UserMask.Flags.Data);
  148. writer.Write(UserMask.BackgroundColor);
  149. writer.Write(UserMask.Rect);
  150. }
  151. }
  152. Util.DebugMessage(writer.BaseStream, "Save, End, MaskInfo");
  153. }
  154. }
  155. }