preflight 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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