dynamicpdf_api 1.2.0 → 1.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4032069e887ac6170c27e3e62b6c53937012fc0fc532bcc1ee078db7cc699279
4
- data.tar.gz: '079b748ab778f13fe486b969f371f563456f7ad2aaebdcea1161b04be0d01d91'
3
+ metadata.gz: a7ac0d6c7b3af40747eebd62d4bbe5312c47f7df899eeeace9e62baafd607f19
4
+ data.tar.gz: 6f3448f2d9daa4d345109bb187797ad2f4f385b5225c6217159868e4d4e79bee
5
5
  SHA512:
6
- metadata.gz: 87516c46b99ab12217f99c0997f9b64dc65f2636d3117aae776a941208bc5c758cc3a4d48e4c2b2e4b6370ace9938b6708d77365f1c9e70a54bbdb08c0c255e9
7
- data.tar.gz: 79cec9da77a1828a018a1865caa6f6d99c5278973c191a991e4132c2ea46d4dfa5e9f20f3524d41c21da18cca25c69296b380ad76465c597eb15d95fc9f267c4
6
+ metadata.gz: 5666463e8fdfa35d273f72b1e13cced90e661054cfb772329869f77069303c28fe7bdfb802ff9dbe5db68aaab7b1b114377d78e0ad15f85e1350287a57f646c1
7
+ data.tar.gz: 8536196f5815157f71fe925c4cd7879a1b09dc5e8ea1f8723d3e94207fbe927ab55b19a38cd9bb80c66a76b3bd4d17c9f6db3bfb4bb5543827fec8bbb59a12a1
@@ -36,17 +36,11 @@ module DynamicPDFApi
36
36
  @type = ResourceType::FONT
37
37
 
38
38
  when ".tiff"
39
- @type = ResourceType::IMAGE
40
39
  when ".tif"
41
- @type = ResourceType::IMAGE
42
40
  when ".png"
43
- @type = ResourceType::IMAGE
44
41
  when ".gif"
45
- @type = ResourceType::IMAGE
46
42
  when ".jpeg"
47
- @type = ResourceType::IMAGE
48
43
  when ".jpg"
49
- @type = ResourceType::IMAGE
50
44
  when ".bmp"
51
45
  @type = ResourceType::IMAGE
52
46
 
@@ -66,16 +60,22 @@ module DynamicPDFApi
66
60
  @file_header = @file_header.bytes
67
61
  if (ImageResource.is_png_image(@file_header))
68
62
  @_mime_type = "image/png"
63
+ ".png"
69
64
  elsif (ImageResource.is_jpeg_image(@file_header))
70
65
  @_mime_type = "image/jpeg"
66
+ ".jpeg"
71
67
  elsif (ImageResource.is_gif_image(@file_header))
72
68
  @_mime_type = "image/gif"
69
+ ".gif"
73
70
  elsif (ImageResource.is_tiff_image(@file_header))
74
71
  @_mime_type = "image/tiff"
72
+ ".tiff"
75
73
  elsif (ImageResource.is_jpeg2000_image(@file_header))
76
74
  @_mime_type = "image/jpeg"
75
+ ".jpeg"
77
76
  elsif (ImageResource.is_valid_bitmap_image(@file_header))
78
77
  @_mime_type = "image/bmp"
78
+ ".bmp"
79
79
  else
80
80
  raise "Not supported image type or invalid image."
81
81
  end
@@ -0,0 +1,31 @@
1
+ module DynamicPDFApi
2
+ #
3
+ # Specifies Encryption Type.
4
+ #
5
+ class EncryptionType
6
+ #
7
+ # RC4 40 bit security.
8
+ #
9
+ RC440 = 'rc440'.freeze
10
+
11
+ #
12
+ # RC4 128 bit security.
13
+ #
14
+ RC4128 = 'rc4128'.freeze
15
+
16
+ #
17
+ # AES 128 bit security with CBC cipher mode.
18
+ #
19
+ AES128CBC = 'aes128cbc'.freeze
20
+
21
+ #
22
+ # AES 256 bit security with CBC cipher mode.
23
+ #
24
+ AES256CBC = 'aes256cbc'.freeze
25
+
26
+ #
27
+ # No security.
28
+ #
29
+ NONE = 'none'.freeze
30
+ end
31
+ end
@@ -1,10 +1,23 @@
1
1
  module DynamicPDFApi
2
2
  require_relative "FontResource"
3
+ require_relative "FullNameTable"
3
4
 
4
5
  #
5
6
  # Represents font.
6
7
  #
7
8
  class Font
