squib 0.14.2 → 0.14.3.pre1
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 +4 -4
- data/.gitignore +41 -41
- data/.travis.yml +19 -19
- data/CHANGELOG.md +366 -357
- data/CONTRIBUTING.md +40 -40
- data/Gemfile +2 -2
- data/LICENSE.txt +22 -22
- data/README.md +121 -121
- data/RELEASE TODO.md +21 -21
- data/Rakefile +48 -48
- data/appveyor.yml +24 -24
- data/bin/squib +4 -4
- data/lib/squib.rb +32 -32
- data/lib/squib/api/background.rb +15 -15
- data/lib/squib/api/data.rb +137 -137
- data/lib/squib/api/groups.rb +54 -54
- data/lib/squib/api/image.rb +49 -49
- data/lib/squib/api/save.rb +83 -83
- data/lib/squib/api/settings.rb +21 -21
- data/lib/squib/api/shapes.rb +124 -124
- data/lib/squib/api/text.rb +25 -25
- data/lib/squib/api/text_embed.rb +71 -71
- data/lib/squib/api/units.rb +27 -27
- data/lib/squib/args/arg_loader.rb +126 -126
- data/lib/squib/args/box.rb +55 -55
- data/lib/squib/args/card_range.rb +32 -32
- data/lib/squib/args/color_validator.rb +12 -12
- data/lib/squib/args/coords.rb +35 -35
- data/lib/squib/args/csv_opts.rb +25 -25
- data/lib/squib/args/dir_validator.rb +16 -16
- data/lib/squib/args/draw.rb +92 -92
- data/lib/squib/args/embed_adjust.rb +25 -25
- data/lib/squib/args/embed_key.rb +17 -17
- data/lib/squib/args/hand_special.rb +37 -37
- data/lib/squib/args/import.rb +40 -40
- data/lib/squib/args/input_file.rb +37 -37
- data/lib/squib/args/paint.rb +44 -44
- data/lib/squib/args/paragraph.rb +116 -116
- data/lib/squib/args/save_batch.rb +63 -63
- data/lib/squib/args/scale_box.rb +53 -53
- data/lib/squib/args/sheet.rb +172 -172
- data/lib/squib/args/showcase_special.rb +38 -38
- data/lib/squib/args/sprue_file.rb +44 -44
- data/lib/squib/args/svg_special.rb +37 -37
- data/lib/squib/args/transform.rb +61 -61
- data/lib/squib/args/typographer.rb +119 -119
- data/lib/squib/args/unit_conversion.rb +29 -29
- data/lib/squib/builtin/layouts/economy.yml +85 -85
- data/lib/squib/builtin/layouts/fantasy.yml +101 -101
- data/lib/squib/builtin/layouts/hand.yml +62 -62
- data/lib/squib/builtin/layouts/party.yml +94 -94
- data/lib/squib/builtin/layouts/playing-card.yml +35 -35
- data/lib/squib/builtin/layouts/tuck_box.yml +46 -46
- data/lib/squib/builtin/projects/advanced/.gitignore +4 -4
- data/lib/squib/builtin/projects/advanced/ABOUT.md +19 -19
- data/lib/squib/builtin/projects/advanced/Gemfile +11 -11
- data/lib/squib/builtin/projects/advanced/Guardfile +21 -21
- data/lib/squib/builtin/projects/advanced/IDEAS.md +22 -22
- data/lib/squib/builtin/projects/advanced/PLAYTESTING.md +26 -26
- data/lib/squib/builtin/projects/advanced/Rakefile +27 -27
- data/lib/squib/builtin/projects/advanced/config.yml +53 -49
- data/lib/squib/builtin/projects/advanced/docs/PNP NOTES.md +3 -3
- data/lib/squib/builtin/projects/advanced/docs/RULES.md +21 -21
- data/lib/squib/builtin/projects/advanced/img/example.svg +60 -60
- data/lib/squib/builtin/projects/advanced/layouts/deck.yml +27 -27
- data/lib/squib/builtin/projects/advanced/src/deck.rb +34 -34
- data/lib/squib/builtin/projects/advanced/src/version.rb +3 -3
- data/lib/squib/builtin/projects/basic/.gitignore +4 -4
- data/lib/squib/builtin/projects/basic/ABOUT.md +19 -19
- data/lib/squib/builtin/projects/basic/Gemfile +3 -3
- data/lib/squib/builtin/projects/basic/IDEAS.md +22 -22
- data/lib/squib/builtin/projects/basic/PLAYTESTING.md +26 -26
- data/lib/squib/builtin/projects/basic/PNP NOTES.md +3 -3
- data/lib/squib/builtin/projects/basic/RULES.md +21 -21
- data/lib/squib/builtin/projects/basic/Rakefile +7 -7
- data/lib/squib/builtin/projects/basic/config.yml +53 -49
- data/lib/squib/builtin/projects/basic/deck.rb +6 -6
- data/lib/squib/builtin/sprues/a4_euro_card.yml +42 -42
- data/lib/squib/builtin/sprues/a4_poker_card_8up.yml +40 -40
- data/lib/squib/builtin/sprues/a4_poker_card_9up.yml +42 -42
- data/lib/squib/builtin/sprues/a4_usa_card.yml +42 -42
- data/lib/squib/builtin/sprues/drivethrucards_1up.yml +10 -10
- data/lib/squib/builtin/sprues/letter_poker_card_9up.yml +25 -25
- data/lib/squib/builtin/sprues/letter_poker_foldable_8up.yml +52 -52
- data/lib/squib/builtin/sprues/printplaygames_18up.yml +68 -68
- data/lib/squib/card.rb +75 -75
- data/lib/squib/commands/cli.rb +39 -39
- data/lib/squib/commands/data/template_option.rb +109 -109
- data/lib/squib/commands/make_sprue.rb +275 -275
- data/lib/squib/commands/new.rb +77 -77
- data/lib/squib/conf.rb +144 -139
- data/lib/squib/constants.rb +17 -17
- data/lib/squib/deck.rb +116 -116
- data/lib/squib/graphics/background.rb +14 -14
- data/lib/squib/graphics/cairo_context_wrapper.rb +113 -113
- data/lib/squib/graphics/embedding_utils.rb +28 -28
- data/lib/squib/graphics/gradient_regex.rb +47 -47
- data/lib/squib/graphics/hand.rb +42 -42
- data/lib/squib/graphics/image.rb +129 -108
- data/lib/squib/graphics/save_doc.rb +61 -61
- data/lib/squib/graphics/save_images.rb +52 -52
- data/lib/squib/graphics/save_pdf.rb +90 -90
- data/lib/squib/graphics/save_sprue.rb +204 -204
- data/lib/squib/graphics/shapes.rb +143 -143
- data/lib/squib/graphics/showcase.rb +85 -85
- data/lib/squib/graphics/text.rb +174 -174
- data/lib/squib/import/data_frame.rb +108 -108
- data/lib/squib/layout_parser.rb +138 -138
- data/lib/squib/progress.rb +38 -38
- data/lib/squib/sample_helpers.rb +34 -34
- data/lib/squib/sprues/crop_line.rb +28 -28
- data/lib/squib/sprues/crop_line_dash.rb +35 -35
- data/lib/squib/sprues/invalid_sprue_definition.rb +9 -9
- data/lib/squib/sprues/sprue.rb +203 -203
- data/lib/squib/sprues/sprue_schema.rb +48 -48
- data/lib/squib/version.rb +10 -10
- data/samples/autoscale_font/_autoscale_font.rb +29 -29
- data/samples/backend/_backend.rb +26 -26
- data/samples/basic.rb +19 -19
- data/samples/bug256/_bug256.rb +13 -0
- data/samples/build_groups/build_groups.rb +36 -36
- data/samples/colors/_colors.rb +38 -38
- data/samples/colors/_gradients.rb +34 -34
- data/samples/config/config_text_markup.rb +20 -20
- data/samples/config/custom_config.rb +18 -18
- data/samples/data/_csv.rb +33 -33
- data/samples/data/_excel.rb +55 -55
- data/samples/data/_yaml.rb +12 -12
- data/samples/hello_world.rb +6 -6
- data/samples/images/_cairo_access.rb +39 -39
- data/samples/images/_images.rb +104 -104
- data/samples/images/_more_load_images.rb +102 -102
- data/samples/intro/01_hello.rb +8 -8
- data/samples/intro/02_options.rb +14 -14
- data/samples/intro/03_layout.rb +11 -11
- data/samples/intro/04_arrays.rb +15 -15
- data/samples/intro/05_excel.rb +14 -14
- data/samples/layouts/builtin_layouts.rb +97 -97
- data/samples/layouts/layouts.rb +71 -71
- data/samples/project/src/characters.rb +8 -8
- data/samples/project/src/skills.rb +7 -7
- data/samples/proofs/_tgc_proofs.rb +16 -16
- data/samples/ranges/_ranges.rb +64 -64
- data/samples/saves/_hand.rb +23 -23
- data/samples/saves/_portrait_landscape.rb +23 -23
- data/samples/saves/_save_pdf.rb +29 -29
- data/samples/saves/_saves.rb +51 -51
- data/samples/saves/_showcase.rb +25 -25
- data/samples/shapes/_draw_shapes.rb +60 -60
- data/samples/shapes/_proofs.rb +22 -22
- data/samples/sprues/_advanced_sprues.rb +24 -24
- data/samples/sprues/_builtin_sprues.rb +21 -21
- data/samples/sprues/_fold_sheet.rb +27 -27
- data/samples/sprues/_hex_tiles.rb +15 -15
- data/samples/sprues/_mints.rb +11 -11
- data/samples/sprues/_sprue_example.rb +11 -11
- data/samples/text/_embed_text.rb +128 -128
- data/samples/text/_text.rb +47 -47
- data/samples/text/_text_options.rb +102 -102
- data/samples/text/bug134.rb +14 -14
- data/samples/units/_units.rb +32 -32
- data/squib.gemspec +52 -52
- metadata +51 -48
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
module Squib
|
|
2
|
-
class Deck
|
|
3
|
-
|
|
4
|
-
# :nodoc:
|
|
5
|
-
# @api private
|
|
6
|
-
def render_sheet(range, batch, sheet)
|
|
7
|
-
sheet_width = (sheet.columns * (@width + 2 * sheet.gap - 2 * sheet.trim)) + (2 * sheet.margin)
|
|
8
|
-
sheet_height = (sheet.rows * (@height + 2 * sheet.gap - 2 * sheet.trim)) + (2 * sheet.margin)
|
|
9
|
-
cc = Cairo::Context.new(Cairo::ImageSurface.new(sheet_width, sheet_height))
|
|
10
|
-
num_this_sheet = 0
|
|
11
|
-
sheet_num = 0
|
|
12
|
-
y = sheet.margin
|
|
13
|
-
x = sheet.rtl ? (sheet_width - sheet.margin - sheet.gap - @width) : sheet.margin
|
|
14
|
-
@progress_bar.start("Saving PNG sheet to #{batch.summary}", @cards.size + 1) do |bar|
|
|
15
|
-
range.each do |i|
|
|
16
|
-
if num_this_sheet >= (sheet.columns * sheet.rows) # new sheet
|
|
17
|
-
filename = batch.full_filename(sheet_num)
|
|
18
|
-
cc.target.write_to_png(filename)
|
|
19
|
-
new_sheet = false
|
|
20
|
-
num_this_sheet = 0
|
|
21
|
-
sheet_num += 1
|
|
22
|
-
y = sheet.margin
|
|
23
|
-
x = sheet.rtl ? (sheet_width - sheet.margin - sheet.gap - @width) : sheet.margin
|
|
24
|
-
cc = Cairo::Context.new(Cairo::ImageSurface.new(sheet_width, sheet_height))
|
|
25
|
-
end
|
|
26
|
-
surface = trim(@cards[i].cairo_surface, sheet.trim, @width, @height)
|
|
27
|
-
cc.set_source(surface, x, y)
|
|
28
|
-
cc.paint
|
|
29
|
-
num_this_sheet += 1
|
|
30
|
-
x += (surface.width + sheet.gap) * (sheet.rtl ? -1 : 1)
|
|
31
|
-
if num_this_sheet % sheet.columns == 0 # new row
|
|
32
|
-
x = sheet.rtl ? (sheet_width - sheet.margin - sheet.gap - @width) : sheet.margin
|
|
33
|
-
y += surface.height + sheet.gap
|
|
34
|
-
end
|
|
35
|
-
bar.increment
|
|
36
|
-
end
|
|
37
|
-
cc.target.write_to_png(batch.full_filename(sheet_num))
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
# Return a new Cairo::ImageSurface that is trimmed from the original
|
|
42
|
-
#
|
|
43
|
-
# @param surface The surface to trim
|
|
44
|
-
# @param trim The number of pixels around the edge to trim
|
|
45
|
-
# @param width The width of the surface prior to the trim
|
|
46
|
-
# @param height The height of the surface prior to the trim
|
|
47
|
-
# :nodoc:
|
|
48
|
-
# @api private
|
|
49
|
-
def trim(surface, trim, width, height)
|
|
50
|
-
if trim > 0
|
|
51
|
-
tmp = Cairo::ImageSurface.new(width - 2 * trim, height - 2 * trim)
|
|
52
|
-
cc = Cairo::Context.new(tmp)
|
|
53
|
-
cc.set_source(surface, -1 * trim, -1 * trim)
|
|
54
|
-
cc.paint
|
|
55
|
-
surface = tmp
|
|
56
|
-
end
|
|
57
|
-
surface
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
end
|
|
61
|
-
end
|
|
1
|
+
module Squib
|
|
2
|
+
class Deck
|
|
3
|
+
|
|
4
|
+
# :nodoc:
|
|
5
|
+
# @api private
|
|
6
|
+
def render_sheet(range, batch, sheet)
|
|
7
|
+
sheet_width = (sheet.columns * (@width + 2 * sheet.gap - 2 * sheet.trim)) + (2 * sheet.margin)
|
|
8
|
+
sheet_height = (sheet.rows * (@height + 2 * sheet.gap - 2 * sheet.trim)) + (2 * sheet.margin)
|
|
9
|
+
cc = Cairo::Context.new(Cairo::ImageSurface.new(sheet_width, sheet_height))
|
|
10
|
+
num_this_sheet = 0
|
|
11
|
+
sheet_num = 0
|
|
12
|
+
y = sheet.margin
|
|
13
|
+
x = sheet.rtl ? (sheet_width - sheet.margin - sheet.gap - @width) : sheet.margin
|
|
14
|
+
@progress_bar.start("Saving PNG sheet to #{batch.summary}", @cards.size + 1) do |bar|
|
|
15
|
+
range.each do |i|
|
|
16
|
+
if num_this_sheet >= (sheet.columns * sheet.rows) # new sheet
|
|
17
|
+
filename = batch.full_filename(sheet_num)
|
|
18
|
+
cc.target.write_to_png(filename)
|
|
19
|
+
new_sheet = false
|
|
20
|
+
num_this_sheet = 0
|
|
21
|
+
sheet_num += 1
|
|
22
|
+
y = sheet.margin
|
|
23
|
+
x = sheet.rtl ? (sheet_width - sheet.margin - sheet.gap - @width) : sheet.margin
|
|
24
|
+
cc = Cairo::Context.new(Cairo::ImageSurface.new(sheet_width, sheet_height))
|
|
25
|
+
end
|
|
26
|
+
surface = trim(@cards[i].cairo_surface, sheet.trim, @width, @height)
|
|
27
|
+
cc.set_source(surface, x, y)
|
|
28
|
+
cc.paint
|
|
29
|
+
num_this_sheet += 1
|
|
30
|
+
x += (surface.width + sheet.gap) * (sheet.rtl ? -1 : 1)
|
|
31
|
+
if num_this_sheet % sheet.columns == 0 # new row
|
|
32
|
+
x = sheet.rtl ? (sheet_width - sheet.margin - sheet.gap - @width) : sheet.margin
|
|
33
|
+
y += surface.height + sheet.gap
|
|
34
|
+
end
|
|
35
|
+
bar.increment
|
|
36
|
+
end
|
|
37
|
+
cc.target.write_to_png(batch.full_filename(sheet_num))
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Return a new Cairo::ImageSurface that is trimmed from the original
|
|
42
|
+
#
|
|
43
|
+
# @param surface The surface to trim
|
|
44
|
+
# @param trim The number of pixels around the edge to trim
|
|
45
|
+
# @param width The width of the surface prior to the trim
|
|
46
|
+
# @param height The height of the surface prior to the trim
|
|
47
|
+
# :nodoc:
|
|
48
|
+
# @api private
|
|
49
|
+
def trim(surface, trim, width, height)
|
|
50
|
+
if trim > 0
|
|
51
|
+
tmp = Cairo::ImageSurface.new(width - 2 * trim, height - 2 * trim)
|
|
52
|
+
cc = Cairo::Context.new(tmp)
|
|
53
|
+
cc.set_source(surface, -1 * trim, -1 * trim)
|
|
54
|
+
cc.paint
|
|
55
|
+
surface = tmp
|
|
56
|
+
end
|
|
57
|
+
surface
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
module Squib
|
|
2
|
-
class Card
|
|
3
|
-
|
|
4
|
-
# :nodoc:
|
|
5
|
-
# @api private
|
|
6
|
-
def save_png(batch)
|
|
7
|
-
surface = if preprocess_save?(batch)
|
|
8
|
-
w, h = compute_dimensions(batch.rotate, batch.trim)
|
|
9
|
-
preprocessed_save(w, h, batch)
|
|
10
|
-
else
|
|
11
|
-
@cairo_surface
|
|
12
|
-
end
|
|
13
|
-
write_png(surface, index, batch.dir, batch.prefix, batch.count_format)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# :nodoc:
|
|
17
|
-
# @api private
|
|
18
|
-
def preprocess_save?(batch)
|
|
19
|
-
batch.rotate != false || batch.trim > 0
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def compute_dimensions(rotate, trim)
|
|
23
|
-
if rotate
|
|
24
|
-
[ @height - 2 * trim, @width - 2 * trim ]
|
|
25
|
-
else
|
|
26
|
-
[ @width - 2 * trim, @height - 2 * trim ]
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def preprocessed_save(width, height, batch)
|
|
31
|
-
new_cc = Cairo::Context.new(Cairo::ImageSurface.new(width, height))
|
|
32
|
-
trim_radius = batch.trim_radius
|
|
33
|
-
if batch.rotate != false
|
|
34
|
-
new_cc.translate(width * 0.5, height * 0.5)
|
|
35
|
-
new_cc.rotate(batch.angle)
|
|
36
|
-
new_cc.translate(height * -0.5, width * -0.5)
|
|
37
|
-
new_cc.rounded_rectangle(0, 0, height, width, trim_radius, trim_radius)
|
|
38
|
-
else
|
|
39
|
-
new_cc.rounded_rectangle(0, 0, width, height, trim_radius, trim_radius)
|
|
40
|
-
end
|
|
41
|
-
new_cc.clip
|
|
42
|
-
new_cc.set_source(@cairo_surface, -batch.trim, -batch.trim)
|
|
43
|
-
new_cc.paint
|
|
44
|
-
return new_cc.target
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def write_png(surface, i, dir, prefix, count_format)
|
|
48
|
-
surface.write_to_png("#{dir}/#{prefix}#{count_format % i}.png")
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
end
|
|
52
|
-
end
|
|
1
|
+
module Squib
|
|
2
|
+
class Card
|
|
3
|
+
|
|
4
|
+
# :nodoc:
|
|
5
|
+
# @api private
|
|
6
|
+
def save_png(batch)
|
|
7
|
+
surface = if preprocess_save?(batch)
|
|
8
|
+
w, h = compute_dimensions(batch.rotate, batch.trim)
|
|
9
|
+
preprocessed_save(w, h, batch)
|
|
10
|
+
else
|
|
11
|
+
@cairo_surface
|
|
12
|
+
end
|
|
13
|
+
write_png(surface, index, batch.dir, batch.prefix, batch.count_format)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# :nodoc:
|
|
17
|
+
# @api private
|
|
18
|
+
def preprocess_save?(batch)
|
|
19
|
+
batch.rotate != false || batch.trim > 0
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def compute_dimensions(rotate, trim)
|
|
23
|
+
if rotate
|
|
24
|
+
[ @height - 2 * trim, @width - 2 * trim ]
|
|
25
|
+
else
|
|
26
|
+
[ @width - 2 * trim, @height - 2 * trim ]
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def preprocessed_save(width, height, batch)
|
|
31
|
+
new_cc = Cairo::Context.new(Cairo::ImageSurface.new(width, height))
|
|
32
|
+
trim_radius = batch.trim_radius
|
|
33
|
+
if batch.rotate != false
|
|
34
|
+
new_cc.translate(width * 0.5, height * 0.5)
|
|
35
|
+
new_cc.rotate(batch.angle)
|
|
36
|
+
new_cc.translate(height * -0.5, width * -0.5)
|
|
37
|
+
new_cc.rounded_rectangle(0, 0, height, width, trim_radius, trim_radius)
|
|
38
|
+
else
|
|
39
|
+
new_cc.rounded_rectangle(0, 0, width, height, trim_radius, trim_radius)
|
|
40
|
+
end
|
|
41
|
+
new_cc.clip
|
|
42
|
+
new_cc.set_source(@cairo_surface, -batch.trim, -batch.trim)
|
|
43
|
+
new_cc.paint
|
|
44
|
+
return new_cc.target
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def write_png(surface, i, dir, prefix, count_format)
|
|
48
|
+
surface.write_to_png("#{dir}/#{prefix}#{count_format % i}.png")
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -1,90 +1,90 @@
|
|
|
1
|
-
require_relative '../args/sheet'
|
|
2
|
-
|
|
3
|
-
module Squib
|
|
4
|
-
module Graphics
|
|
5
|
-
class SavePDF
|
|
6
|
-
|
|
7
|
-
def initialize(deck)
|
|
8
|
-
@deck = deck
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
# :nodoc:
|
|
12
|
-
# @api private
|
|
13
|
-
def render_pdf(range, sheet)
|
|
14
|
-
cc = init_cc(sheet)
|
|
15
|
-
cc.scale(POINTS_PER_IN / @deck.dpi, POINTS_PER_IN / @deck.dpi) # for bug #62
|
|
16
|
-
card_width = @deck.width - 2 * sheet.trim
|
|
17
|
-
card_height = @deck.height - 2 * sheet.trim
|
|
18
|
-
start_x_pos = sheet.rtl ? sheet.width - sheet.margin - card_width - 2 * sheet.trim : sheet.margin
|
|
19
|
-
x_increment = (card_width + sheet.gap) * (sheet.rtl ? -1 : 1)
|
|
20
|
-
y = sheet.margin
|
|
21
|
-
x = start_x_pos
|
|
22
|
-
track_progress(range, sheet) do |bar|
|
|
23
|
-
range.each do |i|
|
|
24
|
-
card = @deck.cards[i]
|
|
25
|
-
cc.translate(x, y)
|
|
26
|
-
cc.rectangle(sheet.trim, sheet.trim, card_width, card_height)
|
|
27
|
-
cc.clip
|
|
28
|
-
case card.backend.downcase.to_sym
|
|
29
|
-
when :memory
|
|
30
|
-
cc.set_source(card.cairo_surface, 0, 0)
|
|
31
|
-
cc.paint
|
|
32
|
-
when :svg
|
|
33
|
-
card.cairo_surface.finish
|
|
34
|
-
cc.save
|
|
35
|
-
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
|
|
36
|
-
cc.render_rsvg_handle(Rsvg::Handle.new_from_file(card.svgfile))
|
|
37
|
-
cc.restore
|
|
38
|
-
else
|
|
39
|
-
abort "No such back end supported for save_pdf: #{backend}"
|
|
40
|
-
end
|
|
41
|
-
bar.increment
|
|
42
|
-
cc.reset_clip
|
|
43
|
-
cc.translate(-x, -y)
|
|
44
|
-
|
|
45
|
-
draw_crop_marks(cc, x, y, sheet)
|
|
46
|
-
x += x_increment
|
|
47
|
-
if (x > (sheet.width - card_width - sheet.margin)) or (x < sheet.margin)
|
|
48
|
-
x = start_x_pos
|
|
49
|
-
y += card.height + sheet.gap - 2 * sheet.trim
|
|
50
|
-
if y > (sheet.height - card_height - sheet.margin)
|
|
51
|
-
cc.show_page # next page
|
|
52
|
-
y = sheet.margin
|
|
53
|
-
x = start_x_pos
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
cc.target.finish
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
private
|
|
62
|
-
|
|
63
|
-
# Initialize the Cairo Context
|
|
64
|
-
def init_cc(sheet)
|
|
65
|
-
Cairo::Context.new(Cairo::PDFSurface.new(
|
|
66
|
-
"#{sheet.dir}/#{sheet.file}",
|
|
67
|
-
sheet.width * POINTS_PER_IN / @deck.dpi, #PDF thinks in 72 DPI "points"
|
|
68
|
-
sheet.height * POINTS_PER_IN / @deck.dpi)
|
|
69
|
-
)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def track_progress(range, sheet)
|
|
73
|
-
msg = "Saving PDF to #{sheet.full_filename}"
|
|
74
|
-
@deck.progress_bar.start(msg, range.size) { |bar| yield(bar) }
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def draw_crop_marks(cc, x, y, sheet)
|
|
78
|
-
sheet.crop_coords(x, y, @deck.width, @deck.height).each do |coord|
|
|
79
|
-
cc.move_to(coord[:x1], coord[:y1])
|
|
80
|
-
cc.line_to(coord[:x2], coord[:y2])
|
|
81
|
-
cc.set_source_color(sheet.crop_stroke_color)
|
|
82
|
-
cc.set_dash(sheet.crop_stroke_dash)
|
|
83
|
-
cc.set_line_width(sheet.crop_stroke_width)
|
|
84
|
-
cc.stroke
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
end
|
|
1
|
+
require_relative '../args/sheet'
|
|
2
|
+
|
|
3
|
+
module Squib
|
|
4
|
+
module Graphics
|
|
5
|
+
class SavePDF
|
|
6
|
+
|
|
7
|
+
def initialize(deck)
|
|
8
|
+
@deck = deck
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# :nodoc:
|
|
12
|
+
# @api private
|
|
13
|
+
def render_pdf(range, sheet)
|
|
14
|
+
cc = init_cc(sheet)
|
|
15
|
+
cc.scale(POINTS_PER_IN / @deck.dpi, POINTS_PER_IN / @deck.dpi) # for bug #62
|
|
16
|
+
card_width = @deck.width - 2 * sheet.trim
|
|
17
|
+
card_height = @deck.height - 2 * sheet.trim
|
|
18
|
+
start_x_pos = sheet.rtl ? sheet.width - sheet.margin - card_width - 2 * sheet.trim : sheet.margin
|
|
19
|
+
x_increment = (card_width + sheet.gap) * (sheet.rtl ? -1 : 1)
|
|
20
|
+
y = sheet.margin
|
|
21
|
+
x = start_x_pos
|
|
22
|
+
track_progress(range, sheet) do |bar|
|
|
23
|
+
range.each do |i|
|
|
24
|
+
card = @deck.cards[i]
|
|
25
|
+
cc.translate(x, y)
|
|
26
|
+
cc.rectangle(sheet.trim, sheet.trim, card_width, card_height)
|
|
27
|
+
cc.clip
|
|
28
|
+
case card.backend.downcase.to_sym
|
|
29
|
+
when :memory
|
|
30
|
+
cc.set_source(card.cairo_surface, 0, 0)
|
|
31
|
+
cc.paint
|
|
32
|
+
when :svg
|
|
33
|
+
card.cairo_surface.finish
|
|
34
|
+
cc.save
|
|
35
|
+
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
|
|
36
|
+
cc.render_rsvg_handle(Rsvg::Handle.new_from_file(card.svgfile))
|
|
37
|
+
cc.restore
|
|
38
|
+
else
|
|
39
|
+
abort "No such back end supported for save_pdf: #{backend}"
|
|
40
|
+
end
|
|
41
|
+
bar.increment
|
|
42
|
+
cc.reset_clip
|
|
43
|
+
cc.translate(-x, -y)
|
|
44
|
+
|
|
45
|
+
draw_crop_marks(cc, x, y, sheet)
|
|
46
|
+
x += x_increment
|
|
47
|
+
if (x > (sheet.width - card_width - sheet.margin)) or (x < sheet.margin)
|
|
48
|
+
x = start_x_pos
|
|
49
|
+
y += card.height + sheet.gap - 2 * sheet.trim
|
|
50
|
+
if y > (sheet.height - card_height - sheet.margin)
|
|
51
|
+
cc.show_page # next page
|
|
52
|
+
y = sheet.margin
|
|
53
|
+
x = start_x_pos
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
cc.target.finish
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
# Initialize the Cairo Context
|
|
64
|
+
def init_cc(sheet)
|
|
65
|
+
Cairo::Context.new(Cairo::PDFSurface.new(
|
|
66
|
+
"#{sheet.dir}/#{sheet.file}",
|
|
67
|
+
sheet.width * POINTS_PER_IN / @deck.dpi, #PDF thinks in 72 DPI "points"
|
|
68
|
+
sheet.height * POINTS_PER_IN / @deck.dpi)
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def track_progress(range, sheet)
|
|
73
|
+
msg = "Saving PDF to #{sheet.full_filename}"
|
|
74
|
+
@deck.progress_bar.start(msg, range.size) { |bar| yield(bar) }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def draw_crop_marks(cc, x, y, sheet)
|
|
78
|
+
sheet.crop_coords(x, y, @deck.width, @deck.height).each do |coord|
|
|
79
|
+
cc.move_to(coord[:x1], coord[:y1])
|
|
80
|
+
cc.line_to(coord[:x2], coord[:y2])
|
|
81
|
+
cc.set_source_color(sheet.crop_stroke_color)
|
|
82
|
+
cc.set_dash(sheet.crop_stroke_dash)
|
|
83
|
+
cc.set_line_width(sheet.crop_stroke_width)
|
|
84
|
+
cc.stroke
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -1,204 +1,204 @@
|
|
|
1
|
-
module Squib
|
|
2
|
-
module Graphics
|
|
3
|
-
# Helper class to generate templated sheet.
|
|
4
|
-
class SaveSprue
|
|
5
|
-
def initialize(deck, tmpl, sheet_args)
|
|
6
|
-
@deck = deck
|
|
7
|
-
@tmpl = tmpl
|
|
8
|
-
@page_number = 1
|
|
9
|
-
@sheet_args = sheet_args # might be Args::Sheet or Args::SaveBatch
|
|
10
|
-
@overlay_lines = @tmpl.crop_lines.select do |line|
|
|
11
|
-
line['overlay_on_cards']
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def render_sheet(range)
|
|
16
|
-
cc = init_cc
|
|
17
|
-
cc.set_source_color(:white) # white backdrop TODO make option
|
|
18
|
-
cc.paint
|
|
19
|
-
slots = @tmpl.cards
|
|
20
|
-
per_sheet = slots.size
|
|
21
|
-
check_oversized_card
|
|
22
|
-
|
|
23
|
-
draw_overlay_below_cards cc if range.size
|
|
24
|
-
|
|
25
|
-
track_progress(range) do |bar|
|
|
26
|
-
range.each do |i|
|
|
27
|
-
cc = next_page_if_needed(cc, i, per_sheet)
|
|
28
|
-
|
|
29
|
-
card = @deck.cards[i]
|
|
30
|
-
slot = slots[i % per_sheet]
|
|
31
|
-
|
|
32
|
-
draw_card cc, card,
|
|
33
|
-
slot['x'], slot['y'],
|
|
34
|
-
slot['rotate'],
|
|
35
|
-
@sheet_args.trim, @sheet_args.trim_radius
|
|
36
|
-
|
|
37
|
-
bar.increment
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
draw_overlay_above_cards cc
|
|
41
|
-
cc.target.finish
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
protected
|
|
46
|
-
|
|
47
|
-
# Initialize the Cairo Context
|
|
48
|
-
def init_cc
|
|
49
|
-
raise NotImplementedError
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def draw_page(cc)
|
|
53
|
-
raise NotImplementedError
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def full_filename
|
|
57
|
-
raise NotImplementedError
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
private
|
|
61
|
-
|
|
62
|
-
def next_page_if_needed(cc, i, per_sheet)
|
|
63
|
-
return cc unless (i != 0) && (i % per_sheet) == 0
|
|
64
|
-
|
|
65
|
-
draw_overlay_above_cards cc
|
|
66
|
-
cc = draw_page cc
|
|
67
|
-
draw_overlay_below_cards cc
|
|
68
|
-
@page_number += 1
|
|
69
|
-
cc
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def track_progress(range)
|
|
73
|
-
msg = "Saving templated sheet to #{full_filename}"
|
|
74
|
-
@deck.progress_bar.start(msg, range.size) { |bar| yield(bar) }
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def draw_overlay_below_cards(cc)
|
|
78
|
-
if @tmpl.crop_line_overlay == :on_margin
|
|
79
|
-
add_margin_overlay_clip_mask cc
|
|
80
|
-
cc.clip
|
|
81
|
-
draw_crop_line cc, @tmpl.crop_lines
|
|
82
|
-
cc.reset_clip
|
|
83
|
-
elsif @tmpl.crop_line_overlay == :beneath_cards
|
|
84
|
-
draw_crop_line cc, @tmpl.crop_lines
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def draw_overlay_above_cards(cc)
|
|
89
|
-
if @tmpl.crop_line_overlay == :overlay_on_cards
|
|
90
|
-
draw_crop_line cc, @tmpl.crop_lines
|
|
91
|
-
else
|
|
92
|
-
draw_crop_line cc, @overlay_lines
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def add_margin_overlay_clip_mask(cc)
|
|
97
|
-
margin = @tmpl.margin
|
|
98
|
-
cc.new_path
|
|
99
|
-
cc.rectangle(
|
|
100
|
-
margin[:left], margin[:top],
|
|
101
|
-
margin[:right] - margin[:left],
|
|
102
|
-
margin[:bottom] - margin[:top]
|
|
103
|
-
)
|
|
104
|
-
cc.new_sub_path
|
|
105
|
-
cc.move_to @tmpl.sheet_width, 0
|
|
106
|
-
cc.line_to 0, 0
|
|
107
|
-
cc.line_to 0, @tmpl.sheet_height
|
|
108
|
-
cc.line_to @tmpl.sheet_width, @tmpl.sheet_height
|
|
109
|
-
cc.close_path
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def draw_crop_line(cc, crop_lines)
|
|
113
|
-
crop_lines.each do |line|
|
|
114
|
-
cc.move_to line['line'].x1, line['line'].y1
|
|
115
|
-
cc.line_to line['line'].x2, line['line'].y2
|
|
116
|
-
cc.set_source_color line['color']
|
|
117
|
-
cc.set_line_width line['width']
|
|
118
|
-
cc.set_dash(line['style'].pattern) if line['style'].pattern
|
|
119
|
-
cc.stroke
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def check_oversized_card
|
|
124
|
-
Squib.logger.warn {
|
|
125
|
-
"Card size is larger than sprue's expected card size "\
|
|
126
|
-
"of #{@tmpl.card_width}x#{@tmpl.card_height}. Cards may overlap."
|
|
127
|
-
} if (@deck.width - 2.0 * @sheet_args.trim) > @tmpl.card_width ||
|
|
128
|
-
(@deck.height - 2.0 * @sheet_args.trim) > @tmpl.card_height
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def draw_card(cc, card, x, y, angle, trim, trim_radius)
|
|
132
|
-
# Compute the true size of the card after trimming
|
|
133
|
-
w = @deck.width - 2.0 * trim
|
|
134
|
-
h = @deck.height - 2.0 * trim
|
|
135
|
-
|
|
136
|
-
# Normalize the angles first
|
|
137
|
-
# TODO do this in the args class
|
|
138
|
-
angle = angle % (2 * Math::PI)
|
|
139
|
-
angle = 2 * Math::PI - angle if angle < 0
|
|
140
|
-
|
|
141
|
-
# Perform the actual rotation and drawing
|
|
142
|
-
mat = cc.matrix # Save the transformation matrix to revert later
|
|
143
|
-
cc.translate x, y
|
|
144
|
-
cc.translate @deck.width / 2.0, @deck.height / 2.0
|
|
145
|
-
cc.rotate angle
|
|
146
|
-
cc.translate -@deck.width / 2.0, -@deck.height / 2.0
|
|
147
|
-
cc.rounded_rectangle(trim, trim, w, h, trim_radius, trim_radius) # clip
|
|
148
|
-
cc.clip
|
|
149
|
-
cc.set_source card.cairo_surface, 0, 0
|
|
150
|
-
cc.matrix = mat
|
|
151
|
-
cc.paint
|
|
152
|
-
cc.reset_clip
|
|
153
|
-
end
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
# Templated sheet renderer in PDF format.
|
|
157
|
-
class SaveSpruePDF < SaveSprue
|
|
158
|
-
def init_cc
|
|
159
|
-
ratio = 72.0 / @deck.dpi
|
|
160
|
-
|
|
161
|
-
surface = Cairo::PDFSurface.new(
|
|
162
|
-
full_filename,
|
|
163
|
-
@tmpl.sheet_width * ratio,
|
|
164
|
-
@tmpl.sheet_height * ratio
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
cc = Cairo::Context.new(surface)
|
|
168
|
-
cc.scale(72.0 / @deck.dpi, 72.0 / @deck.dpi) # make it like pixels
|
|
169
|
-
cc
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
def draw_page(cc)
|
|
173
|
-
cc.show_page
|
|
174
|
-
cc.set_source_color(:white) # white backdrop TODO make option
|
|
175
|
-
cc.paint
|
|
176
|
-
cc
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
def full_filename
|
|
180
|
-
@sheet_args.full_filename
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
# Templated sheet renderer in PNG format.
|
|
185
|
-
class SaveSpruePNG < SaveSprue
|
|
186
|
-
def init_cc
|
|
187
|
-
surface = Cairo::ImageSurface.new @tmpl.sheet_width, @tmpl.sheet_height
|
|
188
|
-
Cairo::Context.new(surface)
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
def draw_page(cc)
|
|
192
|
-
cc.target.write_to_png(full_filename)
|
|
193
|
-
init_cc
|
|
194
|
-
cc.set_source_color(:white) # white backdrop TODO make option
|
|
195
|
-
cc.paint
|
|
196
|
-
cc
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
def full_filename
|
|
200
|
-
@sheet_args.full_filename @page_number
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
end
|
|
204
|
-
end
|
|
1
|
+
module Squib
|
|
2
|
+
module Graphics
|
|
3
|
+
# Helper class to generate templated sheet.
|
|
4
|
+
class SaveSprue
|
|
5
|
+
def initialize(deck, tmpl, sheet_args)
|
|
6
|
+
@deck = deck
|
|
7
|
+
@tmpl = tmpl
|
|
8
|
+
@page_number = 1
|
|
9
|
+
@sheet_args = sheet_args # might be Args::Sheet or Args::SaveBatch
|
|
10
|
+
@overlay_lines = @tmpl.crop_lines.select do |line|
|
|
11
|
+
line['overlay_on_cards']
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def render_sheet(range)
|
|
16
|
+
cc = init_cc
|
|
17
|
+
cc.set_source_color(:white) # white backdrop TODO make option
|
|
18
|
+
cc.paint
|
|
19
|
+
slots = @tmpl.cards
|
|
20
|
+
per_sheet = slots.size
|
|
21
|
+
check_oversized_card
|
|
22
|
+
|
|
23
|
+
draw_overlay_below_cards cc if range.size
|
|
24
|
+
|
|
25
|
+
track_progress(range) do |bar|
|
|
26
|
+
range.each do |i|
|
|
27
|
+
cc = next_page_if_needed(cc, i, per_sheet)
|
|
28
|
+
|
|
29
|
+
card = @deck.cards[i]
|
|
30
|
+
slot = slots[i % per_sheet]
|
|
31
|
+
|
|
32
|
+
draw_card cc, card,
|
|
33
|
+
slot['x'], slot['y'],
|
|
34
|
+
slot['rotate'],
|
|
35
|
+
@sheet_args.trim, @sheet_args.trim_radius
|
|
36
|
+
|
|
37
|
+
bar.increment
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
draw_overlay_above_cards cc
|
|
41
|
+
cc.target.finish
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
protected
|
|
46
|
+
|
|
47
|
+
# Initialize the Cairo Context
|
|
48
|
+
def init_cc
|
|
49
|
+
raise NotImplementedError
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def draw_page(cc)
|
|
53
|
+
raise NotImplementedError
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def full_filename
|
|
57
|
+
raise NotImplementedError
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def next_page_if_needed(cc, i, per_sheet)
|
|
63
|
+
return cc unless (i != 0) && (i % per_sheet) == 0
|
|
64
|
+
|
|
65
|
+
draw_overlay_above_cards cc
|
|
66
|
+
cc = draw_page cc
|
|
67
|
+
draw_overlay_below_cards cc
|
|
68
|
+
@page_number += 1
|
|
69
|
+
cc
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def track_progress(range)
|
|
73
|
+
msg = "Saving templated sheet to #{full_filename}"
|
|
74
|
+
@deck.progress_bar.start(msg, range.size) { |bar| yield(bar) }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def draw_overlay_below_cards(cc)
|
|
78
|
+
if @tmpl.crop_line_overlay == :on_margin
|
|
79
|
+
add_margin_overlay_clip_mask cc
|
|
80
|
+
cc.clip
|
|
81
|
+
draw_crop_line cc, @tmpl.crop_lines
|
|
82
|
+
cc.reset_clip
|
|
83
|
+
elsif @tmpl.crop_line_overlay == :beneath_cards
|
|
84
|
+
draw_crop_line cc, @tmpl.crop_lines
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def draw_overlay_above_cards(cc)
|
|
89
|
+
if @tmpl.crop_line_overlay == :overlay_on_cards
|
|
90
|
+
draw_crop_line cc, @tmpl.crop_lines
|
|
91
|
+
else
|
|
92
|
+
draw_crop_line cc, @overlay_lines
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def add_margin_overlay_clip_mask(cc)
|
|
97
|
+
margin = @tmpl.margin
|
|
98
|
+
cc.new_path
|
|
99
|
+
cc.rectangle(
|
|
100
|
+
margin[:left], margin[:top],
|
|
101
|
+
margin[:right] - margin[:left],
|
|
102
|
+
margin[:bottom] - margin[:top]
|
|
103
|
+
)
|
|
104
|
+
cc.new_sub_path
|
|
105
|
+
cc.move_to @tmpl.sheet_width, 0
|
|
106
|
+
cc.line_to 0, 0
|
|
107
|
+
cc.line_to 0, @tmpl.sheet_height
|
|
108
|
+
cc.line_to @tmpl.sheet_width, @tmpl.sheet_height
|
|
109
|
+
cc.close_path
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def draw_crop_line(cc, crop_lines)
|
|
113
|
+
crop_lines.each do |line|
|
|
114
|
+
cc.move_to line['line'].x1, line['line'].y1
|
|
115
|
+
cc.line_to line['line'].x2, line['line'].y2
|
|
116
|
+
cc.set_source_color line['color']
|
|
117
|
+
cc.set_line_width line['width']
|
|
118
|
+
cc.set_dash(line['style'].pattern) if line['style'].pattern
|
|
119
|
+
cc.stroke
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def check_oversized_card
|
|
124
|
+
Squib.logger.warn {
|
|
125
|
+
"Card size is larger than sprue's expected card size "\
|
|
126
|
+
"of #{@tmpl.card_width}x#{@tmpl.card_height}. Cards may overlap."
|
|
127
|
+
} if (@deck.width - 2.0 * @sheet_args.trim) > @tmpl.card_width ||
|
|
128
|
+
(@deck.height - 2.0 * @sheet_args.trim) > @tmpl.card_height
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def draw_card(cc, card, x, y, angle, trim, trim_radius)
|
|
132
|
+
# Compute the true size of the card after trimming
|
|
133
|
+
w = @deck.width - 2.0 * trim
|
|
134
|
+
h = @deck.height - 2.0 * trim
|
|
135
|
+
|
|
136
|
+
# Normalize the angles first
|
|
137
|
+
# TODO do this in the args class
|
|
138
|
+
angle = angle % (2 * Math::PI)
|
|
139
|
+
angle = 2 * Math::PI - angle if angle < 0
|
|
140
|
+
|
|
141
|
+
# Perform the actual rotation and drawing
|
|
142
|
+
mat = cc.matrix # Save the transformation matrix to revert later
|
|
143
|
+
cc.translate x, y
|
|
144
|
+
cc.translate @deck.width / 2.0, @deck.height / 2.0
|
|
145
|
+
cc.rotate angle
|
|
146
|
+
cc.translate -@deck.width / 2.0, -@deck.height / 2.0
|
|
147
|
+
cc.rounded_rectangle(trim, trim, w, h, trim_radius, trim_radius) # clip
|
|
148
|
+
cc.clip
|
|
149
|
+
cc.set_source card.cairo_surface, 0, 0
|
|
150
|
+
cc.matrix = mat
|
|
151
|
+
cc.paint
|
|
152
|
+
cc.reset_clip
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Templated sheet renderer in PDF format.
|
|
157
|
+
class SaveSpruePDF < SaveSprue
|
|
158
|
+
def init_cc
|
|
159
|
+
ratio = 72.0 / @deck.dpi
|
|
160
|
+
|
|
161
|
+
surface = Cairo::PDFSurface.new(
|
|
162
|
+
full_filename,
|
|
163
|
+
@tmpl.sheet_width * ratio,
|
|
164
|
+
@tmpl.sheet_height * ratio
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
cc = Cairo::Context.new(surface)
|
|
168
|
+
cc.scale(72.0 / @deck.dpi, 72.0 / @deck.dpi) # make it like pixels
|
|
169
|
+
cc
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def draw_page(cc)
|
|
173
|
+
cc.show_page
|
|
174
|
+
cc.set_source_color(:white) # white backdrop TODO make option
|
|
175
|
+
cc.paint
|
|
176
|
+
cc
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def full_filename
|
|
180
|
+
@sheet_args.full_filename
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Templated sheet renderer in PNG format.
|
|
185
|
+
class SaveSpruePNG < SaveSprue
|
|
186
|
+
def init_cc
|
|
187
|
+
surface = Cairo::ImageSurface.new @tmpl.sheet_width, @tmpl.sheet_height
|
|
188
|
+
Cairo::Context.new(surface)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def draw_page(cc)
|
|
192
|
+
cc.target.write_to_png(full_filename)
|
|
193
|
+
init_cc
|
|
194
|
+
cc.set_source_color(:white) # white backdrop TODO make option
|
|
195
|
+
cc.paint
|
|
196
|
+
cc
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def full_filename
|
|
200
|
+
@sheet_args.full_filename @page_number
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|