mork 0.0.3 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cf9368eb34bdddb744f80f7baa1475ba03aedeab
4
- data.tar.gz: 129f95cfa8329b81154186ec175f0b14a9ba3b72
3
+ metadata.gz: 74b53c108c7a1ae34a090aac3b9380805326ee01
4
+ data.tar.gz: f34f58ad865ffc0995cf51a21e0c2c163b4f8e27
5
5
  SHA512:
6
- metadata.gz: 82652798819ce990be08645e337199cc19ce8829bbda397212e958f17f6df3d865c62ab86d80eda12340250cd8f7ac09791b9c7f8a68c9ca060b13c88ff2e9c3
7
- data.tar.gz: e733b22b1de5c615982da5c8725c04877654d297584a4677c5194aad2cf66c94074171abf4f7dd8a01ee82d5e62ef30c6d0c69f7b594667297ffd563cfde4a03
6
+ metadata.gz: 55f9f4dff569c87008aa9e15a4029172258d0c3998746700188f440695ece40948a0b529d21a3512dd632537cfc123ee8730e8bfb99b7dd31a6c708150f742a4
7
+ data.tar.gz: 68b53cf1ab3b9adc014b8da070da4e8d16b8706eb3754f735fa596b8025f6b720b803d8a225efacd1db2d9922b1ba98ae1cba2712b714de694c67b9d1c5f6d6c
data/Guardfile CHANGED
@@ -3,8 +3,8 @@ guard 'rspec', all_after_pass: false do
3
3
  watch(%r{^lib/mork/(.+)\.rb$}) { |m| "spec/mork/#{m[1]}_spec.rb" }
4
4
  end
5
5
 
6
- guard :shell do
7
- watch "tmp/code_sample.pdf" do
8
- system "open tmp/code_sample.pdf"
9
- end
10
- end
6
+ # guard :shell do
7
+ # watch "tmp/code_sample.pdf" do
8
+ # system "open tmp/code_sample.pdf"
9
+ # end
10
+ # end
data/lib/mork/grid.rb CHANGED
@@ -6,10 +6,19 @@ module Mork
6
6
  # All returned values are in the arbitrary units given in the configuration file
7
7
  class Grid
8
8
 
9
- def initialize(type = :default, fname="config/grids.yml")
10
- # from the full YAML file, only get the requested grid type
11
- c = YAML.load_file(fname)
12
- @params = c[type.to_s]
9
+ def initialize(options = {})
10
+ case options.class.to_s
11
+ when "Hash"
12
+ @params = DGRID.merge! options
13
+ when "String"
14
+ @params = DGRID.merge! YAML.load_file(options)
15
+ else
16
+ raise "Invalid options parameter: #{options.class.inspect}"
17
+ end
18
+ end
19
+
20
+ def options
21
+ @params
13
22
  end
14
23
 
15
24
  def set_page_size(x, y)
@@ -17,59 +26,47 @@ module Mork
17
26
  @py = y.to_f
18
27
  end
19
28
 
20
- def default_chlist
21
- [@params["responses"]["max_cells"]] * max_questions
22
- end
23
-
24
29
  def max_questions
25
30
  columns * rows
26
31
  end
27
32
 
28
33
  def max_choices_per_question
29
- @params["responses"]["max_cells"]
34
+ @params[:responses][:max_cells]
30
35
  end
31
36
 
32
37
  def code_bits
33
- CODE_BITS
38
+ @params[:code][:bits].to_i
34
39
  end
35
40
 
36
- def header
37
- @params["header"]
41
+ # ====================================================
42
+ # = Returning {x, y, w, h} hashes for area locations =
43
+ # ====================================================
44
+ def reg_mark_tl_search_area
45
+ reg_mark_search_area 0, 0
38
46
  end
39
47
 
40
- def reg_mark_search_area(n)
41
- rmp = REG_MARGIN + REG_SEARCH
42
- rmm = REG_MARGIN - REG_SEARCH
43
- case n
44
- when :top_left
45
- reg_mark_sa rmm, rmm
46
- when :top_right
47
- reg_mark_sa page_width - rmp, rmm
48
- when :bottom_right
49
- reg_mark_sa page_width - rmp, page_height - rmp
50
- when :bottom_left
51
- reg_mark_sa rmm, page_height - rmp
52
- end
48
+ def reg_mark_tr_search_area
49
+ reg_mark_search_area page_width - reg_search, 0
53
50
  end
54
-
55
- def reg_mark_sa(x, y)
56
- cw = @px / page_width
57
- ch = @py / page_height
58
- {
59
- x: (cw * x).round,
60
- y: (ch * y).round,
61
- w: (cw * REG_SEARCH * 2).round,
62
- h: (ch * REG_SEARCH * 2).round
63
- }
51
+
52
+ def reg_mark_br_search_area
53
+ reg_mark_search_area page_width - reg_search, page_height - reg_search
64
54
  end
65
-
55
+
56
+ def reg_mark_bl_search_area
57
+ reg_mark_search_area 0, page_height - reg_search
58
+ end
59
+
66
60
  def choice_cell_area(q, c)
67
- {
68
- x: (cx * cell_x(q, c)).round,
69
- y: (cy * cell_y(q) ).round,
70
- w: (cx * cell_width ).round,
71
- h: (cy * cell_height ).round
72
- }
61
+ cell_area cell_x(q, c), cell_y(q)
62
+ end
63
+
64
+ def dark_control_cell_area
65
+ cell_area ctrl_cell_left, ctrl_cell_y
66
+ end
67
+
68
+ def light_control_cell_area
69
+ cell_area ctrl_cell_left + cell_spacing, ctrl_cell_y
73
70
  end
74
71
 
75
72
  def white_calibration_area
@@ -92,11 +89,11 @@ module Mork
92
89
  end
93
90
 
