initial commit, works for crma, now to get working for lyfo
This commit is contained in:
commit
9a071262b2
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
*.gem
|
||||
*.rbc
|
||||
.bundle
|
||||
.config
|
||||
.yardoc
|
||||
Gemfile.lock
|
||||
InstalledFiles
|
||||
_yardoc
|
||||
coverage
|
||||
doc/
|
||||
lib/bundler/man
|
||||
pkg
|
||||
rdoc
|
||||
spec/reports
|
||||
test/tmp
|
||||
test/version_tmp
|
||||
tmp
|
8
Gemfile
Normal file
8
Gemfile
Normal file
@ -0,0 +1,8 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
gemspec
|
||||
|
||||
gem 'nokogiri'
|
||||
gem 'virtus'
|
||||
gem 'google_drive'
|
||||
gem 'activesupport'
|
22
LICENSE.txt
Normal file
22
LICENSE.txt
Normal file
@ -0,0 +1,22 @@
|
||||
Copyright (c) 2013 John Bintz
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
57
README.md
Normal file
57
README.md
Normal file
@ -0,0 +1,57 @@
|
||||
# Process Inkscape files and create sets of cards for board games
|
||||
|
||||
Not much in the way of docs yet. You'll need `inkscape`, `convert`, `montage`, and `gs` in your `PATH`.
|
||||
|
||||
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"
|
||||
|
||||
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 'google_drive'
|
||||
require 'virtus'
|
||||
require 'active_support/inflector'
|
||||
|
||||
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.
|
||||
target.replacements = datum[:replacements]
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
You can also have a `.cardrc` file which is run before loading the `Cardfile`.
|
||||
|
||||
Process your cards with `svggvs`:
|
||||
|
||||
* `svggvs merged_file`: Create a big SVG file with al cards as layers
|
||||
* `svggvs svgs`: Write out individual SVG files
|
||||
* `svggvs pngs`: Write out PNG files after writing out the SVG files
|
||||
* `svggvs pdf`: Write out the merged PnP PDF file
|
||||
|
||||
You can also pass in `--cardfile <new file>` to load a different cardfile, say for
|
||||
card backs.
|
||||
|
87
bin/svggvs
Executable file
87
bin/svggvs
Executable file
@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'thor'
|
||||
require 'digest/md5'
|
||||
|
||||
require_relative '../lib/svggvs'
|
||||
|
||||
module SVGGVS
|
||||
class Cli < Thor
|
||||
class_option :cardfile, default: 'Cardfile'
|
||||
|
||||
desc "merged_file", "Write out a merged file"
|
||||
def merged_file
|
||||
context.write_merged_file
|
||||
end
|
||||
|
||||
desc "svgs", "Write out individual SVG files"
|
||||
def svgs
|
||||
write_svgs
|
||||
end
|
||||
|
||||
desc "pngs", "Write out individual PNG files"
|
||||
def pngs
|
||||
write_svgs
|
||||
ensure_tmp
|
||||
|
||||
@exported_pngs = []
|
||||
|
||||
context.individual_files.each_with_index do |svg_file, index|
|
||||
target = Pathname(context.session.png_files_path % index)
|
||||
target.parent.mkpath
|
||||
|
||||
@exported_pngs << target
|
||||
|
||||
system %{inkscape --export-area-page --export-png "#{target.expand_path}" --export-width #{context.session.png_export_width} --export-background="#ffffffff" "#{svg_file.expand_path}"}
|
||||
end
|
||||
end
|
||||
|
||||
desc "pdf", "Create PDF of card images"
|
||||
def pdf
|
||||
pngs
|
||||
|
||||
trimmed_pngs = @exported_pngs.collect do |png|
|
||||
tmp_target = tmp_path.join(Digest::MD5.hexdigest(png.to_s) + '.png')
|
||||
|
||||
system %{convert #{png} -gravity Center -crop #{context.session.pdf_card_size}+0+0 +repage #{tmp_target}}
|
||||
|
||||
tmp_target
|
||||
end
|
||||
|
||||
png_slices = trimmed_pngs.each_slice(9)
|
||||
|
||||
page_count = trimmed_pngs.length / 9
|
||||
|
||||
pages = png_slices.each_with_index.collect do |files, page_index|
|
||||
tmp_pdf_target = tmp_path.join("page%05d.pdf" % page_index)
|
||||
|
||||
system %{montage -density #{context.session.pdf_dpi} -geometry +0+0 #{files.join(' ')} #{tmp_pdf_target}}
|
||||
|
||||
tmp_pdf_target
|
||||
end
|
||||
|
||||
system "gs -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE=#{context.session.pdf_target} -dBATCH #{pages.join(" ")}"
|
||||
end
|
||||
|
||||
no_tasks do
|
||||
def tmp_path
|
||||
@tmp_path ||= Pathname(".tmp")
|
||||
end
|
||||
|
||||
def ensure_tmp
|
||||
tmp_path.rmtree if tmp_path.directory?
|
||||
tmp_path.mkpath
|
||||
end
|
||||
|
||||
def context
|
||||
@context ||= SVGGVS::Context.load(options[:cardfile])
|
||||
end
|
||||
|
||||
def write_svgs
|
||||
context.write_individual_files
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
SVGGVS::Cli.start
|
8
lib/svggvs.rb
Normal file
8
lib/svggvs.rb
Normal file
@ -0,0 +1,8 @@
|
||||
require 'svggvs/file'
|
||||
require 'svggvs/target'
|
||||
require 'svggvs/context'
|
||||
require 'svggvs/session'
|
||||
|
||||
module SVGGVS
|
||||
end
|
||||
|
63
lib/svggvs/context.rb
Normal file
63
lib/svggvs/context.rb
Normal file
@ -0,0 +1,63 @@
|
||||
require 'pathname'
|
||||
|
||||
module SVGGVS
|
||||
class Context
|
||||
attr_reader :individual_files
|
||||
|
||||
def initialize(cardfile = "Cardfile")
|
||||
@cardfile = cardfile
|
||||
|
||||
@individual_files = []
|
||||
end
|
||||
|
||||
def self.load(cardfile = "Cardfile")
|
||||
context = new(cardfile)
|
||||
context.load
|
||||
context
|
||||
end
|
||||
|
||||
def session
|
||||
@session ||= SVGGVS::Session.new
|
||||
end
|
||||
|
||||
def cardrc?
|
||||
::File.file?('.cardrc')
|
||||
end
|
||||
|
||||
def load
|
||||
session
|
||||
|
||||
if cardrc?
|
||||
self.instance_eval(::File.read('.cardrc'))
|
||||
end
|
||||
|
||||
self.instance_eval(cardfile_rb)
|
||||
end
|
||||
|
||||
def cardfile_rb
|
||||
@cardfile_rb ||= ::File.read(@cardfile)
|
||||
end
|
||||
|
||||
def write_merged_file
|
||||
session.on_card_finished = nil
|
||||
session.run
|
||||
|
||||
session.file.save @session.svg_merged_target
|
||||
end
|
||||
|
||||
def write_individual_files
|
||||
session.on_card_finished do |index|
|
||||
target = Pathname(session.individual_files_path % index)
|
||||
|
||||
target.parent.mkpath
|
||||
|
||||
session.file.dup_with_only_last_target.save target.to_s
|
||||
|
||||
@individual_files << target
|
||||
end
|
||||
|
||||
session.run
|
||||
end
|
||||
end
|
||||
end
|
||||
|
83
lib/svggvs/file.rb
Normal file
83
lib/svggvs/file.rb
Normal file
@ -0,0 +1,83 @@
|
||||
require 'nokogiri'
|
||||
|
||||
module SVGGVS
|
||||
class File
|
||||
def initialize(path_or_doc)
|
||||
@instance = 0
|
||||
|
||||
case path_or_doc
|
||||
when String
|
||||
@path = path_or_doc
|
||||
else
|
||||
@doc = path_or_doc
|
||||
end
|
||||
end
|
||||
|
||||
def source
|
||||
return @source if @source
|
||||
|
||||
@source = doc.at_css('g[inkscape|label="Source"]')
|
||||
@source['style'] = 'display:none'
|
||||
@source
|
||||
end
|
||||
|
||||
def root
|
||||
source.parent
|
||||
end
|
||||
|
||||
def target
|
||||
@target ||= doc.at_css('g[inkscape|label="Target"]')
|
||||
end
|
||||
|
||||
def doc
|
||||
return @doc if @doc
|
||||
|
||||
@doc = Nokogiri::XML(::File.read(@path))
|
||||
clear_targets!
|
||||
|
||||
@doc
|
||||
end
|
||||
|
||||
def clear_targets!
|
||||
target.children.each(&:remove)
|
||||
end
|
||||
|
||||
def with_new_target
|
||||
new_target = source.dup
|
||||
new_target[:id] = new_target[:id] + "_#{@instance}"
|
||||
new_target['inkscape:label'] = new_target['inkscape:label'] + "_#{@instance}"
|
||||
|
||||
target_obj = Target.new(new_target)
|
||||
|
||||
yield target_obj
|
||||
|
||||
target_obj.replaced
|
||||
|
||||
target << target_obj.target
|
||||
|
||||
@instance += 1
|
||||
end
|
||||
|
||||
def dup_with_only_last_target
|
||||
dupe = self.class.new(doc.dup)
|
||||
|
||||
target = dupe.target.children.last.dup
|
||||
target[:style] = ''
|
||||
|
||||
dupe.target.remove
|
||||
|
||||
dupe.root.children.each do |child|
|
||||
child[:style] = 'display:none'
|
||||
end
|
||||
|
||||
dupe.root << target
|
||||
|
||||
dupe
|
||||
end
|
||||
|
||||
def save(file)
|
||||
::File.open(file, 'w') { |fh| fh.print doc.to_xml }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
46
lib/svggvs/session.rb
Normal file
46
lib/svggvs/session.rb
Normal file
@ -0,0 +1,46 @@
|
||||
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
|
||||
|
||||
def initialize
|
||||
@index = 0
|
||||
end
|
||||
|
||||
def configure
|
||||
yield self
|
||||
end
|
||||
|
||||
def process(&block)
|
||||
@process = block
|
||||
end
|
||||
|
||||
def card_finished!
|
||||
@on_card_finished.call(@index) if @on_card_finished
|
||||
|
||||
@index += 1
|
||||
end
|
||||
|
||||
def on_card_finished(&block)
|
||||
@on_card_finished = block
|
||||
end
|
||||
|
||||
def file
|
||||
@file ||= SVGGVS::File.new(@svg_source)
|
||||
end
|
||||
|
||||
def run
|
||||
@process.call
|
||||
end
|
||||
|
||||
def with_new_target
|
||||
file.with_new_target do |target|
|
||||
yield target
|
||||
end
|
||||
|
||||
card_finished!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
43
lib/svggvs/target.rb
Normal file
43
lib/svggvs/target.rb
Normal file
@ -0,0 +1,43 @@
|
||||
require 'delegate'
|
||||
|
||||
module SVGGVS
|
||||
class Target < SimpleDelegator
|
||||
attr_reader :target
|
||||
|
||||
def initialize(target)
|
||||
@target = target
|
||||
end
|
||||
|
||||
def __getobj__
|
||||
@target
|
||||
end
|
||||
|
||||
def active_layers=(layers)
|
||||
css("g[inkscape|groupmode='layer']").each do |layer|
|
||||
if layers.include?(layer['inkscape:label'])
|
||||
layer['style'] = ''
|
||||
else
|
||||
layer['style'] = 'display:none'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def replacements=(replacements)
|
||||
@replacements = replacements
|
||||
end
|
||||
|
||||
def replaced(node = @target)
|
||||
if !!@replacements
|
||||
node.children.each do |child|
|
||||
if child.text?
|
||||
if match = child.content[%r{\{% ([^ ]+) %\}}, 1]
|
||||
child.content = @replacements[match] || ''
|
||||
end
|
||||
else
|
||||
replaced(child)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
3
lib/svggvs/version.rb
Normal file
3
lib/svggvs/version.rb
Normal file
@ -0,0 +1,3 @@
|
||||
module Svggvs
|
||||
VERSION = "0.0.1"
|
||||
end
|
22
svggvs.gemspec
Normal file
22
svggvs.gemspec
Normal file
@ -0,0 +1,22 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
lib = File.expand_path('../lib', __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require 'svggvs/version'
|
||||
|
||||
Gem::Specification.new do |gem|
|
||||
gem.name = "svggvs"
|
||||
gem.version = Svggvs::VERSION
|
||||
gem.authors = ["John Bintz"]
|
||||
gem.email = ["john@coswellproductions.com"]
|
||||
gem.description = %q{TODO: Write a gem description}
|
||||
gem.summary = %q{TODO: Write a gem summary}
|
||||
gem.homepage = ""
|
||||
|
||||
gem.files = `git ls-files`.split($/)
|
||||
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
||||
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
||||
gem.require_paths = ["lib"]
|
||||
|
||||
gem.add_dependency 'nokogiri'
|
||||
gem.add_dependency 'thor'
|
||||
end
|
Loading…
Reference in New Issue
Block a user