diff --git a/.gitignore b/.gitignore index d87d4be..1ed86c2 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ spec/reports test/tmp test/version_tmp tmp +.~lock* diff --git a/README.md b/README.md index 0b32947..1fab368 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,8 @@ Install the gem globally with `gem install svggvs` and then run `svggvs install is the name of the directory to place the skeleton project files. You'll get a few files in there: * `template.svg`, an Inkscape template that shoows how to do the basic SVGGVS template setup -* `Cardfile`, the file SVGGVS uses to define each card for printing +* `data.ods`, a LibreOffice spreadsheet that defines the card data and project settings +* `Cardfile`, the file SVGGVS uses to find the data file and optionally process the spreadsheet data after-the-fact * `Gemfile`, in case you need additional gems. It has SVGGVS added already, but you may also want remote data gems like `google_drive`, for instance. @@ -16,7 +17,7 @@ is the name of the directory to place the skeleton project files. You'll get a f Create an Inkscape SVG file in your project directory. Make sure it has a Source and a Target layer. Your card template is made up of sublayers in the Source layer. These layers are copied to the Target layer -upon processing. The names of the layers are what you refer to in the `#active_layers` method in your `Cardfile`. +upon processing. By default, layers are hidden, and hidden layers are deleted after copying to the Target layer, unless they have the following names: @@ -25,50 +26,55 @@ unless they have the following names: Hiding/showing layers is the way that you make certain card elements appear/disappear on different types of cards with with different properties. You can also replace the text in -text boxes (both standard and flowroot boxes) by giving those boxes a distinct label (under Object Properties) -and feeding in a hash of label/text pairs into the `#replacements` method in the `Cardfile`. +text boxes (both standard and flowroot boxes) by giving those boxes a distinct label (under Object Properties). -Create a `Cardfile` in your working directory. It should look -something like this: +Create a spreadsheet in the same directory, or on Google Drive. This project uses the Roo gem +to read spreadsheets, so as long as Roo can read it, you're good to do. + +Give the sheets names so that SVGGVS knows what to do with them: + +* Put "Card Data" somewhere in the name for SVGGVS to use it as a data source +* Name it "SVGGVS Settings" to define your project's settings. + +Under SVGGVS settings, you can currently set the following, as a series of two-column rows: + +* Card Size: Right now, only one option: Poker +* Target: Right now, only one option: The Game Crafter +* SVG Source: The SVG template file +* Individual Files Path: Where final SVG files go +* PNG Files Path: Where rendered PNG files go +* PDF Target: Where the print-n-play PDF goes + +The following can be manually specified if you don't provide Card Size and Target: + +* PNG Export Width: The width of the exported card from Inkscape +* PDF Card Size: The size a card is cropped down to before being placed on the PnP PDF +* PDF DPI: The DPI of the PDF file + +The following Card Size and Target settings set these to the following: + +* The Game Crafter + * Poker + * PNG Export Width: 825 + * PDF Card Size: 750x1050 + * PDF DPI: 300 + +Create a `Cardfile` in your working directory. It should look something like this: ``` ruby @session.configure do |c| - c.svg_source = "template/template.svg" - c.svg_merged_target = "template/output.svg" + # manipulate the data after reading from the spreadsheet + # c.post_read_data = proc { |data| + # data[:replacements]['Superpower Text'] << '!!' + # } - c.png_export_width = 825 - c.pdf_card_size = "750x1050" - c.pdf_dpi = 300 - - c.individual_files_path = "template/output/card_%02d.svg" - c.png_files_path = "template/png/card_%02d.png" - - c.pdf_target = "merged.pdf" -end - -@session.process do - require './card_definitions.rb' - - CardDefinitions.processed.each do |card| - @session.with_new_target do |target| - datum = card.to_svggvs - - # #active_layers indicates what sublayers within the "Source" layer of - # the Inkscape document should be toggled as visible. All others are hidden. - target.active_layers = datum[:active] - - # Any text with {% liquid_like_tags %} will have those tags replaced with the - # values within the hash passed in. - # Additionally, you can label the following and have things replaced: - # * svg:flowRoot will replace the text in the svg:flowPara within - # * svg:text will replace the text in the first svg:tspan within - # * svg:image will replace the xlink:href of the tag, changing the image to load - target.replacements = datum[:replacements] - end - end + c.data_source = "data.ods" end ``` +All of the settings that could be set in your spreadsheet can also be set here. See +`SVGGVS::Session` for more details. + You can also have a `.cardrc` file which is run before loading the `Cardfile`. Process your cards with `svggvs`: diff --git a/lib/svggvs.rb b/lib/svggvs.rb index 83f772b..4984359 100644 --- a/lib/svggvs.rb +++ b/lib/svggvs.rb @@ -2,7 +2,15 @@ require_relative './svggvs/file' require_relative './svggvs/target' require_relative './svggvs/context' require_relative './svggvs/session' +require_relative './svggvs/data_source' module SVGGVS end +require 'active_support/core_ext/string/inflections' + +class String + def spunderscore + self.underscore.gsub(' ', '_') + end +end diff --git a/lib/svggvs/data_source.rb b/lib/svggvs/data_source.rb new file mode 100644 index 0000000..79f0d51 --- /dev/null +++ b/lib/svggvs/data_source.rb @@ -0,0 +1,53 @@ +require 'roo' + +module SVGGVS + class DataSource + def initialize(file) + @file = file + end + + def doc + @doc ||= Roo::Spreadsheet.open(@file) + end + + def settings + settings = {} + + doc.each_with_pagename do |name, sheet| + if name['SVGGVS Settings'] + sheet.each do |setting, value| + settings[setting.spunderscore.to_sym] = value + end + end + end + + settings + end + + def each_card + doc.each_with_pagename do |name, sheet| + if name['Card Data'] + headers = sheet.row(1) + + (sheet.first_row + 1).upto(sheet.last_row) do |index| + card_data = { + :active_layers => [], + :replacements => {} + } + + headers.zip(sheet.row(index)).each do |header, cell| + if header['Active Layer'] + card_data[:active_layers] += cell.split(';') + else + card_data[:replacements][header] = cell + end + end + + yield card_data + end + end + end + end + end +end + diff --git a/lib/svggvs/session.rb b/lib/svggvs/session.rb index f5bbb53..dd51b6f 100644 --- a/lib/svggvs/session.rb +++ b/lib/svggvs/session.rb @@ -2,7 +2,7 @@ module SVGGVS class Session attr_accessor :svg_source, :svg_merged_target, :individual_files_path, :on_card_finished attr_accessor :png_files_path, :png_export_width, :pdf_card_size, :pdf_dpi - attr_accessor :pdf_target, :card_back + attr_accessor :pdf_target, :card_back, :card_size, :target, :post_read_data def initialize @index = 0 @@ -31,9 +31,19 @@ module SVGGVS end def run + if !!@card_size && !!@target + settings_from_hash(EXPORT_DEFAULTS[@card_size.spunderscore.to_sym][@target.spunderscore.to_sym]) + end + @process.call end + def settings_from_hash(hash) + hash.each do |setting, value| + self.send("#{setting}=", value) + end + end + def with_new_target file.with_new_target do |target| yield target @@ -41,6 +51,35 @@ module SVGGVS card_finished! end + + def data_source=(source) + data_source = DataSource.new(source) + + settings_from_hash(data_source.settings) + + @process = proc do + data_source.each_card do |card| + if !!@post_read_data + @post_read_data.call(card) + end + + with_new_target do |target| + target.active_layers = card[:active_layers] + target.replacements = card[:replacements] + end + end + end + end + + EXPORT_DEFAULTS = { + :poker => { + :the_game_crafter => { + :pdf_card_size => '750x1050', + :pdf_dpi => 300, + :png_export_width => 825 + } + } + }.freeze end end diff --git a/lib/svggvs/version.rb b/lib/svggvs/version.rb index 7e62da3..7d0e219 100644 --- a/lib/svggvs/version.rb +++ b/lib/svggvs/version.rb @@ -1,3 +1,3 @@ module SVGGVS - VERSION = "0.0.3" + VERSION = "0.0.4" end diff --git a/skel/Cardfile b/skel/Cardfile index 115e216..6c8918c 100644 --- a/skel/Cardfile +++ b/skel/Cardfile @@ -1,37 +1,9 @@ @session.configure do |c| - c.svg_source = "template.svg" - c.svg_merged_target = "merged-template.svg" + # manipulate the data after reading from the spreadsheet + # c.post_read_data = proc { |data| + # data[:replacements]['Superpower Text'] << '!!' + # } - c.png_export_width = 825 - - c.pdf_dpi = 300 - c.pdf_card_size = "750x1050" - - c.individual_files_path = "svgout/output_%03d.svg" - - c.png_files_path = "pngout-svggvs/output_%03d.png" - - c.pdf_target = "pnp/game.pdf" + c.data_source = "data.ods" end -card_data = [ - { - active_layers: [ 'Action', 'Puppy', 'Name', 'Background' ], - replacements: { 'Name' => 'Woofie', 'Action' => 'Bark at the person who is ringing the doorbell.' } - }, - { - active_layers: [ 'Action', 'Kitten', 'Name', 'Background' ], - replacements: { 'Name' => 'Hisshead', 'Action' => "Demand food by clawing at your owner's lap." } - }, -] - -@session.process do - card_data.each do |card| - @session.with_new_target do |target| - target.active_layers = card[:active_layers] - target.replacements = card[:replacements] - end - end -end - - diff --git a/skel/data.ods b/skel/data.ods new file mode 100644 index 0000000..a5ccbbd Binary files /dev/null and b/skel/data.ods differ diff --git a/skel/images/cat.png.jpg b/skel/images/cat.png.jpg new file mode 100644 index 0000000..74ef8bb Binary files /dev/null and b/skel/images/cat.png.jpg differ diff --git a/skel/images/dog.png.jpg b/skel/images/dog.png.jpg new file mode 100644 index 0000000..e145c8f Binary files /dev/null and b/skel/images/dog.png.jpg differ diff --git a/skel/template.svg b/skel/template.svg index 42f68b7..cd7513d 100644 --- a/skel/template.svg +++ b/skel/template.svg @@ -14,7 +14,7 @@ height="3.75in" id="svg2" version="1.1" - inkscape:version="0.48+devel r12777 custom" + inkscape:version="0.48.2 r9819" viewBox="0 0 2.75 3.75" sodipodi:docname="template.svg"> + inkscape:guide-bbox="true" + inkscape:snap-global="false"> image/svg+xml - + @@ -195,7 +196,7 @@ + inkscape:label="Background (visible)"> + inkscape:label="Name (visible)"> + inkscape:label="Action (visible)"> Perform this action, then pat the nearest animal of this type. + + Superpower! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +