initial commit, works for crma, now to get working for lyfo

This commit is contained in:
John Bintz 2013-11-09 17:34:27 -05:00
commit 9a071262b2
12 changed files with 459 additions and 0 deletions

17
.gitignore vendored Normal file
View 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
View File

@ -0,0 +1,8 @@
source 'https://rubygems.org'
gemspec
gem 'nokogiri'
gem 'virtus'
gem 'google_drive'
gem 'activesupport'

22
LICENSE.txt Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,3 @@
module Svggvs
VERSION = "0.0.1"
end

22
svggvs.gemspec Normal file
View 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