pdf-labels 1.0.1 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +9 -1
- data/LICENCE +0 -0
- data/Manifest.txt +32 -31
- data/Rakefile +2 -2
- data/fonts/Code128.afm +275 -0
- data/fonts/Code128.pfb +0 -0
- data/fonts/Code128.ttf +0 -0
- data/fonts/Code2of5interleaved.afm +275 -0
- data/fonts/Code2of5interleaved.pfb +0 -0
- data/fonts/Code2of5interleaved.ttf +0 -0
- data/fonts/Code3de9.afm +275 -0
- data/fonts/Code3de9.pfb +0 -0
- data/fonts/Code3de9.ttf +0 -0
- data/fonts/CodeDatamatrix.afm +275 -0
- data/fonts/CodeDatamatrix.pfb +0 -0
- data/fonts/CodeDatamatrix.ttf +0 -0
- data/fonts/CodeEAN13.afm +275 -0
- data/fonts/CodeEAN13.pfb +0 -0
- data/fonts/CodeEAN13.ttf +0 -0
- data/fonts/CodePDF417.afm +275 -0
- data/fonts/CodePDF417.pfb +0 -0
- data/fonts/CodePDF417.ttf +0 -0
- data/init.rb +2 -0
- data/lib/pdf/label.rb +12 -0
- data/lib/pdf/label/alias.rb +11 -0
- data/lib/pdf/label/batch.rb +276 -0
- data/lib/pdf/label/glabel_template.rb +38 -0
- data/lib/pdf/label/label.rb +55 -0
- data/lib/pdf/label/layout.rb +15 -0
- data/lib/pdf/label/length_node.rb +52 -0
- data/lib/pdf/label/markup.rb +26 -0
- data/lib/pdf/label/template.rb +39 -0
- data/pdf-labels-patch-to-r62.txt +98 -0
- data/templates/avery-us-templates.xml +0 -0
- data/templates/glabels-2.0.dtd +0 -0
- data/test/test_pdf_label_page.rb +76 -18
- data/vendor/pdf/writer.rb +4 -1
- data/vendor/pdf/writer/object/font.rb +4 -4
- data/vendor/pdf/writer/object/viewerpreferences.rb +2 -2
- data/vendor/pdf_writer_font_patch.diff +35 -0
- metadata +84 -66
- data/lib/alias.rb +0 -8
- data/lib/glabel_template.rb +0 -36
- data/lib/label.rb +0 -52
- data/lib/layout.rb +0 -13
- data/lib/length_node.rb +0 -47
- data/lib/markup.rb +0 -25
- data/lib/pdf_label_page.rb +0 -171
- data/lib/pdf_labels.rb +0 -3
- data/lib/template.rb +0 -37
Binary file
|
Binary file
|
data/init.rb
ADDED
data/lib/pdf/label.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/label/batch')
|
2
|
+
|
3
|
+
module Pdf
|
4
|
+
module Label
|
5
|
+
VERSION = '2.0.1'
|
6
|
+
|
7
|
+
#We want the barcode fonts to be loaded as availible fonts in the font path
|
8
|
+
root = File.expand_path(File.dirname(__FILE__) + "/../../")
|
9
|
+
PDF::Writer::FONT_PATH << (root + "/fonts")
|
10
|
+
PDF::Writer::FontMetrics::METRICS_PATH << (root + "/fonts")
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,276 @@
|
|
1
|
+
$: << File.expand_path(File.dirname(__FILE__) + "/../../../vendor")
|
2
|
+
require 'xml/mapping'
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/glabel_template')
|
4
|
+
require 'pdf/writer'
|
5
|
+
#--- require 'breakpoint'
|
6
|
+
|
7
|
+
module Pdf
|
8
|
+
module Label
|
9
|
+
class Batch
|
10
|
+
attr_accessor :gt, :template, :label, :pdf, :barcode_font
|
11
|
+
@@gt = nil
|
12
|
+
def initialize(template_name, pdf_opts = {})
|
13
|
+
@@gt || self.class.load_template_set
|
14
|
+
unless @template = @@gt.find_template(template_name)
|
15
|
+
raise "Template not found!"
|
16
|
+
end
|
17
|
+
#if the template specifies the paper type, and the user didn't use it.
|
18
|
+
if @template.size && !pdf_opts.has_key?(:paper)
|
19
|
+
pdf_opts[:paper] = @template.size.gsub(/^.*-/,'')
|
20
|
+
end
|
21
|
+
#TODO figure out how to cope with multiple label types on a page
|
22
|
+
@label = @template.labels["0"]
|
23
|
+
#TODO figure out how to handle multiple layouts
|
24
|
+
@layout = @label.layouts[0]
|
25
|
+
@labels_per_page = @layout.nx * @layout.ny
|
26
|
+
@zero_based_labels_per_page = @labels_per_page - 1
|
27
|
+
|
28
|
+
@pdf = PDF::Writer.new(pdf_opts)
|
29
|
+
@pdf.margins_pt(0, 0, 0, 0)
|
30
|
+
|
31
|
+
# Turn off print scaling in the generated PDF to ensure
|
32
|
+
# that the labels are positioned correctly when printing
|
33
|
+
# TODO This goes boom! @pdf.viewer_preferences('PrintScaling', '/None')
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.load_template_set(template_set_file=nil)
|
37
|
+
template_set_file ||= File.expand_path(File.dirname(__FILE__) + "/../../../templates/avery-us-templates.xml")
|
38
|
+
@@gt = GlabelsTemplate.load_from_file(template_set_file)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.all_template_names
|
42
|
+
@@gt || self.load_template_set
|
43
|
+
@@gt.find_all_templates
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.all_barcode_fonts
|
47
|
+
{"Code128.afm" => :translation_needed,
|
48
|
+
"Code2of5interleaved.afm" => :translation_needed,
|
49
|
+
"Code3de9.afm" => :code39,
|
50
|
+
"CodeDatamatrix.afm" => :translation_needed,
|
51
|
+
"CodeEAN13.afm" => :translation_needed,
|
52
|
+
"CodePDF417.afm" => :translation_needed}
|
53
|
+
end
|
54
|
+
|
55
|
+
def code39(text)
|
56
|
+
out = text.upcase
|
57
|
+
raise "Characters Not Encodable in Code3of9" unless out.match(/^[0-9A-Z\-\. \/\$\+%\*]+$/)
|
58
|
+
out = "*" + out unless out.match(/^\*/)
|
59
|
+
out = out + "*" unless out.match(/\*$/)
|
60
|
+
return out
|
61
|
+
end
|
62
|
+
|
63
|
+
def translation_needed(text)
|
64
|
+
$stderr.puts("This barcode format does not automatically get formatted yet")
|
65
|
+
#TODO - Rob need to add barcode formatting
|
66
|
+
return text
|
67
|
+
end
|
68
|
+
|
69
|
+
=begin rdoc
|
70
|
+
add_label takes an argument hash.
|
71
|
+
[:position] Which label slot to print. Positions are top to bottom, left to right so position 1 is the label in the top lefthand corner. Defaults to 0
|
72
|
+
[:x & :y] The (x,y) coordinates on the page to print the text. Ignored if position is specified.
|
73
|
+
[:text] What you want to print in the label. Defaults to the (x,y) of the top left corner of the label.
|
74
|
+
[:use_margin] If the label has a markupMargin, setting this argument to true will respect that margin when writing text. Defaults to true.
|
75
|
+
[:justification] Values can be :left, :right, :center, :full. Defaults to :left
|
76
|
+
[:offset_x, offset_y] If your printer doesn't want to print with out margins you can define these values to fine tune printout.
|
77
|
+
=end
|
78
|
+
def add_label(options = {})
|
79
|
+
label_x, label_y, label_width = setup_add_label_options(options)
|
80
|
+
|
81
|
+
text = options[:text] || "[#{label_x / 72}, #{label_y / 72}]"
|
82
|
+
|
83
|
+
arg_hash = setup_arg_hash(options, label_x, label_y, label_width)
|
84
|
+
|
85
|
+
@pdf.y = label_y
|
86
|
+
@pdf.text(text,arg_hash)
|
87
|
+
end
|
88
|
+
|
89
|
+
=begin rdoc
|
90
|
+
You can add the same text to many labels this way, takes all the arguments of add_label, but must have position instead of x,y. Requires count.
|
91
|
+
[:count] - Number of labels to print
|
92
|
+
=end
|
93
|
+
def add_many_labels(options = {})
|
94
|
+
if (options[:x] || options[:y]) && !options[:position]
|
95
|
+
raise "Can't use X,Y with add_many_labels, you must use position"
|
96
|
+
end
|
97
|
+
if !options[:position]
|
98
|
+
options[:position] = 0
|
99
|
+
end
|
100
|
+
raise "Count required" unless options[:count]
|
101
|
+
count = options[:count]
|
102
|
+
count.times do
|
103
|
+
add_label(options)
|
104
|
+
options[:position] = options[:position] + 1
|
105
|
+
end
|
106
|
+
end
|
107
|
+
=begin rdoc
|
108
|
+
To facilitate aligning a printer we give a method that prints the outlines of the labels
|
109
|
+
=end
|
110
|
+
def draw_boxes(write_coord = true, draw_markups = true)
|
111
|
+
@layout.nx.times do |x|
|
112
|
+
@layout.ny.times do |y|
|
113
|
+
box_x, box_y = get_x_y(x, y)
|
114
|
+
@pdf.rounded_rectangle(box_x,
|
115
|
+
box_y,
|
116
|
+
@label.width.as_pts,
|
117
|
+
@label.height.as_pts,
|
118
|
+
@label.round.as_pts).stroke
|
119
|
+
if write_coord
|
120
|
+
text = "#{box_x / 72}, #{box_y / 72}, #{@label.width.number}, #{label.height.number}"
|
121
|
+
add_label(:x => box_x, :y => box_y, :text => text)
|
122
|
+
end
|
123
|
+
|
124
|
+
if draw_markups
|
125
|
+
@label.markupMargins.each {|margin|
|
126
|
+
size = margin.size.as_pts
|
127
|
+
@pdf.rounded_rectangle(box_x + size,
|
128
|
+
box_y - margin.size.as_pts,
|
129
|
+
@label.width.as_pts - 2*size,
|
130
|
+
@label.height.as_pts - 2*size,
|
131
|
+
@label.round.as_pts).stroke
|
132
|
+
}
|
133
|
+
@label.markupLines.each {|line|
|
134
|
+
@pdf.line(box_x + line.x1.as_pts,
|
135
|
+
box_y + line.y1.as_pts,
|
136
|
+
box_x + line.x2.as_pts,
|
137
|
+
box_y + line.y2.as_pts).stroke
|
138
|
+
}
|
139
|
+
=begin TODO Draw cirles
|
140
|
+
@label.markupCircles.each {|cicle|
|
141
|
+
@pdf.
|
142
|
+
=end
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
=begin rdoc
|
150
|
+
add_label takes an argument hash.
|
151
|
+
[:position] Which label slot to print. Positions are top to bottom, left to right so position 1 is the label in the top lefthand corner. Defaults to 0
|
152
|
+
[:x & :y] The (x,y) coordinates on the page to print the text. Ignored if position is specified.
|
153
|
+
[:text] What you want to print in the label. Defaults to the (x,y) of the top left corner of the label.
|
154
|
+
[:use_margin] If the label has a markupMargin, setting this argument to true will respect that margin when writing text. Defaults to true.
|
155
|
+
[:justification] Values can be :left, :right, :center, :full. Defaults to :left
|
156
|
+
[:offset_x, offset_y] If your printer doesn't want to print with out margins you can define these values to fine tune printout.
|
157
|
+
=end
|
158
|
+
def add_barcode_label(options = {})
|
159
|
+
label_x, label_y, label_width = setup_add_label_options(options)
|
160
|
+
|
161
|
+
text = options[:text] || "[#{label_x / 72}, #{label_y / 72}]"
|
162
|
+
|
163
|
+
bar_text = setup_bar_text(options, text)
|
164
|
+
|
165
|
+
arg_hash = setup_arg_hash(options, label_x, label_y, label_width)
|
166
|
+
|
167
|
+
bar_hash = arg_hash.clone
|
168
|
+
bar_hash[:font_size] = options[:bar_size] || 12
|
169
|
+
|
170
|
+
old_font = @pdf.current_font!
|
171
|
+
@pdf.select_font(self.barcode_font)
|
172
|
+
|
173
|
+
@pdf.y = label_y
|
174
|
+
@pdf.text(bar_text,bar_hash)
|
175
|
+
|
176
|
+
@pdf.select_font(old_font)
|
177
|
+
@pdf.text(text,arg_hash)
|
178
|
+
end
|
179
|
+
|
180
|
+
def save_as(file_name)
|
181
|
+
@pdf.save_as(file_name)
|
182
|
+
end
|
183
|
+
|
184
|
+
def barcode_font
|
185
|
+
@barcode_font ||= "Code3de9.afm"
|
186
|
+
end
|
187
|
+
|
188
|
+
def barcode_font=(value)
|
189
|
+
if Pdf::Label::Batch.all_barcode_fonts.keys.include?(value)
|
190
|
+
@barcode_font = value
|
191
|
+
return @barcode_font
|
192
|
+
else
|
193
|
+
raise "Barcode Font Not Found for #{value}"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
protected
|
198
|
+
|
199
|
+
=begin rdoc
|
200
|
+
Position is top to bottom, left to right, starting at 1 and ending at the end of the page
|
201
|
+
=end
|
202
|
+
def position_to_x_y(position)
|
203
|
+
x = (position * 1.0 / @layout.ny).floor
|
204
|
+
y = position % @layout.ny
|
205
|
+
return get_x_y(x, y)
|
206
|
+
end
|
207
|
+
|
208
|
+
def get_x_y(x, y)
|
209
|
+
label_y = @pdf.absolute_top_margin
|
210
|
+
label_y = label_y + @pdf.top_margin
|
211
|
+
label_y = label_y - @layout.y0.as_pts
|
212
|
+
label_y = label_y - y * @layout.dy.as_pts
|
213
|
+
|
214
|
+
label_x = @pdf.absolute_left_margin
|
215
|
+
label_x = label_x - @pdf.left_margin
|
216
|
+
label_x = label_x + @layout.x0.as_pts
|
217
|
+
label_x = label_x + x * @layout.dx.as_pts
|
218
|
+
|
219
|
+
return label_x, label_y
|
220
|
+
end
|
221
|
+
|
222
|
+
def setup_add_label_options(options)
|
223
|
+
if position = options[:position]
|
224
|
+
# condition to handle multi-page PDF generation. If true, we're past the first page
|
225
|
+
if position > @zero_based_labels_per_page
|
226
|
+
# if remainder is zero, we're dealing with the first label of a new page
|
227
|
+
@pdf.new_page if ((position) % @labels_per_page) == 0
|
228
|
+
# Translate the position to a value between 1 and the number of labels for a given page
|
229
|
+
position = position - (position/@labels_per_page)*@labels_per_page
|
230
|
+
end
|
231
|
+
label_x, label_y = position_to_x_y(position)
|
232
|
+
elsif((label_x = options[:x]) && (label_y = options[:y]))
|
233
|
+
else
|
234
|
+
label_x, label_y = position_to_x_y(0)
|
235
|
+
end
|
236
|
+
#line wrap margin
|
237
|
+
label_width = label_x + @label.width.as_pts
|
238
|
+
|
239
|
+
if (use_margin = options[:use_margin]).nil?
|
240
|
+
use_margin = true
|
241
|
+
end
|
242
|
+
if use_margin
|
243
|
+
@label.markupMargins.each {|margin|
|
244
|
+
label_x = label_x + margin.size.as_pts
|
245
|
+
label_y = label_y - margin.size.as_pts
|
246
|
+
label_width = label_width - margin.size.as_pts
|
247
|
+
}
|
248
|
+
end
|
249
|
+
|
250
|
+
if offset = options[:offset_x]
|
251
|
+
label_x = label_x + offset
|
252
|
+
label_width = label_width + offset
|
253
|
+
end
|
254
|
+
if offset = options[:offset_y]
|
255
|
+
label_y = label_y + offset
|
256
|
+
end
|
257
|
+
return label_x, label_y, label_width
|
258
|
+
end
|
259
|
+
|
260
|
+
def setup_arg_hash(options, label_x, label_y, label_width)
|
261
|
+
arg_hash = {:justification => (options[:justification] || :left),
|
262
|
+
:font_size => (options[:font_size] || 12)}
|
263
|
+
|
264
|
+
arg_hash = arg_hash.merge :absolute_left => label_x,
|
265
|
+
:absolute_right => label_width
|
266
|
+
|
267
|
+
end
|
268
|
+
|
269
|
+
def setup_bar_text(options, text)
|
270
|
+
bar_text = options[:bar_text] || text
|
271
|
+
bar_text = send(Pdf::Label::Batch.all_barcode_fonts[self.barcode_font], bar_text)
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/template')
|
2
|
+
module Pdf
|
3
|
+
module Label
|
4
|
+
class GlabelsTemplate
|
5
|
+
include XML::Mapping
|
6
|
+
|
7
|
+
hash_node :templates, "Template", "@name", :class => Template, :default_value => Hash.new
|
8
|
+
|
9
|
+
def find_all_templates
|
10
|
+
return @t unless @t.nil?
|
11
|
+
@t = []
|
12
|
+
templates.each {|t|
|
13
|
+
@t << "#{t[1].name}"
|
14
|
+
t[1].alias.each {|a|
|
15
|
+
@t << "#{a[1].name}"
|
16
|
+
}
|
17
|
+
}
|
18
|
+
return @t
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def find_template(t_name)
|
23
|
+
return find_all_with_templates if t_name == :all
|
24
|
+
if t = templates[t_name]
|
25
|
+
return t
|
26
|
+
else
|
27
|
+
templates.each { |t|
|
28
|
+
if t[1].alias[t_name]
|
29
|
+
return t[1]
|
30
|
+
end
|
31
|
+
}
|
32
|
+
end
|
33
|
+
return nil
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/length_node')
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/layout')
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/markup')
|
4
|
+
|
5
|
+
module Pdf
|
6
|
+
module Label
|
7
|
+
|
8
|
+
class Label
|
9
|
+
include XML::Mapping
|
10
|
+
attr_accessor :shape
|
11
|
+
numeric_node :id, "@id"
|
12
|
+
array_node :markupMargins, "Markup-margin", :class => MarkupMargin, :default_value => nil
|
13
|
+
array_node :markupLines, "Markup-line", :class => MarkupLine, :default_value => nil
|
14
|
+
array_node :markupCircles, "Markup-circle", :class => MarkupCircle, :default_value => nil
|
15
|
+
|
16
|
+
array_node :layouts, "Layout", :class => Layout
|
17
|
+
|
18
|
+
def markups
|
19
|
+
@markups = Hash.new
|
20
|
+
@markups = @markups.merge @markupMargins
|
21
|
+
@markups = @markups.merge @markupLines
|
22
|
+
@markups = @markups.merge @markupCircles
|
23
|
+
@markups
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
class LabelRectangle < Label
|
31
|
+
length_node :width, "@width"
|
32
|
+
length_node :height, "@height"
|
33
|
+
length_node :round, "@round", :default_value => "0 pt"
|
34
|
+
length_node :waste, "@waste", :default_value => "0 pt"
|
35
|
+
length_node :x_waste, "@x_waste", :default_value => "0 pt"
|
36
|
+
length_node :y_waste, "@y_waste", :default_value => "0 pt"
|
37
|
+
@kind = "Rectangle"
|
38
|
+
end
|
39
|
+
|
40
|
+
class LabelRound < Label
|
41
|
+
length_node :radius, "@radius"
|
42
|
+
length_node :waste, "@radius", :default_value => "0 pt"
|
43
|
+
@kind = "Round"
|
44
|
+
end
|
45
|
+
|
46
|
+
class LabelCD < Label
|
47
|
+
length_node :radius, "@radius"
|
48
|
+
length_node :hole, "@hole"
|
49
|
+
length_node :width, "@width", :default_value => ""
|
50
|
+
length_node :height, "@height", :default_value => ""
|
51
|
+
length_node :waste, "@waste", :default_value => ""
|
52
|
+
@kind = "CD"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/length_node')
|
2
|
+
|
3
|
+
module Pdf
|
4
|
+
module Label
|
5
|
+
class Layout
|
6
|
+
include XML::Mapping
|
7
|
+
numeric_node :nx, "@nx"
|
8
|
+
numeric_node :ny, "@ny"
|
9
|
+
length_node :x0, "@x0", :default_value => "0 pt"
|
10
|
+
length_node :y0, "@y0", :default_value => "0 pt"
|
11
|
+
length_node :dx, "@dx", :default_value => "0 pt"
|
12
|
+
length_node :dy, "@dy", :default_value => "0 pt"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'xml/mapping/base'
|
2
|
+
|
3
|
+
module Pdf
|
4
|
+
module Label
|
5
|
+
class Length
|
6
|
+
attr_accessor :value, :unit, :number
|
7
|
+
|
8
|
+
def initialize(value)
|
9
|
+
@value = value
|
10
|
+
@number = value.match(/[\d\.]*/)[0].to_f
|
11
|
+
@unit = value.delete("#{number}").strip
|
12
|
+
end
|
13
|
+
|
14
|
+
#Return the numeric portion as a Points
|
15
|
+
def as_pts
|
16
|
+
if @unit =~ /pt/
|
17
|
+
return @number
|
18
|
+
elsif @unit =~ /in/
|
19
|
+
return @number * 72 #72.270
|
20
|
+
elsif @unit =~ /mm/
|
21
|
+
return @number * 2.83464566929134
|
22
|
+
elsif @unit =~ /cm/
|
23
|
+
return @number * 28.3464566929134
|
24
|
+
elsif @unit =~ /pc/
|
25
|
+
return 1.0 * @number / 12
|
26
|
+
elsif @unit == ''
|
27
|
+
return @number
|
28
|
+
else
|
29
|
+
raise "Unit #{unit} unknown"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class LengthNode < XML::Mapping::SingleAttributeNode
|
35
|
+
def initialize_impl(path)
|
36
|
+
@path = XML::XXPath.new(path)
|
37
|
+
end
|
38
|
+
|
39
|
+
def extract_attr_value(xml)
|
40
|
+
@value = default_when_xpath_err{@path.first(xml).text}
|
41
|
+
Length.new(@value)
|
42
|
+
end
|
43
|
+
|
44
|
+
def set_attr_value(xml, value)
|
45
|
+
raise "Not a Length: #{value}" unless Length===value
|
46
|
+
@path.first(xml,:ensure_created=>true).text = value.value
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
XML::Mapping.add_node_class LengthNode
|
51
|
+
end
|
52
|
+
end
|