Skip to content

Commit 03a8769

Browse files
authored
Merge pull request #71 from synercoder/features/add-decode-array-for-separation-image
Features/add decode array for separation image
2 parents c717a6b + 4f73d3d commit 03a8769

File tree

6 files changed

+82
-37
lines changed

6 files changed

+82
-37
lines changed

samples/Synercoding.FileFormats.Pdf.ConsoleTester/Program.cs

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -226,33 +226,36 @@ public static void Main(string[] args)
226226
context.Stroke();
227227
});
228228
});
229-
}
230-
231-
using (var pantherPngStream = File.OpenRead("FreePngImage_com/59872-jaguar-panther-royalty-free-cougar-black-cheetah.png"))
232-
using (var pantherImage = SixLabors.ImageSharp.Image.Load<Rgba32>(pantherPngStream))
233-
{
234-
var pantherImg = writer.AddImage(pantherImage);
235-
var transparentPanther = writer.AddSeparationImage(new Separation(LowLevel.PdfName.Get("White"), PredefinedColors.Yellow), pantherImage, GrayScaleMethod.AlphaChannel);
236229

237-
writer.AddPage(page =>
230+
using (var pantherPngStream = File.OpenRead("FreePngImage_com/59872-jaguar-panther-royalty-free-cougar-black-cheetah.png"))
231+
using (var pantherSixImage = SixLabors.ImageSharp.Image.Load<Rgba32>(pantherPngStream))
238232
{
239-
page.MediaBox = mediaBox;
240-
page.TrimBox = trimBox;
233+
var pantherImg = writer.AddImage(pantherSixImage);
234+
var transparentPanther = writer.AddSeparationImage(new Separation(LowLevel.PdfName.Get("White"), PredefinedColors.Yellow), pantherSixImage, GrayScaleMethod.AlphaChannel, [0, 1]);
235+
236+
writer.AddPage(page =>
237+
{
238+
page.MediaBox = mediaBox;
239+
page.TrimBox = trimBox;
241240

242-
var scale = (double)transparentPanther.Width / transparentPanther.Height;
243-
var pantherSize = new Rectangle(0, 0, 216, 216 / scale, Unit.Millimeters);
241+
var scale = (double)blurImage.Width / blurImage.Height;
242+
page.Content.AddImage(reusedImage, new Rectangle(0, 0, scale * 303, 303, Unit.Millimeters));
244243

245-
page.Content.AddImage(pantherImage, pantherSize);
244+
scale = (double)transparentPanther.Width / transparentPanther.Height;
245+
var pantherSize = new Rectangle(0, 0, 216, 216 / scale, Unit.Millimeters);
246246

247-
page.Content.WrapInState(pantherImage, (image, content) =>
248-
{
249-
content.SetExtendedGraphicsState(new ExtendedGraphicsState()
247+
page.Content.AddImage(pantherImg, pantherSize);
248+
249+
page.Content.WrapInState(pantherSixImage, (image, content) =>
250250
{
251-
Overprint = true
251+
content.SetExtendedGraphicsState(new ExtendedGraphicsState()
252+
{
253+
Overprint = true
254+
});
255+
content.AddImage(transparentPanther, pantherSize);
252256
});
253-
content.AddImage(transparentPanther, pantherSize);
254257
});
255-
});
258+
}
256259
}
257260
}
258261
}

src/Synercoding.FileFormats.Pdf/GrayScaleMethod.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,13 @@ public enum GrayScaleMethod
2424
/// <summary>
2525
/// Use the average of the Red, Green and Blue channels.
2626
/// </summary>
27-
AverageOfRGBChannels
27+
AverageOfRGBChannels,
28+
/// <summary>
29+
/// The constants defined by ITU-R BT.601 are 0.299 red + 0.587 green + 0.114 blue.
30+
/// </summary>
31+
BT601,
32+
/// <summary>
33+
/// The constants defined by ITU-R BT.709 are 0.2126 red + 0.7152 green + 0.0722 blue.
34+
/// </summary>
35+
BT709,
2836
}

src/Synercoding.FileFormats.Pdf/Image.cs

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using Synercoding.FileFormats.Pdf.LowLevel;
44
using Synercoding.FileFormats.Pdf.LowLevel.Colors.ColorSpaces;
55
using Synercoding.FileFormats.Pdf.LowLevel.XRef;
6-
using System.IO.Compression;
76

87
namespace Synercoding.FileFormats.Pdf;
98

