testss
This commit is contained in:
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
@@ -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.
|
||||
}
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
}
|
@@ -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; }
|
||||
}
|
||||
}
|
@@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user