squib 0.6.0 → 0.7.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.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +162 -133
  3. data/Gemfile +4 -4
  4. data/README.md +630 -550
  5. data/RELEASE TODO.md +18 -18
  6. data/Rakefile +99 -99
  7. data/lib/squib.rb +32 -32
  8. data/lib/squib/api/background.rb +20 -19
  9. data/lib/squib/api/data.rb +100 -99
  10. data/lib/squib/api/image.rb +90 -76
  11. data/lib/squib/api/save.rb +149 -103
  12. data/lib/squib/api/settings.rb +35 -37
  13. data/lib/squib/api/shapes.rb +230 -228
  14. data/lib/squib/api/text.rb +65 -66
  15. data/lib/squib/api/text_embed.rb +96 -66
  16. data/lib/squib/args/arg_loader.rb +138 -0
  17. data/lib/squib/args/box.rb +55 -0
  18. data/lib/squib/args/card_range.rb +32 -0
  19. data/lib/squib/args/color_validator.rb +12 -0
  20. data/lib/squib/args/coords.rb +33 -0
  21. data/lib/squib/args/dir_validator.rb +16 -0
  22. data/lib/squib/args/draw.rb +92 -0
  23. data/lib/squib/args/embed_adjust.rb +25 -0
  24. data/lib/squib/args/embed_key.rb +17 -0
  25. data/lib/squib/args/hand_special.rb +37 -0
  26. data/lib/squib/args/input_file.rb +37 -0
  27. data/lib/squib/args/paint.rb +44 -0
  28. data/lib/squib/args/paragraph.rb +115 -0
  29. data/lib/squib/args/save_batch.rb +60 -0
  30. data/lib/squib/args/scale_box.rb +53 -0
  31. data/lib/squib/args/sheet.rb +72 -0
  32. data/lib/squib/args/showcase_special.rb +38 -0
  33. data/lib/squib/args/svg_special.rb +37 -0
  34. data/lib/squib/args/transform.rb +25 -0
  35. data/lib/squib/args/typographer.rb +117 -117
  36. data/lib/squib/card.rb +67 -67
  37. data/lib/squib/conf.rb +117 -111
  38. data/lib/squib/constants.rb +178 -178
  39. data/lib/squib/deck.rb +113 -111
  40. data/lib/squib/graphics/cairo_context_wrapper.rb +99 -53
  41. data/lib/squib/graphics/gradient_regex.rb +46 -46
  42. data/lib/squib/graphics/hand.rb +42 -43
  43. data/lib/squib/graphics/image.rb +76 -73
  44. data/lib/squib/graphics/save_doc.rb +103 -137
  45. data/lib/squib/graphics/save_images.rb +33 -33
  46. data/lib/squib/graphics/shapes.rb +119 -152
  47. data/lib/squib/graphics/showcase.rb +85 -88
  48. data/lib/squib/graphics/text.rb +176 -216
  49. data/lib/squib/layout_parser.rb +91 -89
  50. data/lib/squib/layouts/economy.yml +85 -0
  51. data/lib/squib/layouts/fantasy.yml +101 -0
  52. data/lib/squib/layouts/hand.yml +62 -46
  53. data/lib/squib/layouts/playing-card.yml +35 -18
  54. data/lib/squib/project_template/config.yml +45 -40
  55. data/lib/squib/version.rb +10 -10
  56. data/samples/color_shortcuts.rb +6 -0
  57. data/samples/csv_import.rb +18 -18
  58. data/samples/custom-config.yml +5 -5
  59. data/samples/custom_config.rb +18 -18
  60. data/samples/draw_shapes.rb +45 -35
  61. data/samples/embed_text.rb +88 -90
  62. data/samples/hand.rb +24 -24
  63. data/samples/layouts.rb +62 -61
  64. data/samples/layouts_builtin.rb +51 -0
  65. data/samples/load_images.rb +78 -64
  66. data/samples/ranges.rb +64 -53
  67. data/samples/sample.csv +2 -2
  68. data/samples/text_options.rb +102 -94
  69. data/spec/api/api_data_spec.rb +57 -50
  70. data/spec/api/api_settings_spec.rb +37 -17
  71. data/spec/args/box_spec.rb +127 -0
  72. data/spec/args/draw_spec.rb +95 -0
  73. data/spec/args/embed_key_spec.rb +13 -0
  74. data/spec/args/input_file_spec.rb +21 -0
  75. data/spec/args/paint_spec.rb +22 -0
  76. data/spec/args/paragraph_spec.rb +153 -0
  77. data/spec/args/range_spec.rb +36 -0
  78. data/spec/args/save_batch_spec.rb +51 -0
  79. data/spec/args/scale_box_spec.rb +71 -0
  80. data/spec/args/sheet_spec.rb +58 -0
  81. data/spec/args/showcase_special_spec.rb +15 -0
  82. data/spec/data/samples/autoscale_font.rb.txt +84 -87
  83. data/spec/data/samples/basic.rb.txt +209 -203
  84. data/spec/data/samples/cairo_access.rb.txt +2 -2
  85. data/spec/data/samples/config_text_markup.rb.txt +72 -75
  86. data/spec/data/samples/csv_import.rb.txt +76 -80
  87. data/spec/data/samples/custom_config.rb.txt +48 -49
  88. data/spec/data/samples/draw_shapes.rb.txt +100 -42
  89. data/spec/data/samples/embed_text.rb.txt +283 -295
  90. data/spec/data/samples/excel.rb.txt +162 -171
  91. data/spec/data/samples/gradients.rb.txt +79 -67
  92. data/spec/data/samples/hand.rb.txt +538 -514
  93. data/spec/data/samples/hello_world.rb.txt +36 -38
  94. data/spec/data/samples/load_images.rb.txt +41 -5
  95. data/spec/data/samples/portrait-landscape.rb.txt +49 -51
  96. data/spec/data/samples/ranges.rb.txt +460 -429
  97. data/spec/data/samples/saves.rb.txt +801 -785
  98. data/spec/data/samples/showcase.rb.txt +5910 -5906
  99. data/spec/data/samples/text_options.rb.txt +1125 -981
  100. data/spec/data/samples/tgc_proofs.rb.txt +81 -79
  101. data/spec/data/samples/units.rb.txt +18 -12
  102. data/spec/data/xlsx/with_macros.xlsm +0 -0
  103. data/spec/graphics/cairo_context_wrapper_spec.rb +84 -75
  104. data/spec/graphics/graphics_images_spec.rb +94 -85
  105. data/spec/graphics/graphics_save_doc_spec.rb +67 -65
  106. data/spec/samples/expected/hand.png +0 -0
  107. data/spec/samples/expected/hand_pretty.png +0 -0
  108. data/spec/samples/expected/layout_00.png +0 -0
  109. data/spec/samples/expected/load_images_00.png +0 -0
  110. data/spec/samples/expected/ranges_00.png +0 -0
  111. data/spec/samples/expected/shape_00.png +0 -0
  112. data/spec/samples/expected/showcase.png +0 -0
  113. data/spec/samples/expected/showcase2.png +0 -0
  114. data/spec/samples/expected/showcase_individual_00.png +0 -0
  115. data/spec/samples/expected/showcase_individual_01.png +0 -0
  116. data/spec/samples/expected/showcase_individual_02.png +0 -0
  117. data/spec/samples/expected/showcase_individual_03.png +0 -0
  118. data/spec/samples/expected/text_00.png +0 -0
  119. data/spec/samples/expected/text_01.png +0 -0
  120. data/spec/samples/expected/text_02.png +0 -0
  121. data/spec/samples/samples_regression_spec.rb +82 -82
  122. data/spec/spec_helper.rb +3 -2
  123. data/squib.gemspec +48 -48
  124. data/squib.sublime-project +42 -36
  125. metadata +61 -33
  126. data/lib/squib/input_helpers.rb +0 -238
  127. data/spec/api/api_image_spec.rb +0 -38
  128. data/spec/api/api_text_spec.rb +0 -37
  129. data/spec/graphics/graphics_shapes_spec.rb +0 -85
  130. data/spec/graphics/graphics_text_spec.rb +0 -164
  131. data/spec/input_helpers_spec.rb +0 -238
  132. data/spec/samples/expected/embed_multi_00.png +0 -0
  133. data/spec/samples/expected/embed_multi_01.png +0 -0
  134. data/spec/samples/expected/embed_multi_02.png +0 -0
  135. data/spec/samples/expected/ranges_01.png +0 -0
  136. data/spec/samples/expected/ranges_02.png +0 -0
