This commit is contained in:
2021-06-13 10:28:03 +02:00
parent eb70603c85
commit df2d24cbd3
7487 changed files with 943244 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Photoshop PSD FileType Plugin for Paint.NET
// http://psdplugin.codeplex.com/
//
// This software is provided under the MIT License:
// Copyright (c) 2006-2007 Frank Blumenberg
// Copyright (c) 2010-2014 Tao Yue
//
// Portions of this file are provided under the BSD 3-clause License:
// Copyright (c) 2006, Jonas Beckeman
//
// See LICENSE.txt for complete licensing and attribution information.
//
/////////////////////////////////////////////////////////////////////////////////
using System;
using System.Diagnostics;
using System.Globalization;
namespace PhotoshopFile
{
internal class BlendingRanges
{
/// <summary>
/// The layer to which this channel belongs
/// </summary>
public Layer Layer { get; private set; }
public byte[] Data { get; set; }
///////////////////////////////////////////////////////////////////////////
public BlendingRanges(Layer layer)
{
Layer = layer;
Data = new byte[0];
}
///////////////////////////////////////////////////////////////////////////
public BlendingRanges(PsdBinaryReader reader, Layer layer)
{
Util.DebugMessage(reader.BaseStream, "Load, Begin, BlendingRanges");
Layer = layer;
var dataLength = reader.ReadInt32();
if (dataLength <= 0)
return;
Data = reader.ReadBytes(dataLength);
Util.DebugMessage(reader.BaseStream, "Load, End, BlendingRanges");
}
}
}

View File

