Layer.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  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-2019 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.Generic;
  18. using System.Collections.Specialized;
  19. using System.Diagnostics;
  20. using System.Drawing;
  21. using System.Globalization;
  22. using System.IO;
  23. using System.Linq;
  24. using System.Threading;
  25. namespace PhotoshopFile
  26. {
  27. [DebuggerDisplay("Name = {Name}")]
  28. public class Layer
  29. {
  30. internal PsdFile PsdFile { get; private set; }
  31. /// <summary>
  32. /// The rectangle containing the contents of the layer.
  33. /// </summary>
  34. public Rectangle Rect { get; set; }
  35. /// <summary>
  36. /// Image channels.
  37. /// </summary>
  38. public ChannelList Channels { get; private set; }
  39. /// <summary>
  40. /// Returns alpha channel if it exists, otherwise null.
  41. /// </summary>
  42. public Channel AlphaChannel => Channels.SingleOrDefault(x => x.ID == -1);
  43. private string blendModeKey;
  44. /// <summary>
  45. /// Photoshop blend mode key for the layer
  46. /// </summary>
  47. public string BlendModeKey
  48. {
  49. get => blendModeKey;
  50. set
  51. {
  52. if (value.Length != 4)
  53. {
  54. throw new ArgumentException(
  55. $"{nameof(BlendModeKey)} must be 4 characters in length.");
  56. }
  57. blendModeKey = value;
  58. }
  59. }
  60. /// <summary>
  61. /// 0 = transparent ... 255 = opaque
  62. /// </summary>
  63. public byte Opacity { get; set; }
  64. /// <summary>
  65. /// false = base, true = non-base
  66. /// </summary>
  67. public bool Clipping { get; set; }
  68. private static int protectTransBit = BitVector32.CreateMask();
  69. private static int visibleBit = BitVector32.CreateMask(protectTransBit);
  70. BitVector32 flags = new BitVector32();
  71. /// <summary>
  72. /// If true, the layer is visible.
  73. /// </summary>
  74. public bool Visible
  75. {
  76. get => !flags[visibleBit];
  77. set => flags[visibleBit] = !value;
  78. }
  79. /// <summary>
  80. /// Protect the transparency
  81. /// </summary>
  82. public bool ProtectTrans
  83. {
  84. get => flags[protectTransBit];
  85. set => flags[protectTransBit] = value;
  86. }
  87. /// <summary>
  88. /// The descriptive layer name
  89. /// </summary>
  90. public string Name { get; set; }
  91. public BlendingRanges BlendingRangesData { get; set; }
  92. public MaskInfo Masks { get; set; }
  93. public List<LayerInfo> AdditionalInfo { get; set; }
  94. ///////////////////////////////////////////////////////////////////////////
  95. public Layer(PsdFile psdFile)
  96. {
  97. PsdFile = psdFile;
  98. Rect = Rectangle.Empty;
  99. Channels = new ChannelList();
  100. BlendModeKey = PsdBlendMode.Normal;
  101. AdditionalInfo = new List<LayerInfo>();
  102. }
  103. public Layer(PsdBinaryReader reader, PsdFile psdFile)
  104. : this(psdFile)
  105. {
  106. Util.DebugMessage(reader.BaseStream, "Load, Begin, Layer");
  107. Rect = reader.ReadRectangle();
  108. //-----------------------------------------------------------------------
  109. // Read channel headers. Image data comes later, after the layer header.
  110. int numberOfChannels = reader.ReadUInt16();
  111. for (int channel = 0; channel < numberOfChannels; channel++)
  112. {
  113. var ch = new Channel(reader, this);
  114. Channels.Add(ch);
  115. }
  116. //-----------------------------------------------------------------------
  117. //
  118. var signature = reader.ReadAsciiChars(4);
  119. if (signature != "8BIM")
  120. throw (new PsdInvalidException("Invalid signature in layer header."));
  121. BlendModeKey = reader.ReadAsciiChars(4);
  122. Opacity = reader.ReadByte();
  123. Clipping = reader.ReadBoolean();
  124. var flagsByte = reader.ReadByte();
  125. flags = new BitVector32(flagsByte);
  126. reader.ReadByte(); //padding
  127. //-----------------------------------------------------------------------
  128. // This is the total size of the MaskData, the BlendingRangesData, the
  129. // Name and the AdjustmentLayerInfo.
  130. var extraDataSize = reader.ReadUInt32();
  131. var extraDataStartPosition = reader.BaseStream.Position;
  132. Masks = new MaskInfo(reader, this);
  133. BlendingRangesData = new BlendingRanges(reader, this);
  134. Name = reader.ReadPascalString(4);
  135. //-----------------------------------------------------------------------
  136. // Process Additional Layer Information
  137. long adjustmentLayerEndPos = extraDataStartPosition + extraDataSize;
  138. while (reader.BaseStream.Position < adjustmentLayerEndPos)
  139. {
  140. var layerInfo = LayerInfoFactory.Load(reader,
  141. psdFile: this.PsdFile,
  142. globalLayerInfo: false);
  143. AdditionalInfo.Add(layerInfo);
  144. }
  145. foreach (var adjustmentInfo in AdditionalInfo)
  146. {
  147. switch (adjustmentInfo.Key)
  148. {
  149. case "luni":
  150. Name = ((LayerUnicodeName)adjustmentInfo).Name;
  151. break;
  152. }
  153. }
  154. Util.DebugMessage(reader.BaseStream, $"Load, End, Layer, {Name}");
  155. PsdFile.LoadContext.OnLoadLayerHeader(this);
  156. }
  157. ///////////////////////////////////////////////////////////////////////////
  158. /// <summary>
  159. /// Create ImageData for any missing channels.
  160. /// </summary>
  161. public void CreateMissingChannels()
  162. {
  163. var channelCount = this.PsdFile.ColorMode.MinChannelCount();
  164. for (short id = 0; id < channelCount; id++)
  165. {
  166. if (!this.Channels.ContainsId(id))
  167. {
  168. var size = this.Rect.Height * this.Rect.Width;
  169. var ch = new Channel(id, this);
  170. ch.ImageData = new byte[size];
  171. if (size > 0)
  172. {
  173. unsafe
  174. {
  175. fixed (byte* ptr = &ch.ImageData[0])
  176. {
  177. Util.Fill(ptr, ptr + size, (byte)255);
  178. }
  179. }
  180. }
  181. this.Channels.Add(ch);
  182. }
  183. }
  184. }
  185. ///////////////////////////////////////////////////////////////////////////
  186. public void PrepareSave()
  187. {
  188. foreach (var ch in Channels)
  189. {
  190. ch.CompressImageData();
  191. }
  192. // Create or update the Unicode layer name to be consistent with the
  193. // ANSI layer name.
  194. var layerUnicodeNames = AdditionalInfo.Where(x => x is LayerUnicodeName);
  195. if (layerUnicodeNames.Count() > 1)
  196. {
  197. throw new PsdInvalidException(
  198. $"{nameof(Layer)} can only have one {nameof(LayerUnicodeName)}.");
  199. }
  200. var layerUnicodeName = (LayerUnicodeName) layerUnicodeNames.FirstOrDefault();
  201. if (layerUnicodeName == null)
  202. {
  203. layerUnicodeName = new LayerUnicodeName(Name);
  204. AdditionalInfo.Add(layerUnicodeName);
  205. }
  206. else if (layerUnicodeName.Name != Name)
  207. {
  208. layerUnicodeName.Name = Name;
  209. }
  210. }
  211. public void Save(PsdBinaryWriter writer)
  212. {
  213. Util.DebugMessage(writer.BaseStream, "Save, Begin, Layer");
  214. writer.Write(Rect);
  215. //-----------------------------------------------------------------------
  216. writer.Write((short)Channels.Count);
  217. foreach (var ch in Channels)
  218. ch.Save(writer);
  219. //-----------------------------------------------------------------------
  220. writer.WriteAsciiChars("8BIM");
  221. writer.WriteAsciiChars(BlendModeKey);
  222. writer.Write(Opacity);
  223. writer.Write(Clipping);
  224. writer.Write((byte)flags.Data);
  225. writer.Write((byte)0);
  226. //-----------------------------------------------------------------------
  227. using (new PsdBlockLengthWriter(writer))
  228. {
  229. Masks.Save(writer);
  230. BlendingRangesData.Save(writer);
  231. var namePosition = writer.BaseStream.Position;
  232. // Legacy layer name is limited to 31 bytes. Unicode layer name
  233. // can be much longer.
  234. writer.WritePascalString(Name, 4, 31);
  235. foreach (LayerInfo info in AdditionalInfo)
  236. {
  237. info.Save(writer,
  238. globalLayerInfo: false,
  239. isLargeDocument: PsdFile.IsLargeDocument);
  240. }
  241. }
  242. Util.DebugMessage(writer.BaseStream, $"Save, End, Layer, {Name}");
  243. }
  244. }
  245. }