mork 0.4.0 → 0.5.0

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: 9ce19962ba0e1e21013a7081f9ac040e57d0bfa1
4
- data.tar.gz: 2b86b3f7a6338384e6b9ffdf9157cb0a92205dea
3
+ metadata.gz: cedc2c2924bff45051c7d4fdace910882b95ade7
4
+ data.tar.gz: 4a97e442ee44a1e615e9d92dd1be2dfa8af01545
5
5
  SHA512:
6
- metadata.gz: 7d6a2ef2db4358a02a2ba9d3cbdac0505d9208b2b169fbfee67e76a71311844b970a306d19c8a72fbd400288ef269397c645d65f126b284c4832c6283870ba79
7
- data.tar.gz: 3efa05963a68fd82f672f4c0aadf06d739e3eec442a7e0f0c70c82f0422c35f699df3495ab5196d264ab4497ccc85cd579eefbaac3819ccfa5d427e47c61bf83
6
+ metadata.gz: 77283aab2e31e1189a7579f49b6a535b374381254df3b75a4ded1eb2ea871ba11987b441237afef320e59a5fd605a8b9a1863b80c27547221064696f52a75642
7
+ data.tar.gz: b2ea3c69c2fd974d4d047af7ad2aec052dcd34046ca06a5ad20666dd31df1485dd906b52164929ae8c826c857783f7ac25f0aa84da5ea6f2f1266e6548f7226e
data/lib/mork/grid.rb CHANGED
@@ -39,6 +39,10 @@ module Mork
39
39
  columns * rows
40
40
  end
41
41
 
42
+ def max_choices_per_question
43
+ @params[:items][:max_cells].to_i
44
+ end
45
+
42
46
  def barcode_bits
43
47
  @params[:barcode][:bits].to_i
44
48
  end
@@ -68,7 +72,11 @@ module Mork
68
72
  # the distance from the registration frame to the left edge
69
73
  # of the c-th choice cell of the q-th question
70
74
  def cell_x(q,c)
71
- first_x + column_width * (q / rows) + cell_spacing * c - cell_width / 2
75
+ item_x(q) + cell_spacing * c
76
+ end
77
+
78
+ def item_x(q)
79
+ first_x + column_width * (q / rows) - cell_width / 2
72
80
  end
73
81
 
74
82
  def cal_cell_x
@@ -69,7 +69,7 @@ module Mork
69
69
  bits: 40,
70
70
  left: 15,
71
71
  width: 3,
72
- height: 2.5,
72
+ height: 3,
73
73
  spacing: 4
74
74
  }, # barcode end
75
75
  control: {
data/lib/mork/grid_omr.rb CHANGED
@@ -73,7 +73,6 @@ module Mork
73
73
  # areas on the sheet that are certainly white/black
74
74
  def paper_white_area() barcode_bit_area -1 end
75
75
  def ink_black_area() barcode_bit_area 0 end
76
- def max_choices_per_question() @params[:items][:max_cells].to_i end
77
76
  def rm_max_search_area_side() (ppu_x * page_width / 4).round end
78
77
 
79
78
  private
data/lib/mork/grid_pdf.rb CHANGED
@@ -18,62 +18,66 @@ module Mork
18
18
  ]
19
19
  end
20
20
 
21
- def barcode_bit_areas_for(code)
21
+ def barcode_width
22
+ super.mm
23
+ end
24
+
25
+ def barcode_height
26
+ super.mm
27
+ end
28
+
29
+ def barcode_xy_for(code)
22
30
  black = barcode_bits.times.reject { |x| (code>>x)[0]==0 }
23
- black.collect { |x| barcode_area x+1 }
31
+ black.collect { |x| barcode_xy x+1 }
24
32
  end
25
33
 
26
- def calibration_cell_areas
27
- rows.times.collect do |q|
28
- {
29
- p: [(reg_frame_width-cell_spacing).mm, (reg_frame_height - cell_y(q)).mm],
30
- w: cell_width.mm,
31
- h: cell_height.mm
32
- }
33
- end
34
+ def ink_black_xy
35
+ barcode_xy 0
34
36
  end
35
37
 
36
- # Coordinates at which to place calibration cell labels (usually an ‘X’)
37
- def calibration_letter_xy(q)
38
- [
39
- (reg_frame_width-cell_spacing).mm + 2.mm,
40
- item_text_y(q)
41
- ]
38
+ def calibration_cells_xy
39
+ rows.times.collect do |q|
40
+ [(reg_frame_width-cell_spacing).mm, item_y(q).mm]
41
+ end
42
42
  end