@@ -0,0 +1,232 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Photoshop PSD FileType Plugin for Paint.NET
// http://psdplugin.codeplex.com/
//
// This software is provided under the MIT License:
// Copyright (c) 2006-2007 Frank Blumenberg
// Copyright (c) 2010-2016 Tao Yue
//
// Portions of this file are provided under the BSD 3-clause License:
// Copyright (c) 2006, Jonas Beckeman
//
// See LICENSE.txt for complete licensing and attribution information.
//
/////////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Diagnostics;
using PDNWrapper;
using System.Linq;
using Unity.Collections;
using PhotoshopFile.Compression;
namespace PhotoshopFile
{
internal class ChannelList : List<Channel>
{
/// <summary>
/// Returns channels with nonnegative IDs as an array, so that accessing
/// a channel by Id can be optimized into pointer arithmetic rather than
/// being implemented as a List scan.
/// </summary>
/// <remarks>
/// This optimization is crucial for blitting lots of pixels back and
/// forth between Photoshop's per-channel representation, and Paint.NET's
/// per-pixel BGRA representation.
/// </remarks>
public Channel[] ToIdArray()
{
var maxId = this.Max(x => x.ID);
var idArray = new Channel[maxId + 1];
foreach (var channel in this)
{
if (channel.ID >= 0)
idArray[channel.ID] = channel;
}
return idArray;
}
public ChannelList()
: base()
{
}
public Channel GetId(int id)
{
return this.Single(x => x.ID == id);
}
public bool ContainsId(int id)
{
return this.Exists(x => x.ID == id);
}
}
///////////////////////////////////////////////////////////////////////////
[DebuggerDisplay("ID = {ID}")]
internal class Channel
{
/// <summary>
/// The layer to which this channel belongs
/// </summary>
public Layer Layer { get; private set; }
/// <summary>
/// Channel ID.
/// <list type="bullet">
/// <item>-1 = transparency mask</item>
/// <item>-2 = user-supplied layer mask, or vector mask</item>
/// <item>-3 = user-supplied layer mask, if channel -2 contains a vector mask</item>
/// <item>
/// Nonnegative channel IDs give the actual image channels, in the
/// order defined by the colormode. For example, 0, 1, 2 = R, G, B.
/// </item>
/// </list>
/// </summary>
public short ID { get; set; }
public Rectangle Rect
{
get
{
switch (ID)
{
case -2:
return Layer.Masks.LayerMask.Rect;
case -3:
return Layer.Masks.UserMask.Rect;
default:
return Layer.Rect;
}
}
}
/// <summary>
/// Total length of the channel data, including compression headers.
/// </summary>
public long Length { get; set; }
/// <summary>
/// Raw image data for this color channel, in compressed on-disk format.
/// </summary>
/// <remarks>
/// If null, the ImageData will be automatically compressed during save.
/// </remarks>
public byte[] ImageDataRaw { get; set; }
/// <summary>
/// Decompressed image data for this color channel.
/// </summary>
/// <remarks>
/// When making changes to the ImageData, set ImageDataRaw to null so that
/// the correct data will be compressed during save.
/// </remarks>
public NativeArray<byte> ImageData { get; set; }
/// <summary>
/// Image compression method used.
/// </summary>
public ImageCompression ImageCompression { get; set; }
/// <summary>
/// RLE-compressed length of each row.
/// </summary>
public RleRowLengths RleRowLengths { get; set; }
//////////////////////////////////////////////////////////////////
internal Channel(short id, Layer layer)
{
ID = id;
Layer = layer;
}
internal Channel(PsdBinaryReader reader, Layer layer)
{
Util.DebugMessage(reader.BaseStream, "Load, Begin, Channel");
ID = reader.ReadInt16();
Length = (layer.PsdFile.IsLargeDocument)
? reader.ReadInt64()
: reader.ReadInt32();
Layer = layer;
Util.DebugMessage(reader.BaseStream, "Load, End, Channel, {0}", ID);
}
internal void Cleanup()
{
if (ImageData.IsCreated)
ImageData.Dispose();
}
//////////////////////////////////////////////////////////////////
internal void LoadPixelData(PsdBinaryReader reader)
{
Util.DebugMessage(reader.BaseStream, "Load, Begin, Channel image");
if (Length == 0)
{
ImageCompression = ImageCompression.Raw;
ImageDataRaw = new byte[0];
return;
}
var endPosition = reader.BaseStream.Position + this.Length;
ImageCompression = (ImageCompression)reader.ReadInt16();
var longDataLength = this.Length - 2;
Util.CheckByteArrayLength(longDataLength);
var dataLength = (int)longDataLength;
switch (ImageCompression)
{
case ImageCompression.Raw:
ImageDataRaw = reader.ReadBytes(dataLength);
break;
case ImageCompression.Rle:
// RLE row lengths
RleRowLengths = new RleRowLengths(reader, Rect.Height, Layer.PsdFile.IsLargeDocument);
var rleDataLength = (int)(endPosition - reader.BaseStream.Position);
Debug.Assert(rleDataLength == RleRowLengths.Total,
"RLE row lengths do not sum to length of channel image data.");
// The PSD specification states that rows are padded to even sizes.
// However, Photoshop doesn't actually do this. RLE rows can have
// odd lengths in the header, and there is no padding between rows.
ImageDataRaw = reader.ReadBytes(rleDataLength);
break;
case ImageCompression.Zip:
case ImageCompression.ZipPrediction:
ImageDataRaw = reader.ReadBytes(dataLength);
break;
}
Util.DebugMessage(reader.BaseStream, "Load, End, Channel image, {0}", ID, Layer.Name);
Debug.Assert(reader.BaseStream.Position == endPosition, "Pixel data was not fully read in.");
}
/// <summary>
/// Decodes the raw image data from the compressed on-disk format into
/// an uncompressed bitmap, in native byte order.
/// </summary>
public void DecodeImageData()
{
if ((ImageCompression == ImageCompression.Raw) && (Layer.PsdFile.BitDepth <= 8))
{
ImageData = new NativeArray<byte>(ImageDataRaw, Allocator.TempJob);
return;
}
var image = ImageDataFactory.Create(this, ImageDataRaw);
var longLength = (long)image.BytesPerRow * Rect.Height;
Util.CheckByteArrayLength(longLength);
var LocalImageData = new byte[longLength];
image.Read(LocalImageData);
ImageData = new NativeArray<byte>(LocalImageData, Allocator.TempJob);
ImageDataRaw = null; // no longer needed.
}
}
}

View File