9
+ @font_details = []
10
+ @load_required = true
11
+ @lock = Mutex.new
12
+
13
+ # For Windows fonts
14
+ windir = ENV["WINDIR"]
15
+ if windir && !windir.empty?
16
+ @path_to_fonts_resource_directory = File.join(windir, "Fonts")
17
+ else
18
+ @path_to_fonts_resource_directory = nil
19
+ end
20
+
8
21
  #
9
22
  # Initializes a new instance of the Font class using the font name that is present in the cloud resource
10
23
  # manager.
@@ -245,6 +258,70 @@ module DynamicPDFApi
245
258
  font
246
259
  end
247
260
 
261
+ def self.from_system(font_name, resource_name = nil)
262
+ return nil if font_name.nil? || font_name.strip.empty?
263
+
264
+ font_name = font_name.gsub(/[- ]/, "") # Removing the space and - from font_name
265
+
266
+ self.load_fonts if @load_required
267
+
268
+ @font_details.each do |detail|
269
+ if detail._name.casecmp(font_name).zero?
270
+ font_resource = FontResource.new(detail.file_path, resource_name)
271
+ return Font.create_font(font_resource, font_resource.resource_name)
272
+ end
273
+ end
274
+
275
+ nil
276
+ end
277
+
278
+ def self.load_fonts
279
+ return unless @load_required
280
+ loaded_any = false
281
+
282
+ @lock.synchronize do
283
+ if @path_to_fonts_resource_directory && !@path_to_fonts_resource_directory.empty?
284
+ dir_Info = File.join(@path_to_fonts_resource_directory.gsub("\\", "/"), "*")
285
+
286
+ Dir.glob(dir_Info).each do |file_path|
287
+ next unless file_path.downcase.end_with?(".ttf", ".otf")
288
+
289
+ File.open(file_path, "rb") do |reader|
290
+ name_table = self.read_font_name_table(reader)
291
+
292
+ if name_table && name_table._name && !name_table._name.empty?
293
+ @font_details << FontInformation.new(name_table._name, file_path)
294
+ end
295
+ end
296
+ end
297
+ end
298
+ @load_required = false
299
+ end
300
+ end
301
+
302
+ def self.read_font_name_table(reader)
303
+ name_table = nil
304
+ begin
305
+ reader.seek(4, IO::SEEK_SET)
306
+ table_count = (reader.readbyte << 8) | reader.readbyte
307
+ if table_count > 0
308
+ reader.seek(12, IO::SEEK_SET)
309
+ table_directory = reader.read(table_count * 16).b
310
+ (0...table_directory.size).step(16) do |i|
311
+ tag_bytes = table_directory[i, 4]
312
+ tag = tag_bytes.unpack1("V")
313
+ if tag == 1701667182 # "name"
314
+ name_table = FullNameTable.new(reader, table_directory, i)
315
+ break
316
+ end
317
+ end
318
+ end
319
+ rescue => e
320
+ puts "Error in read_font_name_table: #{e.message}"
321
+ end
322
+ name_table
323
+ end
324
+
248
325
  def to_json(_options = {})
249
326
  json_array = {}
250
327
  json_array["name"] = @_name unless @_name.nil?
@@ -1,9 +1,10 @@
1
1
  module DynamicPDFApi
2
2
  class FontInformation
3
- def initialize(font_name, file_path)
4
- @_font_name = font_name
3
+ attr_reader :_name, :file_path
5
4
 
6
- @_file_path = file_path
5
+ def initialize(font_name, file_path)
6
+ @_name = font_name
7
+ @file_path = file_path
7
8
  end
8
9
  end
9
10
  end