94
91
  def pdf_margins
95
- REG_MARGIN.mm
92
+ reg_margin.mm
96
93
  end
97
94
 
98
95
  def pdf_reg_marks
99
- r = REG_RADIUS.mm
96
+ r = @params[:regmarks][:radius].to_f.mm
100
97
  [
101
98
  { p: [0, 0 ], r: r },
102
99
  { p: [0, reg_frame_height.mm], r: r },
@@ -111,14 +108,14 @@ module Mork
111
108
 
112
109
  def pdf_code_areas_for(code)
113
110
  a = []
114
- CODE_BITS.times do |bit|
111
+ code_bits.times do |bit|
115
112
  a << pdf_code_cell_area(bit+1) if code[bit] == 1
116
113
  end
117
114
  a
118
115
  end
119
116
 
120
117
  def pdf_code_bit_areas
121
- (1..CODE_BITS).collect do |bit|
118
+ (1..code_bits).collect do |bit|
122
119
  pdf_code_cell_area bit
123
120
  end
124
121
  end
@@ -126,8 +123,8 @@ module Mork
126
123
  def pdf_code_cell_area(i)
127
124
  {
128
125
  p: [code_cell_x(i).mm, (reg_frame_height - code_y).mm],
129
- w: CODE_WIDTH.mm,
130
- h: CODE_HEIGHT.mm * 2
126
+ w: code_width.mm,
127
+ h: code_height.mm * 2
131
128
  }
132
129
  end
133
130
 
@@ -142,25 +139,33 @@ module Mork
142
139
  def pdf_choice_letter_xy(q, c)
143
140
  [
144
141
  cell_x(q, c).mm + 2.mm,
145
- (reg_frame_height - cell_y(q)).mm - 3.mm
142
+ (reg_frame_height - cell_y(q)).mm - (cell_height*2)
146
143
  ]
147
144
  end
148
145
 
149
146
  def pdf_qnum_xy(q)
150
147
  [
151
- cell_x(q, 0).mm - pdf_qnum_width - Q_NUM_GAP.mm,
152
- (reg_frame_height - cell_y(q)).mm - 0.5.mm
148
+ cell_x(q, 0).mm - pdf_qnum_width - @params[:responses][:number_margin].to_f.mm,
149
+ (reg_frame_height - cell_y(q)).mm - cell_height
153
150
  ]
154
151
  end
152
+
153
+ def pdf_qnum_size
154
+ @params[:responses][:number_size].to_f
155
+ end
156
+
157
+ def pdf_chlett_size
158
+ @params[:responses][:letter_size].to_f
159
+ end
155
160
 
156
161
  def pdf_qnum_width
157
- Q_NUM_WIDTH.mm
162
+ @params[:responses][:number_width].to_f.mm
158
163
  end
159
164
 
160
165
  def pdf_header_xy(k)
161
166
  [
162
- header[k.to_s]["left"].to_f.mm,
163
- (reg_frame_height - header[k.to_s]["top"].to_f).mm
167
+ @params[:header][k][:left].to_f.mm,
168
+ (reg_frame_height - @params[:header][k][:top].to_f).mm
164
169
  ]
165
170
  end
166
171
 
@@ -169,23 +174,69 @@ module Mork
169
174
  1.mm,
170
175
  pdf_header_height(k) - 1.mm
171
176
  ]
172
-
173
177
  end
174
178
 
175
179
  def pdf_header_width(k)
176
- header[k.to_s]["width"].to_f.mm
180
+ @params[:header][k][:width].to_f.mm
177
181
  end
178
182
 
179
183
  def pdf_header_height(k)
180
- header[k.to_s]["height"].to_f.mm
184
+ @params[:header][k][:height].to_f.mm
181
185
  end
182
186
 
183
187
  def pdf_header_size(k)
184
- header[k.to_s]["size"].to_f
188
+ @params[:header][k][:size].to_f
185
189
  end
186
190
 
187
191
  def pdf_header_boxed?(k)
188
- header[k.to_s]["box"] == true
192
+ @params[:header][k][:box] == true
193
+ end
194
+
195
+ def pdf_dark_control_cell_area
196
+ {
197
+ p: [pdf_control_xy[0]+pdf_control_width+ctrl_margin.mm, pdf_control_xy[1]],
198
+ w: cell_width.mm,
199
+ h: cell_height.mm
200
+ }
201
+ end
202
+
203
+ def pdf_light_control_cell_area
204
+ {
205
+ p: [cell_spacing.mm + pdf_control_xy[0]+pdf_control_width+@params[:control][:margin].to_f.mm, pdf_control_xy[1]],
206
+ w: cell_width.mm,
207
+ h: cell_height.mm
208
+ }
209
+ end
210
+
211
+ def pdf_dark_control_letter_xy
212
+ xy = pdf_dark_control_cell_area[:p]
213
+ [
214
+ xy[0] + 2.mm,
215
+ xy[1] - 4.mm
216
+ ]
217
+ end
218
+
219
+ def pdf_light_control_letter_xy
220
+ xy = pdf_light_control_cell_area[:p]
221
+ [
222
+ xy[0] + 2.mm,
223
+ xy[1] - 4.mm
224
+ ]
225
+ end
226
+
227
+ def pdf_control_width
228
+ @params[:control][:width].to_f.mm
229
+ end
230
+
231
+ def pdf_control_xy
232
+ [
233
+ @params[:control][:left].to_f.mm,
234
+ (reg_frame_height - ctrl_cell_y).mm
235
+ ]
236
+ end
237
+
238
+ def pdf_control_size
239
+ @params[:control][:size]
189
240
  end
190
241
 
191
242
  private
@@ -198,12 +249,36 @@ module Mork
198
249
  @py / reg_frame_height
199
250
  end
200
251
 
