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,50 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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;
namespace PhotoshopFile.Compression
{
internal class EndianReverser : ImageData
{
private ImageData imageData;
protected override bool AltersWrittenData
{
get { return true; }
}
public EndianReverser(ImageData imageData)
: base(imageData.Size, imageData.BitDepth)
{
this.imageData = imageData;
}
internal override void Read(byte[] buffer)
{
imageData.Read(buffer);
var numPixels = Size.Width * Size.Height;
if (numPixels == 0)
{
return;
}
Util.SwapByteArray(BitDepth, buffer, 0, numPixels);
}
public override byte[] ReadCompressed()
{
return imageData.ReadCompressed();
}
}
}

View File

@@ -0,0 +1,57 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 PDNWrapper;
using System.IO.Compression;
namespace PhotoshopFile.Compression
{
internal abstract class ImageData
{
public int BitDepth { get; private set; }
public int BytesPerRow { get; private set; }
public Size Size { get; private set; }
protected abstract bool AltersWrittenData { get; }
protected ImageData(Size size, int bitDepth)
{
Size = size;
BitDepth = bitDepth;
BytesPerRow = Util.BytesPerRow(size, bitDepth);
}
/// <summary>
/// Reads decompressed image data.
/// </summary>
public virtual byte[] Read()
{
var imageLongLength = (long)BytesPerRow * Size.Height;
Util.CheckByteArrayLength(imageLongLength);
var buffer = new byte[imageLongLength];
Read(buffer);
return buffer;
}
internal abstract void Read(byte[] buffer);
/// <summary>
/// Reads compressed image data.
/// </summary>
public abstract byte[] ReadCompressed();
}
}

View File

@@ -0,0 +1,96 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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.IO.Compression;
using PDNWrapper;
namespace PhotoshopFile.Compression
{
internal static class ImageDataFactory
{
/// <summary>
/// Creates an ImageData object to compress or decompress image data.
/// </summary>
/// <param name="channel">The Channel associated with the image data.</param>
/// <param name="data">The image data to be decompressed, or null if
/// image data is to be compressed.</param>
public static ImageData Create(Channel channel, byte[] data)
{
var bitDepth = channel.Layer.PsdFile.BitDepth;
ImageData imageData;
switch (channel.ImageCompression)
{
case ImageCompression.Raw:
imageData = new RawImage(data, channel.Rect.Size, bitDepth);
break;
case ImageCompression.Rle:
imageData = new RleImage(data, channel.RleRowLengths,
channel.Rect.Size, bitDepth);
break;
case ImageCompression.Zip:
// Photoshop treats 32-bit Zip as 32-bit ZipPrediction
imageData = (bitDepth == 32)
? CreateZipPredict(data, channel.Rect.Size, bitDepth)
: new ZipImage(data, channel.Rect.Size, bitDepth);
break;
case ImageCompression.ZipPrediction:
imageData = CreateZipPredict(data, channel.Rect.Size, bitDepth);
break;
default:
throw new PsdInvalidException("Unknown image compression method.");
}
// Reverse endianness of multi-byte image data
imageData = WrapEndianness(imageData);
return imageData;
}
private static ImageData CreateZipPredict(byte[] data, Size size,
int bitDepth)
{
switch (bitDepth)
{
case 16:
return new ZipPredict16Image(data, size);
case 32:
return new ZipPredict32Image(data, size);
default:
throw new PsdInvalidException(
"ZIP with prediction is only available for 16 and 32 bit depths.");
}
}
private static ImageData WrapEndianness(ImageData imageData)
{
// Single-byte image does not require endianness reversal
if (imageData.BitDepth <= 8)
{
return imageData;
}
// Bytes will be reordered by the compressor, so no wrapper is needed
if ((imageData is ZipPredict16Image) || (imageData is ZipPredict32Image))
{
return imageData;
}
return new EndianReverser(imageData);
}
}
}

View File

@@ -0,0 +1,44 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 PDNWrapper;
namespace PhotoshopFile.Compression
{
internal class RawImage : ImageData
{
private byte[] data;
protected override bool AltersWrittenData
{
get { return false; }
}
public RawImage(byte[] data, Size size, int bitDepth)
: base(size, bitDepth)
{
this.data = data;
}
internal override void Read(byte[] buffer)
{
Array.Copy(data, buffer, data.Length);
}
public override byte[] ReadCompressed()
{
return data;
}
}
}

View File

@@ -0,0 +1,61 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Photoshop PSD FileType Plugin for Paint.NET
// http://psdplugin.codeplex.com/
//
// This software is ptortorovided 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 PDNWrapper;
using System.IO;
using System.Linq;
namespace PhotoshopFile.Compression
{
internal class RleImage : ImageData
{
private byte[] rleData;
private RleRowLengths rleRowLengths;
protected override bool AltersWrittenData
{
get { return false; }
}
public RleImage(byte[] rleData, RleRowLengths rleRowLengths,
Size size, int bitDepth)
: base(size, bitDepth)
{
this.rleData = rleData;
this.rleRowLengths = rleRowLengths;
}
internal override void Read(byte[] buffer)
{
var rleStream = new MemoryStream(rleData);
var rleReader = new RleReader(rleStream);
var bufferIndex = 0;
for (int i = 0; i < Size.Height; i++)
{
var bytesRead = rleReader.Read(buffer, bufferIndex, BytesPerRow);
if (bytesRead != BytesPerRow)
{
throw new Exception("RLE row decompressed to unexpected length.");
}
bufferIndex += bytesRead;
}
}
public override byte[] ReadCompressed()
{
return rleData;
}
}
}

