Skip to content

Commit 3bfcebe

Browse files
authored
Alpha constant and blend mode support (#92)
* Added support for the current alpha constant * Added support for blend modes
1 parent e064097 commit 3bfcebe

5 files changed

Lines changed: 235 additions & 1 deletion

File tree

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
namespace Synercoding.FileFormats.Pdf.Content;
2+
3+
/// <summary>
4+
/// Specifies the blend mode to be used in the transparent imaging model.
5+
/// </summary>
6+
public enum BlendMode
7+
{
8+
/// <summary>
9+
/// Selects the source color, ignoring the backdrop.
10+
/// </summary>
11+
Normal,
12+
/// <summary>
13+
/// Multiplies the backdrop and source color values.
14+
/// </summary>
15+
/// <remarks>
16+
/// The result color is always at least as dark as either of the two constituent
17+
/// colors. Multiplying any color with black produces black; multiplying with
18+
/// white leaves the original color unchanged. Painting successive overlapping
19+
/// objects with a color other than black or white produces progressively darker
20+
/// colors.
21+
/// </remarks>
22+
Multiply,
23+
/// <summary>
24+
/// Multiplies the complements of the backdrop and source color values,
25+
/// then complements the result
26+
/// </summary>
27+
/// <remarks>
28+
/// The result color is always at least as light as either of the two constituent
29+
/// colors. Screening any color with white produces white; screening with black
30+
/// leaves the original color unchanged. The effect is similar to projecting
31+
/// multiple photographic slides simultaneously onto a single screen.
32+
/// </remarks>
33+
Screen,
34+
/// <summary>
35+
/// Multiplies or screens the colors, depending on the backdrop color value.
36+
/// Source colors overlay the backdrop while preserving its highlights and
37+
/// shadows. The backdrop color is not replaced but is mixed with the source
38+
/// color to reflect the lightness or darkness of the backdrop.
39+
/// </summary>
40+
Overlay,
41+
/// <summary>
42+
/// Selects the darker of the backdrop and source colors.
43+
/// </summary>
44+
/// <remarks>
45+
/// The backdrop is replaced with the source where the source is darker;
46+
/// otherwise, it is left unchanged.
47+
/// </remarks>
48+
Darken,
49+
/// <summary>
50+
/// Selects the lighter of the backdrop and source colors.
51+
/// </summary>
52+
/// <remarks>
53+
/// The backdrop is replaced with the source where the source is lighter;
54+
/// otherwise, it is left unchanged.
55+
/// </remarks>
56+
Lighten,
57+
/// <summary>
58+
/// Brightens the backdrop color to reflect the source color.
59+
/// Painting with black produces no changes.
60+
/// </summary>
61+
ColorDodge,
62+
/// <summary>
63+
/// Darkens the backdrop color to reflect the source color.
64+
/// Painting with white produces no change.
65+
/// </summary>
66+
ColorBurn,
67+
/// <summary>
68+
/// Multiplies or screens the colors, depending on the source color value.
69+
/// The effect is similar to shining a harsh spotlight on the backdrop.
70+
/// </summary>
71+
HardLight,
72+
/// <summary>
73+
/// Darkens or lightens the colors, depending on the source color value.
74+
/// The effect is similar to shining a diffused spotlight on the backdrop.
75+
/// </summary>
76+
SoftLight,
77+
/// <summary>
78+
/// Subtracts the darker of the two constituent colors from the lighter color.
79+
/// </summary>
80+
/// <remarks>
81+
/// Painting with white inverts the backdrop color;
82+
/// painting with black produces no change.
83+
/// </remarks>
84+
Difference,
85+
/// <summary>
86+
/// Produces an effect similar to that of the <see cref="Difference"/> mode but lower in contrast.
87+
/// Painting with white inverts the backdrop color; painting with black produces no change.
88+
/// </summary>
89+
Exclusion,
90+
/// <summary>
91+
/// Creates a color with the hue of the source color and the saturation and luminosity of the backdrop color.
92+
/// </summary>
93+
Hue,
94+
/// <summary>
95+
/// Creates a color with the saturation of the source color and the hue and luminosity of the backdrop color. Painting with this mode in an area of the backdrop that is a pure gray (no saturation) produces no change.
96+
/// </summary>
97+
Saturation,
98+
/// <summary>
99+
/// Creates a color with the hue and saturation of the source color and the luminosity of the backdrop color. This preserves the gray levels of the backdrop and is useful for coloring monochrome images or tinting color images.
100+
/// </summary>
101+
Color,
102+
/// <summary>
103+
/// Creates a color with the luminosity of the source color and the hue and saturation of the backdrop color. This produces an inverse effect to that of the <see cref="Color"/> mode.
104+
/// </summary>
105+
Luminosity
106+
}

‎src/Synercoding.FileFormats.Pdf/Content/ExtendedGraphicsState.cs‎

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Synercoding.FileFormats.Pdf.Content.Extensions;
12
using Synercoding.FileFormats.Pdf.Primitives;
23

34
namespace Synercoding.FileFormats.Pdf.Content;
@@ -22,6 +23,43 @@ public sealed record class ExtendedGraphicsState
2223
/// </summary>
2324
public bool? OverprintNonStroking { get; init; }
2425

26+
/// <summary>
27+
/// The current stroking alpha constant, specifying the constant shape or constant opacity value
28+
/// to be used for stroking operations in the transparent imaging model.
29+
/// </summary>
30+
public double? CurrentAlphaConstantStroking
31+
{
32+
get;
33+
init
34+
{
35+
if (value < 0 || value > 1)
36+
throw new ArgumentOutOfRangeException(nameof(CurrentAlphaConstantStroking), "Value must be between 0 and 1.");
37+
38+
field = value;
39+
}
40+
}
41+
42+
/// <summary>
43+
/// The current non-stroking alpha constant, specifying the constant shape or constant opacity value
44+
/// to be used for non-stroking operations in the transparent imaging model.
45+
/// </summary>
46+
public double? CurrentAlphaConstantNonStroking
47+
{
48+
get;
49+
init
50+
{
51+
if (value < 0 || value > 1)
52+
throw new ArgumentOutOfRangeException(nameof(CurrentAlphaConstantNonStroking), "Value must be between 0 and 1.");
53+
54+
field = value;
55+
}
56+
}
57+
58+
/// <summary>
59+
/// The current blend mode to be used in the transparent imaging model.
60+
/// </summary>
61+
public BlendMode? BlendMode { get; init; }
62+
2563
internal IPdfDictionary ToPdfDictionary()
2664
{
2765
var dictionary = new PdfDictionary()
@@ -33,8 +71,13 @@ internal IPdfDictionary ToPdfDictionary()
3371
dictionary[PdfNames.OP] = new PdfBoolean(Overprint.Value);
3472
if (OverprintNonStroking.HasValue)
3573
dictionary[PdfNames.op] = new PdfBoolean(OverprintNonStroking.Value);
74+
if (CurrentAlphaConstantStroking.HasValue)
75+
dictionary[PdfNames.CA] = new PdfNumber(CurrentAlphaConstantStroking.Value);
76+
if (CurrentAlphaConstantNonStroking.HasValue)
77+
dictionary[PdfNames.ca] = new PdfNumber(CurrentAlphaConstantNonStroking.Value);
78+
if (BlendMode.HasValue)
79+
dictionary[PdfNames.BM] = BlendMode.Value.ToPdfName();
3680

3781
return dictionary;
3882
}
3983
}
40-
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using Synercoding.FileFormats.Pdf.Primitives;
2+
3+
namespace Synercoding.FileFormats.Pdf.Content.Extensions;
4+
5+
internal static class BlendModeExtensions
6+
{
7+
public static PdfName ToPdfName(this BlendMode blendMode)
8+
=> blendMode switch
9+
{
10+
BlendMode.Normal => PdfNames.Normal,
11+
BlendMode.Multiply => PdfNames.Multiply,
12+
BlendMode.Screen => PdfNames.Screen,
13+
BlendMode.Overlay => PdfNames.Overlay,
14+
BlendMode.Darken => PdfNames.Darken,
15+
BlendMode.Lighten => PdfNames.Lighten,
16+
BlendMode.ColorDodge => PdfNames.ColorDodge,
17+
BlendMode.ColorBurn => PdfNames.ColorBurn,
18+
BlendMode.HardLight => PdfNames.HardLight,
19+
BlendMode.SoftLight => PdfNames.SoftLight,
20+
BlendMode.Difference => PdfNames.Difference,
21+
BlendMode.Exclusion => PdfNames.Exclusion,
22+
BlendMode.Hue => PdfNames.Hue,
23+
BlendMode.Saturation => PdfNames.Saturation,
24+
BlendMode.Color => PdfNames.Color,
25+
BlendMode.Luminosity => PdfNames.Luminosity,
26+
_ => throw new ArgumentOutOfRangeException(nameof(blendMode), blendMode, null)
27+
};
28+
}

