prep 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/core/page.rb ADDED
@@ -0,0 +1,87 @@
1
+ # Page クラスのソースファイル
2
+ # Author:: maki-tetsu
3
+ # Date:: 2011/03/11
4
+ # Copyright:: Copyright (c) 2011 maki-tetsu
5
+
6
+ require "rubygems"
7
+ gem "hpdf"
8
+ require "hpdf"
9
+
10
+ module PREP # nodoc
11
+ module Core # nodoc
12
+ # ページ設定を保持するクラス
13
+ class Page
14
+ # ページサイズの設定種別
15
+ SIZES = {
16
+ :a4 => HPDFDoc::HPDF_PAGE_SIZE_A4, # A4
17
+ :a3 => HPDFDoc::HPDF_PAGE_SIZE_A3, # A3
18
+ }
19
+
20
+ # ページ方向の設定種別
21
+ ORIENTATIONS = {
22
+ :portrait => HPDFDoc::HPDF_PAGE_PORTRAIT, # 縦
23
+ :landscape => HPDFDoc::HPDF_PAGE_LANDSCAPE, # 横
24
+ }
25
+
26
+ attr_reader :size, :orientation, :margin, :header_height, :footer_height
27
+
28
+ # 初期化
29
+ def initialize
30
+ @size = SIZES[:a4]
31
+ @orientation = ORIENTATIONS[:portrate]
32
+ @margin = {
33
+ :top => 0,
34
+ :left => 0,
35
+ :bottom => 0,
36
+ :right => 0
37
+ }
38
+ @header_height = 0
39
+ @footer_height = 0
40
+ end
41
+
42
+ def size=(size)
43
+ if SIZES.values.include?(size)
44
+ @size = size
45
+ else
46
+ raise "Unknown PAGE SIZE."
47
+ end
48
+ end
49
+
50
+ def orientation=(orientation)
51
+ if ORIENTATIONS.values.include?(orientation)
52
+ @orientation = orientation
53
+ else
54
+ raise "Unknown PAGE ORIENTATION."
55
+ end
56
+ end
57
+
58
+ def margin=(values)
59
+ sym_key_values = values.keys.inject({ }) do |hash, key|
60
+ hash[key.to_sym] = values[key]
61
+ next hash
62
+ end
63
+ if (sym_key_values.keys - @margin.keys).length.zero?
64
+ @margin.merge!(sym_key_values)
65
+ else
66
+ raise "Unknown margin keys (#{(sym_key_values.keys - @margin.keys).join(",")})."
67
+ end
68
+ end
69
+
70
+ def header_height=(height)
71
+ if height >= 0
72
+ @header_height = height
73
+ else
74
+ raise "Invalid header height(#{height})."
75
+ end
76
+ end
77
+
78
+ def footer_height=(height)
79
+ if height >= 0
80
+ @footer_height = height
81
+ else
82
+ raise "Invalid footer height(#{height})."
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,14 @@
1
+ # HPDFPage の拡張
2
+ require "rubygems"
3
+ gem "hpdf"
4
+ require "hpdf"
5
+
6
+ class HPDFPage
7
+ def drawed?
8
+ return !!@drawed
9
+ end
10
+
11
+ def drawed=(flag)
12
+ @drawed = flag
13
+ end
14
+ end
data/lib/core/point.rb ADDED
@@ -0,0 +1,26 @@
1
+ # Point クラスのソースファイル
2
+ # Author:: maki-tetsu
3
+ # Date:: 2011/03/11
4
+ # Copyright:: Copyright (c) 2011 maki-tetsu
5
+
6
+ module PREP # nodoc
7
+ module Core # nodoc
8
+ class Point
9
+ attr_reader :x, :y
10
+
11
+ def initialize(x, y)
12
+ self.x, self.y = x, y
13
+ end
14
+
15
+ def x=(v)
16
+ raise "x cannot be nil." if v.nil?
17
+ @x = v
18
+ end
19
+
20
+ def y=(v)
21
+ raise "y cannot be nil." if v.nil?
22
+ @y = v
23
+ end
24
+ end
25
+ end
26
+ end
data/lib/core/prep.rb ADDED
@@ -0,0 +1,351 @@
1
+ # Prep クラスのソースファイル
2
+ # Author:: maki-tetsu
3
+ # Date:: 2011/03/11
4
+ # Copyright:: Copyright (c) 2011 maki-tetsu
5
+
6
+ require "yaml"
7
+ require "rubygems"
8
+ gem "hpdf"
9
+ require "hpdf"
10
+
11
+ require File.join(File.dirname(__FILE__), "label")
12
+ require File.join(File.dirname(__FILE__), "line")
13
+ require File.join(File.dirname(__FILE__), "rectangle")
14
+ require File.join(File.dirname(__FILE__), "group")
15
+ require File.join(File.dirname(__FILE__), "region")
16
+ require File.join(File.dirname(__FILE__), "page")
17
+ require File.join(File.dirname(__FILE__), "page_ext")
18
+ require File.join(File.dirname(__FILE__), "..", "mm2pixcel")
19
+
20
+ module PREP
21
+ module Core
22
+ # PREP の中心クラス
23
+ class Prep
24
+ attr_reader :pdf, :pages, :page_pos_x, :page_pos_y, :values
25
+
26
+ # 初期化
27
+ #
28
+ # 設定ファイルのパスが与えられれば初期化
29
+ # 無ければブランクの設定をロード
30
+ def initialize(configuration_file_path = nil)
31
+ if configuration_file_path
32
+ if File.exists?(configuration_file_path)
33
+ load_configuration(configuration_file_path)
34
+ else
35
+ raise "File not found \"#{configuration_file_path}\"."
36
+ end
37
+ else
38
+ init_configuration
39
+ end
40
+ end
41
+
42
+ # データセット雛形を生成して返却
43
+ def generate_sample_dataset
44
+ # ヘッダのデータセット生成
45
+ dataset = { }
46
+ if @content.has_identifier?(:header)
47
+ dataset[:header] = @content[:header].generate_sample_dataset(self)
48
+ end
49
+ dataset[:content] = @content[:content].generate_sample_dataset(self)
50
+ if @content.has_identifier?(:footer)
51
+ dataset[:footer] = @content[:footer].generate_sample_dataset(self)
52
+ end
53
+
54
+ return dataset
55
+ end
56
+
57
+ # 帳票の生成
58
+ def generate(output_file_path, values = { })
59
+ # 再描画用に初期値を保持
60
+ @values = values.dup
61
+ @pdf = HPDFDoc.new
62
+ # 日本語対応
63
+ @pdf.use_jp_fonts
64
+ @pdf.use_jp_encodings
65
+ # ページの初期化
66
+ initialize_pages
67
+
68
+ draw_contents(values)
69
+ draw_headers(values)
70
+ draw_footers(values)
71
+
72
+ # 指定されたファイルへの書込
73
+ @pdf.save_to_file(output_file_path)
74
+ rescue => e
75
+ @pdf.save_to_file(output_file_path) if ENV["DEBUG"]
76
+ puts "Error occured!!\n#{e}"
77
+ raise e
78
+ end
79
+
80
+ # ページの初期化
81
+ def initialize_pages
82
+ # 一次元配列
83
+ @pages = []
84
+ # 二次元配列
85
+ @flat_pages = []
86
+ # ページの作成
87
+ page = generate_page
88
+ # 1ページ目の登録
89
+ @pages << page
90
+ @flat_pages = [[page]] # [0][0] 位置への追加
91
+ # 現在のページの位置情報を初期化
92
+ @page_pos_x, @page_pos_y = 0, 0
93
+
94
+ return page
95
+ end
96
+
97
+ # コンテンツの埋め込み
98
+ def draw_contents(values)
99
+ content = @content[:content]
100
+
101
+ # 描画領域を含めて描画開始
102
+ content.draw(self, page_content_region, values[:content])
103
+ end
104
+
105
+ # ヘッダの埋め込み
106
+ def draw_headers(values)
107
+ return unless @content.has_identifier?(:header)
108
+
109
+ header = @content[:header]
110
+
111
+ # 全てのページに対してインデックスを切り替えながら実行
112
+ @flat_pages.each_with_index do |row_pages, y|
113
+ row_pages.each_with_index do |page, x|
114
+ self.current_page = { :x => x, :y => y }
115
+ header.draw(self, page_header_region, values[:header])
116
+ end
117
+ end
118
+ end
119
+
120
+ # フッタの埋め込み
121
+ def draw_footers(values)
122
+ return unless @content.has_identifier?(:footer)
123
+
124
+ footer = @content[:footer]
125
+
126
+ # 全てのページに対してインデックスを切り替えながら実行
127
+ @flat_pages.each_with_index do |row_pages, y|
128
+ row_pages.each_with_index do |page, x|
129
+ self.current_page = { :x => x, :y => y }
130
+ footer.draw(self, page_footer_region, values[:footer])
131
+ end
132
+ end
133
+ end
134
+
135
+ # ページの移動および追加
136
+ #
137
+ # 指定された位置への移動に際してページが存在しなければページを追加
138
+ def move_page_to(x, y)
139
+ puts "[#{@page_pos_x}:#{@page_pos_y}] => [#{@page_pos_x + x}:#{@page_pos_y + y}]" if ENV["DEBUG"]
140
+ @page_pos_x, @page_pos_y = @page_pos_x + x, @page_pos_y + y
141
+
142
+ @flat_pages[@page_pos_y] ||= []
143
+ if @flat_pages[@page_pos_y][@page_pos_x].nil?
144
+ @flat_pages[@page_pos_y][@page_pos_x] = (page = generate_page)
145
+ @pages << page
146
+ end
147
+
148
+ print_flat_pages if ENV["DEBUG"]
149
+
150
+ return @flat_pages[@page_pos_y][@page_pos_x]
151
+ end
152
+
153
+ # 移動先のページが存在するかどうかをチェック
154
+ def exists_move_to_page?(x, y)
155
+ x += @page_pos_x
156
+ y += @page_pos_y
157
+
158
+ return exists_and_drawed_page?(x, y)
159
+ end
160
+
161
+ # 指定されたページが存在するかどうかをチェック
162
+ def exists_page?(x, y)
163
+ if @flat_pages[y].nil?
164
+ return false
165
+ elsif @flat_pages[y][x].nil?
166
+ return false
167
+ else
168
+ return true
169
+ end
170
+ end
171
+
172
+ # 指定されたページが存在し描画済みであるかどうかをチェック
173
+ def exists_and_drawed_page?(x, y)
174
+ if exists_page?(x, y)
175
+ return @flat_pages[y][x].drawed?
176
+ else
177
+ return false
178
+ end
179
+ end
180
+
181
+ # ページオブジェクトの作成とページ設定
182
+ def generate_page
183
+ page = @pdf.add_page
184
+ page.set_size(@page_config.size, @page_config.orientation)
185
+
186
+ return page
187
+ end
188
+
189
+ # 現在の総ページ数を返却
190
+ def total_pages
191
+ return @pages.size
192
+ end
193
+
194
+ # 現在描画中のページインスタンスを返却
195
+ def current_page
196
+ return @flat_pages[@page_pos_y][@page_pos_x]
197
+ end
198
+
199
+ # 現在の通しページ番号を返却
200
+ def current_page_number
201
+ @pages.each_with_index do |page, index|
202
+ if page === current_page
203
+ return index + 1
204
+ end
205
+ end
206
+ raise "Unknown Page instance \"#{page}\"."
207
+ end
208
+
209
+ # 現在のページを強制的に変更
210
+ #
211
+ # 存在しないページへの移動は不可(例外)
212
+ # 引数の形式はハッシュ: Ex.) { :x => 0, :y => 0 }
213
+ def current_page=(pos)
214
+ if exists_page?(pos[:x], pos[:y])
215
+ puts "[#{@page_pos_x}:#{@page_pos_y}] => [#{pos[:x]}:#{pos[:y]}]" if ENV["DEBUG"]
216
+ @page_pos_x, @page_pos_y = pos[:x], pos[:y]
217
+ print_flat_pages if ENV["DEBUG"]
218
+ return current_page
219
+ else
220
+ print_flat_pages if ENV["DEBUG"]
221
+ raise "Unknown page index [#{pos[:x]},#{pos[:y]}]."
222
+ end
223
+ end
224
+
225
+ # ページ構成を模式印字するデバッグ用メソッド
226
+ def print_flat_pages
227
+ @flat_pages.each_with_index do |flat_page, y|
228
+ flat_page.each_with_index do |one_page, x|
229
+ char = one_page.nil? ? "?" : "."
230
+ if x == page_pos_x && y == page_pos_y
231
+ char = '!'
232
+ end
233
+ STDERR.write("[#{char}]")
234
+ end
235
+ STDERR.write("\n")
236
+ end
237
+ gets if ENV["DEBUG"]
238
+ end
239
+
240
+ # コンテンツ描画領域の取得
241
+ def page_content_region
242
+ # 全体の描画領域を取得
243
+ width = current_page.get_width
244
+ height = current_page.get_height
245
+ x = 0
246
+ y = 0
247
+ # マージンを含める
248
+ x += @page_config.margin[:left]
249
+ width -= (@page_config.margin[:left] + @page_config.margin[:right])
250
+ y += @page_config.margin[:top]
251
+ height -= (@page_config.margin[:top] + @page_config.margin[:bottom])
252
+ # ヘッダ、および、フッタ領域を含める
253
+ y += @page_config.header_height
254
+ height -= (@page_config.header_height + @page_config.footer_height)
255
+
256
+ return Region.new(x, y, width, height)
257
+ end
258
+
259
+ # ヘッダ領域の取得
260
+ def page_header_region
261
+ # 全体の描画領域を取得
262
+ width = current_page.get_width
263
+ height = current_page.get_height
264
+ x = 0
265
+ y = 0
266
+ # マージンを含める
267
+ x += @page_config.margin[:left]
268
+ width -= (@page_config.margin[:left] + @page_config.margin[:right])
269
+ y += @page_config.margin[:top]
270
+ # 高さをヘッダ領域に変更
271
+ height = @page_config.header_height
272
+
273
+ return Region.new(x, y, width, height)
274
+ end
275
+
276
+ # フッタ領域の取得
277
+ def page_footer_region
278
+ # 全体の描画領域を取得
279
+ width = current_page.get_width
280
+ height = current_page.get_height
281
+ x = 0
282
+ y = current_page.get_height
283
+ # マージンを含める
284
+ x += @page_config.margin[:left]
285
+ width -= (@page_config.margin[:left] + @page_config.margin[:right])
286
+ # 高さをフッタ領域に変更
287
+ height = @page_config.footer_height
288
+ # フッタの開始 Y 座標を計算
289
+ y -= (@page_config.margin[:bottom] + height)
290
+
291
+ return Region.new(x, y, width, height)
292
+ end
293
+
294
+ # 設定の初期化
295
+ def init_configuration
296
+ raise "Need configuration file!"
297
+ end
298
+
299
+ # 設定ファイルのロード
300
+ def load_configuration(configuration_file_path)
301
+ # YAML からハッシュ形式に変換
302
+ config_values = YAML.load_file(configuration_file_path)
303
+
304
+ # ページ設定情報を取り込み
305
+ @page_config = Page.new
306
+ if config_values["page"]
307
+ values = config_values["page"]
308
+ if !values["size"].nil? && values["size"] != ""
309
+ @page_config.size = Page::SIZES[values["size"].to_sym]
310
+ end
311
+ if !values["orientation"].nil? && values["orientation"] != ""
312
+ @page_config.orientation = Page::ORIENTATIONS[values["orientation"].to_sym]
313
+ end
314
+ if !values["margin"].nil?
315
+ margin_values = values["margin"].keys.inject({ }) do |hash, key|
316
+ hash[key.to_sym] = values["margin"][key].mm2pixcel
317
+ next hash
318
+ end
319
+ @page_config.margin = margin_values
320
+ end
321
+ if !values["header_height"].nil?
322
+ @page_config.header_height = values["header_height"].mm2pixcel
323
+ end
324
+ if !values["footer_height"].nil?
325
+ @page_config.footer_height = values["footer_height"].mm2pixcel
326
+ end
327
+ end
328
+
329
+ # コンテンツ定義情報を読み込む
330
+ # page 以外について読み込みを実施
331
+ @content = Group.new
332
+ config_values.keys.each do |identifier|
333
+ unless identifier == "page"
334
+ @content.add_drawable(identifier, config_values[identifier], true)
335
+ end
336
+ end
337
+ end
338
+
339
+ # 指定されたグループ識別子を検索して返却
340
+ # 存在しない場合は例外発生
341
+ def group(group_identifiy)
342
+ return @content[group_identifiy]
343
+ end
344
+
345
+ # 指定されたグループ識別子の存在確認
346
+ def has_group?(group_identifiy)
347
+ return @content.drawables.has_key?(group_identifiy.to_sym)
348
+ end
349
+ end
350
+ end
351
+ end