3
3
using Synercoding . FileFormats . Pdf . LowLevel ;
4
4
using Synercoding . FileFormats . Pdf . LowLevel . Colors . ColorSpaces ;
5
5
using Synercoding . FileFormats . Pdf . LowLevel . XRef ;
6
+ using System . IO . Compression ;
6
7
7
8
namespace Synercoding . FileFormats . Pdf ;
8
9
@@ -13,84 +14,19 @@ public class Image : IDisposable
13
14
{
14
15
private protected bool _disposed ;
15
16
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 )
82
18
{
83
19
Reference = id ;
84
20
85
21
Width = width ;
86
22
Height = height ;
87
23
RawStream = jpgStream ;
88
24
ColorSpace = colorSpace ;
89
- DecodeArray = decodeArray ;
90
25
SoftMask = softMask ;
26
+ Filters = filters ;
91
27
}
92
28
93
- internal SoftMask ? SoftMask { get ; private set ; }
29
+ internal Image ? SoftMask { get ; private set ; }
94
30
95
31
internal Stream RawStream { get ; private set ; }
96
32
@@ -112,12 +48,9 @@ internal Image(PdfReference id, Stream jpgStream, int width, int height, PdfName
112
48
/// <summary>
113
49
/// The name of the colorspace used in this <see cref="Image"/>
114
50
/// </summary>
115
- public PdfName ColorSpace { get ; }
51
+ public ColorSpace ColorSpace { get ; }
116
52
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 > ( ) ;
121
54
122
55
/// <inheritdoc />
123
56
public void Dispose ( )
@@ -142,9 +75,60 @@ private static Stream _encodeToJpg(SixLabors.ImageSharp.Image image)
142
75
return ms ;
143
76
}
144
77
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
+ }
150
134
}
0 commit comments