prep 0.2.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/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