mork 0.0.3 → 0.0.5

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.
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