201
- # x, y = cell_xy(q,c)
202
- #
203
- # the distances from the registration frame of the left and top edges
204
- # of the c-th choice cell of the q-th question
205
- def cell_xy(q, c)
206
- return cell_x(q, c), cell_y(q)
252
+ def cw
253
+ @px / page_width
254
+ end
255
+
256
+ def ch
257
+ @py / page_height
258
+ end
259
+
260
+ # {} = cell_area(x, y)
261
+ #
262
+ # the 4 values needed to locate a single cell area
263
+ def cell_area(x,y)
264
+ {
265
+ x: (cx * x ).round,
266
+ y: (cy * y ).round,
267
+ w: (cx * cell_width ).round,
268
+ h: (cy * cell_height ).round
269
+ }
270
+ end
271
+
272
+ # {} = reg_mark_search_area(x, y)
273
+ #
274
+ # the 4 values needed to locate a single registration mark
275
+ def reg_mark_search_area(x, y)
276
+ {
277
+ x: (cw * x).round,
278
+ y: (ch * y).round,
279
+ w: (cw * reg_search).round,
280
+ h: (ch * reg_search).round
281
+ }
207
282
  end
208
283
 
209
284
  # cell_y(q)
@@ -222,46 +297,6 @@ module Mork
222
297
  first_x + column_width * (q / rows) + cell_spacing * c - cell_width / 2
223
298
  end
224
299
 
225
- def cell_width
226
- @params["responses"]["cell_width"].to_f
227
- end
228
-
229
- def cell_height
230
- @params["responses"]["cell_height"].to_f
231
- end
232
-
233
- def cell_spacing
234
- @params["responses"]["x_spacing"].to_f
235
- end
236
-
237
- def response_spacing
238
- @params["responses"]["y_spacing"].to_f
239
- end
240
-
241
- def column_width
242
- @params["responses"]["column_width"].to_f
243
- end
244
-
245
- def row_spacing
246
- @params["responses"]["y_spacing"].to_f
247
- end
248
-
249
- def first_x
250
- @params["responses"]["first_x"].to_f
251
- end
252
-
253
- def first_y
254
- @params["responses"]["first_y"].to_f
255
- end
256
-
257
- def rows
258
- @params["responses"]["rows"]
259
- end
260
-
261
- def columns
262
- @params["responses"]["columns"]
263
- end
264
-
265
300
  # ==============
266
301
  # = sheet code =
267
302
  # ==============
@@ -269,55 +304,50 @@ module Mork
269
304
  {
270
305
  x: (cx * code_cell_x(i)).round,
271
306
  y: (cy * code_y ).round,
272
- w: (cx * CODE_WIDTH ).round,
273
- h: (cy * CODE_HEIGHT ).round
307
+ w: (cx * code_width ).round,
308
+ h: (cy * code_height ).round
274
309
  }
275
310
  end
276
311
 
277
312
  def code_cell_x(i)
278
- CODE_LEFT + CODE_SPACING * i
313
+ @params[:code][:left] + @params[:code][:spacing] * i
279
314
  end
280
315
 
281
316
  def code_y
282
- reg_frame_height - CODE_HEIGHT
317
+ reg_frame_height - code_height
283
318
  end
284
319
 
285
320
  # ======================
286
321
  # = registration sides =
287
322
  # ======================
288
- def reg_frame_width
289
- page_width - REG_MARGIN * 2
290
- end
291
-
292
- def reg_frame_height
293
- page_height - REG_MARGIN * 2
294
- end
295
-
296
- def page_width
297
- @params["page_size"]["width"].to_f
298
- end
299
-
300
- def page_height
301
- @params["page_size"]["height"].to_f
302
- end
303
-
304
- # ============
305
- # = Header
306
- # ============
307
- def name_x
308
- @params["header"]["name"]["top"].to_f
309
- end
310
-
311
- def name_y
312
- @params["header"]["name"]["left"].to_f
313
- end
314
323
 
315
- def name_w
316
- @params["header"]["name"]["width"].to_f
317
- end
318
-
319
- def name_size
320
- @params["header"]["name"]["size"]
321
- end
324
+ # ===============================
325
+ # = Simple parameter extraction =
326
+ # ===============================
327
+ def ctrl_cell_left() @params[:control][:left].to_f + @params[:control][:width].to_f + ctrl_margin end
328
+ def ctrl_margin() @params[:control][:margin].to_f end
329
+ def ctrl_cell_y() @params[:control][:top].to_f end
330
+ def code_height() @params[:code][:height].to_f end
331
+ def code_width() @params[:code][:width].to_f end
332
+ def page_width() @params[:page_size][:width].to_f end
333
+ def page_height() @params[:page_size][:height].to_f end
334
+ def name_x() @params[:header][:name][:top].to_f end
335
+ def name_y() @params[:header][:name][:left].to_f end
336
+ def name_w() @params[:header][:name][:width].to_f end
337
+ def name_size() @params[:header][:name][:size].to_f end
338
+ def cell_width() @params[:responses][:cell_width].to_f end
339
+ def cell_height() @params[:responses][:cell_height].to_f end
340
+ def cell_spacing() @params[:responses][:x_spacing].to_f end
341
+ def response_spacing() @params[:responses][:y_spacing].to_f end
342
+ def column_width() @params[:responses][:column_width].to_f end
343
+ def row_spacing() @params[:responses][:y_spacing].to_f end
344
+ def first_x() @params[:responses][:first_x].to_f end
345
+ def first_y() @params[:responses][:first_y].to_f end
346
+ def rows() @params[:responses][:rows] end
347
+ def columns() @params[:responses][:columns] end
348
+ def reg_margin() @params[:regmarks][:margin].to_f end
349
+ def reg_search() @params[:regmarks][:search].to_f end
350
+ def reg_frame_width() page_width - reg_margin * 2 end
351
+ def reg_frame_height() page_height - reg_margin * 2 end
322
352
  end
