squib 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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