@@ -1,43 +1,42 @@
1
- require 'squib/graphics/cairo_context_wrapper'
2
-
3
- module Squib
4
- class Deck
5
-
6
- # Draw cards in a fan.
7
- # @api private
8
- def render_hand(range, radius, angle_range, trim, trim_radius, margin,
9
- fill_color, dir, file)
10
- cards = range.collect { |i| @cards[i] }
11
- center_x = width / 2.0
12
- center_y = radius + height
13
- out_size = 3.0 * center_y
14
- angle_delta = (angle_range.last - angle_range.first) / cards.size
15
- cxt = Cairo::Context.new(Cairo::RecordingSurface.new(0, 0, out_size, out_size))
16
- cxt.translate(out_size / 2.0, out_size / 2.0)
17
- cxt.rotate(angle_range.first)
18
- cxt.translate(-width, -width)
19
- cards.each_with_index do |card, i|
20
- cxt.translate(center_x, center_y)
21
- cxt.rotate(angle_delta)
22
- cxt.translate(-center_x, -center_y)
23
- card.use_cairo do |card_cxt|
24
- cxt.rounded_rectangle(trim, trim,
25
- width - (2 * trim), height - (2 * trim),
26
- trim_radius, trim_radius)
27
- cxt.clip
28
- cxt.set_source(card_cxt.target)
29
- cxt.paint
30
- cxt.reset_clip
31
- end
32
- end
33
- x, y, w, h = cxt.target.ink_extents # I love Ruby assignment ;)
34
- png_cxt = Squib::Graphics::CairoContextWrapper.new(Cairo::Context.new(Cairo::ImageSurface.new(w + 2*margin, h + 2*margin)))
35
- png_cxt.set_source_squibcolor(fill_color)
36
- png_cxt.paint
37
- png_cxt.translate(-x + margin, -y + margin)
38
- png_cxt.set_source(cxt.target)
39
- png_cxt.paint
40
- png_cxt.target.write_to_png("#{dir}/#{file}")
41
- end
42
- end
43
- end
1
+ require 'squib/graphics/cairo_context_wrapper'
2
+
3
+ module Squib
4
+ class Deck
5
+
6
+ # Draw cards in a fan.
7
+ # @api private
8
+ def render_hand(range, sheet, hand)
9
+ cards = range.collect { |i| @cards[i] }
10
+ center_x = width / 2.0
11
+ center_y = hand.radius + height
12
+ out_size = 3.0 * center_y
13
+ angle_delta = (hand.angle_range.last - hand.angle_range.first) / cards.size
14
+ cxt = Cairo::Context.new(Cairo::RecordingSurface.new(0, 0, out_size, out_size))
15
+ cxt.translate(out_size / 2.0, out_size / 2.0)
16
+ cxt.rotate(hand.angle_range.first)
17
+ cxt.translate(-width, -width)
18
+ cards.each_with_index do |card, i|
19
+ cxt.translate(center_x, center_y)
20
+ cxt.rotate(angle_delta)
21
+ cxt.translate(-center_x, -center_y)
22
+ card.use_cairo do |card_cxt|
23
+ cxt.rounded_rectangle(sheet.trim, sheet.trim,
24
+ width - (2 * sheet.trim), height - (2 * sheet.trim),
25
+ sheet.trim_radius, sheet.trim_radius)
26
+ cxt.clip
27
+ cxt.set_source(card_cxt.target)
28
+ cxt.paint
29
+ cxt.reset_clip
30
+ end
31
+ end
32
+ x, y, w, h = cxt.target.ink_extents # I love Ruby assignment ;)
33
+ png_cxt = Squib::Graphics::CairoContextWrapper.new(Cairo::Context.new(Cairo::ImageSurface.new(w + 2*sheet.margin, h + 2*sheet.margin)))
34
+ png_cxt.set_source_squibcolor(sheet.fill_color)
35
+ png_cxt.paint
36
+ png_cxt.translate(-x + sheet.margin, -y + sheet.margin)
37
+ png_cxt.set_source(cxt.target)
38
+ png_cxt.paint
39
+ png_cxt.target.write_to_png sheet.full_filename
40
+ end
41
+ end
42
+ end
@@ -1,73 +1,76 @@
1
- module Squib
2
-
3
- # Cache all pngs we've already loaded
4
- #
5
- # :nodoc:
6
- # @api private
7
- def cache_load_image(file)
8
- @img_cache ||= {}
9
- @img_cache[file] || @img_cache[file] = Cairo::ImageSurface.from_png(file)
10
- end
11
- module_function :cache_load_image
12
-
13
- class Card
14
-
15
- # :nodoc:
16
- # @api private
17
- def png(file, x, y, width, height, alpha, blend, angle, mask)
18
- Squib.logger.debug {"Rendering: #{file} @#{x},#{y} #{width}x#{height}, alpha: #{alpha}, blend: #{blend}, angle: #{angle}, mask: #{mask}"}
19
- return if file.nil? or file.eql? ''
20
- png = Squib.cache_load_image(file)
21
- use_cairo do |cc|
22
- cc.translate(x, y)
23
- if width != :native || height != :native
24
- width == :native && width = png.width.to_f
25
- height == :native && height = png.height.to_f
26
- Squib.logger.warn "PNG scaling results in antialiasing."
27
- cc.scale(width.to_f / png.width.to_f, height.to_f / png.height.to_f)
28
- end
29
- cc.rotate(angle)
30
- cc.translate(-x, -y)
31
- cc.set_source(png, x, y)
32
- cc.operator = blend unless blend == :none
33
- if mask.nil?
34
- cc.paint(alpha)
35
- else
36
- cc.set_source_squibcolor(mask)
37
- cc.mask(png, x, y)
38
- end
39
- end
40
- end
41
-
42
- # :nodoc:
43
- # @api private
44
- def svg(file, data, id, x, y, width, height, alpha, blend, angle, mask)
45
- Squib.logger.debug {"Rendering: #{file}, id: #{id} @#{x},#{y} #{width}x#{height}, alpha: #{alpha}, blend: #{blend}, angle: #{angle}, mask: #{mask}"}
46
- Squib.logger.warn 'Both an SVG file and SVG data were specified' unless file.to_s.empty? or data.to_s.empty?
47
- return if (file.nil? or file.eql? '') and data.nil? # nothing specified
48
- data = File.read(file) if data.to_s.empty?
49
- svg = RSVG::Handle.new_from_data(data)
50
- width = svg.width if width == :native
51
- height = svg.height if height == :native
52
- scale_width = width.to_f / svg.width.to_f
53
- scale_height = height.to_f / svg.height.to_f
54
- use_cairo do |cc|
55
- cc.translate(x, y)
56
- cc.rotate(angle)
57
- cc.scale(scale_width, scale_height)
58
- cc.operator = blend unless blend == :none
59
- #FIXME Alpha is no longer used since we are not using cc.paint anymore
60
- if mask.nil?
61
- cc.render_rsvg_handle(svg, id)
62
- else
63
- tmp = Cairo::ImageSurface.new(width / scale_width, height / scale_height)
64
- tmp_cc = Cairo::Context.new(tmp)
65
- tmp_cc.render_rsvg_handle(svg, id)
66
- cc.set_source_squibcolor(mask)
67
- cc.mask(tmp, 0, 0)
68
- end
69
- end
70
- end
71
-
72
- end
73
- end
1
+ module Squib
2
+
3
+ # Cache all pngs we've already loaded
4
+ #
5
+ # :nodoc:
6
+ # @api private
7
+ def cache_load_image(file)
8
+ @img_cache ||= {}
9
+ @img_cache[file] || @img_cache[file] = Cairo::ImageSurface.from_png(file)
10
+ end
11
+ module_function :cache_load_image
12
+
13
+ class Card
14
+
15
+ # :nodoc:
16
+ # @api private
17
+ def png(file, box, paint, trans)
18
+ Squib.logger.debug {"RENDERING PNG: \n file: #{file}\n box: #{box}\n paint: #{paint}\n trans: #{trans}"}
19
+ return if file.nil? or file.eql? ''
20
+ png = Squib.cache_load_image(file)
21
+ use_cairo do |cc|
22
+ cc.translate(box.x, box.y)
23
+ if box.width != :native || box.height != :native
24
+ box.width = png.width.to_f if box.width == :native
25
+ box.height = png.height.to_f if box.height == :native
26
+ box.width = png.width.to_f * box.height.to_f / png.height.to_f if box.width == :scale
27
+ box.height = png.height.to_f * box.width.to_f / png.width.to_f if box.height == :scale
28
+ Squib.logger.warn "PNG scaling results in aliasing."
29
+ cc.scale(box.width.to_f / png.width.to_f, box.height.to_f / png.height.to_f)
30
+ end
31
+ cc.rotate(trans.angle)
32
+ cc.translate(-box.x, -box.y)
33
+ cc.set_source(png, box.x, box.y)
34
+ cc.operator = paint.blend unless paint.blend == :none
35
+ if paint.mask.empty?
36
+ cc.paint(paint.alpha)
37
+ else
38
+ cc.set_source_squibcolor(paint.mask)
39
+ cc.mask(png, box.x, box.y)
40
+ end
41
+ end
42
+ end
43
+
44
+ # :nodoc:
45
+ # @api private
46
+ def svg(file, svg_args, box, paint, trans)
47
+ Squib.logger.debug {"Rendering: #{file}, id: #{id} @#{x},#{y} #{width}x#{height}, alpha: #{alpha}, blend: #{blend}, angle: #{angle}, mask: #{mask}"}
48
+ Squib.logger.warn 'Both an SVG file and SVG data were specified' unless file.to_s.empty? || svg_args.data.to_s.empty?
49
+ return if (file.nil? or file.eql? '') and svg_args.data.nil? # nothing specified TODO Move this out to arg validator
50
+ svg_args.data = File.read(file) if svg_args.data.to_s.empty?
51
+ svg = RSVG::Handle.new_from_data(svg_args.data)
52
+ box.width = svg.width if box.width == :native
53
+ box.height = svg.height if box.height == :native
54
+ box.width = svg.width.to_f * box.height.to_f / svg.height.to_f if box.width == :scale
55
+ box.height = svg.height.to_f * box.width.to_f / svg.width.to_f if box.height == :scale
56
+ scale_width = box.width.to_f / svg.width.to_f
57
+ scale_height = box.height.to_f / svg.height.to_f
58
+ use_cairo do |cc|
59
+ cc.translate(box.x, box.y)
60
+ cc.rotate(trans.angle)
61
+ cc.scale(scale_width, scale_height)
62
+ cc.operator = paint.blend unless paint.blend == :none
63
+ if paint.mask.to_s.empty?
64
+ cc.render_rsvg_handle(svg, svg_args.id)
65
+ else
66
+ tmp = Cairo::ImageSurface.new(box.width / scale_width, box.height / scale_height)
67
+ tmp_cc = Cairo::Context.new(tmp)
68
+ tmp_cc.render_rsvg_handle(svg, svg_args.id)
69
+ cc.set_source_squibcolor(paint.mask)
70
+ cc.mask(tmp, 0, 0)
71
+ end
72
+ end
73
+ end
74
+
75
+ end
76
+ end
@@ -1,137 +1,103 @@
1
- module Squib
2
- class Deck
3
-
4
- # Lays out the cards in range and renders a PDF
5
- #
6
- # @example
7
- # save_pdf file: 'deck.pdf', margin: 75, gap: 5, trim: 37
8
- #
9
- # @option opts file [String] the name of the PDF file to save. See {file:README.md#Specifying_Files Specifying Files}
10
- # @option opts dir [String] (_output) the directory to save to. Created if it doesn't exist.
11
- # @option opts width [Integer] (3300) the height of the page in pixels. Default is 11in * 300dpi. Supports unit conversion.
12
- # @option opts height [Integer] (2550) the height of the page in pixels. Default is 8.5in * 300dpi. Supports unit conversion.
13
- # @option opts margin [Integer] (75) the margin around the outside of the page. Supports unit conversion.
14
- # @option opts gap [Integer] (0) the space in pixels between the cards. Supports unit conversion.
15
- # @option opts trim [Integer] (0) the space around the edge of each card to trim (e.g. to cut off the bleed margin for print-and-play). Supports unit conversion.
16
- # @return [nil]
17
- # @api public
18
- def save_pdf(opts = {})
19
- opts = {width: 3300, height: 2550}.merge(opts)
20
- p = needs(opts, [:range, :paper_width, :paper_height, :file_to_save,
21
- :creatable_dir, :margin, :gap, :trim])
22
- paper_width = p[:width]
23
- paper_height = p[:height]
24
- file = "#{p[:dir]}/#{p[:file]}"
25
- cc = Cairo::Context.new(Cairo::PDFSurface.new(file, paper_width * 72.0 / @dpi, paper_height * 72.0 / @dpi))
26
- cc.scale(72.0 / @dpi, 72.0 / @dpi) # for bug #62
27
- x, y = p[:margin], p[:margin]
28
- card_width = @width - 2 * p[:trim]
29
- card_height = @height - 2 * p[:trim]
30
- @progress_bar.start("Saving PDF to #{file}", p[:range].size) do |bar|
31
- p[:range].each do |i|
32
- card = @cards[i]
33
- cc.translate(x,y)
34
- cc.rectangle(p[:trim], p[:trim], card_width, card_height)
35
- cc.clip
36
- case card.backend.downcase.to_sym
37
- when :memory
38
- cc.set_source(card.cairo_surface, 0, 0)
39
- cc.paint
40
- when :svg
41
- card.cairo_surface.finish
42
- cc.save
43
- 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
44
- cc.render_rsvg_handle(RSVG::Handle.new_from_file(card.svgfile), nil)
45
- cc.restore
46
- else
47
- abort "No such back end supported for save_pdf: #{backend}"
48
- end
49
- bar.increment
50
- cc.reset_clip
51
- cc.translate(-x,-y)
52
- x += card.width + p[:gap] - 2*p[:trim]
53
- if x > (paper_width - card_width - p[:margin])
54
- x = p[:margin]
55
- y += card.height + p[:gap] - 2*p[:trim]
56
- if y > (paper_height - card_height - p[:margin])
57
- cc.show_page # next page
58
- x,y = p[:margin],p[:margin]
59
- end
60
- end
61
- end
62
- end
63
- end
64
-
65
- # Lays out the cards in range and renders a stitched PNG sheet
66
- #
67
- # @example
68
- # save_sheet prefix: 'sheet_', margin: 75, gap: 5, trim: 37
69
- #
70
- # @option opts [Enumerable] range (:all) the range of cards over which this will be rendered. See {file:README.md#Specifying_Ranges Specifying Ranges}
71
- # @option opts colulmns [Integer] (5) the number of columns in the grid
72
- # @option opts rows [Integer] (:infinite) the number of rows in the grid. When set to :infinite, the sheet scales to the rows needed. If there are more cards than rows*columns, new sheets are started.
73
- # @option opts [String] prefix (card_) the prefix of the file name(s)
74
- # @option opts [String] count_format (%02d) the format string used for formatting the card count (e.g. padding zeros). Uses a Ruby format string (see the Ruby doc for Kernel::sprintf for specifics)
75
- # @option opts dir [String] (_output) the directory to save to. Created if it doesn't exist.
76
- # @option opts margin [Integer] (0) the margin around the outside of the page.
77
- # @option opts gap [Integer] (0) the space in pixels between the cards
78
- # @option opts trim [Integer] (0) the space around the edge of each card to trim (e.g. to cut off the bleed margin for print-and-play)
79
- # @return [nil]
80
- # @api public
81
- def save_sheet(opts = {})
82
- opts = {margin: 0}.merge(opts) # overriding the non-system default
83
- p = needs(opts, [:range, :prefix, :count_format, :creatable_dir, :margin, :gap, :trim, :rows, :columns])
84
- # EXTRACT METHOD HERE
85
- sheet_width = (p[:columns] * (@width + 2 * p[:gap] - 2 * p[:trim])) + (2 * p[:margin])
86
- sheet_height = (p[:rows] * (@height + 2 * p[:gap] - 2 * p[:trim])) + (2 * p[:margin])
87
- cc = Cairo::Context.new(Cairo::ImageSurface.new(sheet_width, sheet_height))
88
- num_this_sheet = 0
89
- sheet_num = 0
90
- x, y = p[:margin], p[:margin]
91
- @progress_bar.start("Saving PNG sheet to #{p[:dir]}/#{p[:prefix]}_*", @cards.size + 1) do |bar|
92
- p[:range].each do |i|
93
- if num_this_sheet >= (p[:columns] * p[:rows]) # new sheet
94
- filename = "#{p[:dir]}/#{p[:prefix]}#{p[:count_format] % sheet_num}.png"
95
- cc.target.write_to_png(filename)
96
- new_sheet = false
97
- num_this_sheet = 0
98
- sheet_num += 1
99
- x, y = p[:margin], p[:margin]
100
- cc = Cairo::Context.new(Cairo::ImageSurface.new(sheet_width, sheet_height))
101
- end
102
- surface = trim(@cards[i].cairo_surface, p[:trim], @width, @height)
103
- cc.set_source(surface, x, y)
104
- cc.paint
105
- num_this_sheet += 1
106
- x += surface.width + p[:gap]
107
- if num_this_sheet % p[:columns] == 0 # new row
108
- x = p[:margin]
109
- y += surface.height + p[:gap]
110
- end
111
- bar.increment
112
- end
113
- cc.target.write_to_png("#{p[:dir]}/#{p[:prefix]}#{p[:count_format] % sheet_num}.png")
114
- end
115
- end
116
-
117
- # Return a new Cairo::ImageSurface that is trimmed from the original
118
- #
119
- # @param surface The surface to trim
120
- # @param trim The number of pixels around the edge to trim
121
- # @param width The width of the surface prior to the trim
122
- # @param height The height of the surface prior to the trim
123
- # :nodoc:
124
- # @api private
125
- def trim(surface, trim, width, height)
126
- if trim > 0
127
- tmp = Cairo::ImageSurface.new(width-2*trim, height-2*trim)
128
- cc = Cairo::Context.new(tmp)
129
- cc.set_source(surface,-1*trim, -1*trim)
130
- cc.paint
131
- surface = tmp
132
- end
133
- surface
134
- end
135
-
136
- end
137
- end
1
+ module Squib
2
+ class Deck
3
+
4
+ # :nodoc:
5
+ # @api private
6
+ def render_pdf(range, sheet)
7
+ file = "#{sheet.dir}/#{sheet.file}"
8
+ cc = Cairo::Context.new(Cairo::PDFSurface.new(file, sheet.width * 72.0 / @dpi, sheet.height * 72.0 / @dpi))
9
+ cc.scale(72.0 / @dpi, 72.0 / @dpi) # for bug #62
10
+ x, y = sheet.margin, sheet.margin
11
+ card_width = @width - 2 * sheet.trim
12
+ card_height = @height - 2 * sheet.trim
13
+ @progress_bar.start("Saving PDF to #{file}", range.size) do |bar|
14
+ range.each do |i|
15
+ card = @cards[i]
16
+ cc.translate(x,y)
17
+ cc.rectangle(sheet.trim, sheet.trim, card_width, card_height)
18
+ cc.clip
19
+ case card.backend.downcase.to_sym
20
+ when :memory
21
+ cc.set_source(card.cairo_surface, 0, 0)
22
+ cc.paint
23
+ when :svg
24
+ card.cairo_surface.finish
25
+ cc.save
26
+ 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
27
+ cc.render_rsvg_handle(RSVG::Handle.new_from_file(card.svgfile), nil)
28
+ cc.restore
29
+ else
30
+ abort "No such back end supported for save_pdf: #{backend}"
31
+ end
32
+ bar.increment
33
+ cc.reset_clip
34
+ cc.translate(-x,-y)
35
+ x += card.width + sheet.gap - 2*sheet.trim
36
+ if x > (sheet.width - card_width - sheet.margin)
37
+ x = sheet.margin
38
+ y += card.height + sheet.gap - 2*sheet.trim
39
+ if y > (sheet.height - card_height - sheet.margin)
40
+ cc.show_page # next page
41
+ x,y = sheet.margin,sheet.margin
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ # :nodoc:
49
+ # @api private
50
+ def render_sheet(range, batch, sheet)
51
+ sheet_width = (sheet.columns * (@width + 2 * sheet.gap - 2 * sheet.trim)) + (2 * sheet.margin)
52
+ sheet_height = (sheet.rows * (@height + 2 * sheet.gap - 2 * sheet.trim)) + (2 * sheet.margin)
53
+ cc = Cairo::Context.new(Cairo::ImageSurface.new(sheet_width, sheet_height))
54
+ num_this_sheet = 0
55
+ sheet_num = 0
56
+ x, y = sheet.margin, sheet.margin
57
+ @progress_bar.start("Saving PNG sheet to #{batch.summary}", @cards.size + 1) do |bar|
58
+ range.each do |i|
59
+ if num_this_sheet >= (sheet.columns * sheet.rows) # new sheet
60
+ filename = batch.full_filename(sheet_num)
61
+ cc.target.write_to_png(filename)
62
+ new_sheet = false
63
+ num_this_sheet = 0
64
+ sheet_num += 1
65
+ x, y = sheet.margin, sheet.margin
66
+ cc = Cairo::Context.new(Cairo::ImageSurface.new(sheet_width, sheet_height))
67
+ end
68
+ surface = trim(@cards[i].cairo_surface, sheet.trim, @width, @height)
69
+ cc.set_source(surface, x, y)
70
+ cc.paint
71
+ num_this_sheet += 1
72
+ x += surface.width + sheet.gap
73
+ if num_this_sheet % sheet.columns == 0 # new row
74
+ x = sheet.margin
75
+ y += surface.height + sheet.gap
76
+ end
77
+ bar.increment
78
+ end
79
+ cc.target.write_to_png(batch.full_filename(sheet_num))
80
+ end
81
+ end
82
+
83
+ # Return a new Cairo::ImageSurface that is trimmed from the original
84
+ #
85
+ # @param surface The surface to trim
86
+ # @param trim The number of pixels around the edge to trim
87
+ # @param width The width of the surface prior to the trim
88
+ # @param height The height of the surface prior to the trim
89
+ # :nodoc:
90
+ # @api private
91
+ def trim(surface, trim, width, height)
92
+ if trim > 0
93
+ tmp = Cairo::ImageSurface.new(width-2*trim, height-2*trim)
94
+ cc = Cairo::Context.new(tmp)
95
+ cc.set_source(surface,-1*trim, -1*trim)
96
+ cc.paint
97
+ surface = tmp
98
+ end
99
+ surface
100
+ end
101
+
102
+ end
103
+ end