View File

@@ -0,0 +1,101 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 PDNWrapper;
using System.IO;
using System.IO.Compression;
namespace PhotoshopFile.Compression
{
internal class ZipImage : ImageData
{
private MemoryStream zipDataStream;
private DeflateStream zipStream;
protected override bool AltersWrittenData
{
get { return false; }
}
public ZipImage(byte[] data, Size size, int bitDepth)
: base(size, bitDepth)
{
if (data == null)
{
InitCompress();
}
else
{
InitDecompress(data);
}
}
private void InitCompress()
{
zipDataStream = new MemoryStream();
// Write 2-byte zlib (RFC 1950) header
//
// CMF Compression Method and flags:
// CM 0:3 = 8 = deflate
// CINFO 4:7 = 4 = undefined, RFC 1950 only defines CINFO = 8
//
// FLG Flags:
// FCHECK 0:4 = 9 = check bits for CMF and FLG
// FDICT 5 = 0 = no preset dictionary
// FLEVEL 6:7 = 2 = default compression level
zipDataStream.WriteByte(0x48);
zipDataStream.WriteByte(0x89);
zipStream = new DeflateStream(zipDataStream, CompressionMode.Compress,
true);
}
private void InitDecompress(byte[] data)
{
zipDataStream = new MemoryStream(data);
// .NET implements Deflate (RFC 1951) but not zlib (RFC 1950),
// so we have to skip the first two bytes.
zipDataStream.ReadByte();
zipDataStream.ReadByte();
zipStream = new DeflateStream(zipDataStream, CompressionMode.Decompress,
true);
}
internal override void Read(byte[] buffer)
{
var bytesToRead = (long)Size.Height * BytesPerRow;
Util.CheckByteArrayLength(bytesToRead);
var bytesRead = zipStream.Read(buffer, 0, (int)bytesToRead);
if (bytesRead != bytesToRead)
{
throw new Exception("ZIP stream was not fully decompressed.");
}
}
public override byte[] ReadCompressed()
{
// Write out the last block. (Flush leaves the last block open.)
zipStream.Close();
// Do not write the zlib header when the image data is empty
var result = (zipDataStream.Length == 2)
? new byte[0]
: zipDataStream.ToArray();
return result;
}
}
}

View File

@@ -0,0 +1,113 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 PDNWrapper;
using System.IO.Compression;
namespace PhotoshopFile.Compression
{
internal class ZipPredict16Image : ImageData
{
private ImageData zipImage;
protected override bool AltersWrittenData
{
get { return true; }
}
public ZipPredict16Image(byte[] zipData, Size size)
: base(size, 16)
{
// 16-bitdepth images are delta-encoded word-by-word. The deltas
// are thus big-endian and must be reversed for further processing.
var zipRawImage = new ZipImage(zipData, size, 16);
zipImage = new EndianReverser(zipRawImage);
}
internal override void Read(byte[] buffer)
{
if (buffer.Length == 0)
{
return;
}
zipImage.Read(buffer);
{
{
Unpredict(buffer);
}
}
}
public override byte[] ReadCompressed()
{
return zipImage.ReadCompressed();
}
private void Predict(/*UInt16**/ byte[] ptrData)
{
int size = sizeof(UInt16);
// Delta-encode each row
for (int i = 0; i < Size.Height; i++)
{
int rowOffset = Size.Width * i * size;
//UInt16* ptrDataRow = ptrData;
var ptrDataRowEnd = Size.Width - 1;
// Start with the last column in the row
while (ptrDataRowEnd > 0)
{
var v = BitConverter.ToUInt16(ptrData, ptrDataRowEnd * size + rowOffset);
var v1 = BitConverter.ToUInt16(ptrData, (ptrDataRowEnd - 1) * size + rowOffset);
v -= v1;
var b = BitConverter.GetBytes(v);
for (int c = 0; c < b.Length; ++c)
{
ptrData[ptrDataRowEnd * size + rowOffset + c] = b[c];
}
ptrDataRowEnd--;
}
}
}
/// <summary>
/// Unpredicts the decompressed, native-endian image data.
/// </summary>
private void Unpredict(byte[] ptrData)
{
int size = sizeof(UInt16);
// Delta-decode each row
for (int i = 0; i < Size.Height; i++)
{
//UInt16* ptrDataRowEnd = ptrData + Size.Width;
int rowOffset = Size.Width * i * size;
// Start with column index 1 on each row
int start = 1;
while (start < Size.Width)
{
var v = BitConverter.ToUInt16(ptrData, start * size + rowOffset);
var v1 = BitConverter.ToUInt16(ptrData, (start - 1) * size + rowOffset);
v += v1;
var b = BitConverter.GetBytes(v);
for (int c = 0; c < b.Length; ++c)
{
ptrData[start * size + rowOffset + c] = b[c];
}
start++;
}
}
}
}
}