323
353
  end
@@ -1,14 +1,84 @@
1
1
  module Mork
2
- REG_MARGIN = 7.5
3
- REG_RADIUS = 2.5
4
- REG_SEARCH = 5.0
5
- CODE_LEFT = 7.5
6
- CODE_WIDTH = 2.0
7
- CODE_HEIGHT = 2.5
8
- CODE_SPACING = 2.5
9
- CODE_BITS = 64
10
- Q_NUM_GAP = 2.0 # distance between right side of q num and left side of first choice cell
11
- Q_NUM_WIDTH = 8.0 # width of question number text box
12
- Q_NUM_SIZE = 10
13
- CH_LETTER_SZ = 8
14
- end
2
+ # this is the default grid!
3
+ DGRID = {
4
+ # default units are millimiters
5
+ page_size: {
6
+ # this is A4
7
+ width: 210.0,
8
+ height: 297.0
9
+ }, # page end
10
+ regmarks: {
11
+ margin: 10,
12
+ radius: 2.5,
13
+ search: 10
14
+ }, # regmarks end
15
+ header: {
16
+ name: {
17
+ top: 5,
18
+ left: 7.5,
19
+ width: 170,
20
+ size: 14,
21
+ },
22
+ title: {
23
+ top: 15,
24
+ left: 7.5,
25
+ width: 180,
26
+ size: 12
27
+ },
28
+ code: {
29
+ top: 5,
30
+ left: 165,
31
+ width: 20,
32
+ size: 14
33
+ },
34
+ signature: {
35
+ top: 30,
36
+ left: 7.5,
37
+ width: 120,
38
+ height: 15,
39
+ size: 7,
40
+ box: true,
41
+ }
42
+ }, # header end
43
+ responses: {
44
+ columns: 4,
45
+ column_width: 49,
46
+ rows: 30,
47
+ # from the top-left registration mark
48
+ # to the center of the first choice cell
49
+ first_x: 10.5,
50
+ first_y: 55.5,
51
+ # between choices
52
+ x_spacing: 7.0,
53
+ # between rows
54
+ y_spacing: 7.0,
55
+ # darkened area
56
+ cell_width: 6.0,
57
+ cell_height: 5.0,
58
+ # the maximum number of choices per question
59
+ max_cells: 5,
60
+ # font size for the question number
61
+ number_size: 10,
62
+ # distance between right side of q num and left side of first choice cell
63
+ number_width: 8,
64
+ # width of question number text box
65
+ number_margin: 2,
66
+ # font size for the choice letter
67
+ letter_size: 8
68
+ }, # responses end
69
+ code: {
70
+ bits: 40,
71
+ left: 15,
72
+ width: 3.0,
73
+ height: 2.5,
74
+ spacing: 4
75
+ }, # code end
76
+ control: {
77
+ top: 40,
78
+ left: 123,
79
+ width: 50,
80
+ size: 9,
81
+ margin: 2.5
82
+ } # control end
83
+ }
84
+ end
data/lib/mork/mimage.rb CHANGED
@@ -23,8 +23,8 @@ module Mork
23
23
  # = Highlight =
24
24
  # =============
25
25
  def highlight!(c)
26
- m = Magick::Image.new(c[:w], c[:h]) { self.background_color = "red" }
27
- @image.composite! m, c[:x], c[:y], Magick::CopyCompositeOp
26
+ m = Magick::Image.new(c[:w], c[:h]) { self.background_color = "yellow" }
27
+ @image.composite! m, c[:x], c[:y], Magick::CopyYellowCompositeOp
28
28
  end
29
29
 
30
30
  # ============
@@ -17,8 +17,8 @@ module Mork
17
17
  end
18
18
 
19
19
  def [] (i)
20
- puts "I: #{i}"
21
- puts @images[i].inspect
20
+ # puts "I: #{i}"
21
+ # puts @images[i].inspect
22
22
  Mimage.new @images[i]
23
23
  end
24
24
 
data/lib/mork/sheet.rb CHANGED
@@ -20,7 +20,7 @@ module Mork
20
20
 
21
21
  # code_string
22
22
  #
23
- # returns the sheet code as a string of 0s and 1s. The string is CODE_BITS
23
+ # returns the sheet code as a string of 0s and 1s. The string is code_bits
24
24
  # bits long, with most significant bits to the left
25
25
  def code_string
26
26
  cs = (0...@grid.code_bits).inject("") { |c, v| c << code_cell_value(v) }
@@ -32,9 +32,11 @@ module Mork
32
32
  # returns true if the specified question/choice cell has been darkened
33
33
  # false otherwise
34
34
  def marked?(q, c)
35
- shade_of(q, c) < dark_threshold
35
+ shade_of(q, c) < choice_threshold
36
36
  end
37
37
 
38
+ # TODO: define method ‘mark’ to retrieve the choice array for a single item
39
+
38
40
  # mark_array(range)
39
41
  #
40
42
  # returns an array of arrays of marked choices.
@@ -57,10 +59,40 @@ module Mork
57
59
  end
58
60
  end
59
61
 
62
+ # ================
63
+ # = HIGHLIGHTING =
64
+ # ================
65
+
66
+ def highlight_all
67
+ @grid.max_questions.times do |i|
68
+ @grid.max_choices_per_question.times do |j|
69
+ highlight_choice i, j
70
+ end
71
+ end
72
+ @mimage.highlight! @grid.dark_control_cell_area
73
+ @mimage.highlight! @grid.light_control_cell_area
74
+ end
75
+
76
+ def highlight
77
+ mark_array.each_with_index do |qa, i|
78
+ qa.each do |cho|
79
+ highlight_choice i, cho
80
+ end
81
+ end
82
+ @mimage.highlight! @grid.dark_control_cell_area
83
+ @mimage.highlight! @grid.light_control_cell_area
84
+ end
85
+
60
86
  def highlight_choice(q, c)
