save_pdf: add crop marks

Should satisfy #123

Needs some testing on printers but the functionality is there.
This commit is contained in:
Andy Meneely
2016-11-01 12:12:03 -04:00
parent f94f710040
commit 30395aee56
11 changed files with 1731 additions and 526 deletions
+2 -1
View File
@@ -3,6 +3,7 @@ require_relative '../args/hand_special'
require_relative '../args/save_batch'
require_relative '../args/sheet'
require_relative '../args/showcase_special'
require_relative '../graphics/save_pdf'
module Squib
class Deck
@@ -18,7 +19,7 @@ module Squib
def save_pdf(opts = {})
range = Args::CardRange.new(opts[:range], deck_size: size)
sheet = Args::Sheet.new(custom_colors, { file: 'output.pdf' }).load!(opts, expand_by: size, layout: layout, dpi: dpi)
render_pdf(range, sheet)
Graphics::SavePDF.new(self).render_pdf(range, sheet)
end
# DSL method. See http://squib.readthedocs.io
+57 -2
View File
@@ -12,14 +12,23 @@ module Squib
include ColorValidator
include DirValidator
def initialize(custom_colors = {}, dsl_method_defaults = {}, deck_size = 1)
def initialize(custom_colors = {}, dsl_method_defaults = {}, deck_size = 1, dpi = 300)
@custom_colors = custom_colors
@dsl_method_defaults = dsl_method_defaults
@deck_size = deck_size
@dpi = dpi
end
def self.parameters
{
crop_margin_bottom: 0,
crop_margin_left: 0,
crop_margin_right: 0,
crop_margin_top: 0,
crop_marks: false,
crop_stroke_color: :black,
crop_stroke_dash: '',
crop_stroke_width: 1.5,
dir: '_output',
file: 'sheet.png',
fill_color: :white,
@@ -39,7 +48,16 @@ module Squib
end
def self.params_with_units
[ :gap, :height, :margin, :trim_radius, :trim, :width ]
[ :crop_margin_bottom, :crop_margin_left, :crop_margin_right,
:crop_margin_top, :gap, :height, :margin, :trim_radius, :trim,
:width
]
end
def validate_crop_stroke_dash(arg)
arg.to_s.split.collect do |x|
UnitConversion.parse(x, @dpi).to_f
end
end
def validate_fill_color(arg)
@@ -66,6 +84,43 @@ module Squib
"#{dir}/#{file}"
end
def crop_coords(x, y, deck_w, deck_h)
[
{ # Vertical, Upper-left
x1: x + trim + crop_margin_left, y1: 0,
x2: x + trim + crop_margin_left, y2: margin - 1
},
{ # Vertical , Upper-right
x1: x + deck_w - trim - crop_margin_right, y1: 0,
x2: x + deck_w - trim - crop_margin_right, y2: margin - 1
},
{ # Vertical , Lower-left
x1: x + trim + crop_margin_left, y1: height,
x2: x + trim + crop_margin_left, y2: height - margin + 1
},
{ # Vertical , Lower-right
x1: x + deck_w - trim - crop_margin_right, y1: height,
x2: x + deck_w - trim - crop_margin_right, y2: height - margin + 1
},
{ # Horizont al, Upper-left
x1: 0 , y1: y + trim + crop_margin_top,
x2: margin - 1, y2: y + trim + crop_margin_top
},
{ # Horizontal, Upper-Right
x1: width , y1: y + trim + crop_margin_top,
x2: width - margin + 1, y2: y + trim + crop_margin_top
},
{ # Horizontal, Lower-Left
x1: 0 , y1: y + deck_h - trim - crop_margin_bottom,
x2: margin - 1, y2: y + deck_h - trim - crop_margin_bottom
},
{ # Horizontal, Lower-Right
x1: width, y1: y + deck_h - trim - crop_margin_bottom,
x2: width - margin + 1, y2: y + deck_h - trim - crop_margin_bottom
},
]
end
end
end
+1 -1
View File
@@ -26,7 +26,7 @@ module Squib
# Attributes for the width, height (in pixels) and number of cards
# These are expected to be immuatble for the life of Deck
# @api private
attr_reader :width, :height, :cards
attr_reader :width, :height, :cards, :progress_bar
# Delegate these configuration options to the Squib::Conf object
def_delegators :conf, :antialias, :backend, :count_format, :custom_colors, :dir,
-45
View File
@@ -1,51 +1,6 @@
module Squib
class Deck
# :nodoc:
# @api private
def render_pdf(range, sheet)
file = "#{sheet.dir}/#{sheet.file}"
cc = Cairo::Context.new(Cairo::PDFSurface.new(file, sheet.width * 72.0 / @dpi, sheet.height * 72.0 / @dpi))
cc.scale(72.0 / @dpi, 72.0 / @dpi) # for bug #62
x, y = sheet.margin, sheet.margin
card_width = @width - 2 * sheet.trim
card_height = @height - 2 * sheet.trim
@progress_bar.start("Saving PDF to #{file}", range.size) do |bar|
range.each do |i|
card = @cards[i]
cc.translate(x, y)
cc.rectangle(sheet.trim, sheet.trim, card_width, card_height)
cc.clip
case card.backend.downcase.to_sym
when :memory
cc.set_source(card.cairo_surface, 0, 0)
cc.paint
when :svg
card.cairo_surface.finish
cc.save
cc.scale(0.8, 0.8) # I really don't know why I needed to do this at all. But 0.8 is the magic number to get this to scale right
cc.render_rsvg_handle(RSVG::Handle.new_from_file(card.svgfile), nil)
cc.restore
else
abort "No such back end supported for save_pdf: #{backend}"
end
bar.increment
cc.reset_clip
cc.translate(-x, -y)
x += card.width + sheet.gap - 2 * sheet.trim
if x > (sheet.width - card_width - sheet.margin)
x = sheet.margin
y += card.height + sheet.gap - 2 * sheet.trim
if y > (sheet.height - card_height - sheet.margin)
cc.show_page # next page
x, y = sheet.margin, sheet.margin
end
end
end
end
cc.target.finish
end
# :nodoc:
# @api private
def render_sheet(range, batch, sheet)
+85
View File
@@ -0,0 +1,85 @@
require_relative '../args/sheet'
module Squib
module Graphics
class SavePDF
def initialize(deck)
@deck = deck
end
# :nodoc:
# @api private
def render_pdf(range, sheet)
cc = init_cc(sheet)
cc.scale(72.0 / @deck.dpi, 72.0 / @deck.dpi) # for bug #62
x, y = sheet.margin, sheet.margin
card_width = @deck.width - 2 * sheet.trim
card_height = @deck.height - 2 * sheet.trim
track_progress(range, sheet) do |bar|
range.each do |i|
card = @deck.cards[i]
cc.translate(x, y)
cc.rectangle(sheet.trim, sheet.trim, card_width, card_height)
cc.clip
case card.backend.downcase.to_sym
when :memory
cc.set_source(card.cairo_surface, 0, 0)
cc.paint
when :svg
card.cairo_surface.finish
cc.save
cc.scale(0.8, 0.8) # I really don't know why I needed to do this at all. But 0.8 is the magic number to get this to scale right
cc.render_rsvg_handle(RSVG::Handle.new_from_file(card.svgfile), nil)
cc.restore
else
abort "No such back end supported for save_pdf: #{backend}"
end
bar.increment
cc.reset_clip
cc.translate(-x, -y)
draw_crop_marks(cc, x, y, sheet) if sheet.crop_marks
x += card.width + sheet.gap - 2 * sheet.trim
if x > (sheet.width - card_width - sheet.margin)
x = sheet.margin
y += card.height + sheet.gap - 2 * sheet.trim
if y > (sheet.height - card_height - sheet.margin)
cc.show_page # next page
x, y = sheet.margin, sheet.margin
end
end
end
end
cc.target.finish
end
private
# Initialize the Cairo Context
def init_cc(sheet)
Cairo::Context.new(Cairo::PDFSurface.new(
"#{sheet.dir}/#{sheet.file}",
sheet.width * 72.0 / @deck.dpi, #PDF thinks in 72 DPI "points"
sheet.height * 72.0 / @deck.dpi)
)
end
def track_progress(range, sheet)
msg = "Saving PDF to #{sheet.full_filename}"
@deck.progress_bar.start(msg, range.size) { |bar| yield(bar) }
end
def draw_crop_marks(cc, x, y, sheet)
sheet.crop_coords(x, y, @deck.width, @deck.height).each do |coord|
cc.move_to(coord[:x1], coord[:y1])
cc.line_to(coord[:x2], coord[:y2])
cc.set_source_color(sheet.crop_stroke_color)
cc.set_dash(sheet.crop_stroke_dash)
cc.set_line_width(sheet.crop_stroke_width)
cc.stroke
end
end
end
end
end