palapala_pdf 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8ceecc9fff4323ef8cdf26b9e20aeb35f21610e8b55f716a0b8e0c27c0e38613
4
+ data.tar.gz: 4f9f412514ad9a9b63e4b6484488ff245bb0769352374a652845749ac230b6e6
5
+ SHA512:
6
+ metadata.gz: 62c62530b7034a687012bea224b8d284616cef97a2e749ab26151ee2e925ffb3b72ab0d96b13e970ab9d2630bca188c1e134ca59e81bcb37f245dbb1b888f000
7
+ data.tar.gz: 352245729e62e3df55c23848b684af2deb642b3d506de83ef71f8cf0bc4964ac94219baac3e06e776957f15cb15fba41cf3f864ecb4a381c7e057bed75e598f6
data/.rubocop.yml ADDED
@@ -0,0 +1,14 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ # This is a basic RuboCop configuration file
4
+ AllCops:
5
+ TargetRubyVersion: 3.1
6
+ NewCops: enable
7
+ Exclude:
8
+ - db/schema.rb
9
+ - bin/**/*
10
+ - draft/**/*
11
+
12
+ require:
13
+ - rubocop-minitest
14
+ - rubocop-rake
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,44 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2024-08-23 11:11:08 UTC using RuboCop version 1.65.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
11
+ Metrics/AbcSize:
12
+ Max: 33
13
+
14
+ # Offense count: 1
15
+ # Configuration parameters: AllowedMethods, AllowedPatterns.
16
+ Metrics/CyclomaticComplexity:
17
+ Max: 13
18
+
19
+ # Offense count: 1
20
+ # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
21
+ Metrics/MethodLength:
22
+ Max: 19
23
+
24
+ # Offense count: 1
25
+ # Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
26
+ Metrics/ParameterLists:
27
+ Max: 10
28
+
29
+ # Offense count: 1
30
+ # Configuration parameters: AllowedMethods, AllowedPatterns.
31
+ Metrics/PerceivedComplexity:
32
+ Max: 13
33
+
34
+ # Offense count: 2
35
+ Style/ClassVars:
36
+ Exclude:
37
+ - 'lib/palapala/pdf.rb'
38
+
39
+ # Offense count: 1
40
+ # This cop supports safe autocorrection (--autocorrect).
41
+ # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns.
42
+ # URISchemes: http, https
43
+ Layout/LineLength:
44
+ Max: 121
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.3.4
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Quine & Partners
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,132 @@
1
+ # PDF Generation for your Rubies
2
+
3
+ This project is a Ruby gem that provides functionality for generating PDF files from HTML using the Chrome browser. It allows you to easily convert HTML content into PDF documents, making it convenient for tasks such as generating reports, invoices, or any other printable documents. The gem provides a simple and intuitive API for converting HTML to PDF, and it leverages the power and flexibility of the Chrome browser's rendering engine to ensure accurate and high-quality PDF output. With this gem, you can easily integrate PDF generation capabilities into your Ruby applications.
4
+
5
+ At the core, this project leverages the same rendering engine as [Grover](https://github.com/Studiosity/grover), but with significantly reduced overhead and dependencies. Instead of relying on the full Grover stack, this project builds on [Ferrum](https://github.com/rubycdp/ferrum) to enable direct communication from Ruby to a headless Chrome or Chromium browser. This approach ensures efficient, thread-safe operations, providing a streamlined alternative for rendering tasks without sacrificing performance or flexibility.
6
+
7
+ This is how easy and powerfull PDF generation should be:
8
+
9
+ ```ruby
10
+ require "palapala"
11
+ Palapala::Pdf.new("<h1>Hello, world! #{Time.now}</h1>").save('hello.pdf')
12
+ ```
13
+
14
+ And this while having the most modern HTML/CSS/JS availlable to you: flex, grid, canvas, you name it.
15
+
16
+ ## Installation
17
+
18
+ To install the gem and add it to your application's Gemfile, execute the following command:
19
+
20
+ ```
21
+ $ bundle add palapala_pdf
22
+ ```
23
+
24
+ If you are not using bundler to manage dependencies, you can install the gem by running:
25
+
26
+ ```
27
+ $ gem install palapala_pdf
28
+ ```
29
+
30
+ Palapala PDF uses [Ferrum](https://github.com/rubycdp/ferrum) inside and that one is pretty good at finding your Chrome or Chromium.
31
+
32
+ If you want the highest throughput, then use an external Chrome/Chromium. Just start it with (9222 is the default port):
33
+
34
+ ```sh
35
+ chrome --headless --disable-gpu --remote-debugging-port=9222
36
+ ```
37
+
38
+ Then you can run Palapala PDF against that Chrome/Chromium instance (see configuration).
39
+
40
+ ## Usage Instructions
41
+
42
+ To create a PDF from HTML content using the `Palapala` library, follow these steps:
43
+
44
+ 1. **Configuration**:
45
+
46
+ Configure the `Palapala` library with the necessary options, such as the URL for the Ferrum browser and default settings like scale and format.
47
+
48
+ In a Rails context, this could be inside an initializer.
49
+
50
+ ```ruby
51
+ Palapala.setup do |config|
52
+ # run against an external chrome/chromium or leave this out to run against a chrome that is started as a child process
53
+ config.ferrum_opts = { url: 'http://localhost:9222' }
54
+ config.defaults = { scale: 1, format: :A4 }
55
+ end
56
+ ```
57
+
58
+ 2. **Create a PDF from HTML**:
59
+
60
+ Create a PDF file from HTML in IRB
61
+
62
+ ```sh
63
+ gem install palapala_pdf
64
+ ```
65
+
66
+ in IRB, load palapala and create a PDF from an HTML snippet:
67
+
68
+ ```sh
69
+ >irb
70
+ ```
71
+
72
+ ```ruby
73
+ require "palapala"
74
+ Palapala::Pdf.new("<h1>Hello, world! #{Time.now}</h1>").save('hello.pdf')
75
+ ```
76
+
77
+ Instantiate a new Palapala::Pdf object with your HTML content and generate the PDF binary data.
78
+
79
+ ```ruby
80
+ require "palapala"
81
+ binary_data = Palapala::Pdf.new("<h1>Hello, world! #{Time.now}</h1>").binary_data
82
+ ```
83
+
84
+ ## Development
85
+
86
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
87
+
88
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
89
+
90
+ ## Contributing
91
+
92
+ Bug reports and pull requests are welcome on GitHub at https://github.com/palapala-app/palapala_pdf.
93
+
94
+ ## Contributors
95
+
96
+ - [Kenneth Geerts](https://github.com/kennethgeerts) - Your foundational contributions to simplicity are greatly appreciated.
97
+ - [Eugen Neagoe](https://github.com/eneagoe) - Thank you for your valuable input, feedback and opinions.
98
+
99
+ ## Sponsor This Project
100
+
101
+ If you find this project useful and would like to support its development, consider sponsoring or buying a coffee to help keep it going:
102
+
103
+ - **GitHub Sponsors:** [Sponsor on GitHub](https://github.com/sponsors/koenhandekyn)
104
+ - **Buy Me a Coffee:** [Buy a Coffee](https://buymeacoffee.com/koenhandekyn)
105
+
106
+ Your support is greatly appreciated and helps maintain the project!
107
+
108
+ ## Findings
109
+
110
+ For Chrome, mode headless=new seems to be slower for pdf rendering cases.
111
+
112
+ ## Primitive benchmark
113
+
114
+ On a macbook m3, the throughput for 'hello world' PDF generation can reach around 25 docs/second when allowing for some concurrency. As Chrome is actually also very efficient, it scales really well for complex documents also. If you run this in Rails, the concurrency is being taken care of either by the front end thread pool or by the workers and you shouldn't have to think about this. (Using an external Chrome)
115
+
116
+
117
+ ```
118
+ benchmarking 20 docs: 1x20, 2x10, 4x5, 5x4, 20x1 (c is concurrency, n is iterations)
119
+ Total time c:1, n:20 = 1.2048690000083297 seconds
120
+ Total time c:2, n:10 = 0.8969700000016019 seconds
121
+ Total time c:4, n:5 = 0.7497870000079274 seconds
122
+ Total time c:5, n:4 = 0.72492800001055 seconds
123
+ Total time c:20, n:1 = 0.7156629998935387 seconds
124
+ ```
125
+
126
+ ## Advanced stuf
127
+
128
+ ### Headers and Footers
129
+
130
+ ### Title pages
131
+
132
+ ### Page sizes in CSS
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+
5
+ require 'rake/testtask'
6
+
7
+ Rake::TestTask.new do |t|
8
+ t.libs << 'test'
9
+ t.test_files = FileList['test/test_*.rb']
10
+ t.verbose = true
11
+ end
12
+
13
+ task default: :test
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ferrum'
4
+
5
+ module Palapala
6
+ # Page class to generate PDF from HTML content using Chrome in headless mode in a thread-safe way
7
+ class Pdf
8
+ def initialize(content = nil,
9
+ url: nil,
10
+ path: nil,
11
+ header_html: nil,
12
+ footer_html: nil,
13
+ generate_tagged_pdf: false,
14
+ prefer_css_page_size: true,
15
+ scale: Palapala.defaults.fetch(:scale, 1),
16
+ page_ranges: Palapala.defaults.fetch(:page_ranges, ''),
17
+ margin: Palapala.defaults.fetch(:margin, {}))
18
+ @content = content
19
+ @url = url
20
+ @path = path
21
+ @header_html = header_html
22
+ @footer_html = footer_html
23
+ @generate_tagged_pdf = generate_tagged_pdf
24
+ @prefer_css_page_size = prefer_css_page_size
25
+ @page_ranges = page_ranges
26
+ @scale = scale
27
+ @margin = margin
28
+ end
29
+
30
+ def pdf(**opts)
31
+ browser_context = browser.contexts.create
32
+ browser_page = browser_context.page
33
+ # # output console logs for this page
34
+ if opts[:debug]
35
+ browser_page.on('Runtime.consoleAPICalled') do |params|
36
+ params['args'].each { |r| puts(r['value']) }
37
+ end
38
+ end
39
+ # open the page
40
+ url = @url || data_url
41
+ browser_page.go_to(url)
42
+ # Wait for the page to load
43
+ browser_page.network.wait_for_idle
44
+ # Generate PDF
45
+ pdf_binary_data = browser_page.pdf(**opts_with_defaults.merge(opts))
46
+ # Dispose the context
47
+ browser_context.dispose
48
+ # Return the PDF data
49
+ pdf_binary_data
50
+ end
51
+
52
+ def binary_data(**opts)
53
+ pdf(**opts)
54
+ end
55
+
56
+ def save(path, **opts)
57
+ pdf(path:, **opts)
58
+ end
59
+
60
+ private
61
+
62
+ def data_url
63
+ encoded_html = Base64.strict_encode64(@content)
64
+ "data:text/html;base64,#{encoded_html}"
65
+ end
66
+
67
+ def opts_with_defaults
68
+ opts = { scale: @scale,
69
+ printBackground: true,
70
+ dispayHeaderFooter: true,
71
+ pageRanges: @page_ranges, # Empty string means all pages, e.g., "1-3, 5, 7-9"
72
+ encoding: :binary,
73
+ preferCSSPageSize: true,
74
+ headerTemplate: @header_html || '',
75
+ footerTemplate: @footer_html || '' }
76
+
77
+ opts[:path] = @path unless @path.nil?
78
+ opts[:generateTaggedPDF] = @generate_tagged_pdf unless @generate_tagged_pdf.nil?
79
+ opts[:format] = @format unless @format.nil?
80
+ opts[:paperWidth] = @paper_width unless @paper_width.nil?
81
+ opts[:paperHeight] = @paper_height unless @paper_height.nil?
82
+ opts[:landscape] = @landscape unless @landscape.nil?
83
+ opts[:marginTop] = @margin[:top] unless @margin[:top].nil?
84
+ opts[:marginLeft] = @margin[:left] unless @margin[:left].nil?
85
+ opts[:marginBottom] = @margin[:bottom] unless @margin[:bottom].nil?
86
+ opts[:marginRight] = @margin[:right] unless @margin[:right].nil?
87
+
88
+ opts
89
+ end
90
+
91
+ def browser
92
+ # accordng to the docs ferrum is thread safe, however, under heavy load
93
+ # we are seeing some issues, so we are using thread locals to have a
94
+ # browser per thread
95
+ Thread.current[:browser] ||= new_browser
96
+ # @@browser ||= new_browser
97
+ end
98
+
99
+ def new_browser
100
+ Ferrum::Browser.new(Palapala.ferrum_opts)
101
+ end
102
+
103
+ # # TODO use method from template class
104
+ # def cm_to_inches(value)
105
+ # value / 2.54
106
+ # end
107
+ end
108
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Palapala
4
+ VERSION = '0.1.1'
5
+ end
data/lib/palapala.rb ADDED
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'palapala/pdf'
4
+
5
+ # Main module for the gem
6
+ module Palapala
7
+ def self.setup
8
+ yield self
9
+ end
10
+
11
+ def self.ferrum_opts=(ferrum_opts)
12
+ @ferrum_opts = ferrum_opts
13
+ end
14
+
15
+ def self.ferrum_opts
16
+ @ferrum_opts
17
+ end
18
+
19
+ def self.defaults=(defaults)
20
+ @defaults = defaults
21
+ end
22
+
23
+ def self.defaults
24
+ @defaults ||= {}
25
+ end
26
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/palapala/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'palapala_pdf'
7
+ spec.version = Palapala::VERSION
8
+ spec.authors = ['Koen Handekyn']
9
+ spec.email = ['github.com@handekyn.com']
10
+
11
+ spec.summary = 'Convert HTML into PDF directly from Ruby using Chrome/Chromium.'
12
+ spec.description = 'This gem uses Ferrum to render HTML into a PDF using Chrom(e)(ium) with minimal dependencies.'
13
+ spec.homepage = 'https://github.com/palapala-app/palapala_pdf'
14
+ spec.required_ruby_version = '>= 3.1'
15
+ spec.license = 'MIT'
16
+
17
+ # spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
18
+
19
+ spec.metadata['homepage_uri'] = spec.homepage
20
+ # spec.metadata['source_code_uri'] = 'https://github.com/palapala-app/palapala_pdf'
21
+ spec.metadata['changelog_uri'] = 'https://github.com/palapala-app/palapala_pdf/blob/main/changelog.md'
22
+ spec.metadata['rubygems_mfa_required'] = 'true'
23
+
24
+ # Specify which files should be added to the gem when it is released.
25
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
26
+ spec.files = Dir.chdir(__dir__) do
27
+ `git ls-files -z`.split("\x0").reject do |f|
28
+ (File.expand_path(f) == __FILE__) ||
29
+ f.start_with?(*%w[bin/ test/ spec/ draft/ features/ .git appveyor Gemfile])
30
+ end
31
+ end
32
+ spec.bindir = 'exe'
33
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
34
+ spec.require_paths = ['lib']
35
+
36
+ # Uncomment to register a new dependency of your gem
37
+ spec.add_dependency 'ferrum', '~> 0.15'
38
+
39
+ # For more information and examples about making a new gem, check out our
40
+ # guide at: https://bundler.io/guides/creating_gem.html
41
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: palapala_pdf
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Koen Handekyn
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-08-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ferrum
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.15'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.15'
27
+ description: This gem uses Ferrum to render HTML into a PDF using Chrom(e)(ium) with
28
+ minimal dependencies.
29
+ email:
30
+ - github.com@handekyn.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - ".rubocop.yml"
36
+ - ".rubocop_todo.yml"
37
+ - ".ruby-version"
38
+ - LICENSE
39
+ - README.md
40
+ - Rakefile
41
+ - lib/palapala.rb
42
+ - lib/palapala/pdf.rb
43
+ - lib/palapala/version.rb
44
+ - palapala_pdf.gemspec
45
+ homepage: https://github.com/palapala-app/palapala_pdf
46
+ licenses:
47
+ - MIT
48
+ metadata:
49
+ homepage_uri: https://github.com/palapala-app/palapala_pdf
50
+ changelog_uri: https://github.com/palapala-app/palapala_pdf/blob/main/changelog.md
51
+ rubygems_mfa_required: 'true'
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '3.1'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubygems_version: 3.5.17
68
+ signing_key:
69
+ specification_version: 4
70
+ summary: Convert HTML into PDF directly from Ruby using Chrome/Chromium.
71
+ test_files: []