mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-08-20 06:38:07 +08:00
Improve memory allocation by changing IFilter.Decode() signature to use Memory<byte> instead of ReadOnlyMemory/ReadOnlySpan
This commit is contained in:
parent
2b54a546d3
commit
f84f2aceec
25
src/UglyToad.PdfPig.Core/MemoryHelper.cs
Normal file
25
src/UglyToad.PdfPig.Core/MemoryHelper.cs
Normal file
@ -0,0 +1,25 @@
|
||||
namespace UglyToad.PdfPig.Core
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// <summary>
|
||||
/// Memory extensions.
|
||||
/// </summary>
|
||||
public static class MemoryHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a read-only <see cref="MemoryStream"/> from a ReadOnlyMemory<byte>.
|
||||
/// </summary>
|
||||
public static MemoryStream AsReadOnlyMemoryStream(this ReadOnlyMemory<byte> memory)
|
||||
{
|
||||
if (MemoryMarshal.TryGetArray(memory, out ArraySegment<byte> array))
|
||||
{
|
||||
return new MemoryStream(array.Array!, array.Offset, array.Count, false);
|
||||
}
|
||||
|
||||
return new MemoryStream(memory.ToArray(), false);
|
||||
}
|
||||
}
|
||||
}
|
@ -180,7 +180,7 @@
|
||||
{
|
||||
}
|
||||
|
||||
public void EndInlineImage(ReadOnlyMemory<byte> bytes)
|
||||
public void EndInlineImage(Memory<byte> bytes)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@
|
||||
{
|
||||
public bool IsSupported => false;
|
||||
|
||||
public ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex)
|
||||
public Memory<byte> Decode(Memory<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
@ -17,9 +17,9 @@
|
||||
|
||||
public int BitsPerComponent { get; set; } = 8;
|
||||
|
||||
public ReadOnlyMemory<byte> RawMemory { get; }
|
||||
public Memory<byte> RawMemory { get; }
|
||||
|
||||
public ReadOnlySpan<byte> RawBytes => RawMemory.Span;
|
||||
public Span<byte> RawBytes => RawMemory.Span;
|
||||
|
||||
public RenderingIntent RenderingIntent { get; set; } = RenderingIntent.RelativeColorimetric;
|
||||
|
||||
@ -35,11 +35,11 @@
|
||||
|
||||
public ColorSpaceDetails ColorSpaceDetails { get; set; }
|
||||
|
||||
public ReadOnlyMemory<byte> DecodedBytes { get; set; }
|
||||
public Memory<byte> DecodedBytes { get; set; }
|
||||
|
||||
public IPdfImage? MaskImage { get; }
|
||||
|
||||
public bool TryGetBytesAsMemory(out ReadOnlyMemory<byte> bytes)
|
||||
public bool TryGetBytesAsMemory(out Memory<byte> bytes)
|
||||
{
|
||||
bytes = DecodedBytes;
|
||||
return !bytes.IsEmpty;
|
||||
|
@ -208,7 +208,7 @@
|
||||
// Special case handling for inline images.
|
||||
var imageData = ReadInlineImageData();
|
||||
isInInlineImage = false;
|
||||
CurrentToken = new InlineImageDataToken(new ReadOnlyMemory<byte>([..imageData]));
|
||||
CurrentToken = new InlineImageDataToken(new Memory<byte>([..imageData]));
|
||||
hasBytePreRead = false;
|
||||
return true;
|
||||
}
|
||||
|
@ -5,16 +5,16 @@
|
||||
/// <summary>
|
||||
/// Inline image data is used to embed images in PDF content streams. The content is wrapped by ID and ED tags in a BI operation.
|
||||
/// </summary>
|
||||
public sealed class InlineImageDataToken : IDataToken<ReadOnlyMemory<byte>>
|
||||
public sealed class InlineImageDataToken : IDataToken<Memory<byte>>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public ReadOnlyMemory<byte> Data { get; }
|
||||
public Memory<byte> Data { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="InlineImageDataToken"/>.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
public InlineImageDataToken(ReadOnlyMemory<byte> data)
|
||||
public InlineImageDataToken(Memory<byte> data)
|
||||
{
|
||||
Data = data;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
/// A stream consists of a dictionary followed by zero or more bytes bracketed between the keywords stream and endstream.
|
||||
/// The bytes may be compressed by application of zero or more filters which are run in the order specified in the <see cref="StreamDictionary"/>.
|
||||
/// </summary>
|
||||
public class StreamToken : IDataToken<ReadOnlyMemory<byte>>
|
||||
public sealed class StreamToken : IDataToken<Memory<byte>>
|
||||
{
|
||||
/// <summary>
|
||||
/// The dictionary specifying the length of the stream, any applied compression filters and additional information.
|
||||
@ -16,7 +16,7 @@
|
||||
/// <summary>
|
||||
/// The compressed byte data of the stream.
|
||||
/// </summary>
|
||||
public ReadOnlyMemory<byte> Data { get; }
|
||||
public Memory<byte> Data { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StreamToken"/>.
|
||||
@ -34,7 +34,7 @@
|
||||
/// </summary>
|
||||
/// <param name="streamDictionary">The stream dictionary.</param>
|
||||
/// <param name="data">The stream data.</param>
|
||||
public StreamToken(DictionaryToken streamDictionary, ReadOnlyMemory<byte> data)
|
||||
public StreamToken(DictionaryToken streamDictionary, Memory<byte> data)
|
||||
{
|
||||
StreamDictionary = streamDictionary ?? throw new ArgumentNullException(nameof(streamDictionary));
|
||||
Data = data;
|
||||
|
@ -37,12 +37,12 @@
|
||||
/// <summary>
|
||||
/// The encoded memory of the image with all filters still applied.
|
||||
/// </summary>
|
||||
ReadOnlyMemory<byte> RawMemory { get; }
|
||||
Memory<byte> RawMemory { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The encoded memory span of the image with all filters still applied.
|
||||
/// </summary>
|
||||
ReadOnlySpan<byte> RawBytes { get; }
|
||||
Span<byte> RawBytes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The color rendering intent to be used when rendering the image.
|
||||
@ -104,7 +104,7 @@
|
||||
/// Get the decoded memory of the image if applicable. For JPEG images and some other types the
|
||||
/// <see cref="RawMemory"/> should be used directly.
|
||||
/// </summary>
|
||||
bool TryGetBytesAsMemory(out ReadOnlyMemory<byte> memory);
|
||||
bool TryGetBytesAsMemory(out Memory<byte> memory);
|
||||
|
||||
/// <summary>
|
||||
/// Try to convert the image to PNG. Doesn't support conversion of JPG to PNG.
|
||||
|
@ -16,7 +16,7 @@
|
||||
/// </summary>
|
||||
public class InlineImage : IPdfImage
|
||||
{
|
||||
private readonly Lazy<ReadOnlyMemory<byte>>? memoryFactory;
|
||||
private readonly Lazy<Memory<byte>>? memoryFactory;
|
||||
|
||||
/// <inheritdoc />
|
||||
public PdfRectangle Bounds { get; }
|
||||
@ -49,10 +49,10 @@
|
||||
public bool Interpolate { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReadOnlyMemory<byte> RawMemory { get; }
|
||||
public Memory<byte> RawMemory { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReadOnlySpan<byte> RawBytes => RawMemory.Span;
|
||||
public Span<byte> RawBytes => RawMemory.Span;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ColorSpaceDetails ColorSpaceDetails { get; }
|
||||
@ -71,7 +71,7 @@
|
||||
RenderingIntent renderingIntent,
|
||||
bool interpolate,
|
||||
IReadOnlyList<double> decode,
|
||||
ReadOnlyMemory<byte> rawMemory,
|
||||
Memory<byte> rawMemory,
|
||||
ILookupFilterProvider filterProvider,
|
||||
IReadOnlyList<NameToken> filterNames,
|
||||
DictionaryToken streamDictionary,
|
||||
@ -103,13 +103,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
memoryFactory = supportsFilters ? new Lazy<ReadOnlyMemory<byte>>(() =>
|
||||
memoryFactory = supportsFilters ? new Lazy<Memory<byte>>(() =>
|
||||
{
|
||||
var b = RawMemory;
|
||||
for (var i = 0; i < filters.Count; i++)
|
||||
{
|
||||
var filter = filters[i];
|
||||
b = filter.Decode(b.Span, streamDictionary, filterProvider, i);
|
||||
b = filter.Decode(b, streamDictionary, filterProvider, i);
|
||||
}
|
||||
|
||||
return b;
|
||||
@ -119,7 +119,7 @@
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool TryGetBytesAsMemory(out ReadOnlyMemory<byte> bytes)
|
||||
public bool TryGetBytesAsMemory(out Memory<byte> bytes)
|
||||
{
|
||||
bytes = null;
|
||||
if (memoryFactory is null)
|
||||
|
@ -11,33 +11,35 @@
|
||||
{
|
||||
private const byte EmptyBlock = (byte)'z';
|
||||
private const byte Offset = (byte)'!';
|
||||
private const byte EmptyCharacterPadding = (byte) 'u';
|
||||
private const byte EmptyCharacterPadding = (byte)'u';
|
||||
|
||||
private static ReadOnlySpan<byte> EndOfDataBytes => [(byte)'~', (byte)'>'];
|
||||
|
||||
private static readonly int[] PowerByIndex = [
|
||||
private static readonly int[] PowerByIndex =
|
||||
[
|
||||
1,
|
||||
85,
|
||||
85 * 85,
|
||||
85 * 85 * 85,
|
||||
85 * 85 * 85 *85
|
||||
85 * 85 * 85 * 85
|
||||
];
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsSupported { get; } = true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex)
|
||||
public Memory<byte> Decode(Memory<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex)
|
||||
{
|
||||
Span<byte> asciiBuffer = stackalloc byte[5];
|
||||
Span<byte> inputSpan = input.Span;
|
||||
|
||||
var index = 0;
|
||||
|
||||
using var writer = new ArrayPoolBufferWriter<byte>();
|
||||
|
||||
for (var i = 0; i < input.Length; i++)
|
||||
|
||||
for (var i = 0; i < inputSpan.Length; i++)
|
||||
{
|
||||
var value = input[i];
|
||||
var value = inputSpan[i];
|
||||
|
||||
if (IsWhiteSpace(value))
|
||||
{
|
||||
@ -46,7 +48,7 @@
|
||||
|
||||
if (value == EndOfDataBytes[0])
|
||||
{
|
||||
if (i == input.Length - 1 || input[i + 1] == EndOfDataBytes[1])
|
||||
if (i == inputSpan.Length - 1 || inputSpan[i + 1] == EndOfDataBytes[1])
|
||||
{
|
||||
if (index > 0)
|
||||
{
|
||||
@ -80,7 +82,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
asciiBuffer[index] = (byte) (value - Offset);
|
||||
asciiBuffer[index] = (byte)(value - Offset);
|
||||
index++;
|
||||
}
|
||||
|
||||
@ -111,7 +113,7 @@
|
||||
{
|
||||
ascii[i] = EmptyCharacterPadding - Offset;
|
||||
}
|
||||
|
||||
|
||||
int value = 0;
|
||||
value += ascii[0] * PowerByIndex[4];
|
||||
value += ascii[1] * PowerByIndex[3];
|
||||
@ -123,28 +125,23 @@
|
||||
|
||||
if (index > 2)
|
||||
{
|
||||
writer.Write((byte) (value >> 16));
|
||||
writer.Write((byte)(value >> 16));
|
||||
}
|
||||
|
||||
if (index > 3)
|
||||
{
|
||||
writer.Write((byte) (value >> 8));
|
||||
writer.Write((byte)(value >> 8));
|
||||
}
|
||||
|
||||
if (index > 4)
|
||||
{
|
||||
writer.Write((byte) value);
|
||||
writer.Write((byte)value);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsWhiteSpace(byte b)
|
||||
{
|
||||
if (b == '\r' || b == '\n' || b == ' ')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return b == '\r' || b == '\n' || b == ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,26 +28,27 @@
|
||||
public bool IsSupported { get; } = true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex)
|
||||
public Memory<byte> Decode(Memory<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex)
|
||||
{
|
||||
Span<byte> pair = stackalloc byte[2];
|
||||
Span<byte> inputSpan = input.Span;
|
||||
var index = 0;
|
||||
|
||||
using var writer = new ArrayPoolBufferWriter<byte>(input.Length);
|
||||
|
||||
for (var i = 0; i < input.Length; i++)
|
||||
{
|
||||
if (input[i] == '>')
|
||||
if (inputSpan[i] == '>')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (IsWhitespace(input[i]) || input[i] == '<')
|
||||
if (IsWhitespace(inputSpan[i]) || inputSpan[i] == '<')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
pair[index] = input[i];
|
||||
pair[index] = inputSpan[i];
|
||||
index++;
|
||||
|
||||
if (index == 2)
|
||||
@ -86,7 +87,7 @@
|
||||
throw new InvalidOperationException("Invalid character encountered in hex encoded stream: " + (char)hexBytes[0]);
|
||||
}
|
||||
|
||||
var value = (byte) (first * 16 + second);
|
||||
var value = (byte)(first * 16 + second);
|
||||
|
||||
writer.Write(value);
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
namespace UglyToad.PdfPig.Filters
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using Tokens;
|
||||
using CcittFax;
|
||||
using Core;
|
||||
using Tokens;
|
||||
using Util;
|
||||
|
||||
// Filter updated from original port because of issue #982
|
||||
@ -20,7 +20,10 @@
|
||||
public bool IsSupported { get; } = true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex)
|
||||
public Memory<byte> Decode(Memory<byte> input,
|
||||
DictionaryToken streamDictionary,
|
||||
IFilterProvider filterProvider,
|
||||
int filterIndex)
|
||||
{
|
||||
var decodeParms = DecodeParameterResolver.GetFilterParameters(streamDictionary, filterIndex);
|
||||
|
||||
@ -40,8 +43,9 @@
|
||||
|
||||
var k = decodeParms.GetIntOrDefault(NameToken.K, 0);
|
||||
var encodedByteAlign = decodeParms.GetBooleanOrDefault(NameToken.EncodedByteAlign, false);
|
||||
var compressionType = DetermineCompressionType(input, k);
|
||||
using (var stream = new CcittFaxDecoderStream(new MemoryStream(input.ToArray()), cols, compressionType, encodedByteAlign))
|
||||
var compressionType = DetermineCompressionType(input.Span, k);
|
||||
|
||||
using (var stream = new CcittFaxDecoderStream(MemoryHelper.AsReadOnlyMemoryStream(input), cols, compressionType, encodedByteAlign))
|
||||
{
|
||||
var arraySize = (cols + 7) / 8 * rows;
|
||||
var decompressed = new byte[arraySize];
|
||||
@ -109,7 +113,7 @@
|
||||
|
||||
private static void InvertBitmap(Span<byte> bufferData)
|
||||
{
|
||||
for (int i = 0, c = bufferData.Length; i < c; i++)
|
||||
for (int i = 0; i < bufferData.Length; i++)
|
||||
{
|
||||
ref byte b = ref bufferData[i];
|
||||
b = (byte)(~b & 0xFF);
|
||||
|
@ -13,7 +13,7 @@
|
||||
public bool IsSupported { get; } = false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex)
|
||||
public Memory<byte> Decode(Memory<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex)
|
||||
{
|
||||
throw new NotSupportedException("The DST (Discrete Cosine Transform) Filter indicates data is encoded in JPEG format. " +
|
||||
"This filter is not currently supported but the raw data can be supplied to JPEG supporting libraries.");
|
||||
|
@ -5,6 +5,7 @@
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using Tokens;
|
||||
using UglyToad.PdfPig.Core;
|
||||
using Util;
|
||||
|
||||
/// <summary>
|
||||
@ -31,16 +32,15 @@
|
||||
public bool IsSupported { get; } = true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex)
|
||||
public Memory<byte> Decode(Memory<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex)
|
||||
{
|
||||
var parameters = DecodeParameterResolver.GetFilterParameters(streamDictionary, filterIndex);
|
||||
|
||||
var predictor = parameters.GetIntOrDefault(NameToken.Predictor, -1);
|
||||
|
||||
var bytes = input.ToArray();
|
||||
try
|
||||
{
|
||||
var decompressed = Decompress(bytes);
|
||||
var decompressed = Decompress(input);
|
||||
|
||||
if (predictor == -1)
|
||||
{
|
||||
@ -58,12 +58,12 @@
|
||||
// ignored.
|
||||
}
|
||||
|
||||
return bytes;
|
||||
return input;
|
||||
}
|
||||
|
||||
private static byte[] Decompress(byte[] input)
|
||||
private static byte[] Decompress(Memory<byte> input)
|
||||
{
|
||||
using (var memoryStream = new MemoryStream(input))
|
||||
using (var memoryStream = MemoryHelper.AsReadOnlyMemoryStream(input))
|
||||
using (var output = new MemoryStream())
|
||||
{
|
||||
// The first 2 bytes are the header which DeflateStream does not support.
|
||||
|
@ -21,6 +21,6 @@
|
||||
/// <param name="filterProvider">The filter provider.</param>
|
||||
/// <param name="filterIndex">The position of this filter in the pipeline used to encode data.</param>
|
||||
/// <returns>The decoded bytes.</returns>
|
||||
ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex);
|
||||
Memory<byte> Decode(Memory<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex);
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
public bool IsSupported { get; } = false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex)
|
||||
public Memory<byte> Decode(Memory<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex)
|
||||
{
|
||||
throw new NotSupportedException("The JBIG2 Filter for monochrome image data is not currently supported. " +
|
||||
"Try accessing the raw compressed data directly.");
|
||||
|
@ -13,7 +13,7 @@
|
||||
public bool IsSupported { get; } = false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex)
|
||||
public Memory<byte> Decode(Memory<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex)
|
||||
{
|
||||
throw new NotSupportedException("The JPX Filter (JPEG2000) for image data is not currently supported. " +
|
||||
"Try accessing the raw compressed data directly.");
|
||||
|
@ -29,7 +29,7 @@ namespace UglyToad.PdfPig.Filters
|
||||
public bool IsSupported { get; } = true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex)
|
||||
public Memory<byte> Decode(Memory<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex)
|
||||
{
|
||||
var parameters = DecodeParameterResolver.GetFilterParameters(streamDictionary, filterIndex);
|
||||
|
||||
@ -39,7 +39,7 @@ namespace UglyToad.PdfPig.Filters
|
||||
|
||||
if (predictor > 1)
|
||||
{
|
||||
var decompressed = Decode(input, earlyChange == 1);
|
||||
var decompressed = Decode(input.Span, earlyChange == 1);
|
||||
|
||||
var colors = Math.Min(parameters.GetIntOrDefault(NameToken.Colors, DefaultColors), 32);
|
||||
var bitsPerComponent = parameters.GetIntOrDefault(NameToken.BitsPerComponent, DefaultBitsPerComponent);
|
||||
@ -48,7 +48,7 @@ namespace UglyToad.PdfPig.Filters
|
||||
return PngPredictor.Decode(decompressed, predictor, colors, bitsPerComponent, columns);
|
||||
}
|
||||
|
||||
return Decode(input, earlyChange == 1);
|
||||
return Decode(input.Span, earlyChange == 1);
|
||||
}
|
||||
|
||||
private static byte[] Decode(ReadOnlySpan<byte> input, bool isEarlyChange)
|
||||
|
@ -16,14 +16,16 @@
|
||||
public bool IsSupported { get; } = true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReadOnlyMemory<byte> Decode(ReadOnlySpan<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex)
|
||||
public Memory<byte> Decode(Memory<byte> input, DictionaryToken streamDictionary, IFilterProvider filterProvider, int filterIndex)
|
||||
{
|
||||
using var output = new ArrayPoolBufferWriter<byte>(input.Length);
|
||||
|
||||
Span<byte> inputSpan = input.Span;
|
||||
|
||||
var i = 0;
|
||||
while (i < input.Length)
|
||||
{
|
||||
var runLength = input[i];
|
||||
var runLength = inputSpan[i];
|
||||
|
||||
if (runLength == EndOfDataLength)
|
||||
{
|
||||
@ -39,7 +41,7 @@
|
||||
{
|
||||
i++;
|
||||
|
||||
output.Write(input[i]);
|
||||
output.Write(inputSpan[i]);
|
||||
|
||||
rangeToWriteLiterally--;
|
||||
}
|
||||
@ -52,7 +54,7 @@
|
||||
{
|
||||
var numberOfTimesToCopy = 257 - runLength;
|
||||
|
||||
var byteToCopy = input[i + 1];
|
||||
var byteToCopy = inputSpan[i + 1];
|
||||
|
||||
output.GetSpan(numberOfTimesToCopy).Slice(0, numberOfTimesToCopy).Fill(byteToCopy);
|
||||
output.Advance(numberOfTimesToCopy);
|
||||
|
@ -1,7 +1,7 @@
|
||||
namespace UglyToad.PdfPig.Functions
|
||||
{
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UglyToad.PdfPig.Core;
|
||||
using UglyToad.PdfPig.Functions.Type4;
|
||||
using UglyToad.PdfPig.Tokens;
|
||||
@ -20,8 +20,7 @@
|
||||
internal PdfFunctionType4(StreamToken function, ArrayToken domain, ArrayToken range)
|
||||
: base(function, domain, range)
|
||||
{
|
||||
byte[] bytes = FunctionStream!.Data.ToArray();
|
||||
string str = OtherEncodings.Iso88591.GetString(bytes);
|
||||
string str = OtherEncodings.Iso88591.GetString(FunctionStream!.Data.Span);
|
||||
this.instructions = InstructionSequenceBuilder.Parse(str);
|
||||
}
|
||||
|
||||
|
@ -833,7 +833,7 @@
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void EndInlineImage(ReadOnlyMemory<byte> bytes)
|
||||
public virtual void EndInlineImage(Memory<byte> bytes)
|
||||
{
|
||||
if (InlineImageBuilder is null)
|
||||
{
|
||||
|
@ -159,7 +159,7 @@
|
||||
/// <summary>
|
||||
/// Indicates that the current inline image is complete.
|
||||
/// </summary>
|
||||
void EndInlineImage(ReadOnlyMemory<byte> bytes);
|
||||
void EndInlineImage(Memory<byte> bytes);
|
||||
|
||||
/// <summary>
|
||||
/// Modify the clipping rule of the current path.
|
||||
|
@ -1,10 +1,8 @@
|
||||
namespace UglyToad.PdfPig.Graphics
|
||||
{
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Content;
|
||||
using Core;
|
||||
using Filters;
|
||||
@ -27,7 +25,7 @@
|
||||
/// <summary>
|
||||
/// Inline image bytes.
|
||||
/// </summary>
|
||||
public ReadOnlyMemory<byte> Bytes { get; internal set; }
|
||||
public Memory<byte> Bytes { get; internal set; }
|
||||
|
||||
internal InlineImage CreateInlineImage(
|
||||
in TransformationMatrix transformationMatrix,
|
||||
|
@ -1,7 +1,6 @@
|
||||
namespace UglyToad.PdfPig.Graphics.Operations.InlineImages
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -18,7 +17,7 @@
|
||||
/// <summary>
|
||||
/// The raw data for the inline image which should be interpreted according to the corresponding <see cref="BeginInlineImageData.Dictionary"/>.
|
||||
/// </summary>
|
||||
public ReadOnlyMemory<byte> ImageData { get; }
|
||||
public Memory<byte> ImageData { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Operator => Symbol;
|
||||
@ -27,7 +26,7 @@
|
||||
/// Create a new <see cref="EndInlineImage"/> operation.
|
||||
/// </summary>
|
||||
/// <param name="imageData">The raw byte data of this image.</param>
|
||||
public EndInlineImage(ReadOnlyMemory<byte> imageData)
|
||||
public EndInlineImage(Memory<byte> imageData)
|
||||
{
|
||||
ImageData = imageData;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
/// change the data but for <see cref="ColorSpace.Indexed"/> it will convert the bytes which are indexes into the
|
||||
/// real pixel data into the real pixel data.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<byte> Convert(ColorSpaceDetails details, ReadOnlySpan<byte> decoded, int bitsPerComponent, int imageWidth, int imageHeight)
|
||||
public static Span<byte> Convert(ColorSpaceDetails details, Span<byte> decoded, int bitsPerComponent, int imageWidth, int imageHeight)
|
||||
{
|
||||
if (decoded.IsEmpty)
|
||||
{
|
||||
@ -27,25 +27,22 @@
|
||||
return decoded;
|
||||
}
|
||||
|
||||
// TODO - We should aim at removing this alloc.
|
||||
// The decoded input variable needs to become a Span<byte>
|
||||
Span<byte> data = decoded.ToArray();
|
||||
|
||||
if (bitsPerComponent != 8)
|
||||
{
|
||||
// Unpack components such that they occupy one byte each
|
||||
data = UnpackComponents(data, bitsPerComponent, details.Type);
|
||||
decoded = UnpackComponents(decoded, bitsPerComponent, details.Type);
|
||||
}
|
||||
|
||||
// Remove padding bytes when the stride width differs from the image width
|
||||
var bytesPerPixel = details.NumberOfColorComponents;
|
||||
var strideWidth = data.Length / imageHeight / bytesPerPixel;
|
||||
var strideWidth = decoded.Length / imageHeight / bytesPerPixel;
|
||||
if (strideWidth != imageWidth)
|
||||
{
|
||||
data = RemoveStridePadding(data, strideWidth, imageWidth, imageHeight, bytesPerPixel);
|
||||
decoded = RemoveStridePadding(decoded, strideWidth, imageWidth, imageHeight, bytesPerPixel);
|
||||
}
|
||||
|
||||
return details.Transform(data);
|
||||
return details.Transform(decoded);
|
||||
}
|
||||
|
||||
private static Span<byte> UnpackComponents(Span<byte> input, int bitsPerComponent, ColorSpace colorSpace)
|
||||
@ -102,7 +99,6 @@
|
||||
return unpacked;
|
||||
}
|
||||
|
||||
|
||||
private static Span<byte> RemoveStridePadding(Span<byte> input, int strideWidth, int imageWidth, int imageHeight, int multiplier)
|
||||
{
|
||||
int size = imageWidth * imageHeight * multiplier;
|
||||
|
@ -55,14 +55,14 @@
|
||||
/// <summary>
|
||||
/// Get the decoded data from this stream.
|
||||
/// </summary>
|
||||
public static ReadOnlyMemory<byte> Decode(this StreamToken stream, IFilterProvider filterProvider)
|
||||
public static Memory<byte> Decode(this StreamToken stream, IFilterProvider filterProvider)
|
||||
{
|
||||
var filters = filterProvider.GetFilters(stream.StreamDictionary);
|
||||
|
||||
var transform = stream.Data;
|
||||
for (var i = 0; i < filters.Count; i++)
|
||||
{
|
||||
transform = filters[i].Decode(transform.Span, stream.StreamDictionary, filterProvider, i);
|
||||
transform = filters[i].Decode(transform, stream.StreamDictionary, filterProvider, i);
|
||||
}
|
||||
|
||||
return transform;
|
||||
@ -71,14 +71,14 @@
|
||||
/// <summary>
|
||||
/// Get the decoded data from this stream.
|
||||
/// </summary>
|
||||
public static ReadOnlyMemory<byte> Decode(this StreamToken stream, ILookupFilterProvider filterProvider, IPdfTokenScanner scanner)
|
||||
public static Memory<byte> Decode(this StreamToken stream, ILookupFilterProvider filterProvider, IPdfTokenScanner scanner)
|
||||
{
|
||||
var filters = filterProvider.GetFilters(stream.StreamDictionary, scanner);
|
||||
|
||||
var transform = stream.Data;
|
||||
for (var i = 0; i < filters.Count; i++)
|
||||
{
|
||||
transform = filters[i].Decode(transform.Span, stream.StreamDictionary, filterProvider, i);
|
||||
transform = filters[i].Decode(transform, stream.StreamDictionary, filterProvider, i);
|
||||
}
|
||||
|
||||
return transform;
|
||||
|
@ -115,7 +115,7 @@
|
||||
{
|
||||
var toUnicode = DirectObjectFinder.Get<StreamToken>(toUnicodeObj, pdfScanner);
|
||||
|
||||
if (toUnicode.Decode(filterProvider, pdfScanner) is ReadOnlyMemory<byte> decodedUnicodeCMap)
|
||||
if (toUnicode?.Decode(filterProvider, pdfScanner) is { } decodedUnicodeCMap)
|
||||
{
|
||||
toUnicodeCMap = CMapCache.Parse(new MemoryInputBytes(decodedUnicodeCMap));
|
||||
}
|
||||
|
@ -75,7 +75,7 @@
|
||||
|
||||
if (DirectObjectFinder.TryGet<StreamToken>(toUnicodeValue, scanner, out var toUnicodeStream))
|
||||
{
|
||||
if (toUnicodeStream?.Decode(filterProvider, scanner) is ReadOnlyMemory<byte> decodedUnicodeCMap)
|
||||
if (toUnicodeStream?.Decode(filterProvider, scanner) is { } decodedUnicodeCMap)
|
||||
{
|
||||
toUnicodeCMap = CMapCache.Parse(new MemoryInputBytes(decodedUnicodeCMap));
|
||||
}
|
||||
|
@ -93,7 +93,7 @@
|
||||
{
|
||||
var toUnicode = DirectObjectFinder.Get<StreamToken>(toUnicodeObj, pdfScanner);
|
||||
|
||||
if (toUnicode?.Decode(filterProvider, pdfScanner) is ReadOnlyMemory<byte> decodedUnicodeCMap)
|
||||
if (toUnicode?.Decode(filterProvider, pdfScanner) is { } decodedUnicodeCMap)
|
||||
{
|
||||
toUnicodeCMap = CMapCache.Parse(new MemoryInputBytes(decodedUnicodeCMap));
|
||||
}
|
||||
|
@ -49,7 +49,7 @@
|
||||
{
|
||||
var toUnicode = DirectObjectFinder.Get<StreamToken>(toUnicodeObj, scanner);
|
||||
|
||||
if (toUnicode?.Decode(filterProvider, scanner) is ReadOnlyMemory<byte> decodedUnicodeCMap)
|
||||
if (toUnicode?.Decode(filterProvider, scanner) is { } decodedUnicodeCMap)
|
||||
{
|
||||
toUnicodeCMap = CMapCache.Parse(new MemoryInputBytes(decodedUnicodeCMap));
|
||||
}
|
||||
|
@ -144,7 +144,7 @@
|
||||
}
|
||||
|
||||
var streamToken = new StreamToken(dictionary, xObject.Stream.Data); // Needed as Resolve(pdfScanner) was called on the dictionary
|
||||
var decodedBytes = supportsFilters ? new Lazy<ReadOnlyMemory<byte>>(() => streamToken.Decode(filterProvider, pdfScanner))
|
||||
var decodedBytes = supportsFilters ? new Lazy<Memory<byte>>(() => streamToken.Decode(filterProvider, pdfScanner))
|
||||
: null;
|
||||
|
||||
var decode = Array.Empty<double>();
|
||||
|
@ -16,7 +16,7 @@
|
||||
/// </summary>
|
||||
public class XObjectImage : IPdfImage
|
||||
{
|
||||
private readonly Lazy<ReadOnlyMemory<byte>>? memoryFactory;
|
||||
private readonly Lazy<Memory<byte>>? memoryFactory;
|
||||
|
||||
/// <inheritdoc />
|
||||
public PdfRectangle Bounds { get; }
|
||||
@ -56,10 +56,10 @@
|
||||
public DictionaryToken ImageDictionary { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReadOnlyMemory<byte> RawMemory { get; }
|
||||
public Memory<byte> RawMemory { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReadOnlySpan<byte> RawBytes => RawMemory.Span;
|
||||
public Span<byte> RawBytes => RawMemory.Span;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ColorSpaceDetails? ColorSpaceDetails { get; }
|
||||
@ -80,8 +80,8 @@
|
||||
bool interpolate,
|
||||
IReadOnlyList<double> decode,
|
||||
DictionaryToken imageDictionary,
|
||||
ReadOnlyMemory<byte> rawMemory,
|
||||
Lazy<ReadOnlyMemory<byte>>? bytes,
|
||||
Memory<byte> rawMemory,
|
||||
Lazy<Memory<byte>>? bytes,
|
||||
ColorSpaceDetails? colorSpaceDetails,
|
||||
IPdfImage? softMaskImage)
|
||||
{
|
||||
@ -102,7 +102,7 @@
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool TryGetBytesAsMemory(out ReadOnlyMemory<byte> bytes)
|
||||
public bool TryGetBytesAsMemory(out Memory<byte> bytes)
|
||||
{
|
||||
bytes = null;
|
||||
if (memoryFactory is null)
|
||||
|
Loading…
Reference in New Issue
Block a user