@@ -0,0 +1,67 @@
1
+ module DynamicPDFApi
2
+ require "stringio"
3
+
4
+ class FullNameTable
5
+ attr_reader :_name
6
+ def initialize(io, table_directory, position)
7
+
8
+ if table_directory != nil
9
+ int_offset = read_ulong(table_directory, position + 8)
10
+ int_length = read_ulong(table_directory, position + 12)
11
+
12
+ io.seek(int_offset, IO::SEEK_SET)
13
+ @data = io.read(int_length).b
14
+ end
15
+
16
+ @_name = ""
17
+
18
+ dataStart = read_ushort(4)
19
+ headerStart = 6
20
+ headerEnd = (read_ushort(2)* 12)
21
+
22
+ (headerStart...headerEnd).step(12) do |i|
23
+ if read_ushort(i + 6) == 4 # 4 is the Name ID for Full font name
24
+ if read_ushort(i) == 3 && read_ushort(i + 2) == 1 && read_ushort(i + 4) == 0x0409 # 3 for PlatForm ID, 1 for Encoding ID and 0x0409 Language ID for English(United States)
25
+ offset = read_ushort(i + 10)
26
+ length = read_ushort(i + 8)
27
+ raw_bytes = @data[dataStart + offset, length]
28
+ if raw_bytes
29
+ decoded = raw_bytes.dup.force_encoding("UTF-16BE").encode("UTF-8", invalid: :replace, undef: :replace).strip
30
+ @_name = decoded
31
+ break unless @_name.empty?
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ if @_name.empty?
38
+ (headerStart...headerEnd).step(12) do |i|
39
+ if read_ushort(i + 6) == 4 # 4 is the Name ID for Full font name
40
+ if read_ushort(i) == 3 # 3 for PlatForm ID, 0 for Encoding ID and 0x0409 Language ID for English(United States)
41
+ offset = read_ushort(i + 10)
42
+ length = read_ushort(i + 8)
43
+ raw_bytes = @data[dataStart + offset, length]
44
+ if raw_bytes
45
+ decoded = raw_bytes.dup.force_encoding("UTF-16BE").encode("UTF-8", invalid: :replace, undef: :replace).strip
46
+ @_name = decoded
47
+ break
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ # Remove spaces and hyphens
55
+ @_name.gsub!(/[ -]/, "") unless @_name.nil?
56
+ end
57
+
58
+
59
+ def read_ushort(index)
60
+ @data[index, 2]&.unpack1("n") || 0
61
+ end
62
+
63
+ def read_ulong(array, index)
64
+ array[index, 4].unpack1("N")
65
+ end
66
+ end
67
+ end
@@ -339,8 +339,11 @@ module DynamicPDFApi
339
339
  }
340
340
 
341
341
  resource_array = []
342
- resource_array << ["Instructions", data_string,
343
- { content_type: "application/octet-stream", filename: "Instructions.json" }]
342
+ json_bytes = data_string.encode("UTF-8") # UTF-8 text
343
+ resource_array << ["Instructions",json_bytes.force_encoding("ASCII-8BIT"), # send as binary even if UTF-8 text
344
+ { content_type: "application/json", filename: "Instructions.json" }
345
+ ]
346
+
344
347
  @resources.each_value do |field|
345
348
  data = if !field._file_path.nil?
346
349
  File.binread(field._file_path)