View File

@@ -0,0 +1,175 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 PDNWrapper;
namespace PhotoshopFile.Compression
{
internal class ZipPredict32Image : ImageData
{
private ZipImage zipImage;
protected override bool AltersWrittenData
{
// Prediction will pack the data into a temporary buffer, so the
// original data will remain unchanged.
get { return false; }
}
public ZipPredict32Image(byte[] zipData, Size size)
: base(size, 32)
{
zipImage = new ZipImage(zipData, size, 32);
}
internal override void Read(byte[] buffer)
{
if (buffer.Length == 0)
{
return;
}
var predictedData = new byte[buffer.Length];
zipImage.Read(predictedData);
{
//fixed (byte* ptrData = &predictedData[0])
//fixed (byte* ptrOutput = &buffer[0])
{
Unpredict(predictedData, buffer);
}
}
}
public override byte[] ReadCompressed()
{
return zipImage.ReadCompressed();
}
private void Predict(byte[] ptrData, byte[] ptrOutput /*Int32* ptrData, byte* ptrOutput*/)
{
int size = sizeof(Int32);
int inputIndex = 0;
int outputIndex = 0;
for (int i = 0; i < Size.Height; i++)
{
// Pack together the individual bytes of the 32-bit words, high-order
// bytes before low-order bytes.
int offset1 = Size.Width;
int offset2 = 2 * offset1;
int offset3 = 3 * offset1;
//Int32* ptrDataRow = ptrData;
//Int32* ptrDataRowEnd = ptrDataRow + Size.Width;
int start = 0, end = Size.Width;
//while (ptrData < ptrDataRowEnd)
while (start < end)
{
Int32 data = BitConverter.ToInt32(ptrData, inputIndex);
ptrOutput[start + outputIndex] = (byte)(data >> 24);
ptrOutput[start + outputIndex + offset1] = (byte)(data >> 16);
ptrOutput[start + outputIndex + offset2] = (byte)(data >> 8);
ptrOutput[start + outputIndex + offset3] = (byte)(data);
//ptrData++;
//ptrOutput++;
start++;
inputIndex += size;
}
// Delta-encode the row
//byte* ptrOutputRow = ptrOutput;
//byte* ptrOutputRowEnd = ptrOutputRow + BytesPerRow;
//ptrOutput = ptrOutputRowEnd - 1;
start = BytesPerRow - 1;
while (start > 0)
{
ptrOutput[start + outputIndex] -= ptrOutput[start + outputIndex - 1];
start--;
}
outputIndex += BytesPerRow;
// Advance pointer to next row
//ptrOutput = ptrOutputRowEnd;
//Debug.Assert(ptrData == ptrDataRowEnd);
}
}
/// <summary>
/// Unpredicts the raw decompressed image data into a 32-bpp bitmap with
/// native endianness.
/// </summary>
private void Unpredict(byte[] ptrData, byte[] ptrOutput /*byte* ptrData, Int32* ptrOutput*/)
{
int inputIndex = 0;
int outputIndex = 0;
for (int i = 0; i < Size.Height; i++)
{
//byte* ptrDataRow = ptrData;
//byte* ptrDataRowEnd = ptrDataRow + BytesPerRow;
// Delta-decode each row
//ptrData++;
//while (ptrData < ptrDataRowEnd)
int startIndex = 1;
while (startIndex < BytesPerRow)
{
//*ptrData += *(ptrData - 1);
//ptrData++;
ptrData[inputIndex + startIndex] += ptrData[inputIndex + startIndex - 1];
startIndex++;
}
// Within each row, the individual bytes of the 32-bit words are
// packed together, high-order bytes before low-order bytes.
// We now unpack them into words.
int offset1 = Size.Width;
int offset2 = 2 * offset1;
int offset3 = 3 * offset1;
//ptrData = ptrDataRow;
//Int32* ptrOutputRowEnd = ptrOutput + Size.Width;
//while (ptrOutput < ptrOutputRowEnd)
startIndex = 0;
while (startIndex < Size.Width)
{
Int32 pp = (Int32)ptrData[inputIndex + startIndex] << 24;
pp |= (Int32)ptrData[inputIndex + startIndex + offset1] << 16;
pp |= (Int32)ptrData[inputIndex + startIndex + offset2] << 8;
pp |= (Int32)ptrData[inputIndex + startIndex + offset3];
byte[] rr = BitConverter.GetBytes(pp);
for (int k = 0; k < rr.Length; ++k)
{
ptrOutput[outputIndex] = rr[k];
outputIndex++;
}
startIndex++;
//*ptrOutput = *(ptrData) << 24
// | *(ptrData + offset1) << 16
// | *(ptrData + offset2) << 8
// | *(ptrData + offset3);
//ptrData++;
//ptrOutput++;
}
// Advance pointer to next row
//ptrData = ptrDataRowEnd;
//Debug.Assert(ptrOutput == ptrOutputRowEnd);
inputIndex += BytesPerRow;
}
}
}
}