43
43
 
44
44
  # Coordinates at which to place item numbers
45
45
  def qnum_xy(q)
46
46
  [
47
- cell_x(q, 0).mm - qnum_width - @params[:items][:number_margin].to_f.mm,
48
- item_text_y(q)
47
+ item_x(q).mm - qnum_width - qnum_margin,
48
+ item_y(q).mm
49
49
  ]
50
50
  end
51
51
 
52
- # Coordinates at which to place choice labels
53
- def choice_letter_xy(q, c)
54
- [
55
- cell_x(q, c).mm + 2.mm,
56
- item_text_y(q)
57
- ]
52
+ def width_of_cell
53
+ cell_width.mm
58
54
  end
59
55
 
60
- def choice_cell_area(q, c)
61
- {
62
- p: [cell_x(q, c).mm, (reg_frame_height - cell_y(q)).mm],
63
- w: cell_width.mm,
64
- h: cell_height.mm
65
- }
56
+ def height_of_cell
57
+ cell_height.mm
58
+ end
59
+
60
+ def choice_spacing
61
+ cell_spacing.mm
62
+ end
63
+
64
+ def item_xy(q)
65
+ [item_x(q).mm, item_y(q).mm]
66
+ end
67
+
68
+ def cround
69
+ @cround ||= [width_of_cell, height_of_cell].min / 2
66
70
  end
67
71
 
68
- def page_size() [page_width.mm, page_height.mm] end
69
- def margins() reg_margin.mm end
70
- def ink_black_area() barcode_area(0) end
71
- def qnum_width() @params[:items][:number_width].to_f.mm end
72
- def item_font_size() @params[:items][:font_size].to_f end
73
- def header_width(k) @params[:header][k][:width].to_f.mm end
74
- def header_height(k) @params[:header][k][:height].to_f.mm end
75
- def header_size(k) @params[:header][k][:size].to_f end
76
- def header_boxed?(k) @params[:header][k][:box] == true end
72
+ def page_size() [page_width.mm, page_height.mm] end
73
+ def margins() reg_margin.mm end
74
+ def qnum_margin() @params[:items][:number_margin].to_f.mm end
75
+ def qnum_width() @params[:items][:number_width].to_f.mm end
76
+ def item_font_size() @params[:items][:font_size].to_f end
77
+ def header_width(k) @params[:header][k][:width].to_f.mm end
78
+ def header_height(k) @params[:header][k][:height].to_f.mm end
79
+ def header_size(k) @params[:header][k][:size].to_f end
80
+ def header_boxed?(k) @params[:header][k][:box] == true end
77
81
 
78
82
  def header_xy(k)
79
83
  [
@@ -88,12 +92,18 @@ module Mork
88
92
  header_height(k) - 1.mm
89
93
  ]
90
94
  end
91
-
92
95
 
93
96
  private
94
-
95
- def item_text_y(q)
96
- (reg_frame_height - cell_y(q) - cell_height/4).mm
97
+
98
+ def item_y(q)
99
+ reg_frame_height - cell_y(q)
100
+ end
101
+
102
+ def barcode_xy(i)
103
+ [
104
+ barcode_bit_x(i).mm,
105
+ barcode_height
106
+ ]
97
107
  end
98
108
 
99
109
  def barcode_area(i)
data/lib/mork/mimage.rb CHANGED
@@ -142,22 +142,16 @@ module Mork
142
142
  # if the 2nd arg is false, then stretching is not applied
143
143
  def write(fname=nil, reg=true)
144
144
  if fname
145
- # img = MiniMagick::Image.open @path
146
- # img.combine_options {|c| exec_mm_cmd c, reg }
147
- # begin
148
- # img.write fname
149
- # @write = :ok
150
- # rescue Exception
151
- # @write = :fail
152
- # end
153
145
  MiniMagick::Tool::Convert.new(false) do |img|
154
146
  img << @path
155
- img.distort(:perspective, perspective_points) if reg
156
- @cmd.each { |cmd| img.send *cmd }
147
+ exec_mm_cmd img, reg
157
148
  img << fname
158
149
  end
159
150
  else
160
- MiniMagick::Image.new(@path) { |c| exec_mm_cmd c, reg }
151
+ MiniMagick::Tool::Mogrify.new(false) do |img|
152
+ img << @path
153
+ exec_mm_cmd img, reg
154
+ end
161
155
  end