@@ -0,0 +1,102 @@
1
+ module DynamicPDFApi
2
+ require_relative 'EncryptionType'
3
+
4
+ # Represents the PDF security info endpoint.
5
+ class PdfSecurityInfo
6
+ def initialize(data = {})
7
+ @encryption_type_string = data["encryptionType"]
8
+ @allow_edit = data["allowEdit"]
9
+ @allow_print = data["allowPrint"]
10
+ @allow_update_annots_and_fields = data["allowUpdateAnnotsAndFields"]
11
+ @allow_copy = data["allowCopy"]
12
+ @allow_high_resolution_printing = data["allowHighResolutionPrinting"]
13
+ @allow_document_assembly = data["allowDocumentAssembly"]
14
+ @allow_form_filling = data["allowFormFilling"]
15
+ @allow_accessibility = data["allowAccessibility"]
16
+ @encrypt_all_except_metadata = data["encryptAllExceptMetadata"]
17
+ @encrypt_only_file_attachments = data["encryptOnlyFileAttachments"]
18
+ @has_owner_password = data["hasOwnerPassword"]
19
+ @has_user_password = data["hasUserPassword"]
20
+ @encryption_type = encryption_type()
21
+ end
22
+
23
+ #
24
+ # Gets or sets if the document can be edited by the user.
25
+ #
26
+ attr_accessor :allow_edit
27
+
28
+ #
29
+ # Gets or sets if the document can be printed by the user.
30
+ #
31
+ attr_accessor :allow_print
32
+
33
+ #
34
+ # Gets or sets if annotations and form fields can be added, edited and modified by the user.
35
+ #
36
+ attr_accessor :allow_update_annots_and_fields
37
+
38
+ #
39
+ # Gets or sets if text and images can be copied to the clipboard by the user.
40
+ #
41
+ attr_accessor :allow_copy
42
+
43
+ #
44
+ # Gets or sets if the document can be printed at a high resolution by the user.
45
+ #
46
+ attr_accessor :allow_high_resolution_printing
47
+
48
+ #
49
+ # Gets or sets if the document can be assembled and manipulated by the user.
50
+ #
51
+ attr_accessor :allow_document_assembly
52
+
53
+ #
54
+ # Gets or sets if form filling should be allowed by the user.
55
+ #
56
+ attr_accessor :allow_form_filling
57
+
58
+ #
59
+ # Gets or sets if accessibility programs should be able to read the documents text and images for the user.
60
+ #
61
+ attr_accessor :allow_accessibility
62
+
63
+ #
64
+ # Gets or sets a value indicating whether all data should be encrypted except for metadata.
65
+ #
66
+ attr_accessor :encrypt_all_except_metadata
67
+
68
+ #
69
+ # Gets or sets a value indicating whether only file attachments should be encrypted.
70
+ #
71
+ attr_accessor :encrypt_only_file_attachments
72
+
73
+ #
74
+ # Gets or sets a value indicating whether the PDF document has an owner password set.
75
+ #
76
+ attr_accessor :has_owner_password
77
+
78
+ #
79
+ # Gets or sets a value indicating whether the PDF document has an user password set.
80
+ #
81
+ attr_accessor :has_user_password
82
+
83
+
84
+ # Gets or sets the encryption type.
85
+ attr_accessor :encryption_type_string
86
+
87
+ def encryption_type
88
+ case (@encryption_type_string).downcase
89
+ when "rc4-40"
90
+ EncryptionType::RC440
91
+ when "rc4-128"
92
+ EncryptionType::RC4128
93
+ when "aes-128-cbc"
94
+ EncryptionType::AES128CBC
95
+ when "aes-256-cbc"
96
+ EncryptionType::AES256CBC
97
+ else
98
+ EncryptionType::NONE
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,71 @@
1
+ module DynamicPDFApi
2
+ require_relative 'Endpoint'
3
+ require_relative 'PdfSecurityInfoResponse'
4
+
5
+ #
6
+ # Represents the pdf security info endpoint.
7
+ #
8
+ class PdfSecurityInfoEndpoint < Endpoint
9
+ #
10
+ # Initializes a new instance of the PdfSecurityInfoEndpoint class.
11
+ #
12
+ # @param resource [PdfResource] The resource of type PdfResource.
13
+ #
14
+ def initialize(resource)
15
+ super()
16
+ @resource = resource
17
+ @_endpoint_name = 'pdf-security-info'
18
+ end
19
+
20
+ #
21
+ # Process the pdf resource to get pdf's security information.
22
+ # @return PdfInfoResponse Returns collection of PdfSecurityInfoResponse.
23
+ #
24
+ def process
25
+ header = {
26
+ 'Authorization': "Bearer #{@api_key}",
27
+ 'Content-Length': @resource.data.length.to_s,
28
+ 'Expect': '100-continue',
29
+ 'Content-Type': 'application/pdf'
30
+ }
31
+ uri = URI.parse("#{@base_url}/v1.0/#{@_endpoint_name}")
32
+
33
+ request = Net::HTTP::Post.new(uri.request_uri, header)
34
+
35
+ req_options = {
36
+ use_ssl: uri.scheme == 'https',
37
+ verify_mode: OpenSSL::SSL::VERIFY_NONE
38
+
39
+ }
40
+
41
+ request.content_type = 'application/pdf'
42
+
43
+ request.body = @resource.data
44
+
45
+ response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
46
+ http.request(request)
47
+ end
48
+ out_data = response.body
49
+ ret_object = PdfSecurityInfoResponse.new(out_data)
50
+ ret_object.is_successful = false
51
+ ret_object.status_code = response.code
52
+ if ret_object.status_code == '200'
53
+ ret_object.is_successful = true
54
+ else
55
+ if ret_object.status_code == '401'
56
+ raise "Invalid api key specified."
57
+ end
58
+ out_data_json = JSON.parse(out_data)
59
+ ret_object.error_json = out_data
60
+ ret_object.error_message = if !out_data_json['message'].nil?
61
+ out_data_json['message']
62
+ else
63
+ "status_code : #{Net::HTTPResponse::CODE_TO_OBJ[ret_object.status_code]}"
64
+ end
65
+ ret_object.error_id = out_data_json['id']
66
+ end
67
+
68
+ ret_object
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,28 @@
1
+ module DynamicPDFApi
2
+ require_relative 'JsonResponse'
3
+ require_relative 'PdfSecurityInfo'
4
+
5
+ #
6
+ # Represents the pdf security info response.
7
+ #
8
+ class PdfSecurityInfoResponse < JsonResponse
9
+ #
10
+ # Initializes a new instance of the PdfSecurityInfoResponse class.
11
+ #
12
+ # @param json_content [String] The json content
13
+ #
14
+ def initialize(json_content = nil)
15
+ @content = nil
16
+ super(json_content) unless json_content.nil?
17
+ @content = PdfSecurityInfo.new(JSON.parse(json_content))
18
+
19
+ end
20
+ # # @content.instance_variable_set(:@encryption_type, @content.encryption_type)
21
+ # end
22
+
23
+ #
24
+ # Gets the collection of PdfContent.
25
+ #
26
+ attr_accessor :content
27
+ end
28
+ end
@@ -18,6 +18,6 @@ module DynamicPDFApi
18
18
  #