61
87
  @mimage.highlight! @grid.choice_cell_area(q, c)
62
88
  end
63
89
 
90
+ def highlight_code
91
+ @grid.code_bits.times do |bit|
92
+ @mimage.highlight! @grid.code_bit_area bit
93
+ end
94
+ end
95
+
64
96
  def highlight_code_bit(i)
65
97
  @mimage.highlight! @grid.code_bit_area(i)
66
98
  end
@@ -77,23 +109,8 @@ module Mork
77
109
  @mimage.write(fname)
78
110
  end
79
111
 
80
- def dark_code_bit_shade
81
- NPatch.new(@mimage.crop @grid.black_calibration_area).average
82
- end
83
-
84
- def light_code_bit_shade
85
- NPatch.new(@mimage.crop @grid.white_calibration_area).average
86
- end
87
-
88
112
  private
89
- def shade_of(q, c)
90
- NPatch.new(@mimage.crop @grid.choice_cell_area(q, c)).average
91
- end
92
113
 
93
- def dark_threshold
94
- 50000
95
- end
96
-
97
114
  def question_range(r)
98
115
  if r.nil?
99
116
  (0...@grid.max_questions)
@@ -104,12 +121,29 @@ module Mork
104
121
  end
105
122
  end
106
123
 
124
+ # =================================
125
+ # = compute shading with NPatches =
126
+ # =================================
127
+ def shade_of(q, c)
128
+ naverage @grid.choice_cell_area(q, c)
129
+ end
130
+
107
131
  def shade_of_code_bit(i)
108
- NPatch.new(@mimage.crop @grid.code_bit_area(i)).average
132
+ naverage @grid.code_bit_area(i)
109
133
  end
110
134
 
111
135
  def code_cell_value(i)
112
- shade_of_code_bit(i) < dark_threshold ? "1" : "0"
136
+ shade_of_code_bit(i) < code_threshold ? "1" : "0"
137
+ end
138
+
139
+ def choice_threshold
140
+ @choice_threshold ||= (naverage(@grid.dark_control_cell_area) +
141
+ naverage(@grid.light_control_cell_area)) / 2
142
+ end
143
+
144
+ def code_threshold
145
+ @code_threshold ||= (naverage(@grid.black_calibration_area) +
146
+ naverage(@grid.white_calibration_area)) / 2
113
147
  end
114
148
 
115
149
  # ================
@@ -118,10 +152,10 @@ module Mork
118
152
 
119
153
  def register(img)
120
154
  # find the XY coordinates of the 4 registration marks
121
- x1, y1 = reg_centroid_on(img, @grid.reg_mark_search_area(:top_left))
122
- x2, y2 = reg_centroid_on(img, @grid.reg_mark_search_area(:top_right))
123
- x3, y3 = reg_centroid_on(img, @grid.reg_mark_search_area(:bottom_right))
124
- x4, y4 = reg_centroid_on(img, @grid.reg_mark_search_area(:bottom_left))
155
+ x1, y1 = reg_centroid_on(img, @grid.reg_mark_tl_search_area)
156
+ x2, y2 = reg_centroid_on(img, @grid.reg_mark_tr_search_area)
157
+ x3, y3 = reg_centroid_on(img, @grid.reg_mark_br_search_area)
158
+ x4, y4 = reg_centroid_on(img, @grid.reg_mark_bl_search_area)
125
159
  # stretch the 4 points to fit the original size and return the resulting image
