pdfinfo 1.2.0 → 1.3.1
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.
- checksums.yaml +13 -5
- data/lib/pdfinfo.rb +112 -72
- metadata +11 -39
checksums.yaml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NGI3ZTIzYzMxYzEyNTkyYmQ2ZDEwNzBjMDg2NWYxOGFkNTk3MTM2YQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZDQ1NzRmMjczZmMyNTI4YWEzNDcwZWUyOWYxYTNhZDAyNDI4NGRlZA==
|
5
7
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZTY5YWU4M2Q3Y2VhNzIxYTg3ZDZlNWY4OGRiZjZmMmMwMzcyZTJlMjU3ODA2
|
10
|
+
ZDBiYmRkNDMwNTgwNzgyY2EwNTYzZDNkNmY5MmZjNjIwZmI4OGNmMDMwYzU2
|
11
|
+
M2I1ZTBhMjgwOGM2MzkwMjA1MDVhYWEyOTM1MDM4N2Q4MjE5YjE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MzVhZjE1MmQwYTNiYjM4NjY5MjY0NTE2NzA3MjRjOTE1MDc3YTdjMzdiYjEw
|
14
|
+
NWFlODJjMzI1MTY1MzA2ZDg0MTMzZmU1NGJjZGQ2ODEzNTEwODQyMTE3NWVh
|
15
|
+
YWJiZWY5YjhkNjUzODcyMDczNTExNzgwMWFhM2FhMjAyNDgzMzQ=
|
data/lib/pdfinfo.rb
CHANGED
@@ -1,79 +1,62 @@
|
|
1
1
|
require 'open3'
|
2
2
|
require 'shellwords'
|
3
|
+
require 'date'
|
3
4
|
require 'time'
|
5
|
+
%w(object_to_hash errors page).each {|f| require File.expand_path("../pdfinfo/#{f}", __FILE__)}
|
4
6
|
|
5
7
|
class Pdfinfo
|
6
|
-
|
8
|
+
include ObjectToHash
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
+
attr_reader :pages, :title, :subject, :keywords, :author, :creator,
|
11
|
+
:creation_date, :modified_date, :usage_rights, :producer,
|
12
|
+
:form, :page_count, :width, :height, :file_size, :pdf_version
|
10
13
|
|
11
|
-
class
|
12
|
-
def
|
13
|
-
|
14
|
+
class << self
|
15
|
+
def pdfinfo_command
|
16
|
+
@pdfinfo_command || 'pdfinfo'
|
14
17
|
end
|
15
|
-
end
|
16
18
|
|
19
|
+
def pdfinfo_command=(cmd)
|
20
|
+
@pdfinfo_command = cmd
|
21
|
+
end
|
17
22
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
:creator,
|
23
|
-
:creation_date,
|
24
|
-
:usage_rights,
|
25
|
-
:producer,
|
26
|
-
:form,
|
27
|
-
:page_count,
|
28
|
-
:width,
|
29
|
-
:height,
|
30
|
-
:file_size,
|
31
|
-
:pdf_version
|
32
|
-
|
33
|
-
def self.exec(file_path, opts = {})
|
34
|
-
raise CommandNotFound, 'pdfinfo' unless pdfinfo_command?
|
35
|
-
flags = []
|
36
|
-
flags.concat(['-enc', opts.fetch(:encoding, 'UTF-8')])
|
37
|
-
flags.concat(['-opw', opts[:owner_password]]) if opts[:owner_password]
|
38
|
-
flags.concat(['-upw', opts[:user_password]]) if opts[:user_password]
|
23
|
+
# @return [Boolean]
|
24
|
+
def pdfinfo_command?
|
25
|
+
system("type #{pdfinfo_command} >/dev/null 2>&1")
|
26
|
+
end
|
39
27
|
|
40
|
-
|
41
|
-
stdout, status = Open3.capture2(command)
|
42
|
-
stdout.encode('UTF-8', invalid: :replace, replace: '', undef: :replace)
|
28
|
+
attr_accessor :config_path
|
43
29
|
end
|
44
30
|
|
45
|
-
def
|
46
|
-
@
|
47
|
-
end
|
31
|
+
def initialize(source_path, opts = {})
|
32
|
+
@pages = []
|
48
33
|
|
49
|
-
|
50
|
-
@pdfinfo_command = cmd
|
51
|
-
end
|
34
|
+
info_hash = parse_shell_response(exec(source_path, opts))
|
52
35
|
|
53
|
-
|
54
|
-
|
55
|
-
|
36
|
+
info_hash.delete_if do |key, value|
|
37
|
+
@pages << Page.from_string(value) if key.match(/Page\s+\d+\ssize/)
|
38
|
+
end
|
56
39
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
@
|
61
|
-
@
|
62
|
-
@
|
63
|
-
@
|
64
|
-
@
|
65
|
-
@
|
66
|
-
@
|
67
|
-
@
|
68
|
-
@
|
69
|
-
@
|
70
|
-
@
|
71
|
-
|
72
|
-
@
|
73
|
-
@
|
74
|
-
|
75
|
-
raw_usage_rights = Hash[
|
76
|
-
booleanize_usage_right = lambda {|val|
|
40
|
+
encrypted_val = info_hash.delete('Encrypted')
|
41
|
+
|
42
|
+
@title = presence(info_hash.delete('Title'))
|
43
|
+
@subject = presence(info_hash.delete('Subject'))
|
44
|
+
@author = presence(info_hash.delete('Author'))
|
45
|
+
@creator = presence(info_hash.delete('Creator'))
|
46
|
+
@producer = presence(info_hash.delete('Producer'))
|
47
|
+
@tagged = !!(info_hash.delete('Tagged') =~ /yes/)
|
48
|
+
@encrypted = !!(encrypted_val =~ /yes/)
|
49
|
+
@page_count = info_hash.delete('Pages').to_i
|
50
|
+
@file_size = info_hash.delete('File size').to_i
|
51
|
+
@form = info_hash.delete('Form')
|
52
|
+
@pdf_version = info_hash.delete('PDF version')
|
53
|
+
@optimized = !!(info_hash.delete('Optimized') =~ /yes/)
|
54
|
+
@keywords = (info_hash.delete('Keywords') || '').split(/\s/)
|
55
|
+
@creation_date = parse_time(info_hash.delete('CreationDate'))
|
56
|
+
@modified_date = parse_time(info_hash.delete('ModDate'))
|
57
|
+
|
58
|
+
raw_usage_rights = Hash[encrypted_val.scan(/(\w+):(\w+)/)]
|
59
|
+
booleanize_usage_right = lambda {|val| raw_usage_rights[val] != 'no' }
|
77
60
|
|
78
61
|
@usage_rights = {}.tap do |ur|
|
79
62
|
ur[:print] = booleanize_usage_right.call('print')
|
@@ -82,47 +65,104 @@ class Pdfinfo
|
|
82
65
|
ur[:add_notes] = booleanize_usage_right.call('addNotes')
|
83
66
|
end
|
84
67
|
|
85
|
-
|
68
|
+
# temporarily continue setting #width and #height on Pdfinfo object
|
69
|
+
# to maintain legacy behavior
|
70
|
+
@width = @pages[0].width
|
71
|
+
@height = @pages[0].height
|
86
72
|
end
|
87
73
|
|
74
|
+
# @return [Boolean]
|
88
75
|
def tagged?
|
89
76
|
@tagged
|
90
77
|
end
|
91
78
|
|
79
|
+
# @return [Boolean]
|
92
80
|
def encrypted?
|
93
81
|
@encrypted
|
94
82
|
end
|
95
83
|
|
84
|
+
# @return [Boolean]
|
85
|
+
def optimized?
|
86
|
+
@optimized
|
87
|
+
end
|
88
|
+
|
96
89
|
%w(print copy change).each do |ur|
|
90
|
+
# @return [Boolean]
|
97
91
|
define_method("#{ur}able?") { @usage_rights[ur.to_sym] }
|
98
92
|
end
|
99
93
|
alias modifiable? changeable?
|
100
94
|
|
95
|
+
# @return [Boolean]
|
101
96
|
def annotatable?
|
102
97
|
@usage_rights[:add_notes]
|
103
98
|
end
|
104
99
|
|
105
|
-
def to_hash
|
106
|
-
instance_variables.inject({}) {|h, var| h[var[1..-1].to_sym] = instance_variable_get(var); h }
|
107
|
-
end
|
108
100
|
private
|
101
|
+
# executes pdfinfo command with supplied options
|
102
|
+
# @param [String,Pathname] file_path
|
103
|
+
# @param [Hash] opts
|
104
|
+
# @return [String] output
|
105
|
+
def exec(file_path, opts = {})
|
106
|
+
validate_pdfinfo_command!
|
107
|
+
|
108
|
+
flags = build_options(opts)
|
109
|
+
|
110
|
+
command = [self.class.pdfinfo_command, *flags, file_path.to_s].shelljoin
|
111
|
+
|
112
|
+
stdout, status = Open3.capture2(command)
|
113
|
+
force_utf8_encoding(stdout)
|
114
|
+
end
|
115
|
+
|
116
|
+
# prepares array of flags to pass as command line options
|
117
|
+
# ---
|
118
|
+
# @todo: add option builder class
|
119
|
+
# +++
|
120
|
+
# @param [Hash] opts of options
|
121
|
+
# @option opts [String] :encoding ('UTF-8')
|
122
|
+
# @option opts [String] :owner_password
|
123
|
+
# @option opts [String] :user_password
|
124
|
+
# @return [Array<String>] array of flags
|
125
|
+
def build_options(opts = {})
|
126
|
+
flags = []
|
127
|
+
xpdfrc_path = opts.fetch(:config_path, self.class.config_path)
|
128
|
+
|
129
|
+
# these flag will always be part of the cli options. Values have defaults and can be overridden
|
130
|
+
flags.concat(['-f', opts.fetch(:first_page, 0)])
|
131
|
+
flags.concat(['-l', opts.fetch(:last_page, -1)])
|
132
|
+
flags.concat(['-enc', opts.fetch(:encoding, Encoding::UTF_8)])
|
133
|
+
# optional flags. if no value, the flag wont be added
|
134
|
+
flags.concat(['-cfg', xpdfrc_path]) if xpdfrc_path
|
135
|
+
flags.concat(['-opw', opts[:owner_password]]) if opts[:owner_password]
|
136
|
+
flags.concat(['-upw', opts[:user_password]]) if opts[:user_password]
|
137
|
+
flags.map(&:to_s)
|
138
|
+
end
|
139
|
+
|
140
|
+
# @param [String] str
|
141
|
+
# @return [String] UTF-8 encoded string
|
142
|
+
def force_utf8_encoding(str)
|
143
|
+
return str if str.valid_encoding?
|
144
|
+
str = str.encode(Encoding::UTF_16, invalid: :replace, undef: :replace, replace: '')
|
145
|
+
str.encode!(Encoding::UTF_8)
|
146
|
+
end
|
147
|
+
|
109
148
|
def presence(val)
|
110
|
-
(val.nil? || val.empty?) ? nil : val
|
149
|
+
(val.nil? || val.empty? ) ? nil : val
|
111
150
|
end
|
112
151
|
|
113
152
|
def parse_shell_response(response_str)
|
114
153
|
Hash[response_str.split(/\n/).map {|kv| kv.split(/:/, 2).map(&:strip) }]
|
115
154
|
end
|
116
155
|
|
117
|
-
def extract_page_dimensions(str)
|
118
|
-
return unless str
|
119
|
-
str.match(DIMENSIONS_REGEXP).captures.map(&:to_f)
|
120
|
-
end
|
121
|
-
|
122
156
|
def parse_time(str)
|
123
|
-
|
157
|
+
return unless presence(str)
|
158
|
+
DateTime.strptime(str, '%a %b %e %H:%M:%S %Y')
|
124
159
|
rescue ArgumentError => e
|
125
|
-
warn(e.message)
|
126
160
|
nil
|
127
161
|
end
|
162
|
+
|
163
|
+
def validate_pdfinfo_command!
|
164
|
+
unless self.class.pdfinfo_command?
|
165
|
+
raise CommandNotFound, self.class.pdfinfo_command
|
166
|
+
end
|
167
|
+
end
|
128
168
|
end
|
metadata
CHANGED
@@ -1,83 +1,55 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pdfinfo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Venegas
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.6'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.6'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: prawn
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: rspec
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
44
30
|
requirements:
|
45
|
-
- -
|
31
|
+
- - ~>
|
46
32
|
- !ruby/object:Gem::Version
|
47
33
|
version: 3.1.0
|
48
34
|
type: :development
|
49
35
|
prerelease: false
|
50
36
|
version_requirements: !ruby/object:Gem::Requirement
|
51
37
|
requirements:
|
52
|
-
- -
|
38
|
+
- - ~>
|
53
39
|
- !ruby/object:Gem::Version
|
54
40
|
version: 3.1.0
|
55
41
|
- !ruby/object:Gem::Dependency
|
56
42
|
name: rake
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
58
44
|
requirements:
|
59
|
-
- -
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: coveralls
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
45
|
+
- - ! '>='
|
74
46
|
- !ruby/object:Gem::Version
|
75
47
|
version: '0'
|
76
48
|
type: :development
|
77
49
|
prerelease: false
|
78
50
|
version_requirements: !ruby/object:Gem::Requirement
|
79
51
|
requirements:
|
80
|
-
- -
|
52
|
+
- - ! '>='
|
81
53
|
- !ruby/object:Gem::Version
|
82
54
|
version: '0'
|
83
55
|
description: Simple ruby wrapper around the pdfinfo executable
|
@@ -97,17 +69,17 @@ require_paths:
|
|
97
69
|
- lib
|
98
70
|
required_ruby_version: !ruby/object:Gem::Requirement
|
99
71
|
requirements:
|
100
|
-
- -
|
72
|
+
- - ! '>='
|
101
73
|
- !ruby/object:Gem::Version
|
102
74
|
version: 1.9.3
|
103
75
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
76
|
requirements:
|
105
|
-
- -
|
77
|
+
- - ! '>='
|
106
78
|
- !ruby/object:Gem::Version
|
107
79
|
version: '0'
|
108
80
|
requirements: []
|
109
81
|
rubyforge_project:
|
110
|
-
rubygems_version: 2.
|
82
|
+
rubygems_version: 2.2.2
|
111
83
|
signing_key:
|
112
84
|
specification_version: 4
|
113
85
|
summary: Simple ruby wrapper around the pdfinfo executable
|