162
156
  end
163
157
 
@@ -166,10 +160,7 @@ module Mork
166
160
  # ============================================================#
167
161
  def exec_mm_cmd(c, reg)
168
162
  c.distort(:perspective, perspective_points) if reg
169
-
170
- @cmd.each do |cmd|
171
- c.send *cmd
172
- end
163
+ @cmd.each { |cmd| c.send *cmd }
173
164
  end
174
165
 
175
166
  def img_size
@@ -2,6 +2,9 @@ require 'mork/grid_pdf'
2
2
  require 'prawn'
3
3
 
4
4
  module Mork
5
+
6
+ #TODO: read the prawn manual, we should probably use views
7
+
5
8
  class SheetPDF < Prawn::Document
6
9
  def initialize(content, grip=GridPDF.new)
7
10
  @grip = case grip
@@ -26,21 +29,6 @@ module Mork
26
29
 
27
30
  private
28
31
 
29
- def process
30
- # for each response sheet
31
- @content.each_with_index do |content, i|
32
- start_new_page if i>0
33
- fill_color "000000"
34
- stroke_color "000000"
35
- line_width 0.3
36
- registration_marks
37
- barcode content[:barcode]
38
- header content[:header]
39
- questions_and_choices content[:choices]
40
- calibration_cells
41
- end
42
- end
43
-
44
32
  def my_page_params
45
33
  {
46
34
  page_size: @grip.page_size,
@@ -48,38 +36,50 @@ module Mork
48
36
  }
49
37
  end
50
38
 
51
- def registration_marks
52
- fill do
53
- @grip.reg_marks.each do |r|
54
- circle r[:p], r[:r]
39
+ def process
40
+ # for all sheets
41
+ line_width 0.3
42
+ font_size @grip.item_font_size
43
+ create_stamps
44
+ make_repeaters
45
+ # for each response sheet
46
+ @content.each_with_index do |content, i|
47
+ start_new_page if i>0
48
+ barcode content[:barcode]
49
+ header content[:header]
50
+ unless equal_choice_number?
51
+ questions_and_choices ch_len[i]
55
52
  end
56
53
  end
57
54
  end
58
55
 
59
- def calibration_cells
60
- font_size @grip.item_font_size do
61
- stroke do
62
- stroke_color "ff0000"
63
- @grip.calibration_cell_areas.each_with_index do |a, i|
64
- rounded_rectangle a[:p], a[:w], a[:h], [a[:h], a[:w]].min / 2
65
- fill_color "ff0000"
66
- text_box 'X', at: @grip.calibration_letter_xy(i)
56
+ def make_repeaters
57
+ if equal_choice_number?
58
+ repeat(:all) do
59
+ questions_and_choices ch_len.first
60
+ end
61
+ end
62
+
63
+ repeat(:all) do
64
+ calibration_cells
65
+ fill do
66
+ @grip.reg_marks.each do |r|
67
+ circle r[:p], r[:r]
67
68
  end
68
69
  end
69
70
  end
70
71
  end
71
72
 
73
+ def calibration_cells
74
+ @grip.calibration_cells_xy.each { |c| stamp_at 'X', c }
75
+ end
76
+
72
77
  def barcode(code)
73
- fill do
74
- # draw the dark calibration bar
75
- c = @grip.ink_black_area
76
- rectangle c[:p], c[:w], c[:h]
77
- # draw the bars corresponding to the code
78
- # least to most significant bit, left to right
79
- @grip.barcode_bit_areas_for(code).each do |c|
80
- rectangle c[:p], c[:w], c[:h]
81
- end
82
- end
78
+ # draw the dark calibration bar
79
+ stamp_at 'barcode', @grip.ink_black_xy
80
+ # draw the bars corresponding to the code
81
+ # least to most significant bit, left to right
82
+ @grip.barcode_xy_for(code).each { |c| stamp_at 'barcode', c }
83
83
  end
84
84
 
85
85
  def header(content)
@@ -99,24 +99,68 @@ module Mork
99
99
  end
100
100
  end
101
101
 
