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.
Files changed (43) hide show
  1. data/CHANGELOG +8 -1
  2. data/README.rdoc +21 -4
  3. data/lib/preflight.rb +1 -0
  4. data/lib/preflight/issue.rb +35 -0
  5. data/lib/preflight/profile.rb +38 -16
  6. data/lib/preflight/profiles/pdfa1a.rb +0 -1
  7. data/lib/preflight/profiles/pdfx1a.rb +4 -3
  8. data/lib/preflight/rules.rb +17 -2
  9. data/lib/preflight/rules/box_nesting.rb +35 -23
  10. data/lib/preflight/rules/compression_algorithms.rb +14 -4
  11. data/lib/preflight/rules/consistent_boxes.rb +63 -0
  12. data/lib/preflight/rules/cropbox_matches_mediabox.rb +38 -0
  13. data/lib/preflight/rules/document_id.rb +14 -2
  14. data/lib/preflight/rules/info_has_keys.rb +15 -3
  15. data/lib/preflight/rules/info_specifies_trapping.rb +16 -3
  16. data/lib/preflight/rules/match_info_entries.rb +17 -3
  17. data/lib/preflight/rules/max_ink_density.rb +69 -0
  18. data/lib/preflight/rules/max_version.rb +14 -2
  19. data/lib/preflight/rules/mediabox_at_origin.rb +42 -0
  20. data/lib/preflight/rules/min_bleed.rb +171 -0
  21. data/lib/preflight/rules/min_ppi.rb +54 -116
  22. data/lib/preflight/rules/no_cmyk.rb +113 -0
  23. data/lib/preflight/rules/no_filespecs.rb +15 -5
  24. data/lib/preflight/rules/no_font_subsets.rb +15 -6
  25. data/lib/preflight/rules/no_gray.rb +105 -0
  26. data/lib/preflight/rules/no_page_rotation.rb +36 -0
  27. data/lib/preflight/rules/no_private_data.rb +37 -0
  28. data/lib/preflight/rules/no_registration_black.rb +102 -0
  29. data/lib/preflight/rules/no_rgb.rb +112 -0
  30. data/lib/preflight/rules/no_separation.rb +85 -0
  31. data/lib/preflight/rules/no_transparency.rb +90 -0
  32. data/lib/preflight/rules/only_embedded_fonts.rb +28 -14
  33. data/lib/preflight/rules/output_intent_for_pdfx.rb +14 -2
  34. data/lib/preflight/rules/page_box_height.rb +88 -0
  35. data/lib/preflight/rules/page_box_size.rb +106 -0
  36. data/lib/preflight/rules/page_box_width.rb +88 -0
  37. data/lib/preflight/rules/page_count.rb +87 -0
  38. data/lib/preflight/rules/pdfx_output_intent_has_keys.rb +12 -2
  39. data/lib/preflight/rules/print_boxes.rb +21 -19
  40. data/lib/preflight/rules/root_has_keys.rb +15 -3
  41. metadata +97 -113
  42. data/lib/preflight/rules/no_encryption.rb +0 -16
  43. 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
- # PDF/X files are not allowed to use Filespecs to refer
7
- # to external files.
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 messages(ohash)
12
- if count_filespec_dicts(ohash) > 0
13
- ["File uses at least 1 Filespec to refer to an external file"]
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
- # in standards like PDFX/1a, but they make it hard to edit a
8
- # file
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 messages(ohash)
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]} is a partial subset"
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].match(/.+\+.+/)
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