Singularity/Library/PackageCache/com.unity.2d.psdimporter@6.0.7/Editor/PSDPlugin/PsdFile/Util.cs

391 lines
12 KiB
C#
Raw Normal View History

2024-05-06 14:45:45 -04:00
/////////////////////////////////////////////////////////////////////////////////
//
// 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.Diagnostics;
using PDNWrapper;
using System.IO;
using System.Linq;
using System.Text;
using Unity.Collections;
namespace PhotoshopFile
{
internal static class Util
{
[DebuggerDisplay("Top = {Top}, Bottom = {Bottom}, Left = {Left}, Right = {Right}")]
internal struct RectanglePosition
{
public int Top { get; set; }
public int Bottom { get; set; }
public int Left { get; set; }
public int Right { get; set; }
}
public static Rectangle IntersectWith(
this Rectangle thisRect, Rectangle rect)
{
thisRect.Intersect(rect);
return thisRect;
}
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Fills a buffer with a byte value.
/// </summary>
static public void Fill(byte[] ptr, int start, int end, byte value)
{
while (start < end)
{
ptr[start] = value;
start++;
}
}
static public void Invert(byte[] ptr, int ptrStart, int ptrEnd)
{
while (ptrStart < ptrEnd)
{
ptr[ptrStart] = (byte)(ptr[ptrStart] ^ 0xff);
ptrStart++;
}
}
/// <summary>
/// Fills a buffer with a byte value.
/// </summary>
static public void Fill(NativeArray<byte> ptr, int start, int end, byte value)
{
while (start < end)
{
ptr[start] = value;
start++;
}
}
static public void Invert(NativeArray<byte> ptr, int ptrStart, int ptrEnd)
{
while (ptrStart < ptrEnd)
{
ptr[ptrStart] = (byte)(ptr[ptrStart] ^ 0xff);
ptrStart++;
}
}
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Reverses the endianness of a 2-byte word.
/// </summary>
static public void SwapBytes2(byte[] ptr, int start)
{
byte byte0 = ptr[start];
ptr[start] = ptr[start + 1];
ptr[start + 1] = byte0;
}
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Reverses the endianness of a 4-byte word.
/// </summary>
static public void SwapBytes4(byte[] ptr, int start)
{
byte byte0 = ptr[start];
byte byte1 = ptr[start + 1];
ptr[start] = ptr[start + 3];
ptr[start + 1] = ptr[start + 2];
ptr[start + 2] = byte1;
ptr[start + 3] = byte0;
}
/// <summary>
/// Reverses the endianness of a word of arbitrary length.
/// </summary>
static public void SwapBytes(byte[] ptr, int start, int nLength)
{
for (long i = 0; i < nLength / 2; ++i)
{
byte t = ptr[start + i];
ptr[start + i] = ptr[start + nLength - i - 1];
ptr[start + nLength - i - 1] = t;
}
}
///////////////////////////////////////////////////////////////////////////
public static void SwapByteArray(int bitDepth,
byte[] byteArray, int startIdx, int count)
{
switch (bitDepth)
{
case 1:
case 8:
break;
case 16:
SwapByteArray2(byteArray, startIdx, count);
break;
case 32:
SwapByteArray4(byteArray, startIdx, count);
break;
default:
throw new Exception(
"Byte-swapping implemented only for 16-bit and 32-bit depths.");
}
}
/// <summary>
/// Reverses the endianness of 2-byte words in a byte array.
/// </summary>
/// <param name="byteArray">Byte array containing the sequence on which to swap endianness</param>
/// <param name="startIdx">Byte index of the first word to swap</param>
/// <param name="count">Number of words to swap</param>
public static void SwapByteArray2(byte[] byteArray, int startIdx, int count)
{
int endIdx = startIdx + count * 2;
if (byteArray.Length < endIdx)
throw new IndexOutOfRangeException();
{
//fixed (byte* arrayPtr = &byteArray[0])
{
//byte* ptr = arrayPtr + startIdx;
//byte* endPtr = arrayPtr + endIdx;
while (startIdx < endIdx)
{
SwapBytes2(byteArray, startIdx);
startIdx += 2;
}
}
}
}
/// <summary>
/// Reverses the endianness of 4-byte words in a byte array.
/// </summary>
/// <param name="byteArray">Byte array containing the sequence on which to swap endianness</param>
/// <param name="startIdx">Byte index of the first word to swap</param>
/// <param name="count">Number of words to swap</param>
public static void SwapByteArray4(byte[] byteArray, int startIdx, int count)
{
int endIdx = startIdx + count * 4;
if (byteArray.Length < endIdx)
throw new IndexOutOfRangeException();
{
//fixed (byte* arrayPtr = &byteArray[0])
{
//byte* ptr = arrayPtr + startIdx;
//byte* endPtr = arrayPtr + endIdx;
while (startIdx < endIdx)
{
SwapBytes4(byteArray, startIdx);
startIdx += 4;
}
}
}
}
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Calculates the number of bytes required to store a row of an image
/// with the specified bit depth.
/// </summary>
/// <param name="size">The size of the image in pixels.</param>
/// <param name="bitDepth">The bit depth of the image.</param>
/// <returns>The number of bytes needed to store a row of the image.</returns>
public static int BytesPerRow(Size size, int bitDepth)
{
switch (bitDepth)
{
case 1:
return (size.Width + 7) / 8;
default:
return size.Width * BytesFromBitDepth(bitDepth);
}
}
/// <summary>
/// Round the integer to a multiple.
/// </summary>
public static int RoundUp(int value, int multiple)
{
if (value == 0)
return 0;
if (Math.Sign(value) != Math.Sign(multiple))
{
throw new ArgumentException(
"value and multiple cannot have opposite signs.");
}
var remainder = value % multiple;
if (remainder > 0)
{
value += (multiple - remainder);
}
return value;
}
/// <summary>
/// Get number of bytes required to pad to the specified multiple.
/// </summary>
public static int GetPadding(int length, int padMultiple)
{
if ((length < 0) || (padMultiple < 0))
throw new ArgumentException();
var remainder = length % padMultiple;
if (remainder == 0)
return 0;
var padding = padMultiple - remainder;
return padding;
}
/// <summary>
/// Returns the number of bytes needed to store a single pixel of the
/// specified bit depth.
/// </summary>
public static int BytesFromBitDepth(int depth)
{
switch (depth)
{
case 1:
case 8:
return 1;
case 16:
return 2;
case 32:
return 4;
default:
throw new ArgumentException("Invalid bit depth.");
}
}
public static short MinChannelCount(this PsdColorMode colorMode)
{
switch (colorMode)
{
case PsdColorMode.Bitmap:
case PsdColorMode.Duotone:
case PsdColorMode.Grayscale:
case PsdColorMode.Indexed:
case PsdColorMode.Multichannel:
return 1;
case PsdColorMode.Lab:
case PsdColorMode.RGB:
return 3;
case PsdColorMode.CMYK:
return 4;
}
throw new ArgumentException("Unknown color mode.");
}
/// <summary>
/// Verify that the offset and count will remain within the bounds of the
/// buffer.
/// </summary>
/// <returns>True if in bounds, false if out of bounds.</returns>
public static bool CheckBufferBounds(byte[] data, int offset, int count)
{
if (offset < 0)
return false;
if (count < 0)
return false;
if (offset + count > data.Length)
return false;
return true;
}
public static void CheckByteArrayLength(long length)
{
if (length < 0)
{
throw new Exception("Byte array cannot have a negative length.");
}
if (length > 0x7fffffc7)
{
throw new OutOfMemoryException(
"Byte array cannot exceed 2,147,483,591 in length.");
}
}
/// <summary>
/// Writes a message to the debug console, indicating the current position
/// in the stream in both decimal and hexadecimal formats.
/// </summary>
[Conditional("DEBUG")]
public static void DebugMessage(Stream stream, string message,
params object[] args)
{
//var formattedMessage = String.Format(message, args);
//Debug.WriteLine("0x{0:x}, {0}, {1}",
//stream.Position, formattedMessage);
}
}
/// <summary>
/// Fixed-point decimal, with 16-bit integer and 16-bit fraction.
/// </summary>
internal class UFixed16_16
{
public UInt16 Integer { get; set; }
public UInt16 Fraction { get; set; }
public UFixed16_16(UInt16 integer, UInt16 fraction)
{
Integer = integer;
Fraction = fraction;
}
/// <summary>
/// Split the high and low words of a 32-bit unsigned integer into a
/// fixed-point number.
/// </summary>
public UFixed16_16(UInt32 value)
{
Integer = (UInt16)(value >> 16);
Fraction = (UInt16)(value & 0x0000ffff);
}
public UFixed16_16(double value)
{
if (value >= 65536.0) throw new OverflowException();
if (value < 0) throw new OverflowException();
Integer = (UInt16)value;
// Round instead of truncate, because doubles may not represent the
// fraction exactly.
Fraction = (UInt16)((value - Integer) * 65536 + 0.5);
}
public static implicit operator double(UFixed16_16 value)
{
return (double)value.Integer + value.Fraction / 65536.0;
}
}
}