102
- def questions_and_choices(content)
103
- stroke do
104
- content.length.times do |q|
105
- fill_color "000000"
106
- text_box "#{q+1}", at: @grip.qnum_xy(q),
107
- width: @grip.qnum_width,
108
- align: :right,
109
- size: @grip.item_font_size
110
- stroke_color "ff0000"
111
- font_size @grip.item_font_size
112
- content[q].times do |c|
113
- a = @grip.choice_cell_area q, c
114
- rounded_rectangle a[:p], a[:w], a[:h], [a[:h], a[:w]].min / 2
115
- fill_color "ff0000"
116
- text_box (65+c).chr, at: @grip.choice_letter_xy(q, c)
102
+ def questions_and_choices(n_ch)
103
+ n_ch.each_with_index do |n, i|
104
+ text_box "#{i+1}",
105
+ at: @grip.qnum_xy(i),
106
+ width: @grip.qnum_width,
107
+ height: @grip.height_of_cell,
108
+ align: :right,
109
+ valign: :center
110
+ stamp_at "s#{n}", @grip.item_xy(i)
111
+ end
112
+ end
113
+
114
+ def create_stamps
115
+ create_choice_stamps
116
+ create_stamp('X') do
117
+ cell_stamp_content 'X', 0
118
+ end
119
+ create_stamp('barcode') do
120
+ fill do
121
+ rectangle [0,0], @grip.barcode_width, @grip.barcode_height
122
+ end
123
+ end
124
+ end
125
+
126
+ def create_choice_stamps
127
+ ch_len.flatten.uniq.each do |t|
128
+ create_stamp("s#{t}") do
129
+ t.times do |i|
130
+ cell_stamp_content letter_for(i), @grip.choice_spacing*i
117
131
  end
118
132
  end
119
133
  end
120
134
  end
135
+
136
+ def cell_stamp_content(l, x)
137
+ stroke_rounded_rectangle [x,0],
138
+ @grip.width_of_cell,
139
+ @grip.height_of_cell,
140
+ @grip.cround
141
+ text_box l,
142
+ at: [x,0],
143
+ width: @grip.width_of_cell,
144
+ height: @grip.height_of_cell,
145
+ align: :center,
146
+ valign: :center
147
+ end
148
+
149
+ def equal_choice_number?
150
+ return false unless ch_len.all? { |c| c.length == ch_len[0].length }
151
+ ch_len[0].each_with_index do |c, i|
152
+ return false unless ch_len.all? { |x| c == x[i] }
153
+ end
154
+ true
155
+ end
156
+
157
+ def ch_len
158
+ @all_choice_lengths ||= @content.collect { |c| c[:choices] }
159
+ end
160
+
161
+ # Choices are labeled 'A', 'B', ...
162
+ def letter_for(c)
163
+ (65+c).chr
164
+ end
121
165
  end
122
166
  end
data/lib/mork/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mork
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -62,11 +62,18 @@ module Mork
62
62
  it 'creates a PDF sheet with 160 items' do
63
63
  s = SheetPDF.new(content.merge({choices: [5] * 160}), 'spec/samples/grid160.yml')
64
64
  s.save('spec/out/i160.pdf')
65
+ system 'open spec/out/i160.pdf'
65
66
  end
66
67
 
67
- it 'creates a multipage pdf' do
68
- s = SheetPDF.new([content, content, content])
69
- s.save('spec/out/p2.pdf')
68
+ it 'creates a PDF sheet with unequal choices per item' do
69
+ s = SheetPDF.new(content.merge({choices: [5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1]}), 'spec/samples/layout.yml')
70
+ s.save('spec/out/uneq.pdf')
71
+ end
72
+
73
+ it 'creates 20 PDF sheets' do
74
+ c = content
75
+ s = SheetPDF.new([c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c])
76
+ s.save('spec/out/p20.pdf')
70
77
  end
71
78
  end
72
79
  end
@@ -47,7 +47,7 @@ barcode:
47
47
  bits: 40
48
48
  left: 15
49
49
  width: 3.0
50
- height: 2.5
50
+ height: 3
51
51
  spacing: 4
52
52
  control:
53
53
  top: 40
@@ -6,6 +6,7 @@ reg_marks:
6
6
  radius: 2.5 # registration mark radius
7
7
  search: 12 # initial size of the registration mark search area (*)
8
8
  offset: 2 # distance between the search area and each page border (*)
9
+
9
10
  header:
10
11
  name: # ‘name’ is just a label; you can add arbitrary header elements
11
12
  top: 5 # margin relative to registration frame top side
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.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Giuseppe Bertini
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-05 00:00:00.000000000 Z
11
+ date: 2015-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: narray