Last active
January 3, 2016 06:38
-
-
Save swistak/8423518 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'fileutils' | |
require 'logger' | |
require 'erb' | |
# Pdf generation service based on wkhtmltopdf. | |
class PdfGenerator | |
class WkhtmltopdfError < RuntimeError; end | |
DPI = 96 # Pixels in inch | |
DPC = (DPI / 2.54) # = 37.795 Pixels in centimeter | |
# See http://madalgo.au.dk/~jakobt/wkhtmltoxdoc/wkhtmltopdf-0.9.9-doc.html | |
# | |
# Options without argument just take true, rest should have string as value. | |
# To disable option set it to false. | |
PDF_OPTIONS = { | |
'quiet' => true, | |
# Header is disabled. | |
# 'header-html' => 'header.html', | |
# 'footer-html' => 'footer.html', | |
'print-media-type' => true, | |
# 'disable-smart-shrinking' => true, | |
'page-size' => 'A4', | |
'margin-top' => '0.5cm', | |
'margin-right' => '0.5cm', | |
'margin-bottom' => '1cm', | |
'margin-left' => '0.5cm', | |
'encoding' => "UTF-8", | |
} | |
PDF_DIR = 'pdfs' | |
FileUtils.mkdir_p(PDF_DIR) | |
attr_accessor :error_message | |
attr_accessor :note | |
def logger | |
defined?(Rails) ? Rails.logger : (@logger ||= Logger.new($stdout)) | |
end | |
def pdf_options | |
PDF_OPTIONS | |
end | |
def note_url | |
'index.html' | |
end | |
def pdf_path | |
File.join(PDF_DIR, "ramki.pdf") | |
end | |
def wkhtmltopdf | |
@wkhtmltopdf ||= begin | |
pdf_command = [ | |
`ls -1 bin/wkhtmltopdf* 2>/dev/null`.split("\n").last, | |
`which wkhtmltopdf` | |
].detect{|c| !c.nil? } | |
raise("Cannot locate wkhtmltopdf in #{Dir.pwd} or $PATH") if pdf_command.nil? | |
pdf_command.strip | |
end | |
end | |
def xvfb_wrapper | |
"" #'xvfb-run -s "-screen 0, 1600x1200x24"' | |
end | |
# wkhtmltopdf [OPTIONS]... <input file> [More input files] <output file> | |
def pdf_command | |
normalized_options = pdf_options.map{|k, v| | |
v ? "--#{k} #{v == true ? "" : v}" : nil | |
}.compact.join(" ") | |
"#{xvfb_wrapper} #{wkhtmltopdf} #{normalized_options} #{note_url} #{pdf_path}" | |
end | |
def render | |
File.open('index.html', 'w') do |f| | |
f.write ERB.new(File.read('index.html.erb')).result | |
end | |
end | |
# Generates a pdf. | |
def generate | |
render | |
perform | |
end | |
# Performs a pdf generation. | |
def perform | |
logger.debug "Running: " + pdf_command | |
# See http://mentalized.net/journal/2010/03/08/5_ways_to_run_commands_from_ruby/ | |
redirection = " 2>&1" | |
@out = IO.popen(pdf_command + redirection, "wb+") do |pdf| | |
pdf.close_write | |
pdf.gets(nil) | |
end | |
unless $? == 0 | |
self.error_message = "Failed to generate pdf via: #{wkhtmltopdf}. Exit code: #{$?}." | |
raise(WkhtmltopdfError, error_message, caller[1..-1]) | |
end | |
end | |
end | |
if __FILE__ == $0 | |
PdfGenerator.new.generate | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Printing styles based on HTML5 Boilerplate | |
* | |
* What follows is the result of much research on cross-browser styling. | |
* Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal, | |
* Kroc Camen, and the H5BP dev community and team. | |
* | |
* Additional modifications and printing classes by Marcin Raczkowski | |
*/ | |
/* ========================================================================== | |
Base styles: opinionated defaults + Print styles. | |
Inlined to avoid required HTTP connection: h5bp.com/r | |
========================================================================== */ | |
html, | |
body, | |
button, | |
input, | |
select, | |
textarea { | |
color: #000;/* Black prints faster: h5bp.com/s */ | |
background-color: #fff; | |
} | |
html, body { | |
font-size: 9pt; | |
line-height: 1.4; | |
font-family: Georgia, serif; | |
} | |
@media screen { | |
html, body { | |
font-size: 10px; | |
} | |
} | |
body { | |
/* Print related */ | |
box-shadow: none !important; | |
text-shadow: none !important; | |
} | |
a, | |
a:visited { | |
text-decoration: underline; | |
} | |
a[href]:after { | |
content: " (" attr(href) ")"; | |
} | |
abbr[title]:after { | |
content: " (" attr(title) ")"; | |
} | |
/* | |
* Don't show links for images, or javascript/internal links | |
*/ | |
.ir a:after, | |
a[href^="javascript:"]:after, | |
a[href^="#"]:after { | |
content: ""; | |
} | |
pre, | |
blockquote { | |
border: 1px solid #999; | |
page-break-inside: avoid; | |
} | |
thead { | |
display: table-header-group; /* h5bp.com/t */ | |
} | |
tr, | |
img { | |
page-break-inside: avoid; | |
} | |
img { | |
max-width: 100% !important; | |
} | |
p, | |
h2, | |
h3 { | |
orphans: 3; | |
widows: 3; | |
} | |
h2, | |
h3 { | |
page-break-after: avoid; | |
} | |
/* | |
* A better looking default horizontal rule | |
*/ | |
hr { | |
display: block; | |
height: 1px; | |
border: 0; | |
border-top: 1px solid #ccc; | |
margin: 1em 0; | |
padding: 0; | |
} | |
/* | |
* Remove the gap between images and the bottom of their containers: h5bp.com/i/440 | |
*/ | |
img { | |
vertical-align: middle; | |
} | |
/* | |
* Remove default fieldset styles. | |
*/ | |
fieldset { | |
border: 0; | |
margin: 0; | |
padding: 0; | |
} | |
/* | |
* Allow only vertical resizing of textareas. | |
*/ | |
textarea { | |
resize: vertical; | |
} | |
/* ========================================================================== | |
Additional print styles. Usefull for previews & document authoring. | |
========================================================================== */ | |
body { | |
margin: 0 auto; | |
position: relative; | |
} | |
body.vertical { | |
width: 21cm; /* A4 sized page with 0.5 cm margin/padding */ | |
padding: 0.5cm 0.5cm 1cm; /* USe these values if smart shrinking is disabled,they must mach margins */ | |
} | |
body.horizontal { | |
width: 29.7cm; /* A4(210x297) sized page with 0.5 cm margin top & 1cm margin bottom */ | |
padding: 0.5cm 0.5cm 1cm; | |
} | |
body.vertical .page { | |
width: 20cm; /* A4 sized page with 0.5 cm margin */ | |
height: 28.1cm; /* 29.7 height - 0.5 top margin - 1cm bottom margin - 0.1 for rounding errors. */ | |
} | |
body.horizontal .page { | |
width: 29.7cm; /* A4 sized page with 0.5 cm margin */ | |
height: 19.4cm; /* 21 (A4 H) - 0.5 (top margin) - 1 (bottom margin) - 0.1(rounding errors) */ | |
} | |
/* gives us roughly 200x287 or 287x200 cm working area */ | |
body .page { | |
position: relative; | |
margin: 0; | |
page-break-inside: avoid; | |
} | |
@media screen { | |
body .page { | |
overflow: hidden; | |
padding: 2px; | |
outline: black 1px solid; | |
outline-offset: 0.5cm; | |
margin-top: 1cm; | |
margin-bottom: 1.5cm; | |
} | |
} | |
/* Compact definition list */ | |
dl.compact { | |
margin: 0; | |
font-size: 0.9em; | |
width: 5cm; | |
} | |
dl.compact dt { | |
font-weight: bold; | |
clear: left; float: left; | |
width: 2.25cm; | |
white-space: nowrap; | |
overflow: hidden; | |
} | |
dl.compact dd { | |
float: left; | |
margin: 0 0 0 20px; | |
white-space: nowrap; | |
overflow: hidden; | |
} | |
/* Fixed width tables + some default table styles */ | |
table.fixed { | |
table-layout: fixed; | |
} | |
table.fixed td, | |
table.fixed th { | |
white-space: nowrap; | |
overflow: visible; | |
word-break: break-all; | |
} | |
table td, | |
table th { | |
padding: 0.3em 0.6em; | |
border: 1px solid black; | |
white-space: nowrap; | |
} | |
table th { | |
padding: 0.3em 0; | |
text-align: center; | |
} | |
table.zebra { | |
width: 100%; | |
border: 2px solid black; | |
} | |
table.zebra th { background-color: #aaa !important; } | |
table.zebra td { background-color: #fff !important; } | |
table.zebra td:nth-child(2n) { background-color: #ccc !important; } | |
/* ========================================================================== | |
Helper classes | |
========================================================================== */ | |
.hidden { | |
display: none !important; | |
visibility: hidden; | |
} | |
/* | |
* Hide visually and from screenreaders, but maintain layout | |
*/ | |
.invisible { | |
visibility: hidden; | |
} | |
/* | |
* Clearfix: contain floats | |
* | |
* For modern browsers | |
* 1. The space content is one way to avoid an Opera bug when the | |
* `contenteditable` attribute is included anywhere else in the document. | |
* Otherwise it causes space to appear at the top and bottom of elements | |
* that receive the `clearfix` class. | |
* 2. The use of `table` rather than `block` is only necessary if using | |
* `:before` to contain the top-margins of child elements. | |
*/ | |
.clearfix:before, | |
.clearfix:after { | |
content: " "; /* 1 */ | |
display: table; /* 2 */ | |
} | |
.clearfix:after { | |
clear: both; | |
} | |
/* | |
* For IE 6/7 only | |
* Include this rule to trigger hasLayout and contain floats. | |
*/ | |
.clearfix { | |
*zoom: 1; | |
} | |
.ruler { | |
border-left: 1px solid black; | |
border-bottom: 1px solid black; | |
border-right: 1px solid black; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment