preflight 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +8 -1
- data/README.rdoc +21 -4
- data/lib/preflight.rb +1 -0
- data/lib/preflight/issue.rb +35 -0
- data/lib/preflight/profile.rb +38 -16
- data/lib/preflight/profiles/pdfa1a.rb +0 -1
- data/lib/preflight/profiles/pdfx1a.rb +4 -3
- data/lib/preflight/rules.rb +17 -2
- data/lib/preflight/rules/box_nesting.rb +35 -23
- data/lib/preflight/rules/compression_algorithms.rb +14 -4
- data/lib/preflight/rules/consistent_boxes.rb +63 -0
- data/lib/preflight/rules/cropbox_matches_mediabox.rb +38 -0
- data/lib/preflight/rules/document_id.rb +14 -2
- data/lib/preflight/rules/info_has_keys.rb +15 -3
- data/lib/preflight/rules/info_specifies_trapping.rb +16 -3
- data/lib/preflight/rules/match_info_entries.rb +17 -3
- data/lib/preflight/rules/max_ink_density.rb +69 -0
- data/lib/preflight/rules/max_version.rb +14 -2
- data/lib/preflight/rules/mediabox_at_origin.rb +42 -0
- data/lib/preflight/rules/min_bleed.rb +171 -0
- data/lib/preflight/rules/min_ppi.rb +54 -116
- data/lib/preflight/rules/no_cmyk.rb +113 -0
- data/lib/preflight/rules/no_filespecs.rb +15 -5
- data/lib/preflight/rules/no_font_subsets.rb +15 -6
- data/lib/preflight/rules/no_gray.rb +105 -0
- data/lib/preflight/rules/no_page_rotation.rb +36 -0
- data/lib/preflight/rules/no_private_data.rb +37 -0
- data/lib/preflight/rules/no_registration_black.rb +102 -0
- data/lib/preflight/rules/no_rgb.rb +112 -0
- data/lib/preflight/rules/no_separation.rb +85 -0
- data/lib/preflight/rules/no_transparency.rb +90 -0
- data/lib/preflight/rules/only_embedded_fonts.rb +28 -14
- data/lib/preflight/rules/output_intent_for_pdfx.rb +14 -2
- data/lib/preflight/rules/page_box_height.rb +88 -0
- data/lib/preflight/rules/page_box_size.rb +106 -0
- data/lib/preflight/rules/page_box_width.rb +88 -0
- data/lib/preflight/rules/page_count.rb +87 -0
- data/lib/preflight/rules/pdfx_output_intent_has_keys.rb +12 -2
- data/lib/preflight/rules/print_boxes.rb +21 -19
- data/lib/preflight/rules/root_has_keys.rb +15 -3
- metadata +97 -113
- data/lib/preflight/rules/no_encryption.rb +0 -16
- data/lib/preflight/rules/no_proprietary_fonts.rb +0 -50
@@ -0,0 +1,113 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module Preflight
|
6
|
+
module Rules
|
7
|
+
|
8
|
+
# Some print workflows forbid the use of CMYK colour.
|
9
|
+
#
|
10
|
+
# Arguments: none
|
11
|
+
#
|
12
|
+
# Usage:
|
13
|
+
#
|
14
|
+
# class MyPreflight
|
15
|
+
# include Preflight::Profile
|
16
|
+
#
|
17
|
+
# rule Preflight::Rules::NoCmyk
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
class NoCmyk
|
21
|
+
extend Forwardable
|
22
|
+
|
23
|
+
# Graphics State Operators
|
24
|
+
def_delegators :@state, :save_graphics_state, :restore_graphics_state
|
25
|
+
|
26
|
+
# Matrix Operators
|
27
|
+
def_delegators :@state, :concatenate_matrix
|
28
|
+
|
29
|
+
attr_reader :issues
|
30
|
+
|
31
|
+
# we're about to start a new page, reset state
|
32
|
+
#
|
33
|
+
def page=(page)
|
34
|
+
@page = page
|
35
|
+
@state = PDF::Reader::PageState.new(page)
|
36
|
+
@issues = []
|
37
|
+
@resource_labels_seen = []
|
38
|
+
end
|
39
|
+
|
40
|
+
# descend into nested form xobjects
|
41
|
+
#
|
42
|
+
def invoke_xobject(label)
|
43
|
+
@state.invoke_xobject(label) do |xobj|
|
44
|
+
case xobj
|
45
|
+
when PDF::Reader::FormXObject then
|
46
|
+
xobj.walk(self)
|
47
|
+
when PDF::Reader::Stream then
|
48
|
+
check_xobject(xobj)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def set_cmyk_color_for_stroking(c, m, y, k)
|
54
|
+
cmyk_detected(c, m, y, k)
|
55
|
+
end
|
56
|
+
|
57
|
+
def set_cmyk_color_for_nonstroking(c, m, y, k)
|
58
|
+
cmyk_detected(c, m, y, k)
|
59
|
+
end
|
60
|
+
|
61
|
+
def set_stroke_color_space(label)
|
62
|
+
check_color_space(label)
|
63
|
+
end
|
64
|
+
|
65
|
+
def set_nonstroke_color_space(label)
|
66
|
+
check_color_space(label)
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def color_space_is_cmyk?(cs)
|
72
|
+
case cs
|
73
|
+
when Symbol then cs == :DeviceCMYK
|
74
|
+
when Array then
|
75
|
+
cs[0] == :DeviceCMYK || cs[2] == :DeviceCMYK
|
76
|
+
else
|
77
|
+
false
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def check_color_space(label)
|
82
|
+
return if @resource_labels_seen.include?(label)
|
83
|
+
|
84
|
+
if color_space_is_cmyk?(@state.find_color_space(label))
|
85
|
+
@issues << Issue.new("CMYK color detected", self, :page => @page.number)
|
86
|
+
end
|
87
|
+
|
88
|
+
@resource_labels_seen << label
|
89
|
+
end
|
90
|
+
|
91
|
+
def check_xobject(xobject)
|
92
|
+
cs = xobject.hash[:ColorSpace]
|
93
|
+
if cs == :DeviceCMYK
|
94
|
+
@issues << Issue.new("CMYK image detected", self, :page => @page.number)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def cmyk_detected(c, m, y, k)
|
99
|
+
@issues << Issue.new("CMYK color detected", self, :page => @page.number,
|
100
|
+
:cyan => c,
|
101
|
+
:magenta => m,
|
102
|
+
:yellow => y,
|
103
|
+
:k => k)
|
104
|
+
end
|
105
|
+
|
106
|
+
def deref(obj)
|
107
|
+
@page.objects.deref(obj)
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
@@ -3,14 +3,24 @@
|
|
3
3
|
module Preflight
|
4
4
|
module Rules
|
5
5
|
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# Check the target PDF doesn't use Filespecs to refer to external files.
|
7
|
+
#
|
8
|
+
# Arguments: none
|
9
|
+
#
|
10
|
+
# Usage:
|
11
|
+
#
|
12
|
+
# class MyPreflight
|
13
|
+
# include Preflight::Profile
|
14
|
+
#
|
15
|
+
# rule Preflight::Rules::NoFilespecs
|
16
|
+
# end
|
8
17
|
#
|
9
18
|
class NoFilespecs
|
10
19
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
20
|
+
def check_hash(ohash)
|
21
|
+
filespecs_count = count_filespec_dicts(ohash)
|
22
|
+
if filespecs_count > 0
|
23
|
+
[Issue.new("File uses at least 1 Filespec to refer to an external file", self, :filespecs_count => filespecs_count)]
|
14
24
|
else
|
15
25
|
[]
|
16
26
|
end
|
@@ -3,18 +3,27 @@
|
|
3
3
|
module Preflight
|
4
4
|
module Rules
|
5
5
|
|
6
|
-
# check a file has no font subsets. Subsets are handy and valid
|
7
|
-
#
|
8
|
-
#
|
6
|
+
# check a file has no font subsets. Subsets are handy and valid in
|
7
|
+
# standards like PDFX/1a, but they can make it hard to edit a file
|
8
|
+
#
|
9
|
+
# Arguments: none
|
10
|
+
#
|
11
|
+
# Usage:
|
12
|
+
#
|
13
|
+
# class MyPreflight
|
14
|
+
# include Preflight::Profile
|
15
|
+
#
|
16
|
+
# rule Preflight::Rules::NoFontSubsets
|
17
|
+
# end
|
9
18
|
#
|
10
19
|
class NoFontSubsets
|
11
20
|
|
12
|
-
def
|
21
|
+
def check_hash(ohash)
|
13
22
|
array = []
|
14
23
|
ohash.each do |key, obj|
|
15
24
|
next unless obj.is_a?(::Hash) && obj[:Type] == :Font
|
16
25
|
if subset?(obj)
|
17
|
-
array << "Font #{obj[:BaseFont]}
|
26
|
+
array << Issue.new("Font partially subseted (#{obj[:BaseFont]})", self, :base_font => obj[:BaseFont])
|
18
27
|
end
|
19
28
|
end
|
20
29
|
array
|
@@ -23,7 +32,7 @@ module Preflight
|
|
23
32
|
private
|
24
33
|
|
25
34
|
def subset?(font)
|
26
|
-
font[:BaseFont] && font[:BaseFont].
|
35
|
+
font[:BaseFont] && font[:BaseFont].to_s[/.+\+.+/]
|
27
36
|
end
|
28
37
|
end
|
29
38
|
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module Preflight
|
6
|
+
module Rules
|
7
|
+
|
8
|
+
# Some print workflows forbid the use of Gray colour.
|
9
|
+
#
|
10
|
+
# Arguments: none
|
11
|
+
#
|
12
|
+
# Usage:
|
13
|
+
#
|
14
|
+
# class MyPreflight
|
15
|
+
# include Preflight::Profile
|
16
|
+
#
|
17
|
+
# rule Preflight::Rules::NoGray
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
class NoGray
|
21
|
+
extend Forwardable
|
22
|
+
|
23
|
+
# Graphics State Operators
|
24
|
+
def_delegators :@state, :save_graphics_state, :restore_graphics_state
|
25
|
+
|
26
|
+
# Matrix Operators
|
27
|
+
def_delegators :@state, :concatenate_matrix
|
28
|
+
|
29
|
+
attr_reader :issues
|
30
|
+
|
31
|
+
# we're about to start a new page, reset state
|
32
|
+
#
|
33
|
+
def page=(page)
|
34
|
+
@page = page
|
35
|
+
@state = PDF::Reader::PageState.new(page)
|
36
|
+
@issues = []
|
37
|
+
@resource_labels_seen = []
|
38
|
+
end
|
39
|
+
|
40
|
+
# descend into nested form xobjects
|
41
|
+
#
|
42
|
+
def invoke_xobject(label)
|
43
|
+
@state.invoke_xobject(label) do |xobj|
|
44
|
+
case xobj
|
45
|
+
when PDF::Reader::FormXObject then
|
46
|
+
xobj.walk(self)
|
47
|
+
when PDF::Reader::Stream then
|
48
|
+
check_xobject(xobj)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def set_gray_for_stroking(g)
|
54
|
+
gray_detected(g)
|
55
|
+
end
|
56
|
+
|
57
|
+
def set_gray_for_nonstroking(g)
|
58
|
+
gray_detected(g)
|
59
|
+
end
|
60
|
+
|
61
|
+
def set_stroke_color_space(label)
|
62
|
+
check_color_space(label)
|
63
|
+
end
|
64
|
+
|
65
|
+
def set_nonstroke_color_space(label)
|
66
|
+
check_color_space(label)
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def color_space_is_gray?(cs)
|
72
|
+
case cs
|
73
|
+
when Symbol then cs == :DeviceGray
|
74
|
+
when Array then
|
75
|
+
cs[0] == :DeviceGray || cs[2] == :DeviceGray
|
76
|
+
else
|
77
|
+
false
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def check_color_space(label)
|
82
|
+
return if @resource_labels_seen.include?(label)
|
83
|
+
|
84
|
+
if color_space_is_gray?(@state.find_color_space(label))
|
85
|
+
@issues << Issue.new("Gray color detected", self, :page => @page.number)
|
86
|
+
end
|
87
|
+
|
88
|
+
@resource_labels_seen << label
|
89
|
+
end
|
90
|
+
|
91
|
+
def check_xobject(xobject)
|
92
|
+
cs = xobject.hash[:ColorSpace]
|
93
|
+
if cs == :DeviceGray
|
94
|
+
@issues << Issue.new("Gray image detected", self, :page => @page.number)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def gray_detected(g)
|
99
|
+
@issues << Issue.new("Gray color detected", self, :page => @page.number,
|
100
|
+
:gray => g)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Preflight
|
4
|
+
module Rules
|
5
|
+
|
6
|
+
# Ensure the target file contains no page rotation.
|
7
|
+
#
|
8
|
+
# Rotating pages is generally acceptable in most specs but it can cause
|
9
|
+
# rendering issues with poor waulity PDF consumers.
|
10
|
+
#
|
11
|
+
# Arguments: none
|
12
|
+
#
|
13
|
+
# Usage:
|
14
|
+
#
|
15
|
+
# class MyPreflight
|
16
|
+
# include Preflight::Profile
|
17
|
+
#
|
18
|
+
# rule Preflight::Rules::NoPageRotation
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
class NoPageRotation
|
22
|
+
|
23
|
+
attr_reader :issues
|
24
|
+
|
25
|
+
def page=(page)
|
26
|
+
attrs = page.attributes
|
27
|
+
|
28
|
+
if attrs[:Rotate] && attrs[:Rotate] != 0
|
29
|
+
@issues = [Issue.new("Page is rotated", self, :page => page.number)]
|
30
|
+
else
|
31
|
+
@issues = []
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Preflight
|
4
|
+
module Rules
|
5
|
+
|
6
|
+
# Ensure the target file contains no private application data.
|
7
|
+
#
|
8
|
+
# PDF generating apps (like Adobe Illustrator) can embed their own private
|
9
|
+
# data in saved PDFs. This data is generally harmless and ignored by all
|
10
|
+
# other PDF consumers, but it can lead to large increases in file size.
|
11
|
+
#
|
12
|
+
# Arguments: none
|
13
|
+
#
|
14
|
+
# Usage:
|
15
|
+
#
|
16
|
+
# class MyPreflight
|
17
|
+
# include Preflight::Profile
|
18
|
+
#
|
19
|
+
# rule Preflight::Rules::NoPrivateData
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
class NoPrivateData
|
23
|
+
|
24
|
+
attr_reader :issues
|
25
|
+
|
26
|
+
def page=(page)
|
27
|
+
attrs = page.attributes
|
28
|
+
|
29
|
+
if attrs[:PieceInfo]
|
30
|
+
@issues = [Issue.new("Page contains private PieceInfo data", self, :page => page.number)]
|
31
|
+
else
|
32
|
+
@issues = []
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module Preflight
|
6
|
+
module Rules
|
7
|
+
|
8
|
+
# Some print workflows forbid the use of Registration Black
|
9
|
+
#
|
10
|
+
# Arguments: none
|
11
|
+
#
|
12
|
+
# Usage:
|
13
|
+
#
|
14
|
+
# class MyPreflight
|
15
|
+
# include Preflight::Profile
|
16
|
+
#
|
17
|
+
# rule Preflight::Rules::NoRegistrationBlack
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
class NoRegistrationBlack
|
21
|
+
extend Forwardable
|
22
|
+
|
23
|
+
# Graphics State Operators
|
24
|
+
def_delegators :@state, :save_graphics_state, :restore_graphics_state
|
25
|
+
|
26
|
+
# Matrix Operators
|
27
|
+
def_delegators :@state, :concatenate_matrix
|
28
|
+
|
29
|
+
attr_reader :issues
|
30
|
+
|
31
|
+
# we're about to start a new page, reset state
|
32
|
+
#
|
33
|
+
def page=(page)
|
34
|
+
@page = page
|
35
|
+
@state = PDF::Reader::PageState.new(page)
|
36
|
+
@issues = []
|
37
|
+
@resource_labels_seen = []
|
38
|
+
end
|
39
|
+
|
40
|
+
# descend into nested form xobjects
|
41
|
+
#
|
42
|
+
def invoke_xobject(label)
|
43
|
+
@state.invoke_xobject(label) do |xobj|
|
44
|
+
case xobj
|
45
|
+
when PDF::Reader::FormXObject then
|
46
|
+
xobj.walk(self)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def set_cmyk_color_for_stroking(c, m, y, k)
|
52
|
+
reg_black_detected(c, m, y, k) if registration_black?(c, m, y, k)
|
53
|
+
end
|
54
|
+
|
55
|
+
def set_cmyk_color_for_nonstroking(c, m, y, k)
|
56
|
+
reg_black_detected(c, m, y, k) if registration_black?(c, m, y, k)
|
57
|
+
end
|
58
|
+
|
59
|
+
def set_stroke_color_space(label)
|
60
|
+
check_color_space(label)
|
61
|
+
end
|
62
|
+
|
63
|
+
def set_nonstroke_color_space(label)
|
64
|
+
check_color_space(label)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def registration_black?(c, m, y, k)
|
70
|
+
c == 1 && m == 1 && y == 1 && k == 1
|
71
|
+
end
|
72
|
+
|
73
|
+
def color_space_is_all?(cs)
|
74
|
+
cs.is_a?(Array) && cs[1].to_s.downcase == "all"
|
75
|
+
end
|
76
|
+
|
77
|
+
def check_color_space(label)
|
78
|
+
return if @resource_labels_seen.include?(label)
|
79
|
+
|
80
|
+
if color_space_is_all?(@state.find_color_space(label))
|
81
|
+
@issues << Issue.new("'All' separation color detected", self, :page => @page.number)
|
82
|
+
end
|
83
|
+
|
84
|
+
@resource_labels_seen << label
|
85
|
+
end
|
86
|
+
|
87
|
+
def reg_black_detected(c, m, y, k)
|
88
|
+
@issues << Issue.new("Registration black detected", self, :page => @page.number,
|
89
|
+
:cyan => c,
|
90
|
+
:magenta => m,
|
91
|
+
:yellow => y,
|
92
|
+
:k => k)
|
93
|
+
end
|
94
|
+
|
95
|
+
def deref(obj)
|
96
|
+
@page.objects.deref(obj)
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|