19
19
  # RC4 128 bit security.
20
20
  #
21
- RC_4128 = 'aC4128'.freeze
21
+ RC_4128 = 'rc4128'.freeze
22
22
  end
23
23
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyClient
4
- VERSION = "1.2.0"
4
+ VERSION = "1.3.0"
5
5
  end
data/lib/ruby_client.rb CHANGED
@@ -16,6 +16,7 @@ require_relative "ruby_client/DlexInput.rb"
16
16
  require_relative "ruby_client/DlexLayout.rb"
17
17
  require_relative "ruby_client/DlexResource.rb"
18
18
  require_relative "ruby_client/EncryptDocumentComponents.rb"
19
+ require_relative "ruby_client/EncryptionType.rb"
19
20
  require_relative "ruby_client/Endpoint.rb"
20
21
  require_relative "ruby_client/EndPointException.rb"
21
22
  require_relative "ruby_client/EndpointResource.rb"
@@ -26,6 +27,7 @@ require_relative "ruby_client/FontInformation.rb"
26
27
  require_relative "ruby_client/FontResource.rb"
27
28
  require_relative "ruby_client/FormField.rb"
28
29
  require_relative "ruby_client/FormFieldInformation.rb"
30
+ require_relative "ruby_client/FullNameTable.rb"
29
31
  require_relative "ruby_client/GoToAction.rb"
30
32
  require_relative "ruby_client/Grayscale.rb"
31
33
  require_relative "ruby_client/HtmlInput.rb"
@@ -58,6 +60,9 @@ require_relative "ruby_client/PdfInput.rb"
58
60
  require_relative "ruby_client/PdfInstructions.rb"
59
61
  require_relative "ruby_client/PdfResource.rb"
60
62
  require_relative "ruby_client/PdfResponse.rb"
63
+ require_relative "ruby_client/PdfSecurityInfo.rb"
64
+ require_relative "ruby_client/PdfSecurityInfoEndpoint.rb"
65
+ require_relative "ruby_client/PdfSecurityInfoResponse.rb"
61
66
  require_relative "ruby_client/PdfText.rb"
62
67
  require_relative "ruby_client/PdfTextResponse.rb"
63
68
  require_relative "ruby_client/PdfXmp.rb"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dynamicpdf_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dynamicpdf
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-05-20 00:00:00.000000000 Z
11
+ date: 2025-11-14 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A Ruby Client API that uses the DynamicPDF API to create, merge, split,
14
14
  form fill, stamp, secure/encrypt PDF documents and convert word/Excel files to PDF.
@@ -72,6 +72,7 @@ files:
72
72
  - lib/ruby_client/Elements/TextElement.rb
73
73
  - lib/ruby_client/Elements/ValueType.rb
74
74
  - lib/ruby_client/EncryptDocumentComponents.rb
75
+ - lib/ruby_client/EncryptionType.rb
75
76
  - lib/ruby_client/EndPointException.rb
76
77
  - lib/ruby_client/Endpoint.rb
77
78
  - lib/ruby_client/EndpointResource.rb
@@ -82,6 +83,7 @@ files:
82
83
  - lib/ruby_client/FontResource.rb
83
84
  - lib/ruby_client/FormField.rb
84
85
  - lib/ruby_client/FormFieldInformation.rb
86
+ - lib/ruby_client/FullNameTable.rb
85
87
  - lib/ruby_client/GoToAction.rb
86
88
  - lib/ruby_client/Grayscale.rb
87
89
  - lib/ruby_client/HtmlInput.rb
@@ -145,6 +147,9 @@ files:
145
147
  - lib/ruby_client/PdfInstructions.rb
146
148
  - lib/ruby_client/PdfResource.rb
147
149
  - lib/ruby_client/PdfResponse.rb
150
+ - lib/ruby_client/PdfSecurityInfo.rb
151
+ - lib/ruby_client/PdfSecurityInfoEndpoint.rb
152
+ - lib/ruby_client/PdfSecurityInfoResponse.rb
148
153
  - lib/ruby_client/PdfText.rb
149
154
  - lib/ruby_client/PdfTextResponse.rb
150
155
  - lib/ruby_client/PdfXmp.rb