@@ -14,7 +13,7 @@ public class Image : IDisposable
1413
{
1514
private protected bool _disposed;
1615

17-
internal Image(PdfReference id, Stream jpgStream, int width, int height, ColorSpace colorSpace, Image? softMask, params StreamFilter[] filters)
16+
internal Image(PdfReference id, Stream jpgStream, int width, int height, ColorSpace colorSpace, Image? softMask, double[]? decodeArray, params StreamFilter[] filters)
1817
{
1918
Reference = id;
2019

@@ -23,13 +22,16 @@ internal Image(PdfReference id, Stream jpgStream, int width, int height, ColorSp
2322
RawStream = jpgStream;
2423
ColorSpace = colorSpace;
2524
SoftMask = softMask;
25+
DecodeArray = decodeArray;
2626
Filters = filters;
2727
}
2828

2929
internal Image? SoftMask { get; private set; }
3030

3131
internal Stream RawStream { get; private set; }
3232

33+
internal double[]? DecodeArray { get; private set; }
34+
3335
/// <summary>
3436
/// A pdf reference object that can be used to reference to this object
3537
/// </summary>
@@ -77,23 +79,46 @@ private static Stream _encodeToJpg(SixLabors.ImageSharp.Image image)
7779

7880
internal static Image Get(TableBuilder tableBuilder, Image<Rgba32> image)
7981
{
80-
return new Image(tableBuilder.ReserveId(), _encodeToJpg(image), image.Width, image.Height, DeviceRGB.Instance, GetMask(tableBuilder, image), StreamFilter.DCTDecode);
82+
return new Image(tableBuilder.ReserveId(), _encodeToJpg(image), image.Width, image.Height, DeviceRGB.Instance, GetMask(tableBuilder, image), null, StreamFilter.DCTDecode);
8183
}
8284

8385
internal static Image? GetMask(TableBuilder tableBuilder, Image<Rgba32> image)
8486
{
85-
var hasTrans = image.Metadata.TryGetPngMetadata(out var pngMeta)
86-
&&
87-
(
88-
pngMeta.ColorType == SixLabors.ImageSharp.Formats.Png.PngColorType.RgbWithAlpha
89-
|| pngMeta.ColorType == SixLabors.ImageSharp.Formats.Png.PngColorType.GrayscaleWithAlpha
90-
);
91-
92-
return hasTrans
93-
? new Image(tableBuilder.ReserveId(), AsImageByteStream(image, GrayScaleMethod.AlphaChannel), image.Width, image.Height, DeviceGray.Instance, null, StreamFilter.FlateDecode)
87+
return _hasTransparancy(image)
88+
? new Image(tableBuilder.ReserveId(), AsImageByteStream(image, GrayScaleMethod.AlphaChannel), image.Width, image.Height, DeviceGray.Instance, null, null, StreamFilter.FlateDecode)
9489
: null;
9590
}
9691

92+
private static bool _hasTransparancy(Image<Rgba32> image)
93+
{
94+
if( image.Metadata.TryGetPngMetadata(out var pngMeta))
95+
{
96+
if (pngMeta.ColorType == SixLabors.ImageSharp.Formats.Png.PngColorType.RgbWithAlpha)
97+
return true;
98+
if (pngMeta.ColorType == SixLabors.ImageSharp.Formats.Png.PngColorType.GrayscaleWithAlpha)
99+
return true;
100+
}
101+
102+
bool hasTransparancy = false;
103+
image.ProcessPixelRows(accessor =>
104+
{
105+
for (int y = 0; y < accessor.Height; y++)
106+
{
107+
var row = accessor.GetRowSpan(y);
108+
for (int x = 0; x < row.Length; x++)
109+
{
110+
ref Rgba32 pixel = ref row[x];
111+
if (pixel.A != 0xFF)
112+
{
113+
hasTransparancy = true;
114+
return;
115+
}
116+
}
117+
}
118+
});
119+
return hasTransparancy;
120+
}
121+
97122
internal static Stream AsImageByteStream(Image<Rgba32> image, GrayScaleMethod grayScaleMethod)
98123
{
99124
using (var byteStream = new MemoryStream())
@@ -118,6 +143,8 @@ internal static Stream AsImageByteStream(Image<Rgba32> image, GrayScaleMethod gr
118143
GrayScaleMethod.GreenChannel => pixel.G,
119144
GrayScaleMethod.BlueChannel => pixel.B,
120145
GrayScaleMethod.AverageOfRGBChannels => (byte)( ( pixel.R + pixel.G + pixel.B ) / 3 ),
146+
GrayScaleMethod.BT601 => (byte)( ( pixel.R * 0.299 ) + ( pixel.G * 0.587 ) + ( pixel.B * 0.114 ) ),
147+
GrayScaleMethod.BT709 => (byte)( ( pixel.R * 0.2126 ) + ( pixel.G * 0.7152 ) + ( pixel.B * 0.0722 ) ),
121148
_ => throw new NotImplementedException()
122149
};
123150

src/Synercoding.FileFormats.Pdf/LowLevel/Internal/PageResources.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public PdfName AddJpgUnsafe(System.IO.Stream jpgStream, int originalWidth, int o
5757
{
5858
var id = _tableBuilder.ReserveId();
5959

60-
var pdfImage = new Image(id, jpgStream, originalWidth, originalHeight, colorSpace, null, StreamFilter.DCTDecode);
60+
var pdfImage = new Image(id, jpgStream, originalWidth, originalHeight, colorSpace, null, null, StreamFilter.DCTDecode);
6161

6262
return AddImage(pdfImage);
6363
}

src/Synercoding.FileFormats.Pdf/LowLevel/ObjectStream.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public ObjectStream Write(Image image)
103103
.Write(PdfName.Get("Width"), image.Width)
104104
.Write(PdfName.Get("Height"), image.Height)
105105
.Write(PdfName.Get("BitsPerComponent"), 8)
106-
.Write(PdfName.Get("Decode"), _decodeArray(image.ColorSpace))
106+
.Write(PdfName.Get("Decode"), image.DecodeArray ?? _decodeArray(image.ColorSpace))
107107
.WriteIfNotNull(PdfName.Get("SMask"), image.SoftMask?.Reference);
108108

109109

src/Synercoding.FileFormats.Pdf/PdfWriter.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,18 +167,25 @@ public Image AddImage(Image<Rgba32> image)
167167
/// <param name="separation">The <see cref="Separation"/> to use.</param>
168168
/// <param name="image">The image to use.</param>
169169
/// <param name="grayScaleMethod">The <see cref="GrayScaleMethod"/> to use.</param>
170+
/// <param name="decodeArray">Optional decode array to use, default value is <c>[ 0.0 1.0 ]</c></param>
170171
/// <returns>The SeparationImage reference that can be used in pages</returns>
171-
public Image AddSeparationImage(Separation separation, Image<Rgba32> image, GrayScaleMethod grayScaleMethod)
172+
public Image AddSeparationImage(Separation separation, Image<Rgba32> image, GrayScaleMethod grayScaleMethod, double[]? decodeArray = null)
172173
{
173174
_throwWhenEndingWritten();
174175

176+
decodeArray ??= new double[] { 0, 1 };
177+
if(decodeArray.Length != 2)
178+
throw new ArgumentOutOfRangeException(nameof(decodeArray), "Length of decode array for separation images should be 2.");
179+
if (decodeArray.Any(v => v < 0 || v > 1))
180+
throw new ArgumentOutOfRangeException(nameof(decodeArray), "All values of the decode array should be between 0 and 1.");
181+
175182
var id = _tableBuilder.ReserveId();
176183

177184
var mask = Image.GetMask(_tableBuilder, image);
178185

179186
var imageStream = Image.AsImageByteStream(image, grayScaleMethod);
180187

181-
var pdfImage = new Image(id, imageStream, image.Width, image.Height, separation, mask, StreamFilter.FlateDecode);
188+
var pdfImage = new Image(id, imageStream, image.Width, image.Height, separation, mask, decodeArray, StreamFilter.FlateDecode);
182189

183190
_objectStream.Write(pdfImage);
184191

@@ -202,7 +209,7 @@ public Image AddJpgUnsafe(Stream jpgStream, int originalWidth, int originalHeigh
202209

203210
var id = _tableBuilder.ReserveId();
204211

205-
var pdfImage = new Image(id, jpgStream, originalWidth, originalHeight, colorSpace, null, StreamFilter.DCTDecode);
212+
var pdfImage = new Image(id, jpgStream, originalWidth, originalHeight, colorSpace, null, null, StreamFilter.DCTDecode);
206213

207214
_objectStream.Write(pdfImage);
208215

0 commit comments

Comments
 (0)