diff --git a/lib/squib/api/save.rb b/lib/squib/api/save.rb index 82f5b9a..fbe14f6 100644 --- a/lib/squib/api/save.rb +++ b/lib/squib/api/save.rb @@ -55,6 +55,8 @@ module Squib # @option opts [String] prefix (card_) the prefix of the file name to be printed. # @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) # @option opts [Boolean, :clockwise, :counterclockwise] rotate (false) if true, the saved cards will be rotated 90 degrees clockwise. Or, rotate by the number of radians. Intended to rendering landscape instead of portrait. + # @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. + # @option opts trim_radius [Integer] (38) the rounded rectangle radius around the card to trim before putting into the showcase # @return [nil] Returns nothing # @api public def save_png(opts = {}) diff --git a/lib/squib/args/save_batch.rb b/lib/squib/args/save_batch.rb index 7b3ab42..d0364f6 100644 --- a/lib/squib/args/save_batch.rb +++ b/lib/squib/args/save_batch.rb @@ -12,11 +12,14 @@ module Squib end def self.parameters - { dir: '_output', - prefix: 'card_', + { + angle: 0, count_format: '%02d', + dir: '_output', + prefix: 'card_', rotate: false, - angle: 0, + trim_radius: 0, + trim: 0, } end @@ -25,7 +28,7 @@ module Squib end def self.params_with_units - [] # none of them + [:trim, :trim_radius] end def validate_dir(arg, _i) diff --git a/lib/squib/graphics/save_images.rb b/lib/squib/graphics/save_images.rb index 15f672d..5107b7d 100644 --- a/lib/squib/graphics/save_images.rb +++ b/lib/squib/graphics/save_images.rb @@ -4,27 +4,33 @@ module Squib # :nodoc: # @api private def save_png(batch) - surface = if batch.rotate - rotated_image(batch.angle) + surface = if preprocess_save?(batch) + preprocessed_save(batch.angle, batch.trim, batch.trim_radius) else - surface = @cairo_surface + @cairo_surface end write_png(surface, index, batch.dir, batch.prefix, batch.count_format) end # :nodoc: # @api private - def rotated_image(angle) - rotated_cc = Cairo::Context.new(Cairo::ImageSurface.new(@height, @width) ) - rotated_cc.translate(@height * 0.5, @width * 0.5) - rotated_cc.rotate(angle) - rotated_cc.translate(@width * -0.5, @height * -0.5) - rotated_cc.set_source(@cairo_surface) - rotated_cc.paint - rotated_cc.target + def preprocess_save?(batch) + batch.rotate || batch.trim > 0 end - # :nodoc: - # @api private + + def preprocessed_save(angle, trim, trim_radius) + new_width, new_height = @width - 2*trim, @height - 2*trim + new_cc = Cairo::Context.new(Cairo::ImageSurface.new(new_width, new_height)) + new_cc.translate(new_width * 0.5, new_height * 0.5) + new_cc.rotate(angle) + new_cc.translate(new_width * -0.5, new_height * -0.5) + new_cc.set_source(@cairo_surface, -trim, -trim) + new_cc.rounded_rectangle(0, 0, new_width, new_height, trim_radius, trim_radius) + new_cc.clip + new_cc.paint + new_cc.target + end + def write_png(surface, i, dir, prefix, count_format) surface.write_to_png("#{dir}/#{prefix}#{count_format % i}.png") end diff --git a/samples/saves.rb b/samples/saves.rb index 0d7addc..ac98a86 100644 --- a/samples/saves.rb +++ b/samples/saves.rb @@ -4,10 +4,18 @@ require 'squib' Squib::Deck.new(width: 825, height: 1125, cards: 16) do background color: :gray - rect x: 38, y: 38, width: 750, height: 1050, x_radius: 38, y_radius: 38 + rect x: 38, y: 38, width: 750, height: 1050, + x_radius: 38, y_radius: 38, stroke: 3.0, dash: '4 4' text str: (1..16).to_a, x: 220, y: 78, font: 'Arial 54' + # Here's what a regular save_png looks like for just the first card + save_png range: 0, prefix: 'save_png_' + + # save_png supports trim and trim_radius + save_png trim: 30, trim_radius: 38, + range: 0, prefix: 'save_png_trimmed_' + # Place on multiple pages over the PDF, with bleed beeing trimmed off save_pdf file: 'save-pdf.pdf', margin: 75, gap: 5, trim: 37 diff --git a/spec/data/samples/portrait-landscape.rb.txt b/spec/data/samples/portrait-landscape.rb.txt index 14992a7..c5cc9ae 100644 --- a/spec/data/samples/portrait-landscape.rb.txt +++ b/spec/data/samples/portrait-landscape.rb.txt @@ -41,9 +41,11 @@ cairo: move_to([0, 0]) cairo: show_pango_layout([MockDouble]) pango: ellipsized?([]) cairo: restore([]) -cairo: translate([412.5, 562.5]) +cairo: translate([562.5, 412.5]) cairo: rotate([1.5707963267948966]) cairo: translate([-562.5, -412.5]) -cairo: set_source([MockDouble]) +cairo: set_source([MockDouble, 0, 0]) +cairo: rounded_rectangle([0, 0, 1125, 825, 0, 0]) +cairo: clip([]) cairo: paint([]) surface: write_to_png(["_output/landscape_00.png"]) diff --git a/spec/data/samples/saves.rb.txt b/spec/data/samples/saves.rb.txt index 04cb319..5c51e97 100644 --- a/spec/data/samples/saves.rb.txt +++ b/spec/data/samples/saves.rb.txt @@ -86,7 +86,7 @@ cairo: set_source_color(["black"]) cairo: set_line_width([2.0]) cairo: set_line_join([0]) cairo: set_line_cap([0]) -cairo: set_dash([[]]) +cairo: set_dash([[4.0, 4.0]]) cairo: stroke([]) cairo: restore([]) cairo: save([]) @@ -97,7 +97,7 @@ cairo: set_source_color(["black"]) cairo: set_line_width([2.0]) cairo: set_line_join([0]) cairo: set_line_cap([0]) -cairo: set_dash([[]]) +cairo: set_dash([[4.0, 4.0]]) cairo: stroke([]) cairo: restore([]) cairo: save([]) @@ -108,7 +108,7 @@ cairo: set_source_color(["black"]) cairo: set_line_width([2.0]) cairo: set_line_join([0]) cairo: set_line_cap([0]) -cairo: set_dash([[]]) +cairo: set_dash([[4.0, 4.0]]) cairo: stroke([]) cairo: restore([]) cairo: save([]) @@ -119,7 +119,7 @@ cairo: set_source_color(["black"]) cairo: set_line_width([2.0]) cairo: set_line_join([0]) cairo: set_line_cap([0]) -cairo: set_dash([[]]) +cairo: set_dash([[4.0, 4.0]]) cairo: stroke([]) cairo: restore([]) cairo: save([]) @@ -130,7 +130,7 @@ cairo: set_source_color(["black"]) cairo: set_line_width([2.0]) cairo: set_line_join([0]) cairo: set_line_cap([0]) -cairo: set_dash([[]]) +cairo: set_dash([[4.0, 4.0]]) cairo: stroke([]) cairo: restore([]) cairo: save([]) @@ -141,7 +141,7 @@ cairo: set_source_color(["black"]) cairo: set_line_width([2.0]) cairo: set_line_join([0]) cairo: set_line_cap([0]) -cairo: set_dash([[]]) +cairo: set_dash([[4.0, 4.0]]) cairo: stroke([]) cairo: restore([]) cairo: save([]) @@ -152,7 +152,7 @@ cairo: set_source_color(["black"]) cairo: set_line_width([2.0]) cairo: set_line_join([0]) cairo: set_line_cap([0]) -cairo: set_dash([[]]) +cairo: set_dash([[4.0, 4.0]]) cairo: stroke([]) cairo: restore([]) cairo: save([]) @@ -163,7 +163,7 @@ cairo: set_source_color(["black"]) cairo: set_line_width([2.0]) cairo: set_line_join([0]) cairo: set_line_cap([0]) -cairo: set_dash([[]]) +cairo: set_dash([[4.0, 4.0]]) cairo: stroke([]) cairo: restore([]) cairo: save([]) @@ -174,7 +174,7 @@ cairo: set_source_color(["black"]) cairo: set_line_width([2.0]) cairo: set_line_join([0]) cairo: set_line_cap([0]) -cairo: set_dash([[]]) +cairo: set_dash([[4.0, 4.0]]) cairo: stroke([]) cairo: restore([]) cairo: save([]) @@ -185,7 +185,7 @@ cairo: set_source_color(["black"]) cairo: set_line_width([2.0]) cairo: set_line_join([0]) cairo: set_line_cap([0]) -cairo: set_dash([[]]) +cairo: set_dash([[4.0, 4.0]]) cairo: stroke([]) cairo: restore([]) cairo: save([]) @@ -196,7 +196,7 @@ cairo: set_source_color(["black"]) cairo: set_line_width([2.0]) cairo: set_line_join([0]) cairo: set_line_cap([0]) -cairo: set_dash([[]]) +cairo: set_dash([[4.0, 4.0]]) cairo: stroke([]) cairo: restore([]) cairo: save([]) @@ -207,7 +207,7 @@ cairo: set_source_color(["black"]) cairo: set_line_width([2.0]) cairo: set_line_join([0]) cairo: set_line_cap([0]) -cairo: set_dash([[]]) +cairo: set_dash([[4.0, 4.0]]) cairo: stroke([]) cairo: restore([]) cairo: save([]) @@ -218,7 +218,7 @@ cairo: set_source_color(["black"]) cairo: set_line_width([2.0]) cairo: set_line_join([0]) cairo: set_line_cap([0]) -cairo: set_dash([[]]) +cairo: set_dash([[4.0, 4.0]]) cairo: stroke([]) cairo: restore([]) cairo: save([]) @@ -229,7 +229,7 @@ cairo: set_source_color(["black"]) cairo: set_line_width([2.0]) cairo: set_line_join([0]) cairo: set_line_cap([0]) -cairo: set_dash([[]]) +cairo: set_dash([[4.0, 4.0]]) cairo: stroke([]) cairo: restore([]) cairo: save([]) @@ -240,7 +240,7 @@ cairo: set_source_color(["black"]) cairo: set_line_width([2.0]) cairo: set_line_join([0]) cairo: set_line_cap([0]) -cairo: set_dash([[]]) +cairo: set_dash([[4.0, 4.0]]) cairo: stroke([]) cairo: restore([]) cairo: save([]) @@ -251,7 +251,7 @@ cairo: set_source_color(["black"]) cairo: set_line_width([2.0]) cairo: set_line_join([0]) cairo: set_line_cap([0]) -cairo: set_dash([[]]) +cairo: set_dash([[4.0, 4.0]]) cairo: stroke([]) cairo: restore([]) cairo: save([]) @@ -510,6 +510,15 @@ cairo: move_to([0, 0]) cairo: show_pango_layout([MockDouble]) pango: ellipsized?([]) cairo: restore([]) +surface: write_to_png(["_output/save_png_00.png"]) +cairo: translate([382.5, 532.5]) +cairo: rotate([0]) +cairo: translate([-382.5, -532.5]) +cairo: set_source([MockDouble, -30, -30]) +cairo: rounded_rectangle([0, 0, 765, 1065, 38, 38]) +cairo: clip([]) +cairo: paint([]) +surface: write_to_png(["_output/save_png_trimmed_00.png"]) cairo: scale([0.24, 0.24]) cairo: translate([75, 75]) cairo: rectangle([37, 37, 751, 1051])