Skip to content

Commit 443d5a1

Browse files
authored
Fix EPS protocol violations in PostscriptQRCode: remove showpage and setpagedevice from EPS output (#694)
* Fix EPS protocol violations in PostscriptQRCode: remove showpage and setpagedevice from EPS output * Update TransposeVerificationTests postscript approval file for EPS/PS format fixes * Improve EPS DSC compliance: use standard prolog/setup sections and fix current-point leak * Use private dictionary in EPS prolog to prevent name collisions in host document * Remove %%Origin from EPS header (not applicable to EPS files) * Fix EPS private dictionary size from 5 to 7 (includes sz and sc)
1 parent 4973174 commit 443d5a1

7 files changed

+142
-75
lines changed

QRCoder/PostscriptQRCode.cs

Lines changed: 91 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -101,20 +101,24 @@ public string GetGraphic(Size viewBox, Color darkColor, Color lightColor, bool d
101101
var drawableModulesCount = QrCodeData.ModuleMatrix.Count - (drawQuietZones ? 0 : offset * 2);
102102
var pointsPerModule = (double)Math.Min(viewBox.Width, viewBox.Height) / (double)drawableModulesCount;
103103

104-
var estimatedCapacity = PS_HEADER.Length + PS_FUNCTIONS.Length + PS_FOOTER.Length +
104+
var header = epsFormat ? EPS_HEADER : PS_HEADER;
105+
var functions = epsFormat ? EPS_FUNCTIONS : PS_FUNCTIONS;
106+
var footer = epsFormat ? EPS_FOOTER : PS_FOOTER;
107+
108+
var estimatedCapacity = header.Length + functions.Length + footer.Length +
105109
(drawableModulesCount * drawableModulesCount * 2) + // modules (either "f " or "b ")
106110
drawableModulesCount * 3 + // newlines ("nl\n")
107111
200; // embedded numbers
108112
var sb = new StringBuilder(estimatedCapacity);
109113

110-
sb.AppendFormat(CultureInfo.InvariantCulture, PS_HEADER, [
111-
CleanSvgVal(viewBox.Width), CleanSvgVal(pointsPerModule),
112-
epsFormat ? "EPSF-3.0" : string.Empty
114+
sb.AppendFormat(CultureInfo.InvariantCulture, header, [
115+
CleanSvgVal(viewBox.Width), CleanSvgVal(pointsPerModule)
113116
]);
114-
sb.AppendFormat(CultureInfo.InvariantCulture, PS_FUNCTIONS, [
117+
sb.AppendFormat(CultureInfo.InvariantCulture, functions, [
115118
CleanSvgVal(darkColor.R /255.0), CleanSvgVal(darkColor.G /255.0), CleanSvgVal(darkColor.B /255.0),
116119
CleanSvgVal(lightColor.R /255.0), CleanSvgVal(lightColor.G /255.0), CleanSvgVal(lightColor.B /255.0),
117-
drawableModulesCount
120+
drawableModulesCount,
121+
CleanSvgVal(viewBox.Width), CleanSvgVal(pointsPerModule)
118122
]);
119123

120124
for (int xi = offset; xi < offset + drawableModulesCount; xi++)
@@ -127,7 +131,7 @@ public string GetGraphic(Size viewBox, Color darkColor, Color lightColor, bool d
127131
}
128132
}
129133
sb.Append('\n');
130-
sb.Append(PS_FOOTER);
134+
sb.Append(footer);
131135
return sb.ToString();
132136
}
133137

@@ -140,15 +144,17 @@ public string GetGraphic(Size viewBox, Color darkColor, Color lightColor, bool d
140144

141145
// Note: line terminations here will encode differently based on which platform QRCoder was compiled on (CRLF vs LF);
142146
// however, PostScript interpreters should handle both equally well.
147+
148+
// Standard PostScript header — includes media/page setup and setpagedevice (valid for standalone PS documents).
143149
private const string PS_HEADER = """
144-
%!PS-Adobe-3.0 {2}
150+
%!PS-Adobe-3.0
145151
%%Creator: QRCoder.NET
146152
%%Title: QRCode
147153
%%DocumentData: Clean7Bit
148154
%%Origin: 0
149155
%%DocumentMedia: Default {0} {0} 0 () ()
150156
%%BoundingBox: 0 0 {0} {0}
151-
%%LanguageLevel: 2
157+
%%LanguageLevel: 2
152158
%%Pages: 1
153159
%%Page: 1 1
154160
%%EndComments
@@ -162,8 +168,22 @@ public string GetGraphic(Size viewBox, Color darkColor, Color lightColor, bool d
162168
163169
""";
164170

171+
// EPS header — omits %%DocumentMedia, %%Pages, %%Page, and setpagedevice, all of which are
172+
// forbidden or inappropriate in Encapsulated PostScript (Adobe Technical Note #5002).
173+
// Constants (sz, sc) and procedure definitions are emitted in EPS_FUNCTIONS below.
174+
private const string EPS_HEADER = """
175+
%!PS-Adobe-3.0 EPSF-3.0
176+
%%Creator: QRCoder.NET
177+
%%Title: QRCode
178+
%%DocumentData: Clean7Bit
179+
%%BoundingBox: 0 0 {0} {0}
180+
%%LanguageLevel: 2
181+
%%EndComments
182+
183+
""";
184+
165185
private const string PS_FUNCTIONS = """
166-
%%BeginFunctions
186+
%%BeginFunctions
167187
/csquare {{
168188
newpath
169189
0 0 moveto
@@ -174,15 +194,15 @@ 1 0 rlineto
174194
setrgbcolor
175195
fill
176196
}} def
177-
/f {{
197+
/f {{
178198
{0} {1} {2} csquare
179199
1 0 translate
180200
}} def
181-
/b {{
201+
/b {{
182202
1 0 translate
183-
}} def
184-
/background {{
185-
{3} {4} {5} csquare
203+
}} def
204+
/background {{
205+
{3} {4} {5} csquare
186206
}} def
187207
/nl {{
188208
-{6} -1 translate
@@ -200,10 +220,65 @@ sc sc scale
200220
201221
""";
202222

223+
// EPS variant: uses standard DSC %%BeginProlog/%%EndProlog for procedure definitions,
224+
// %%BeginSetup/%%EndSetup for constants, and moves 0 0 moveto inside gsave so it does
225+
// not leak the current point into the surrounding document.
226+
private const string EPS_FUNCTIONS = """
227+
%%BeginProlog
228+
7 dict begin
229+
/csquare {{
230+
newpath
231+
0 0 moveto
232+
0 1 rlineto
233+
1 0 rlineto
234+
0 -1 rlineto
235+
closepath
236+
setrgbcolor
237+
fill
238+
}} def
239+
/f {{
240+
{0} {1} {2} csquare
241+
1 0 translate
242+
}} def
243+
/b {{
244+
1 0 translate
245+
}} def
246+
/background {{
247+
{3} {4} {5} csquare
248+
}} def
249+
/nl {{
250+
-{6} -1 translate
251+
}} def
252+
%%EndProlog
253+
%%BeginSetup
254+
/sz {7} def
255+
/sc {8} def
256+
%%EndSetup
257+
gsave
258+
0 0 moveto
259+
sz sz scale
260+
background
261+
grestore
262+
gsave
263+
sc sc scale
264+
0 {6} 1 sub translate
265+
266+
""";
267+
268+
// Standard PostScript footer — showpage is required for standalone PS documents.
203269
private const string PS_FOOTER = """
204270
%%EndBody
205271
grestore
206-
showpage
272+
showpage
273+
%%EOF
274+
275+
""";
276+
277+
// EPS footer — showpage is forbidden in EPS files (Adobe Technical Note #5002).
278+
// 'end' pops the private dictionary pushed in %%BeginProlog to avoid polluting the host dict stack.
279+
private const string EPS_FOOTER = """
280+
grestore
281+
end
207282
%%EOF
208283
209284
""";

QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_colors.approved.txt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
%!PS-Adobe-3.0
1+
%!PS-Adobe-3.0
22
%%Creator: QRCoder.NET
33
%%Title: QRCode
44
%%DocumentData: Clean7Bit
55
%%Origin: 0
66
%%DocumentMedia: Default 165 165 0 () ()
77
%%BoundingBox: 0 0 165 165
8-
%%LanguageLevel: 2
8+
%%LanguageLevel: 2
99
%%Pages: 1
1010
%%Page: 1 1
1111
%%EndComments
@@ -16,7 +16,7 @@
1616
%%BeginFeature: *PageSize Default
1717
<< /PageSize [ sz sz ] /ImagingBBox null >> setpagedevice
1818
%%EndFeature
19-
%%BeginFunctions
19+
%%BeginFunctions
2020
/csquare {
2121
newpath
2222
0 0 moveto
@@ -27,15 +27,15 @@
2727
setrgbcolor
2828
fill
2929
} def
30-
/f {
30+
/f {
3131
1 0 0 csquare
3232
1 0 translate
3333
} def
34-
/b {
34+
/b {
3535
1 0 translate
36-
} def
37-
/background {
38-
0 0 1 csquare
36+
} def
37+
/background {
38+
0 0 1 csquare
3939
} def
4040
/nl {
4141
-33 -1 translate
@@ -85,5 +85,5 @@ b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b nl
8585
b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b
8686
%%EndBody
8787
grestore
88-
showpage
88+
showpage
8989
%%EOF

QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_eps.approved.txt

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,11 @@
22
%%Creator: QRCoder.NET
33
%%Title: QRCode
44
%%DocumentData: Clean7Bit
5-
%%Origin: 0
6-
%%DocumentMedia: Default 165 165 0 () ()
75
%%BoundingBox: 0 0 165 165
8-
%%LanguageLevel: 2
9-
%%Pages: 1
10-
%%Page: 1 1
6+
%%LanguageLevel: 2
117
%%EndComments
12-
%%BeginConstants
13-
/sz 165 def
14-
/sc 5 def
15-
%%EndConstants
16-
%%BeginFeature: *PageSize Default
17-
<< /PageSize [ sz sz ] /ImagingBBox null >> setpagedevice
18-
%%EndFeature
19-
%%BeginFunctions
8+
%%BeginProlog
9+
7 dict begin
2010
/csquare {
2111
newpath
2212
0 0 moveto
@@ -27,23 +17,26 @@
2717
setrgbcolor
2818
fill
2919
} def
30-
/f {
20+
/f {
3121
0 0 0 csquare
3222
1 0 translate
3323
} def
34-
/b {
24+
/b {
3525
1 0 translate
36-
} def
37-
/background {
38-
1 1 1 csquare
26+
} def
27+
/background {
28+
1 1 1 csquare
3929
} def
4030
/nl {
4131
-33 -1 translate
4232
} def
43-
%%EndFunctions
44-
%%BeginBody
45-
0 0 moveto
33+
%%EndProlog
34+
%%BeginSetup
35+
/sz 165 def
36+
/sc 5 def
37+
%%EndSetup
4638
gsave
39+
0 0 moveto
4740
sz sz scale
4841
background
4942
grestore
@@ -83,7 +76,6 @@ b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b nl
8376
b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b nl
8477
b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b nl
8578
b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b
86-
%%EndBody
8779
grestore
88-
showpage
80+
end
8981
%%EOF

QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_simple.approved.txt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
%!PS-Adobe-3.0
1+
%!PS-Adobe-3.0
22
%%Creator: QRCoder.NET
33
%%Title: QRCode
44
%%DocumentData: Clean7Bit
55
%%Origin: 0
66
%%DocumentMedia: Default 165 165 0 () ()
77
%%BoundingBox: 0 0 165 165
8-
%%LanguageLevel: 2
8+
%%LanguageLevel: 2
99
%%Pages: 1
1010
%%Page: 1 1
1111
%%EndComments
@@ -16,7 +16,7 @@
1616
%%BeginFeature: *PageSize Default
1717
<< /PageSize [ sz sz ] /ImagingBBox null >> setpagedevice
1818
%%EndFeature
19-
%%BeginFunctions
19+
%%BeginFunctions
2020
/csquare {
2121
newpath
2222
0 0 moveto
@@ -27,15 +27,15 @@
2727
setrgbcolor
2828
fill
2929
} def
30-
/f {
30+
/f {
3131
0 0 0 csquare
3232
1 0 translate
3333
} def
34-
/b {
34+
/b {
3535
1 0 translate
36-
} def
37-
/background {
38-
1 1 1 csquare
36+
} def
37+
/background {
38+
1 1 1 csquare
3939
} def
4040
/nl {
4141
-33 -1 translate
@@ -85,5 +85,5 @@ b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b nl
8585
b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b
8686
%%EndBody
8787
grestore
88-
showpage
88+
showpage
8989
%%EOF

QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_size.approved.txt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
%!PS-Adobe-3.0
1+
%!PS-Adobe-3.0
22
%%Creator: QRCoder.NET
33
%%Title: QRCode
44
%%DocumentData: Clean7Bit
55
%%Origin: 0
66
%%DocumentMedia: Default 33 33 0 () ()
77
%%BoundingBox: 0 0 33 33
8-
%%LanguageLevel: 2
8+
%%LanguageLevel: 2
99
%%Pages: 1
1010
%%Page: 1 1
1111
%%EndComments
@@ -16,7 +16,7 @@
1616
%%BeginFeature: *PageSize Default
1717
<< /PageSize [ sz sz ] /ImagingBBox null >> setpagedevice
1818
%%EndFeature
19-
%%BeginFunctions
19+
%%BeginFunctions
2020
/csquare {
2121
newpath
2222
0 0 moveto
@@ -27,15 +27,15 @@
2727
setrgbcolor
2828
fill
2929
} def
30-
/f {
30+
/f {
3131
0 0 0 csquare
3232
1 0 translate
3333
} def
34-
/b {
34+
/b {
3535
1 0 translate
36-
} def
37-
/background {
38-
1 1 1 csquare
36+
} def
37+
/background {
38+
1 1 1 csquare
3939
} def
4040
/nl {
4141
-33 -1 translate
@@ -85,5 +85,5 @@ b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b nl
8585
b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b
8686
%%EndBody
8787
grestore
88-
showpage
88+
showpage
8989
%%EOF

0 commit comments

Comments
 (0)