126
160
  img.stretch [
127
161
  x1, y1, 0, 0,
@@ -138,5 +172,9 @@ module Mork
138
172
  return nil, nil if cx.nil?
139
173
  return cx + c[:x], cy + c[:y]
140
174
  end
175
+
176
+ def naverage(where)
177
+ NPatch.new(@mimage.crop where).average
178
+ end
141
179
  end
142
180
  end
@@ -4,12 +4,36 @@ module Mork
4
4
  class SheetPDF < Prawn::Document
5
5
  def initialize(grid, info)
6
6
  @grid = grid
7
- @info = info
8
7
  super my_page_params
9
- registration_marks
10
- calibration_and_code @info[:code]
11
- header
12
- questions_and_choices
8
+ # @info should be an array of hashes, one per page;
9
+ # convert to array if a single hash was passed
10
+ @info = info.class == Hash ? [info] : info
11
+ process
12
+ end
13
+
14
+ def save(fn)
15
+ render_file fn
16
+ end
17
+
18
+ def to_pdf
19
+ render
20
+ end
21
+
22
+ private
23
+
24
+ def process
25
+ # for each response sheet
26
+ @info.each_with_index do |info, i|
27
+ start_new_page if i>0
28
+ fill_color "000000"
29
+ stroke_color "000000"
30
+ line_width 0.3
31
+ registration_marks
32
+ calibration_and_code info[:code]
33
+ header info[:header]
34
+ control info[:control] if info[:control]
35
+ questions_and_choices info[:choices]
36
+ end
13
37
  end
14
38
 
15
39
  def my_page_params
@@ -20,11 +44,11 @@ module Mork
20
44
  end
21
45
 
22
46
  def registration_marks
23
- fill {
47
+ fill do
24
48
  @grid.pdf_reg_marks.each do |r|
25
49
  circle r[:p], r[:r]
26
50
  end
27
- }
51
+ end
28
52
  end
29
53
 
30
54
  def calibration_and_code(code)
@@ -40,8 +64,31 @@ module Mork
40
64
  end
41
65
  end
42
66
 
43
- def header
44
- @info[:header].each do |k,v|
67
+ def control(info)
68
+ font_size @grid.pdf_control_size do
69
+ text_box info[:string], at: @grid.pdf_control_xy,
70
+ width: @grid.pdf_control_width,
71
+ align: :right
72
+ stroke do
73
+ font_size
74
+ stroke_color "ff0000"
75
+ # dark
76
+ a = @grid.pdf_dark_control_cell_area
77
+ rounded_rectangle a[:p], a[:w], a[:h], [a[:h], a[:w]].min / 2
78
+ fill_color "ff0000"
79
+ draw_text info[:labels][0], at: @grid.pdf_dark_control_letter_xy
80
+ # light
81
+ a = @grid.pdf_light_control_cell_area
82
+ rounded_rectangle a[:p], a[:w], a[:h], [a[:h], a[:w]].min / 2
83
+ fill_color "ff0000"
84
+ draw_text info[:labels][1], at: @grid.pdf_light_control_letter_xy
85
+
86
+ end
87
+ end
88
+ end
89
+
90
+ def header(info)
91
+ info.each do |k,v|
45
92
  font_size @grid.pdf_header_size(k) do
46
93
  if @grid.pdf_header_boxed?(k)
47
94
  bounding_box @grid.pdf_header_xy(k), width: @grid.pdf_header_width(k), height: @grid.pdf_header_height(k) do
@@ -57,20 +104,19 @@ module Mork
57
104
  end
58
105
  end
59
106
 
60
- def questions_and_choices
107
+ def questions_and_choices(info)
61
108
  stroke do
62
- line_width 0.3
63
- nquestions.times do |q|
109
+ info.length.times do |q|
64
110
  fill_color "000000"
65
111
  text_box "#{q+1}", at: @grid.pdf_qnum_xy(q),
66
- width: @grid.pdf_qnum_width,
67
- align: :right,
68
- size: Q_NUM_SIZE
112
+ width: @grid.pdf_qnum_width,
113
+ align: :right,
114
+ size: @grid.pdf_qnum_size
69
115
  stroke_color "ff0000"
70
- font_size CH_LETTER_SZ
71
- nchoices(q).times do |c|
116
+ font_size @grid.pdf_chlett_size
117
+ info[q].times do |c|
72
118
  a = @grid.pdf_choice_cell_area q, c
73
- rounded_rectangle a[:p], a[:w], a[:h], 2.mm
119
+ rounded_rectangle a[:p], a[:w], a[:h], [a[:h], a[:w]].min / 2
74
120
  fill_color "ff0000"
75
121
  draw_text (65+c).chr, at: @grid.pdf_choice_letter_xy(q, c)
76
122
  end
@@ -78,18 +124,13 @@ module Mork
78
124
  end
79
125
  end
80
126
 
81
- def save(fn)
82
- render_file fn
83
- end
84
-
85
- private
86
- def nquestions
87
- @info[:choices].length
88
- end
89
-
90
- def nchoices(i)
91
- @info[:choices][i]
92
- end
127
+ # def nquestions
128
+ # @info[:choices].length
129
+ # end
130
+ #
131
+ # def nchoices(i)
132
+ # @info[:choices][i]
133
+ # end
93
134
  end
94
135
  end
95
136
 
data/lib/mork/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mork
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.5"
3
3
  end
data/lib/mork.rb CHANGED
@@ -1,9 +1,8 @@
1
- require "mork/version"
1
+ require 'mork/version'
2
2
  require 'mork/sheet'
3
3
  require 'mork/grid'
4
4
  require 'mork/grid_const'
5
5
  require 'mork/mimage'
6
6
  require 'mork/mimage_list'
7
- require 'mork/report'
8
7
  require 'mork/npatch'
9
8
  require 'mork/sheet_pdf'
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  module Mork
4
4
  describe Grid do
5
- let(:grid) { Grid.new(:default) }
5
+ let(:grid) { Grid.new }
6
6
 
7
7
  describe "#initialize" do
8
8
  it "returns a Grid object" do
@@ -2,30 +2,113 @@ require 'spec_helper'
2
2
 
3
3
  module Mork
4
4
  describe SheetPDF do
5
+
5
6
  it "should create a basic pdf" do
6
7
  info = {
7
- code: 18446744073709551615,
8
- choices: [5] * 100,
8
+ code: 1099511627775,
9
+ choices: [5] * 120,
9
10
  header: {
10
- name: "Bertini Giuseppe VR123456 Bertini Giuseppe VR123456",
11
- title: "Esame di Fondamenti Morfologici e Funzionali della Vita - 18 gennaio 2013 Esame di Fondamenti Morfologici e Funzionali della Vita - 18 gennaio 2013",
11
+ name: "Bertini Giuseppe VR123456",
12
+ title: "Esame di Fondamenti Morfologici e Funzionali della Vita - 18 gennaio 2013",
12
13
  code: "119.27",
13
14
  signature: "Firma"
15
+ },
16
+ control: {
17
+ string: "Annerisci solo la casella ‘V’:",
18
+ labels: ['V', 'F']
14
19
  }
15
20
  }
16
- s = SheetPDF.new(Grid.new(:default), info)
17
- s.save("tmp/f1.pdf")
21
+
22
+ grid_opts = {
23
+ regmarks: {
24
+ margin: 10,
25
+ radius: 2.5,
26
+ search: 10
27
+ },
28
+ header: {
29
+ name: {
30
+ top: 5,
31
+ left: 7.5,
32
+ width: 170,
33
+ size: 14,
34
+ },
35
+ title: {
36
+ top: 15,
37
+ left: 7.5,
38
+ width: 180,
39
+ size: 12
40
+ },
41
+ code: {
42
+ top: 5,
43
+ left: 165,
44
+ width: 20,
45
+ size: 14
46
+ },
47
+ signature: {
48
+ top: 30,
49
+ left: 7.5,
50
+ width: 120,
51
+ height: 15,
52
+ size: 7,
53
+ box: true,
54
+ }
55
+ }, # header end
56
+ responses: {
57
+ columns: 4,
58
+ column_width: 49,
59
+ rows: 30,
60
+ # from the top-left registration mark
61
+ # to the center of the first choice cell
62
+ first_x: 10.5,
63
+ first_y: 55.5,
64
+ # between choices
65
+ x_spacing: 7.0,
66
+ # between rows
67
+ y_spacing: 7.0,
68
+ # darkened area
69
+ cell_width: 6.0,
70
+ cell_height: 5.0,
71
+ # the maximum number of choices per question
72
+ max_cells: 5,
73
+ # font size for the question number
74
+ number_size: 10,
75
+ # distance between right side of q num and left side of first choice cell
76
+ number_width: 8,
77
+ # width of question number text box
78
+ number_margin: 2,
79
+ # font size for the choice letter
80
+ letter_size: 8
81
+ },
82
+ code: {
83
+ bits: 40,
84
+ left: 15,
85
+ width: 3.0,
86
+ height: 2.5,
87
+ spacing: 4
88
+ },
89
+ control: {
90
+ top: 40,
91
+ left: 123,
92
+ width: 50,
93
+ size: 9,
94
+ margin: 2.5
95
+ }
96
+ }
97
+
98
+ # s = SheetPDF.new(Grid.new(grid_opts), info)
99
+ # s.save("tmp/f1.pdf")
18
100
 
19
101
  info = {
20
- code: 17382938642823887837,
21
- choices: [5] * 100,
102
+ code: 5512,
103
+ choices: [5] * 160,
22
104
  header: {
23
- name: "Francesco Gagliardi VR765432",
105
+ name: "Bonazza Sara vr354320",
24
106
  title: "Esame di Fondamenti Morfologici e Funzionali della Vita - 18 gennaio 2013",
25
- code: "119.28"
107
+ code: "201.48",
108
+ signature: "Firma"
26
109
  }
27
110
  }
28
- s = SheetPDF.new(Grid.new(:default), info)
111
+ s = SheetPDF.new(Grid.new, info)
29
112
  s.save("tmp/f2.pdf")
30
113
 
31
114
  info = {
@@ -38,9 +121,36 @@ module Mork
38
121
  signature: "Firma"
39
122
  }
40
123
  }