‎src/Synercoding.FileFormats.Pdf/Primitives/PdfName.cs‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ public sealed class PdfName : IPdfPrimitive, IEquatable<PdfName>
2323
{ "BitsPerComponent", new PdfName("BitsPerComponent") },
2424
{ "Black", new PdfName("Black") },
2525
{ "BleedBox", new PdfName("BleedBox") },
26+
{ "BM", new PdfName("BM") },
27+
{ "CA", new PdfName("CA") },
28+
{ "ca", new PdfName("ca") },
2629
{ "CapHeight", new PdfName("CapHeight") },
2730
{ "Catalog", new PdfName("Catalog") },
2831
{ "CCITTFaxDecode", new PdfName("CCITTFaxDecode") },
@@ -31,6 +34,9 @@ public sealed class PdfName : IPdfPrimitive, IEquatable<PdfName>
3134
{ "CIDFontType2", new PdfName("CIDFontType2") },
3235
{ "CIDSystemInfo", new PdfName("CIDSystemInfo") },
3336
{ "CIDToGIDMap", new PdfName("CIDToGIDMap") },
37+
{ "Color", new PdfName("Color") },
38+
{ "ColorBurn", new PdfName("ColorBurn") },
39+
{ "ColorDodge", new PdfName("ColorDodge") },
3440
{ "ColorSpace", new PdfName("ColorSpace") },
3541
{ "Colors", new PdfName("Colors") },
3642
{ "Columns", new PdfName("Columns") },
@@ -41,6 +47,7 @@ public sealed class PdfName : IPdfPrimitive, IEquatable<PdfName>
4147
{ "CropBox", new PdfName("CropBox") },
4248
{ "Crypt", new PdfName("Crypt") },
4349
{ "Cyan", new PdfName("Cyan") },
50+
{ "Darken", new PdfName("Darken") },
4451
{ "DCTDecode", new PdfName("DCTDecode") },
4552
{ "Decode", new PdfName("Decode") },
4653
{ "DecodeParms", new PdfName("DecodeParms") },
@@ -50,11 +57,13 @@ public sealed class PdfName : IPdfPrimitive, IEquatable<PdfName>
5057
{ "DeviceCMYK", new PdfName("DeviceCMYK") },
5158
{ "DeviceGray", new PdfName("DeviceGray") },
5259
{ "DeviceRGB", new PdfName("DeviceRGB") },
60+
{ "Difference", new PdfName("Difference") },
5361
{ "EarlyChange", new PdfName("EarlyChange") },
5462
{ "Encoding", new PdfName("Encoding") },
5563
{ "EFF", new PdfName("EFF") },
5664
{ "Encrypt", new PdfName("Encrypt") },
5765
{ "EncryptMetadata", new PdfName("EncryptMetadata") },
66+
{ "Exclusion", new PdfName("Exclusion") },
5867
{ "ExtGState", new PdfName("ExtGState") },
5968
{ "Filter", new PdfName("Filter") },
6069
{ "First", new PdfName("First") },
@@ -66,7 +75,9 @@ public sealed class PdfName : IPdfPrimitive, IEquatable<PdfName>
6675
{ "FlateDecode", new PdfName("FlateDecode") },
6776
{ "Font", new PdfName("Font") },
6877
{ "FullScreen", new PdfName("FullScreen") },
78+
{ "HardLight", new PdfName("HardLight") },
6979
{ "Height", new PdfName("Height") },
80+
{ "Hue", new PdfName("Hue") },
7081
{ "ID", new PdfName("ID") },
7182
{ "Identity", new PdfName("Identity") },
7283
{ "Identity-H", new PdfName("Identity-H") },
@@ -80,20 +91,25 @@ public sealed class PdfName : IPdfPrimitive, IEquatable<PdfName>
8091
{ "Kids", new PdfName("Kids") },
8192
{ "Length", new PdfName("Length") },
8293
{ "Length1", new PdfName("Length1") },
94+
{ "Lighten", new PdfName("Lighten") },
95+
{ "Luminosity", new PdfName("Luminosity") },
8396
{ "LZWDecode", new PdfName("LZWDecode") },
8497
{ "Magenta", new PdfName("Magenta") },
8598
{ "MediaBox", new PdfName("MediaBox") },
8699
{ "Metadata", new PdfName("Metadata") },
87100
{ "ModDate", new PdfName("ModDate") },
101+
{ "Multiply", new PdfName("Multiply") },
88102
{ "N", new PdfName("N") },
89103
{ "None", new PdfName("None") },
104+
{ "Normal", new PdfName("Normal") },
90105
{ "O", new PdfName("O") },
91106
{ "ObjStm", new PdfName("ObjStm") },
92107
{ "OE", new PdfName("OE") },
93108
{ "OneColumn", new PdfName("OneColumn") },
94109
{ "OP", new PdfName("OP") },
95110
{ "op", new PdfName("op") },
96111
{ "Ordering", new PdfName("Ordering") },
112+
{ "Overlay", new PdfName("Overlay") },
97113
{ "P", new PdfName("P") },
98114
{ "Page", new PdfName("Page") },
99115
{ "PageLayout", new PdfName("PageLayout") },
@@ -113,11 +129,14 @@ public sealed class PdfName : IPdfPrimitive, IEquatable<PdfName>
113129
{ "Root", new PdfName("Root") },
114130
{ "Rotate", new PdfName("Rotate") },
115131
{ "RunLengthDecode", new PdfName("RunLengthDecode") },
132+
{ "Saturation", new PdfName("Saturation") },
133+
{ "Screen", new PdfName("Screen") },
116134
{ "Separation", new PdfName("Separation") },
117135
{ "Shading", new PdfName("Shading") },
118136
{ "SinglePage", new PdfName("SinglePage") },
119137
{ "Size", new PdfName("Size") },
120138
{ "SMask", new PdfName("SMask") },
139+
{ "SoftLight", new PdfName("SoftLight") },
121140
{ "Standard", new PdfName("Standard") },
122141
{ "StemV", new PdfName("StemV") },
123142
{ "StmF", new PdfName("StmF") },

0 commit comments

Comments
 (0)