fn_document 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +20 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/fn_document.gemspec +95 -0
- data/lib/fn/block.rb +27 -0
- data/lib/fn/document.rb +204 -0
- data/lib/fn/migrate.xslt +224 -0
- data/lib/fn/node/base.rb +69 -0
- data/lib/fn/node/context.rb +70 -0
- data/lib/fn/node/root.rb +14 -0
- data/lib/fn/pdf/node/begin_document.rb +22 -0
- data/lib/fn/pdf/node/begin_page_ext.rb +24 -0
- data/lib/fn/pdf/node/create_textflow.rb +137 -0
- data/lib/fn/pdf/node/end_page_ext.rb +22 -0
- data/lib/fn/pdf/node/fit_image.rb +28 -0
- data/lib/fn/pdf/node/fit_pdi_page.rb +26 -0
- data/lib/fn/pdf/node/fit_textflow.rb +27 -0
- data/lib/fn/pdf/node/invert.rb +36 -0
- data/lib/fn/pdf/node/load_image.rb +21 -0
- data/lib/fn/pdf/node/open_pdi.rb +22 -0
- data/lib/fn/pdf/node/open_pdi_page.rb +31 -0
- data/lib/fn/pdf/node/resume_page.rb +21 -0
- data/lib/fn/pdf/node/set_parameter.rb +22 -0
- data/lib/fn/pdf/node/watermark.rb +24 -0
- data/lib/fn/pdf/struct.rb +40 -0
- data/lib/fn/pdf/writer.rb +205 -0
- data/lib/fn/resource.rb +53 -0
- data/lib/fn/swf/node/break.rb +19 -0
- data/lib/fn/swf/node/flash.rb +24 -0
- data/lib/fn/swf/node/font.rb +24 -0
- data/lib/fn/swf/node/frame.rb +19 -0
- data/lib/fn/swf/node/hot_spot.rb +43 -0
- data/lib/fn/swf/node/image.rb +19 -0
- data/lib/fn/swf/node/page.rb +30 -0
- data/lib/fn/swf/node/photo_block.rb +53 -0
- data/lib/fn/swf/node/text.rb +51 -0
- data/lib/fn/swf/struct.rb +43 -0
- data/lib/fn/swf/writer.rb +89 -0
- data/lib/fn/util.rb +27 -0
- data/lib/fn/validation.rng +172 -0
- data/lib/fn_document.rb +3 -0
- data/test/helper.rb +18 -0
- data/test/test_fn_document.rb +7 -0
- metadata +150 -0
data/lib/fn/resource.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/util"
|
2
|
+
|
3
|
+
class String
|
4
|
+
def starts_with?(other)
|
5
|
+
head = self[0, other.length]
|
6
|
+
head == other
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module FN
|
11
|
+
class Resource
|
12
|
+
include Util
|
13
|
+
attr_reader :node
|
14
|
+
|
15
|
+
def initialize(node)
|
16
|
+
raise_unless_xml_node node
|
17
|
+
@node = node
|
18
|
+
end
|
19
|
+
|
20
|
+
def complete?
|
21
|
+
!@node.children.empty?
|
22
|
+
end
|
23
|
+
|
24
|
+
def manual?
|
25
|
+
!!@node["manual"]
|
26
|
+
end
|
27
|
+
|
28
|
+
def path=(p)
|
29
|
+
@node.children.each{|c| c.remove! }
|
30
|
+
@node << p.to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
def path
|
34
|
+
@node.first? && @node.first.to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
def path_from(root)
|
38
|
+
File.expand_path("#{root}#{path}")
|
39
|
+
end
|
40
|
+
|
41
|
+
def key
|
42
|
+
@node["id"]
|
43
|
+
end
|
44
|
+
|
45
|
+
def type
|
46
|
+
@node["type"]
|
47
|
+
end
|
48
|
+
|
49
|
+
def delete
|
50
|
+
@node.remove!
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../../node/base"
|
2
|
+
module FN
|
3
|
+
module SWF
|
4
|
+
module Node
|
5
|
+
def Break
|
6
|
+
FN::Node::Base("break").extend(Break)
|
7
|
+
end
|
8
|
+
|
9
|
+
module Break
|
10
|
+
include FN::Node::Base
|
11
|
+
|
12
|
+
def visit(struct)
|
13
|
+
has_no_children
|
14
|
+
struct.break
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../../node/base"
|
2
|
+
module FN
|
3
|
+
module SWF
|
4
|
+
module Node
|
5
|
+
def Flash(width, height)
|
6
|
+
FN::Node::Base("flash", :width => width, :height => height).extend(Flash)
|
7
|
+
end
|
8
|
+
|
9
|
+
module Flash
|
10
|
+
include FN::Node::Base
|
11
|
+
|
12
|
+
def visit(struct)
|
13
|
+
w = self[:width]
|
14
|
+
h = self[:height]
|
15
|
+
size = "#{w}x#{h}"
|
16
|
+
struct.<< %[.flash bbox="#{size}" compress version=6] do
|
17
|
+
struct.<< %[.box bkg width=#{w} height=#{h} color=white fill]
|
18
|
+
visit_children struct
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../../node/base"
|
2
|
+
module FN
|
3
|
+
module SWF
|
4
|
+
module Node
|
5
|
+
|
6
|
+
def Font(name, file)
|
7
|
+
FN::Node::Base("font", :name => name, :file => file).extend(Font)
|
8
|
+
end
|
9
|
+
|
10
|
+
module Font
|
11
|
+
include FN::Node::Base
|
12
|
+
|
13
|
+
def self.load_all_variants(key, path)
|
14
|
+
# no-op, since at present, we aren't using custom fonts?!
|
15
|
+
end
|
16
|
+
|
17
|
+
def visit(struct)
|
18
|
+
has_no_children
|
19
|
+
struct << %[.font #{self[:name]} "#{self[:file]}"]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../../node/base"
|
2
|
+
module FN
|
3
|
+
module SWF
|
4
|
+
module Node
|
5
|
+
def Frame(name, file)
|
6
|
+
FN::Node::Base("frame", :name => name, :file => file).extend(Frame)
|
7
|
+
end
|
8
|
+
|
9
|
+
module Frame
|
10
|
+
include FN::Node::Base
|
11
|
+
|
12
|
+
def visit(struct)
|
13
|
+
has_no_children
|
14
|
+
struct << %[.font #{self[:name]} "#{self[:file]}"]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../../node/base"
|
2
|
+
module FN
|
3
|
+
module SWF
|
4
|
+
module Node
|
5
|
+
def HotSpot(page)
|
6
|
+
x, y, x2, y2 = page[:hotspot].gsub(/\s/, '').split(",").map{|s| s.to_i}
|
7
|
+
w = x2 - x
|
8
|
+
h = y2 - y
|
9
|
+
FN::Node::Base("hot_spot", :x => x, :y => y, :w => w, :h => h, :n => page[:number]).extend(HotSpot)
|
10
|
+
end
|
11
|
+
|
12
|
+
module HotSpot
|
13
|
+
include FN::Node::Base
|
14
|
+
|
15
|
+
def visit(struct)
|
16
|
+
has_no_children
|
17
|
+
|
18
|
+
x = self[:x]
|
19
|
+
y = self[:y]
|
20
|
+
w = self[:w]
|
21
|
+
h = self[:h]
|
22
|
+
n = self[:n]
|
23
|
+
|
24
|
+
struct << ".box btni#{n} width=#{w} height=#{h} color=red fill=white"
|
25
|
+
|
26
|
+
struct.<< ".button btn#{n}" do
|
27
|
+
struct.<< ".show btni#{n} as=area", :no_end_tag do
|
28
|
+
struct.<< ".on_release:" do
|
29
|
+
struct << "gotoAndStop(#{n});"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
struct.<< ".action:" do
|
35
|
+
struct << "_root.attachMovie('btn#{n}', 'btni#{n}', #{$depth+=1}, {_x:#{x}, _y:#{y}});"
|
36
|
+
struct << "_root['btni#{n}']._x = #{x};"
|
37
|
+
struct << "_root['btni#{n}']._y = #{y};"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../../node/base"
|
2
|
+
module FN
|
3
|
+
module SWF
|
4
|
+
module Node
|
5
|
+
def Image(name, file)
|
6
|
+
FN::Node::Base("image", :name => name, :file => file).extend(Image)
|
7
|
+
end
|
8
|
+
|
9
|
+
module Image
|
10
|
+
include FN::Node::Base
|
11
|
+
|
12
|
+
def visit(struct)
|
13
|
+
has_no_children
|
14
|
+
struct << %[.jpeg #{self[:name]} "#{self[:file]}"]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../../node/base"
|
2
|
+
module FN
|
3
|
+
module SWF
|
4
|
+
module Node
|
5
|
+
|
6
|
+
def Page(number, bkg)
|
7
|
+
FN::Node::Base("page", :number => number, :bkg => bkg).extend(Page)
|
8
|
+
end
|
9
|
+
|
10
|
+
module Page
|
11
|
+
include FN::Node::Base
|
12
|
+
|
13
|
+
def visit(struct)
|
14
|
+
n = self[:number]
|
15
|
+
bkg = self[:bkg]
|
16
|
+
struct << ".frame #{n}"
|
17
|
+
struct.<< ".sprite page#{n}" do
|
18
|
+
struct << ".put bkg 0 0"
|
19
|
+
struct << ".put #{bkg} x=0 y=0"
|
20
|
+
visit_children(struct)
|
21
|
+
end
|
22
|
+
struct << ".put page#{n} 0 00"
|
23
|
+
struct.<< ".action:" do
|
24
|
+
struct << "stop();"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../../node/base"
|
2
|
+
module FN
|
3
|
+
module SWF
|
4
|
+
module Node
|
5
|
+
|
6
|
+
def PhotoBlock(node, image_dims = {})
|
7
|
+
dims = image_dims[node[:src]]
|
8
|
+
FN::Node::Base("photo_block", node.attributes.to_h.update(
|
9
|
+
:orig_width => dims[0],
|
10
|
+
:orig_height => dims[1]
|
11
|
+
)).extend(PhotoBlock)
|
12
|
+
end
|
13
|
+
|
14
|
+
module PhotoBlock
|
15
|
+
include FN::Node::Base
|
16
|
+
|
17
|
+
# <block type="photo" src="logo" width="162" boxX="30" boxY="40"
|
18
|
+
# boxWidth="185" boxHeight="99" align="middlecenter"/>
|
19
|
+
def visit(struct)
|
20
|
+
has_no_children
|
21
|
+
|
22
|
+
src = self[:src]
|
23
|
+
bx = self[:boxX].to_i
|
24
|
+
by = self[:boxY].to_i
|
25
|
+
bw = self[:boxWidth].to_i
|
26
|
+
bh = self[:boxHeight].to_i
|
27
|
+
w = self[:width].to_i
|
28
|
+
ow = self[:orig_width].to_i
|
29
|
+
oh = self[:orig_height].to_i
|
30
|
+
align = self[:align]
|
31
|
+
|
32
|
+
scale = w.to_f / ow
|
33
|
+
percent = "#{scale * 100}%"
|
34
|
+
h = ow * scale
|
35
|
+
|
36
|
+
x = case align
|
37
|
+
when /center/: bx + (bw - w) / 2.0;
|
38
|
+
when /right/: bx + (bw - w)
|
39
|
+
else; bx
|
40
|
+
end
|
41
|
+
|
42
|
+
y = case align
|
43
|
+
when /middle/: by + (bh - h) / 2.0;
|
44
|
+
when /bottom/: by + (bh - h)
|
45
|
+
else; by
|
46
|
+
end
|
47
|
+
|
48
|
+
struct << ".put #{src} x=#{x} y=#{y} scalex=#{percent} scaley=#{percent}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../../node/base"
|
2
|
+
module FN
|
3
|
+
module SWF
|
4
|
+
module Node
|
5
|
+
def Text(node, alt_text)
|
6
|
+
out = FN::Node::Base("text", node.attributes.to_h)
|
7
|
+
out.extend(Text)
|
8
|
+
out.text = node.children.to_s
|
9
|
+
out.text = alt_text if out.text.empty?
|
10
|
+
out
|
11
|
+
end
|
12
|
+
|
13
|
+
module Text
|
14
|
+
include FN::Node::Base
|
15
|
+
SPACE = /\s+/
|
16
|
+
|
17
|
+
def text
|
18
|
+
(child && child.content).to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
def text=(s)
|
22
|
+
self.children.map{|c| c.remove! }
|
23
|
+
self << XML::Node.new_cdata(s)
|
24
|
+
end
|
25
|
+
|
26
|
+
def escaped_text
|
27
|
+
text.gsub("\\", "\\\\").gsub("\"", "\\\"").gsub(SPACE, " ")
|
28
|
+
end
|
29
|
+
|
30
|
+
def visit(struct)
|
31
|
+
has_no_children
|
32
|
+
name = "#{self[:text]}_#{self[:index]}"
|
33
|
+
x = self[:x]
|
34
|
+
y = self[:y]
|
35
|
+
w = self[:width]
|
36
|
+
h = self[:height].to_i + 20 # Fudge
|
37
|
+
|
38
|
+
struct.<< ".action:" do
|
39
|
+
struct << "this.createTextField('#{name}', #{$depth+=1}, #{x}, #{y}, #{w}, #{h});"
|
40
|
+
struct << "id = this['#{name}'];"
|
41
|
+
struct << "id.html=true;"
|
42
|
+
struct << "id.multiline=true;"
|
43
|
+
struct << "id.wordWrap=true;"
|
44
|
+
struct << "id.htmlText = \"#{escaped_text}\";"
|
45
|
+
struct << "id.selectable = false;"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module FN
|
2
|
+
module SWF
|
3
|
+
class Struct < Hash
|
4
|
+
TAB = " "
|
5
|
+
|
6
|
+
attr_reader :buffer
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@buffer = ""
|
10
|
+
@indent_level = 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def break
|
14
|
+
self << ""
|
15
|
+
end
|
16
|
+
|
17
|
+
def <<(s, omit_end_tag = false, &b)
|
18
|
+
@buffer << "#{tabs}#{s}\n"
|
19
|
+
if block_given?
|
20
|
+
indent(&b)
|
21
|
+
@buffer << "#{tabs}.end\n" unless omit_end_tag
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def tabs
|
26
|
+
TAB * @indent_level
|
27
|
+
end
|
28
|
+
|
29
|
+
def indent
|
30
|
+
@indent_level += 1
|
31
|
+
if block_given?
|
32
|
+
yield
|
33
|
+
@indent_level -= 1
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def undent
|
38
|
+
@indent_level -= 1
|
39
|
+
raise "can't indent < 0" if @indent_level < 0
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
Dir[File.dirname(__FILE__) + "/**/*.rb"].each do |f|
|
2
|
+
require_dependency f.sub(/\.rb$/, '')
|
3
|
+
end
|
4
|
+
|
5
|
+
module FN
|
6
|
+
module SWF
|
7
|
+
class Writer
|
8
|
+
include FN::SWF::Node
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
end
|
12
|
+
|
13
|
+
def image_dimensions(image)
|
14
|
+
img = `identify "#{image}"`.scan(/ JPEG (\d+)x(\d+)/).flatten.map{|a|a.to_i}
|
15
|
+
end
|
16
|
+
|
17
|
+
def write(doc, options = {})
|
18
|
+
write_xml translate(doc, options), options[:save_as]
|
19
|
+
end
|
20
|
+
|
21
|
+
def write_xml(xml, file)
|
22
|
+
xml.root.extend(FN::Node::Root)
|
23
|
+
File.open("#{file}.txt", "w") {|f| f.puts xml.root.visit(FN::SWF::Struct.new).buffer }
|
24
|
+
cmd = %[swfc -o #{file} #{file}.txt]
|
25
|
+
system(cmd) ? file : raise("couldn't write swf")
|
26
|
+
end
|
27
|
+
|
28
|
+
def translate(doc, options = {})
|
29
|
+
raise "Not an FN Document" unless doc.is_a?(FN::Document)
|
30
|
+
|
31
|
+
file = options[:save_as] or raise "must provide :save_as"
|
32
|
+
root = options[:resource_root]
|
33
|
+
|
34
|
+
context = FN::Node::Context.new
|
35
|
+
$depth = 500
|
36
|
+
|
37
|
+
page = doc.pages.first
|
38
|
+
context << Flash(page[:width], page[:height])
|
39
|
+
|
40
|
+
# sorta no-op-ish
|
41
|
+
# doc.fonts.each do |font|
|
42
|
+
# context.add Font.load_all_variants(font.key, font.path_from(root))
|
43
|
+
# end
|
44
|
+
|
45
|
+
global_texts = doc.textflows.inject({}) do |memo, node|
|
46
|
+
memo[node["id"]] = node.children.to_s
|
47
|
+
memo
|
48
|
+
end
|
49
|
+
|
50
|
+
context.add Break()
|
51
|
+
|
52
|
+
image_dims = {}
|
53
|
+
|
54
|
+
doc.images.each do |img|
|
55
|
+
if img.complete?
|
56
|
+
path = img.path_from(root)
|
57
|
+
context.add Image(img.key, path)
|
58
|
+
image_dims[img.key] = image_dimensions(path)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context.add Break()
|
63
|
+
|
64
|
+
doc.pages.each do |page|
|
65
|
+
context.retain_after do
|
66
|
+
context.pre HotSpot(page)
|
67
|
+
context << Page(page[:number], page[:background])
|
68
|
+
|
69
|
+
doc.text_blocks_by(page["number"]).each do |block|
|
70
|
+
context.add Text(block, global_texts[block["text"]])
|
71
|
+
end
|
72
|
+
|
73
|
+
context.add Break()
|
74
|
+
|
75
|
+
i = 0
|
76
|
+
doc.photo_blocks_by(page["number"]).each do |block|
|
77
|
+
i += 1
|
78
|
+
context.add PhotoBlock(block, image_dims)
|
79
|
+
end
|
80
|
+
|
81
|
+
context.add Break()
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
return context.doc
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|