Skip to content

Commit f30a16d

Browse files
committed
Added lazy image byte loading and EagerlyLoadImageBytes option
1 parent e5c04fe commit f30a16d

7 files changed

Lines changed: 1552 additions & 1501 deletions

File tree

src/UglyToad.PdfPig.Tests/TestPdfImage.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ public class TestPdfImage : IPdfImage
3838

3939
public Memory<byte> DecodedBytes { get; set; }
4040

41+
public bool HasLoadedBytes => !RawMemory.IsEmpty;
42+
4143
public IPdfImage? MaskImage { get; }
4244

4345
public bool TryGetBytesAsMemory(out Memory<byte> bytes)
Lines changed: 125 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,116 +1,125 @@
1-
namespace UglyToad.PdfPig.Content
2-
{
3-
using System;
4-
using System.Collections.Generic;
5-
using System.Diagnostics.CodeAnalysis;
6-
using Core;
7-
using Graphics.Colors;
8-
using Graphics.Core;
9-
using UglyToad.PdfPig.Tokens;
10-
using XObjects;
11-
12-
/// <summary>
13-
/// An image in a PDF document, may be an <see cref="InlineImage"/> or a PostScript image XObject (<see cref="XObjectImage"/>).
14-
/// </summary>
15-
public interface IPdfImage: IBoundingBox
16-
{
17-
/// <summary>
18-
/// The placement rectangle of the image in PDF coordinates.
19-
/// Kept so not major breaking API change. Use instead <see cref="IBoundingBox.BoundingBox"/>
20-
/// </summary>
21-
[Obsolete("Use BoundingBox instead.")]
22-
PdfRectangle Bounds { get; }
23-
24-
/// <summary>
25-
/// The width of the image in samples.
26-
/// </summary>
27-
int WidthInSamples { get; }
28-
29-
/// <summary>
30-
/// The height of the image in samples.
31-
/// </summary>
32-
int HeightInSamples { get; }
33-
34-
/// <summary>
35-
/// The number of bits used to represent each color component.
36-
/// </summary>
37-
int BitsPerComponent { get; }
38-
39-
/// <summary>
40-
/// The encoded memory of the image with all filters still applied.
41-
/// </summary>
42-
Memory<byte> RawMemory { get; }
43-
44-
/// <summary>
45-
/// The encoded memory span of the image with all filters still applied.
46-
/// </summary>
47-
Span<byte> RawBytes { get; }
48-
49-
/// <summary>
50-
/// The color rendering intent to be used when rendering the image.
51-
/// </summary>
52-
RenderingIntent RenderingIntent { get; }
53-
54-
/// <summary>
55-
/// Indicates whether the image is to be treated as an image mask.
56-
/// If <see langword="true"/> the image is a monochrome image in which each sample
57-
/// is specified by a single bit (<see cref="BitsPerComponent"/> is 1).
58-
/// The image represents a stencil where sample values represent places on the page
59-
/// that should be marked with the current color or masked (not marked).
60-
/// </summary>
61-
bool IsImageMask { get; }
62-
63-
/// <summary>
64-
/// Describes how to map image samples into the values appropriate for the
65-
/// <see cref="ColorSpace"/>.
66-
/// The image data is initially composed of values in the range 0 to 2^n - 1
67-
/// where n is <see cref="BitsPerComponent"/>.
68-
/// The decode array contains a pair of numbers for each component in the <see cref="ColorSpace"/>.
69-
/// The value from the image data is then interpolated into the values relevant to the <see cref="ColorSpace"/>
70-
/// using the corresponding values of the decode array.
71-
/// </summary>
72-
IReadOnlyList<double> Decode { get; }
73-
74-
/// <summary>
75-
/// Specifies whether interpolation is to be performed. Interpolation smooths images where a single component in the image
76-
/// as defined may correspond to many pixels on the output device. The interpolation algorithm is implementation
77-
/// dependent and is not defined by the specification.
78-
/// </summary>
79-
bool Interpolate { get; }
80-
81-
/// <summary>
82-
/// Whether this image is an <see cref="InlineImage"/> or a <see cref="XObjectImage"/>.
83-
/// </summary>
84-
bool IsInlineImage { get; }
85-
86-
/// <summary>
87-
/// The full dictionary for this image object.
88-
/// </summary>
89-
DictionaryToken ImageDictionary { get; }
90-
91-
/// <summary>
92-
/// The <see cref="ColorSpaceDetails"/> used to interpret the image.
93-
/// <para>
94-
/// This is not defined where <see cref="IsImageMask"/> is <see langword="true"/> and is optional where the image is JPXEncoded for <see cref="XObjectImage"/>.
95-
/// </para>
96-
/// </summary>
97-
ColorSpaceDetails? ColorSpaceDetails { get; }
98-
99-
/// <summary>
100-
/// The image mask.
101-
/// <para>Either a Soft-mask or a Stencil mask.</para>
102-
/// </summary>
103-
IPdfImage? MaskImage { get; }
104-
105-
/// <summary>
106-
/// Get the decoded memory of the image if applicable. For JPEG images and some other types the
107-
/// <see cref="RawMemory"/> should be used directly.
108-
/// </summary>
109-
bool TryGetBytesAsMemory(out Memory<byte> memory);
110-
111-
/// <summary>
112-
/// Try to convert the image to PNG. Doesn't support conversion of JPG to PNG.
113-
/// </summary>
114-
bool TryGetPng([NotNullWhen(true)] out byte[]? bytes);
115-
}
116-
}
1+
namespace UglyToad.PdfPig.Content
2+
{
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Diagnostics.CodeAnalysis;
6+
using Core;
7+
using Graphics.Colors;
8+
using Graphics.Core;
9+
using UglyToad.PdfPig.Tokens;
10+
using XObjects;
11+
12+
/// <summary>
13+
/// An image in a PDF document, may be an <see cref="InlineImage"/> or a PostScript image XObject (<see cref="XObjectImage"/>).
14+
/// </summary>
15+
public interface IPdfImage: IBoundingBox
16+
{
17+
/// <summary>
18+
/// The placement rectangle of the image in PDF coordinates.
19+
/// Kept so not major breaking API change. Use instead <see cref="IBoundingBox.BoundingBox"/>
20+
/// </summary>
21+
[Obsolete("Use BoundingBox instead.")]
22+
PdfRectangle Bounds { get; }
23+
24+
/// <summary>
25+
/// The width of the image in samples.
26+
/// </summary>
27+
int WidthInSamples { get; }
28+
29+
/// <summary>
30+
/// The height of the image in samples.
31+
/// </summary>
32+
int HeightInSamples { get; }
33+
34+
/// <summary>
35+
/// The number of bits used to represent each color component.
36+
/// </summary>
37+
int BitsPerComponent { get; }
38+
39+
/// <summary>
40+
/// The encoded memory of the image with all filters still applied.
41+
/// Accesing this property may trigger loading of the image bytes from the PDF stream.
42+
/// </summary>
43+
Memory<byte> RawMemory { get; }
44+
45+
/// <summary>
46+
/// The encoded memory span of the image with all filters still applied.
47+
/// Accesing this property may trigger loading of the image bytes from the PDF stream.
48+
/// </summary>
49+
Span<byte> RawBytes { get; }
50+
51+
/// <summary>
52+
/// Whether the image byte data is available. Returns <see langword="false"/> when
53+
/// <see cref="ParsingOptions.EagerlyLoadImageBytes"/> is <see langword="false"/>.
54+
/// Image metadata (dimensions, color space, bounding box) is available regardless.
55+
/// </summary>
56+
bool HasLoadedBytes { get; }
57+
58+
/// <summary>
59+
/// The color rendering intent to be used when rendering the image.
60+
/// </summary>
61+
RenderingIntent RenderingIntent { get; }
62+
63+
/// <summary>
64+
/// Indicates whether the image is to be treated as an image mask.
65+
/// If <see langword="true"/> the image is a monochrome image in which each sample
66+
/// is specified by a single bit (<see cref="BitsPerComponent"/> is 1).
67+
/// The image represents a stencil where sample values represent places on the page
68+
/// that should be marked with the current color or masked (not marked).
69+
/// </summary>
70+
bool IsImageMask { get; }
71+
72+
/// <summary>
73+
/// Describes how to map image samples into the values appropriate for the
74+
/// <see cref="ColorSpace"/>.
75+
/// The image data is initially composed of values in the range 0 to 2^n - 1
76+
/// where n is <see cref="BitsPerComponent"/>.
77+
/// The decode array contains a pair of numbers for each component in the <see cref="ColorSpace"/>.
78+
/// The value from the image data is then interpolated into the values relevant to the <see cref="ColorSpace"/>
79+
/// using the corresponding values of the decode array.
80+
/// </summary>
81+
IReadOnlyList<double> Decode { get; }
82+
83+
/// <summary>
84+
/// Specifies whether interpolation is to be performed. Interpolation smooths images where a single component in the image
85+
/// as defined may correspond to many pixels on the output device. The interpolation algorithm is implementation
86+
/// dependent and is not defined by the specification.
87+
/// </summary>
88+
bool Interpolate { get; }
89+
90+
/// <summary>
91+
/// Whether this image is an <see cref="InlineImage"/> or a <see cref="XObjectImage"/>.
92+
/// </summary>
93+
bool IsInlineImage { get; }
94+
95+
/// <summary>
96+
/// The full dictionary for this image object.
97+
/// </summary>
98+
DictionaryToken ImageDictionary { get; }
99+
100+
/// <summary>
101+
/// The <see cref="ColorSpaceDetails"/> used to interpret the image.
102+
/// <para>
103+
/// This is not defined where <see cref="IsImageMask"/> is <see langword="true"/> and is optional where the image is JPXEncoded for <see cref="XObjectImage"/>.
104+
/// </para>
105+
/// </summary>
106+
ColorSpaceDetails? ColorSpaceDetails { get; }
107+
108+
/// <summary>
109+
/// The image mask.
110+
/// <para>Either a Soft-mask or a Stencil mask.</para>
111+
/// </summary>
112+
IPdfImage? MaskImage { get; }
113+
114+
/// <summary>
115+
/// Get the decoded memory of the image if applicable. For JPEG images and some other types the
116+
/// <see cref="RawMemory"/> should be used directly.
117+
/// </summary>
118+
bool TryGetBytesAsMemory(out Memory<byte> memory);
119+
120+
/// <summary>
121+
/// Try to convert the image to PNG. Doesn't support conversion of JPG to PNG.
122+
/// </summary>
123+
bool TryGetPng([NotNullWhen(true)] out byte[]? bytes);
124+
}
125+
}

0 commit comments

Comments
 (0)