41
- s = SheetPDF.new(Grid.new(:default), info)
124
+ s = SheetPDF.new(Grid.new, info)
42
125
  s.save("tmp/f3.pdf")
43
126
  end
127
+
128
+ it "should create a multipage pdf" do
129
+ info = [
130
+ {
131
+ code: 18446744073709551615,
132
+ choices: [5] * 100,
133
+ header: {
134
+ name: "Bertini Giuseppe VR123456 Bertini Giuseppe VR123456",
135
+ title: "Esame di Fondamenti Morfologici e Funzionali della Vita - 18 gennaio 2013 Esame di Fondamenti Morfologici e Funzionali della Vita - 18 gennaio 2013",
136
+ code: "119.27",
137
+ signature: "Firma"
138
+ }
139
+ },
140
+ {
141
+ code: 5512,
142
+ choices: [5] * 160,
143
+ header: {
144
+ name: "Bonazza Sara vr354320",
145
+ title: "Esame di Fondamenti Morfologici e Funzionali della Vita - 18 gennaio 2013",
146
+ code: "201.48",
147
+ signature: "Firma"
148
+ }
149
+ }
150
+ ]
151
+ s = SheetPDF.new(Grid.new, info)
152
+ s.save("tmp/p2.pdf")
153
+ end
44
154
  end
45
155
  end
46
156
 
@@ -4,14 +4,18 @@ module Mork
4
4
  describe Sheet do
5
5
  context "describing marked choices" do
6
6
  before(:all) do
7
- fn = sample_img(:sample01).filename
8
- @sheet = Sheet.new(fn, Grid.new)
7
+ @sheet = Sheet.new('spec/samples/sample02.jpg')
9
8
  end
10
9
 
11
10
  describe "#marked?" do
12
11
  it "should return true for a darkened choice" do
13
12
  @sheet.marked?(0,0).should be_true
14
13
  end
14
+
15
+ it "should highlight and show" do
16
+ @sheet.highlight_all
17
+ @sheet.write 'tmp/all_highlights.jpg'
18
+ end
15
19
 
16
20
  it "should return false for a blank choice" do
17
21
  @sheet.marked?(0,1).should be_false
@@ -59,20 +63,20 @@ module Mork
59
63
  @cshe = Sheet.new(@smp.filename, Grid.new)
60
64
  end
61
65
 
62
- describe "#dark_code_bit_shade" do
63
- it "should be less than a certain amount" do
64
- v = @cshe.dark_code_bit_shade
65
- v.should < @cshe.send(:dark_threshold)
66
- end
67
- end
68
-
69
- describe "#light_code_bit_shade" do
70
- it "should be more than a certain amount" do
71
- v = @cshe.light_code_bit_shade
72
- v.should > @cshe.send(:dark_threshold)
73
- end
74
-
75
- end
66
+ # describe "#dark_code_bit_shade" do
67
+ # it "should be less than a certain amount" do
68
+ # v = @cshe.dark_code_bit_shade
69
+ # v.should < @cshe.send(:dark_threshold)
70
+ # end
71
+ # end
72
+ #
73
+ # describe "#light_code_bit_shade" do
74
+ # it "should be more than a certain amount" do
75
+ # v = @cshe.light_code_bit_shade
76
+ # v.should > @cshe.send(:dark_threshold)
77
+ # end
78
+ #
79
+ # end
76
80
 
77
81
  describe "#code_string" do
78
82
  it "should read the bit string" do