@@ -0,0 +1,240 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Photoshop PSD FileType Plugin for Paint.NET
// http://psdplugin.codeplex.com/
//
// This software is provided under the MIT License:
// Copyright (c) 2006-2007 Frank Blumenberg
// Copyright (c) 2010-2016 Tao Yue
//
// Portions of this file are provided under the BSD 3-clause License:
// Copyright (c) 2006, Jonas Beckeman
//
// See LICENSE.txt for complete licensing and attribution information.
//
/////////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using PDNWrapper;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
namespace PhotoshopFile
{
[DebuggerDisplay("Name = {Name}")]
internal class Layer
{
internal PsdFile PsdFile { get; private set; }
/// <summary>
/// The rectangle containing the contents of the layer.
/// </summary>
public Rectangle Rect { get; set; }
public bool IsGroup { get; set; }
public bool IsEndGroupMarker { get; set; }
public Layer ParentLayer {get; set; }
// ID from Key "lyid"
public int LayerID { get; set; }
/// <summary>
/// Image channels.
/// </summary>
public ChannelList Channels { get; private set; }
/// <summary>
/// Returns alpha channel if it exists, otherwise null.
/// </summary>
public Channel AlphaChannel
{
get
{
if (Channels.ContainsId(-1))
return Channels.GetId(-1);
else
return null;
}
}
private string blendModeKey;
/// <summary>
/// Photoshop blend mode key for the layer
/// </summary>
public string BlendModeKey
{
get { return blendModeKey; }
set
{
if (value.Length != 4)
{
throw new ArgumentException(
"BlendModeKey must be 4 characters in length.");
}
blendModeKey = value;
}
}
/// <summary>
/// 0 = transparent ... 255 = opaque
/// </summary>
public byte Opacity { get; set; }
/// <summary>
/// false = base, true = non-base
/// </summary>
public bool Clipping { get; set; }
private static int protectTransBit = BitVector32.CreateMask();
private static int visibleBit = BitVector32.CreateMask(protectTransBit);
BitVector32 flags = new BitVector32();
/// <summary>
/// If true, the layer is visible.
/// </summary>
public bool Visible
{
get { return !flags[visibleBit]; }
set { flags[visibleBit] = !value; }
}
/// <summary>
/// Protect the transparency
/// </summary>
public bool ProtectTrans
{
get { return flags[protectTransBit]; }
set { flags[protectTransBit] = value; }
}
/// <summary>
/// The descriptive layer name
/// </summary>
public string Name { get; set; }
public BlendingRanges BlendingRangesData { get; set; }
public MaskInfo Masks { get; set; }
public List<LayerInfo> AdditionalInfo { get; set; }
///////////////////////////////////////////////////////////////////////////
public Layer(PsdFile psdFile)
{
PsdFile = psdFile;
Rect = Rectangle.Empty;
Channels = new ChannelList();
BlendModeKey = PsdBlendMode.Normal;
AdditionalInfo = new List<LayerInfo>();
IsGroup = false;
ParentLayer = null;
IsEndGroupMarker = false;
}
public Layer(PsdBinaryReader reader, PsdFile psdFile)
: this(psdFile)
{
Util.DebugMessage(reader.BaseStream, "Load, Begin, Layer");
Rect = reader.ReadRectangle();
//-----------------------------------------------------------------------
// Read channel headers. Image data comes later, after the layer header.
int numberOfChannels = reader.ReadUInt16();
for (int channel = 0; channel < numberOfChannels; channel++)
{
var ch = new Channel(reader, this);
Channels.Add(ch);
}
//-----------------------------------------------------------------------
//
var signature = reader.ReadAsciiChars(4);
if (signature != "8BIM")
throw (new PsdInvalidException("Invalid signature in layer header."));
BlendModeKey = reader.ReadAsciiChars(4);
Opacity = reader.ReadByte();
Clipping = reader.ReadBoolean();
var flagsByte = reader.ReadByte();
flags = new BitVector32(flagsByte);
reader.ReadByte(); //padding
//-----------------------------------------------------------------------
// This is the total size of the MaskData, the BlendingRangesData, the
// Name and the AdjustmentLayerInfo.
var extraDataSize = reader.ReadUInt32();
var extraDataStartPosition = reader.BaseStream.Position;
Masks = new MaskInfo(reader, this);
BlendingRangesData = new BlendingRanges(reader, this);
Name = reader.ReadPascalString(4);
//-----------------------------------------------------------------------
// Process Additional Layer Information
long adjustmentLayerEndPos = extraDataStartPosition + extraDataSize;
while (reader.BaseStream.Position < adjustmentLayerEndPos)
{
var layerInfo = LayerInfoFactory.Load(reader, this.PsdFile, false, adjustmentLayerEndPos);
AdditionalInfo.Add(layerInfo);
}
foreach (var adjustmentInfo in AdditionalInfo)
{
switch (adjustmentInfo.Key)
{
case "luni":
Name = ((LayerUnicodeName)adjustmentInfo).Name;
break;
case "lyid":
LayerID = ((LayerId)adjustmentInfo).ID;
break;
}
}
Util.DebugMessage(reader.BaseStream, "Load, End, Layer, {0}", Name);
PsdFile.LoadContext.OnLoadLayerHeader(this);
}
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Create ImageData for any missing channels.
/// </summary>
public void CreateMissingChannels()
{
var channelCount = this.PsdFile.ColorMode.MinChannelCount();
for (short id = 0; id < channelCount; id++)
{
if (!this.Channels.ContainsId(id))
{
var size = this.Rect.Height * this.Rect.Width;
var ch = new Channel(id, this);
ch.ImageData = new NativeArray<byte>(size, Allocator.TempJob);
unsafe
{
UnsafeUtility.MemSet(ch.ImageData.GetUnsafePtr(), (byte)255, size);
}
this.Channels.Add(ch);
}
}
}
///////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,168 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Photoshop PSD FileType Plugin for Paint.NET
// http://psdplugin.codeplex.com/
//
// This software is provided under the MIT License:
// Copyright (c) 2006-2007 Frank Blumenberg
// Copyright (c) 2010-2016 Tao Yue
//
// See LICENSE.txt for complete licensing and attribution information.
//
/////////////////////////////////////////////////////////////////////////////////
using System;
using System.Diagnostics;
using System.IO;
namespace PhotoshopFile
{
internal static class LayerInfoFactory
{
/// <summary>
/// Loads the next LayerInfo record.
/// </summary>
/// <param name="reader">The file reader</param>
/// <param name="psdFile">The PSD file.</param>
/// <param name="globalLayerInfo">True if the LayerInfo record is being
/// loaded from the end of the Layer and Mask Information section;
/// false if it is being loaded from the end of a Layer record.</param>
public static LayerInfo Load(PsdBinaryReader reader, PsdFile psdFile,
bool globalLayerInfo, long fileEndPos)
{
Util.DebugMessage(reader.BaseStream, "Load, Begin, LayerInfo");
// Some keys use a signature of 8B64, but the identity of these keys
// is undocumented. We will therefore accept either signature.
var signature = reader.ReadAsciiChars(4);
if ((signature != "8BIM") && (signature != "8B64"))
{
throw new PsdInvalidException(
"LayerInfo signature invalid, must be 8BIM or 8B64.");
}
var key = reader.ReadAsciiChars(4);
var hasLongLength = LayerInfoUtil.HasLongLength(key, psdFile.IsLargeDocument);
LayerInfo result = new RawLayerInfo("dummy");
bool breakFromLoop = false;
while (!breakFromLoop)
{
var baseStartPosition = reader.BaseStream.Position;
var length = hasLongLength
? reader.ReadInt64()
: reader.ReadInt32();
var startPosition = reader.BaseStream.Position;
switch (key)
{
case "Layr":
case "Lr16":
case "Lr32":
result = new InfoLayers(reader, psdFile, key, length);
break;
case "lsct":
case "lsdk":
result = new LayerSectionInfo(reader, key, (int)length);
break;
case "luni":
result = new LayerUnicodeName(reader);
break;
case "lyid":
result = new LayerId(reader, key, length);
break;
default:
result = new RawLayerInfo(reader, signature, key, length);
break;
}
// May have additional padding applied.
var endPosition = startPosition + length;
if (reader.BaseStream.Position < endPosition)
reader.BaseStream.Position = endPosition;
// Documentation states that the length is even-padded. Actually:
// 1. Most keys have 4-padded lengths.
// 2. However, some keys (LMsk) have even-padded lengths.
// 3. Other keys (Txt2, Lr16, Lr32) have unpadded lengths.
//
// Photoshop writes data that is always 4-padded, even when the stated
// length is not a multiple of 4. The length mismatch seems to occur
// only on global layer info. We do not read extra padding in other
// cases because third-party programs are likely to follow the spec.
if (globalLayerInfo)
{
reader.ReadPadding(startPosition, 4);
}
//try if we can read the next signature
if (reader.BaseStream.Position < fileEndPos)
{
var nowPosition = reader.BaseStream.Position;
signature = reader.ReadAsciiChars(4);
if ((signature != "8BIM") && (signature != "8B64"))
{
hasLongLength = true;
reader.BaseStream.Position = baseStartPosition;
}
else
{
reader.BaseStream.Position = nowPosition;
breakFromLoop = true;
}
}
else
breakFromLoop = true;
}
Util.DebugMessage(reader.BaseStream, "Load, End, LayerInfo, {0}, {1}",
result.Signature, result.Key);
return result;
}
}
internal static class LayerInfoUtil
{
internal static bool HasLongLength(string key, bool isLargeDocument)
{
if (!isLargeDocument)
{
return false;
}
//return false;
switch (key)
{
case "LMsk":
case "Lr16":
case "Lr32":
case "Layr":
case "Mt16":
case "Mt32":
case "Mtrn":
case "Alph":
case "FMsk":
case "lnk2":
case "FEid":
case "FXid":
case "PxSD":
case "lnkE": // Undocumented
case "extn": // Undocumented
case "cinf": // Undocumented
return true;
default:
return false;
}
}
}
internal abstract class LayerInfo
{
public abstract string Signature { get; }
public abstract string Key { get; }
}
}

View File

@@ -0,0 +1,87 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Photoshop PSD FileType Plugin for Paint.NET
// http://psdplugin.codeplex.com/
//
// This software is provided under the MIT License:
// Copyright (c) 2006-2007 Frank Blumenberg
// Copyright (c) 2010-2016 Tao Yue
//
// See LICENSE.txt for complete licensing and attribution information.
//
/////////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PhotoshopFile
{
/// <summary>
/// Layers that are stored as Additional Info, rather than in the main
/// Layers section of the PSD file.
/// </summary>
/// <remarks>
/// Photoshop stores layers in the Additional Info section for 16-bit and
/// 32-bit depth images. The Layers section in the PSD file is left empty.
///
/// This appears to be for backward-compatibility purposes, but it is not
/// required. Photoshop will successfully load a high-bitdepth image that
/// puts the layers in the Layers section.
/// </remarks>
internal class InfoLayers : LayerInfo
{
public override string Signature
{
get { return "8BIM"; }
}
private string key;
public override string Key
{
get { return key; }
}
public PsdFile PsdFile { get; set; }
public InfoLayers(PsdFile psdFile, string key)
{
PsdFile = psdFile;
switch (key)
{
// The key does not have to match the bit depth, but it does have to
// be one of the known values.
case "Layr":
case "Lr16":
case "Lr32":
this.key = key;
break;
default:
throw new PsdInvalidException(
"InfoLayers key must be Layr, Lr16, or Lr32.");
}
}
public InfoLayers(PsdBinaryReader reader, PsdFile psdFile,
string key, long dataLength)
: this(psdFile, key)
{
if (psdFile.Layers.Count > 0)
{
throw new PsdInvalidException(
"Cannot have both regular layers and Additional Info layers");
}
var endPosition = reader.BaseStream.Position + dataLength;
psdFile.LoadLayers(reader, false);
if (reader.BaseStream.Position != endPosition)
{
throw new PsdInvalidException(
"Incorrect length for InfoLayers.");
}
}
}
}

View File

@@ -0,0 +1,71 @@
/////////////////////////////////////////////////////////////////////////////////
// Author : leoyaik@unity3d.com
/////////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace PhotoshopFile
{
/// <summary>
/// Layers that are stored as Additional Info, rather than in the main
/// Layers section of the PSD file.
/// </summary>
/// <remarks>
/// Photoshop stores layers in the Additional Info section for 16-bit and
/// 32-bit depth images. The Layers section in the PSD file is left empty.
///
/// This appears to be for backward-compatibility purposes, but it is not
/// required. Photoshop will successfully load a high-bitdepth image that
/// puts the layers in the Layers section.
/// </remarks>
internal class LayerId : LayerInfo
{
public override string Signature
{
get { return "8BIM"; }
}
private string key;
public override string Key
{
get { return key; }
}
private int id = 0;
public int ID
{
get { return id; }
}
public LayerId(string key)
{
switch (key)
{
// The key does not have to match the bit depth, but it does have to
// be one of the known values.
case "lyid":
case "lnsr":
this.key = key;
break;
default:
throw new PsdInvalidException(
"LayerId key should be lyid or lnsr");
}
}
public LayerId(PsdBinaryReader reader,
string key, long dataLength)
: this(key)
{
if (dataLength == 4)
id = reader.ReadInt32();
else
throw new PsdInvalidException("LayerId data length should be 4");
}
}
}

View File

@@ -0,0 +1,94 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Photoshop PSD FileType Plugin for Paint.NET
// http://psdplugin.codeplex.com/
//
// This software is provided under the MIT License:
// Copyright (c) 2006-2007 Frank Blumenberg
// Copyright (c) 2010-2015 Tao Yue
//
// See LICENSE.txt for complete licensing and attribution information.
//
/////////////////////////////////////////////////////////////////////////////////
using System;
namespace PhotoshopFile
{
internal enum LayerSectionType
{
Layer = 0,
OpenFolder = 1,
ClosedFolder = 2,
SectionDivider = 3
}
internal enum LayerSectionSubtype
{
Normal = 0,
SceneGroup = 1
}
/// <summary>
/// Layer sections are known as Groups in the Photoshop UI.
/// </summary>
internal class LayerSectionInfo : LayerInfo
{
public override string Signature
{
get { return "8BIM"; }
}
private string key;
public override string Key
{
get { return key; }
}
public LayerSectionType SectionType { get; set; }
private LayerSectionSubtype? subtype;
public LayerSectionSubtype Subtype
{
get { return subtype ?? LayerSectionSubtype.Normal; }
set { subtype = value; }
}
private string blendModeKey;
public string BlendModeKey
{
get { return blendModeKey; }
set
{
if (value.Length != 4)
{
throw new ArgumentException(
"BlendModeKey must be 4 characters in length.");
}
blendModeKey = value;
}
}
public LayerSectionInfo(PsdBinaryReader reader, string key, int dataLength)
{
// The key for layer section info is documented to be "lsct". However,
// some Photoshop files use the undocumented key "lsdk", with apparently
// the same data format.
this.key = key;
SectionType = (LayerSectionType)reader.ReadInt32();
if (dataLength >= 12)
{
var signature = reader.ReadAsciiChars(4);
if (signature != "8BIM")
throw new PsdInvalidException("Invalid section divider signature.");
BlendModeKey = reader.ReadAsciiChars(4);
if (dataLength >= 16)
{
Subtype = (LayerSectionSubtype)reader.ReadInt32();
}
}
}
}
}

View File

@@ -0,0 +1,42 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Photoshop PSD FileType Plugin for Paint.NET
// http://psdplugin.codeplex.com/
//
// This software is provided under the MIT License:
// Copyright (c) 2006-2007 Frank Blumenberg
// Copyright (c) 2010-2014 Tao Yue
//
// See LICENSE.txt for complete licensing and attribution information.
//
/////////////////////////////////////////////////////////////////////////////////
using System;
namespace PhotoshopFile
{
internal class LayerUnicodeName : LayerInfo
{
public override string Signature
{
get { return "8BIM"; }
}
public override string Key
{
get { return "luni"; }
}
public string Name { get; set; }
public LayerUnicodeName(string name)
{
Name = name;
}
public LayerUnicodeName(PsdBinaryReader reader)
{
Name = reader.ReadUnicodeString();
}
}
}

View File

@@ -0,0 +1,52 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Photoshop PSD FileType Plugin for Paint.NET
// http://psdplugin.codeplex.com/
//
// This software is provided under the MIT License:
// Copyright (c) 2006-2007 Frank Blumenberg
// Copyright (c) 2010-2014 Tao Yue
//
// See LICENSE.txt for complete licensing and attribution information.
//
/////////////////////////////////////////////////////////////////////////////////
using System;
using System.Diagnostics;
namespace PhotoshopFile
{
[DebuggerDisplay("Layer Info: { key }")]
internal class RawLayerInfo : LayerInfo
{
private string signature;
public override string Signature
{
get { return signature; }
}
private string key;
public override string Key
{
get { return key; }
}
public byte[] Data { get; private set; }
public RawLayerInfo(string key, string signature = "8BIM")
{
this.signature = signature;
this.key = key;
}
public RawLayerInfo(PsdBinaryReader reader, string signature, string key,
long dataLength)
{
this.signature = signature;
this.key = key;
Util.CheckByteArrayLength(dataLength);
Data = reader.ReadBytes((int)dataLength);
}
}
}

View File

@@ -0,0 +1,149 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Photoshop PSD FileType Plugin for Paint.NET
// http://psdplugin.codeplex.com/
//
// This software is provided under the MIT License:
// Copyright (c) 2006-2007 Frank Blumenberg
// Copyright (c) 2010-2014 Tao Yue
//
// Portions of this file are provided under the BSD 3-clause License:
// Copyright (c) 2006, Jonas Beckeman
//
// See LICENSE.txt for complete licensing and attribution information.
//
/////////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Specialized;
using System.Diagnostics;
using PDNWrapper;
using System.Globalization;
using Unity.Collections;
namespace PhotoshopFile
{
internal class Mask
{
/// <summary>
/// The layer to which this mask belongs
/// </summary>
public Layer Layer { get; private set; }
/// <summary>
/// The rectangle enclosing the mask.
/// </summary>
public Rectangle Rect { get; set; }
private byte backgroundColor;
public byte BackgroundColor
{
get { return backgroundColor; }
set
{
if ((value != 0) && (value != 255))
throw new PsdInvalidException("Mask background must be fully-opaque or fully-transparent.");
backgroundColor = value;
}
}
private static int positionVsLayerBit = BitVector32.CreateMask();
private static int disabledBit = BitVector32.CreateMask(positionVsLayerBit);
private static int invertOnBlendBit = BitVector32.CreateMask(disabledBit);
private BitVector32 flags;
public BitVector32 Flags { get { return flags; } }
/// <summary>
/// If true, the position of the mask is relative to the layer.
/// </summary>
public bool PositionVsLayer
{
get { return flags[positionVsLayerBit]; }
set { flags[positionVsLayerBit] = value; }
}
public bool Disabled
{
get { return flags[disabledBit]; }
set { flags[disabledBit] = value; }
}
/// <summary>
/// if true, invert the mask when blending.
/// </summary>
public bool InvertOnBlend
{
get { return flags[invertOnBlendBit]; }
set { flags[invertOnBlendBit] = value; }
}
/// <summary>
/// Mask image data.
/// </summary>
public NativeArray<byte> ImageData { get; set; }
public Mask(Layer layer)
{
Layer = layer;
this.flags = new BitVector32();
}
public Mask(Layer layer, Rectangle rect, byte color, BitVector32 flags)
{
Layer = layer;
Rect = rect;
BackgroundColor = color;
this.flags = flags;
}
}
/// <summary>
/// Mask info for a layer. Contains both the layer and user masks.
/// </summary>
internal class MaskInfo
{
public Mask LayerMask { get; set; }
public Mask UserMask { get; set; }
/// <summary>
/// Construct MaskInfo with null masks.
/// </summary>
public MaskInfo()
{
}
public MaskInfo(PsdBinaryReader reader, Layer layer)
{
Util.DebugMessage(reader.BaseStream, "Load, Begin, MaskInfo");
var maskLength = reader.ReadUInt32();
if (maskLength <= 0)
return;
var startPosition = reader.BaseStream.Position;
var endPosition = startPosition + maskLength;
// Read layer mask
var rectangle = reader.ReadRectangle();
var backgroundColor = reader.ReadByte();
var flagsByte = reader.ReadByte();
LayerMask = new Mask(layer, rectangle, backgroundColor, new BitVector32(flagsByte));
// User mask is supplied separately when there is also a vector mask.
if (maskLength == 36)
{
var userFlagsByte = reader.ReadByte();
var userBackgroundColor = reader.ReadByte();
var userRectangle = reader.ReadRectangle();
UserMask = new Mask(layer, userRectangle, userBackgroundColor, new BitVector32(userFlagsByte));
}
// 20-byte mask data will end with padding.
reader.BaseStream.Position = endPosition;
Util.DebugMessage(reader.BaseStream, "Load, End, MaskInfo");
}
}
}