33using Synercoding . FileFormats . Pdf . LowLevel ;
44using Synercoding . FileFormats . Pdf . LowLevel . Colors . ColorSpaces ;
55using Synercoding . FileFormats . Pdf . LowLevel . XRef ;
6+ using System . IO . Compression ;
67
78namespace Synercoding . FileFormats . Pdf ;
89
@@ -13,84 +14,19 @@ public class Image : IDisposable
1314{
1415 private protected bool _disposed ;
1516
16- internal static Image Get ( TableBuilder tableBuilder , Image < Rgba32 > image )
17- {
18- return new Image ( tableBuilder . ReserveId ( ) , _encodeToJpg ( image ) , image . Width , image . Height , DeviceRGB . Instance , GetMask ( tableBuilder , image ) ) ;
19- }
20-
21- internal static SoftMask ? GetMask ( TableBuilder tableBuilder , Image < Rgba32 > image )
22- {
23- var hasTrans = image . Metadata . TryGetPngMetadata ( out var pngMeta )
24- &&
25- (
26- pngMeta . ColorType == SixLabors . ImageSharp . Formats . Png . PngColorType . RgbWithAlpha
27- || pngMeta . ColorType == SixLabors . ImageSharp . Formats . Png . PngColorType . GrayscaleWithAlpha
28- ) ;
29-
30- return hasTrans
31- ? new SoftMask ( tableBuilder . ReserveId ( ) , AsImageByteStream ( image , GrayScaleMethod . AlphaChannel ) , image . Width , image . Height )
32- : null ;
33- }
34-
35- internal static Stream AsImageByteStream ( Image < Rgba32 > image , GrayScaleMethod grayScaleMethod )
36- {
37- var ms = new MemoryStream ( ) ;
38-
39- image . ProcessPixelRows ( accessor =>
40- {
41- for ( int y = 0 ; y < accessor . Height ; y ++ )
42- {
43- var pixelRow = accessor . GetRowSpan ( y ) ;
44-
45- // pixelRow.Length has the same value as accessor.Width,
46- // but using pixelRow.Length allows the JIT to optimize away bounds checks:
47- for ( int x = 0 ; x < pixelRow . Length ; x ++ )
48- {
49- // Get a reference to the pixel at position x
50- ref Rgba32 pixel = ref pixelRow [ x ] ;
51-
52- var pixelValue = grayScaleMethod switch
53- {
54- GrayScaleMethod . AlphaChannel => pixel . A ,
55- GrayScaleMethod . RedChannel => pixel . R ,
56- GrayScaleMethod . GreenChannel => pixel . G ,
57- GrayScaleMethod . BlueChannel => pixel . B ,
58- GrayScaleMethod . AverageOfRGBChannels => ( byte ) ( ( pixel . R + pixel . G + pixel . B ) / 3 ) ,
59- _ => throw new NotImplementedException ( )
60- } ;
61-
62- ms . WriteByte ( pixelValue ) ;
63-
64- }
65- }
66- } ) ;
67-
68- ms . Position = 0 ;
69-
70- return ms ;
71- }
72-
73- //internal Image(PdfReference id, SixLabors.ImageSharp.Image image)
74- // : this(id, _encodeToJpg(image), image.Width, image.Height, DeviceRGB.Instance, null)
75- //{ }
76-
77- internal Image ( PdfReference id , Stream jpgStream , int width , int height , ColorSpace colorSpace , SoftMask ? softMask )
78- : this ( id , jpgStream , width , height , colorSpace . Name , _decodeArray ( colorSpace ) , softMask )
79- { }
80-
81- internal Image ( PdfReference id , Stream jpgStream , int width , int height , PdfName colorSpace , double [ ] decodeArray , SoftMask ? softMask )
17+ internal Image ( PdfReference id , Stream jpgStream , int width , int height , ColorSpace colorSpace , Image ? softMask , params StreamFilter [ ] filters )
8218 {
8319 Reference = id ;
8420
8521 Width = width ;
8622 Height = height ;
8723 RawStream = jpgStream ;
8824 ColorSpace = colorSpace ;
89- DecodeArray = decodeArray ;
9025 SoftMask = softMask ;
26+ Filters = filters ;
9127 }
9228
93- internal SoftMask ? SoftMask { get ; private set ; }
29+ internal Image ? SoftMask { get ; private set ; }
9430
9531 internal Stream RawStream { get ; private set ; }
9632
@@ -112,12 +48,9 @@ internal Image(PdfReference id, Stream jpgStream, int width, int height, PdfName
11248 /// <summary>
11349 /// The name of the colorspace used in this <see cref="Image"/>
11450 /// </summary>
115- public PdfName ColorSpace { get ; }
51+ public ColorSpace ColorSpace { get ; }
11652
117- /// <summary>
118- /// The decode array used in this <see cref="Image"/>
119- /// </summary>
120- public double [ ] DecodeArray { get ; }
53+ internal StreamFilter [ ] Filters { get ; } = Array . Empty < StreamFilter > ( ) ;
12154
12255 /// <inheritdoc />
12356 public void Dispose ( )
@@ -142,9 +75,60 @@ private static Stream _encodeToJpg(SixLabors.ImageSharp.Image image)
14275 return ms ;
14376 }
14477
145- private static double [ ] _decodeArray ( ColorSpace colorSpace )
146- => Enumerable . Range ( 0 , colorSpace . Components )
147- . Select ( _ => new double [ ] { 0 , 1 } )
148- . SelectMany ( x => x )
149- . ToArray ( ) ;
78+ internal static Image Get ( TableBuilder tableBuilder , Image < Rgba32 > image )
79+ {
80+ return new Image ( tableBuilder . ReserveId ( ) , _encodeToJpg ( image ) , image . Width , image . Height , DeviceRGB . Instance , GetMask ( tableBuilder , image ) , StreamFilter . DCTDecode ) ;
81+ }
82+
83+ internal static Image ? GetMask ( TableBuilder tableBuilder , Image < Rgba32 > image )
84+ {
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 )
94+ : null ;
95+ }
96+
97+ internal static Stream AsImageByteStream ( Image < Rgba32 > image , GrayScaleMethod grayScaleMethod )
98+ {
99+ using ( var byteStream = new MemoryStream ( ) )
100+ {
101+ image . ProcessPixelRows ( accessor =>
102+ {
103+ for ( int y = 0 ; y < accessor . Height ; y ++ )
104+ {
105+ var pixelRow = accessor . GetRowSpan ( y ) ;
106+
107+ // pixelRow.Length has the same value as accessor.Width,
108+ // but using pixelRow.Length allows the JIT to optimize away bounds checks:
109+ for ( int x = 0 ; x < pixelRow . Length ; x ++ )
110+ {
111+ // Get a reference to the pixel at position x
112+ ref Rgba32 pixel = ref pixelRow [ x ] ;
113+
114+ var pixelValue = grayScaleMethod switch
115+ {
116+ GrayScaleMethod . AlphaChannel => pixel . A ,
117+ GrayScaleMethod . RedChannel => pixel . R ,
118+ GrayScaleMethod . GreenChannel => pixel . G ,
119+ GrayScaleMethod . BlueChannel => pixel . B ,
120+ GrayScaleMethod . AverageOfRGBChannels => ( byte ) ( ( pixel . R + pixel . G + pixel . B ) / 3 ) ,
121+ _ => throw new NotImplementedException ( )
122+ } ;
123+
124+ byteStream . WriteByte ( pixelValue ) ;
125+ }
126+ }
127+ } ) ;
128+
129+ byteStream . Position = 0 ;
130+
131+ return PdfWriter . FlateEncode ( byteStream ) ;
132+ }
133+ }
150134}
0 commit comments