@@ -91,7 +95,7 @@ module Mork
91
95
  it "should highlight all high bits in red" do
92
96
  smp = sample_img(:code_sample)
93
97
  s = Sheet.new(smp.filename, Grid.new)
94
- CODE_BITS.times do |i|
98
+ 64.times do |i|
95
99
  if smp.code_int[i] == 1
96
100
  s.highlight_code_bit i
97
101
  end
@@ -112,6 +116,21 @@ module Mork
112
116
  s.write "tmp/light_bit.pdf"
113
117
  end
114
118
  end
119
+
120
+ context "faded, b&w sheet" do
121
+ before(:all) do
122
+ @smp = sample_img(:bw_faded_sample)
123
+ @sheet = Sheet.new(@smp.filename, Grid.new)
124
+ end
125
+
126
+ it "should return the correct code" do
127
+ @sheet.code.should == @smp.code_int
128
+ end
129
+
130
+ it "should return the darkened choices" do
131
+ @sheet.mark_array(12).should == [[2], [3], [4], [0], [1], [2], [0,4], [], [3], [1], [], []]
132
+ end
133
+ end
115
134
 
116
135
  context "multi-page pdf" do
117
136
  before(:all) do
@@ -30,7 +30,13 @@ sample01:
30
30
  q160:
31
31
  tl_x: 1818
32
32
  tl_y: 2974
33
-
33
+ bw_faded_sample:
34
+ filename: spec/samples/qzc006.jpg
35
+ pages: 1
36
+ width: 1196
37
+ height: 1682
38
+ code_int: 5512
39
+
34
40
  reg_mark:
35
41
  filename: spec/samples/reg_mark.jpg
36
42
  centroid_x: 92
Binary file
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mork
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Giuseppe Bertini
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-25 00:00:00.000000000 Z
11
+ date: 2014-09-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: narray
@@ -173,7 +173,6 @@ files:
173
173
  - lib/mork/mimage.rb
174
174
  - lib/mork/mimage_list.rb
175
175
  - lib/mork/npatch.rb
176
- - lib/mork/report.rb
177
176
  - lib/mork/sheet.rb
178
177
  - lib/mork/sheet_pdf.rb
179
178
  - lib/mork/version.rb
@@ -182,7 +181,6 @@ files:
182
181
  - spec/mork/mimage_list_spec.rb
183
182
  - spec/mork/mimage_spec.rb
184
183
  - spec/mork/npatch_spec.rb
185
- - spec/mork/report_spec.rb
186
184
  - spec/mork/sheet_pdf_spec.rb
187
185
  - spec/mork/sheet_spec.rb
188
186
  - spec/samples/22161694.pdf
@@ -190,9 +188,11 @@ files:
190
188
  - spec/samples/code_sample.png
191
189
  - spec/samples/code_zero.pdf
192
190
  - spec/samples/info.yml
191
+ - spec/samples/qzc006.jpg
193
192
  - spec/samples/reg_mark.jpg
194
193
  - spec/samples/sample.pages
195
194
  - spec/samples/sample01.jpg
195
+ - spec/samples/sample02.jpg
196
196
  - spec/samples/sheet1.jpg
197
197
  - spec/samples/sheet1.pdf
198
198
  - spec/samples/two_pages.pdf
@@ -225,7 +225,6 @@ test_files:
225
225
  - spec/mork/mimage_list_spec.rb
226
226
  - spec/mork/mimage_spec.rb
227
227
  - spec/mork/npatch_spec.rb
228
- - spec/mork/report_spec.rb
229
228
  - spec/mork/sheet_pdf_spec.rb
230
229
  - spec/mork/sheet_spec.rb
231
230
  - spec/samples/22161694.pdf
@@ -233,9 +232,11 @@ test_files:
233
232
  - spec/samples/code_sample.png
234
233
  - spec/samples/code_zero.pdf
235
234
  - spec/samples/info.yml
235
+ - spec/samples/qzc006.jpg
236
236
  - spec/samples/reg_mark.jpg
237
237
  - spec/samples/sample.pages
238
238
  - spec/samples/sample01.jpg
239
+ - spec/samples/sample02.jpg
239
240
  - spec/samples/sheet1.jpg
240
241
  - spec/samples/sheet1.pdf
241
242
  - spec/samples/two_pages.pdf
data/lib/mork/report.rb DELETED
@@ -1,39 +0,0 @@
1
- module Mork
2
- class Report
3
- def initialize(im, opts={})
4
- grid_type = opts[:grid_type] || :default
5
- grid_file = opts[:grid_file] || 'config/grids.yml'
6
- @grid = Grid.new grid_type, grid_file
7
- @sheet = Sheet.new(im, @grid)
8
- @chlist = opts[:chlist] || @grid.default_chlist
9
- end
10
-
11
- def sheet_code
12
- @sheet.code
13
- end
14
-
15
- def selected_choices
16
- # sc = []
17
- # @chlist.each_with_index do |ch, i|
18
- # sc[i] = (0...ch).collect do |x|
19
- # puts "Q.#{i} Ch.#{x}"
20
- # @mimage.darkened? @ruler.cell(i, x)
21
- # end
22
- # end
23
- # sc
24
- end
25
-
26
- def highlight_all_choices
27
- @chlist.each_with_index do |ch, i|
28
- (0...ch).each do |x|
29
- @sheet.highlight_choice(i, x)
30
- end
31
- end
32
- @sheet.highlight_code
33
- end
34
-
35
- def write_sheet(fname)
36
- @sheet.write(fname)
37
- end
38
- end
39
- end
@@ -1,13 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Mork
4
- describe Report do
5
- let(:smp) { sample_img(:sample01) }
6
-
7
- describe ".new" do
8
- it "should create a Report" do
9
- Report.new(smp.filename).should be_a(Report)
10
- end
11
- end
12
- end
13
- end