zebra-zpl 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/Guardfile +11 -0
- data/LICENSE +21 -0
- data/LICENSE_ORIGINAL.txt +22 -0
- data/README.md +180 -0
- data/Rakefile +1 -0
- data/lib/zebra/print_job.rb +35 -0
- data/lib/zebra/zpl/barcode.rb +55 -0
- data/lib/zebra/zpl/barcode_type.rb +34 -0
- data/lib/zebra/zpl/box.rb +50 -0
- data/lib/zebra/zpl/character_set.rb +45 -0
- data/lib/zebra/zpl/country_code.rb +36 -0
- data/lib/zebra/zpl/font.rb +47 -0
- data/lib/zebra/zpl/justification.rb +21 -0
- data/lib/zebra/zpl/label.rb +97 -0
- data/lib/zebra/zpl/language.rb +76 -0
- data/lib/zebra/zpl/multipliers.rb +42 -0
- data/lib/zebra/zpl/print_mode.rb +18 -0
- data/lib/zebra/zpl/printable.rb +58 -0
- data/lib/zebra/zpl/qrcode.rb +37 -0
- data/lib/zebra/zpl/rotation.rb +20 -0
- data/lib/zebra/zpl/text.rb +80 -0
- data/lib/zebra/zpl/version.rb +5 -0
- data/lib/zebra/zpl.rb +18 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/zebra/print_job_spec.rb +36 -0
- data/spec/zebra/zpl/barcode_spec.rb +196 -0
- data/spec/zebra/zpl/box_spec.rb +71 -0
- data/spec/zebra/zpl/character_set_spec.rb +100 -0
- data/spec/zebra/zpl/label_spec.rb +138 -0
- data/spec/zebra/zpl/qrcode_spec.rb +101 -0
- data/spec/zebra/zpl/text_spec.rb +139 -0
- data/spec/zebra/zpl/zpl_spec.rb +5 -0
- data/zebra-zpl.gemspec +28 -0
- metadata +174 -0
@@ -0,0 +1,97 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Zebra
|
4
|
+
module Zpl
|
5
|
+
class Label
|
6
|
+
class InvalidPrintSpeedError < StandardError; end
|
7
|
+
class InvalidPrintDensityError < StandardError; end
|
8
|
+
class PrintSpeedNotInformedError < StandardError; end
|
9
|
+
|
10
|
+
attr_writer :copies
|
11
|
+
attr_reader :elements, :tempfile
|
12
|
+
attr_accessor :width, :length, :gap, :print_speed, :print_density
|
13
|
+
|
14
|
+
def initialize(options = {})
|
15
|
+
options.each_pair { |key, value| self.__send__("#{key}=", value) if self.respond_to?("#{key}=") }
|
16
|
+
@elements = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def length_and_gap=(length_and_gap)
|
20
|
+
self.length = length_and_gap[0]
|
21
|
+
self.gap = length_and_gap[1]
|
22
|
+
end
|
23
|
+
|
24
|
+
def print_speed=(s)
|
25
|
+
raise InvalidPrintSpeedError unless (0..6).include?(s)
|
26
|
+
@print_speed = s
|
27
|
+
end
|
28
|
+
|
29
|
+
def print_density=(d)
|
30
|
+
raise InvalidPrintDensityError unless (0..6).include?(d)
|
31
|
+
@print_density = d
|
32
|
+
end
|
33
|
+
|
34
|
+
def copies
|
35
|
+
@copies || 1
|
36
|
+
end
|
37
|
+
|
38
|
+
def <<(element)
|
39
|
+
element.width = self.width
|
40
|
+
elements << element
|
41
|
+
end
|
42
|
+
|
43
|
+
def dump_contents(io = STDOUT)
|
44
|
+
check_required_configurations
|
45
|
+
# Start format
|
46
|
+
io << "^XA"
|
47
|
+
# ^LL<label height in dots>,<space between labels in dots>
|
48
|
+
# io << "^LL#{length},#{gap}\n" if length && gap
|
49
|
+
io << "^LL#{length}" if length
|
50
|
+
# ^LH<label home - x,y coordinates of top left label>
|
51
|
+
io << "^LH0,0"
|
52
|
+
# ^LS<shift the label to the left(or right)>
|
53
|
+
io << "^LS10"
|
54
|
+
# ^PW<label width in dots>
|
55
|
+
io << "^PW#{width}" if width
|
56
|
+
# Print Rate(speed) (^PR command)
|
57
|
+
io << "^PR#{print_speed}"
|
58
|
+
# Density (D command) "Carried over from EPL, does this exist in ZPL ????"
|
59
|
+
# io << "D#{print_density}\n" if print_density
|
60
|
+
|
61
|
+
# TEST ZPL (comment everything else out)...
|
62
|
+
# io << "^XA^WD*:*.FNT*^XZ"
|
63
|
+
# TEST ZPL SEGMENT
|
64
|
+
# io << "^WD*:*.FNT*"
|
65
|
+
# TEST AND GET CONFIGS
|
66
|
+
# io << "^HH"
|
67
|
+
|
68
|
+
elements.each do |element|
|
69
|
+
io << element.to_zpl
|
70
|
+
end
|
71
|
+
# Specify how many copies to print
|
72
|
+
io << "^PQ#{copies}"
|
73
|
+
# End format
|
74
|
+
io << "^XZ"
|
75
|
+
end
|
76
|
+
|
77
|
+
def persist
|
78
|
+
# debugger
|
79
|
+
tempfile = Tempfile.new "zebra_label"
|
80
|
+
dump_contents tempfile
|
81
|
+
tempfile.close
|
82
|
+
@tempfile = tempfile
|
83
|
+
tempfile
|
84
|
+
end
|
85
|
+
|
86
|
+
def persisted?
|
87
|
+
!!self.tempfile
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def check_required_configurations
|
93
|
+
raise PrintSpeedNotInformedError unless print_speed
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Zebra
|
3
|
+
module Zpl
|
4
|
+
class Language
|
5
|
+
class InvalidLanguageError < StandardError; end
|
6
|
+
class InvalidLanguageForNumberOfDataBitsError < StandardError; end
|
7
|
+
|
8
|
+
# 8 bits languages
|
9
|
+
ENGLISH_US = "0"
|
10
|
+
LATIN_1 = "1"
|
11
|
+
LATIN_2 = "2"
|
12
|
+
PORTUGUESE = "3"
|
13
|
+
FRENCH_CANADIAN = "4"
|
14
|
+
NORDIC = "5"
|
15
|
+
TURKISH = "6"
|
16
|
+
ICELANDIC = "7"
|
17
|
+
HEBREW = "8"
|
18
|
+
CYRILLIC = "9"
|
19
|
+
CYRILLIC_CIS_1 = "10"
|
20
|
+
GREEK = "11"
|
21
|
+
GREEK_1 = "12"
|
22
|
+
GREEK_2 = "13"
|
23
|
+
LATIN_1_WINDOWS = "A"
|
24
|
+
LATIN_2_WINDOWS = "B"
|
25
|
+
CYRILLIC_WINDOWS = "C"
|
26
|
+
GREEK_WINDOWS = "D"
|
27
|
+
TURKISH_WINDOWS = "E"
|
28
|
+
HEBREW_WINDOWS = "F"
|
29
|
+
|
30
|
+
# 7 bits languages
|
31
|
+
USA = "0"
|
32
|
+
BRITISH = "1"
|
33
|
+
GERMAN = "2"
|
34
|
+
FRENCH = "3"
|
35
|
+
DANISH = "4"
|
36
|
+
ITALIAN = "5"
|
37
|
+
SPANISH = "6"
|
38
|
+
SWEDISH = "7"
|
39
|
+
SWISS = "8"
|
40
|
+
|
41
|
+
def self.valid_language?(language)
|
42
|
+
("0".."13").include?(language) || ("A".."F").include?(language)
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.validate_language(language)
|
46
|
+
raise InvalidLanguageError unless valid_language?(language)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.validate_language_for_number_of_data_bits(language, number_of_data_bits)
|
50
|
+
if number_of_data_bits == 8
|
51
|
+
validate_8_data_bits_language language
|
52
|
+
elsif number_of_data_bits == 7
|
53
|
+
validate_7_data_bits_language language
|
54
|
+
else
|
55
|
+
raise ArgumentError.new("Unknown number of data bits")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def self.validate_8_data_bits_language(language)
|
62
|
+
raise InvalidLanguageForNumberOfDataBitsError unless [ENGLISH_US,
|
63
|
+
LATIN_1, LATIN_2, PORTUGUESE, FRENCH_CANADIAN, NORDIC,
|
64
|
+
TURKISH, ICELANDIC, HEBREW, CYRILLIC, CYRILLIC_CIS_1, GREEK,
|
65
|
+
GREEK_1, GREEK_2, LATIN_1_WINDOWS, LATIN_2_WINDOWS, CYRILLIC_WINDOWS,
|
66
|
+
GREEK_WINDOWS, TURKISH_WINDOWS, HEBREW_WINDOWS].include?(language)
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.validate_7_data_bits_language(language)
|
70
|
+
raise InvalidLanguageForNumberOfDataBitsError unless [USA, BRITISH,
|
71
|
+
GERMAN, FRENCH, DANISH, ITALIAN, SPANISH, SWEDISH, SWISS].include?(language)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Zebra
|
2
|
+
module Zpl
|
3
|
+
module BaseMultiplier
|
4
|
+
class InvalidMultiplierError < StandardError; end
|
5
|
+
|
6
|
+
VALUE_1 = 1
|
7
|
+
VALUE_2 = 2
|
8
|
+
VALUE_3 = 3
|
9
|
+
VALUE_4 = 4
|
10
|
+
VALUE_5 = 5
|
11
|
+
VALUE_6 = 6
|
12
|
+
VALUE_7 = 7
|
13
|
+
VALUE_8 = 8
|
14
|
+
|
15
|
+
def self.included(base_module)
|
16
|
+
base_module.instance_eval do
|
17
|
+
def validate_multiplier(multiplier)
|
18
|
+
raise InvalidMultiplierError unless valid_multiplier?(multiplier)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module HorizontalMultiplier
|
25
|
+
include BaseMultiplier
|
26
|
+
|
27
|
+
def self.valid_multiplier?(multiplier)
|
28
|
+
(1..8).include? multiplier
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module VerticalMultiplier
|
33
|
+
include BaseMultiplier
|
34
|
+
|
35
|
+
VALUE_9 = 9
|
36
|
+
|
37
|
+
def self.valid_multiplier?(multiplier)
|
38
|
+
(1..9).include? multiplier
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Zebra
|
2
|
+
module Zpl
|
3
|
+
module PrintMode
|
4
|
+
class InvalidPrintModeError < StandardError; end
|
5
|
+
|
6
|
+
NORMAL = "N"
|
7
|
+
REVERSE = "R"
|
8
|
+
|
9
|
+
def self.valid_mode?(mode)
|
10
|
+
%w(N R).include? mode
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.validate_mode(mode)
|
14
|
+
raise InvalidPrintModeError unless valid_mode?(mode)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Zebra
|
2
|
+
module Zpl
|
3
|
+
module Printable
|
4
|
+
class MissingAttributeError < StandardError
|
5
|
+
def initialize(message)
|
6
|
+
super("Can't print if #{message}")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :position, :x, :y, :margin
|
11
|
+
attr_accessor :data
|
12
|
+
|
13
|
+
def initialize(options = {})
|
14
|
+
options.each_pair { |attribute, value| self.__send__ "#{attribute}=", value }
|
15
|
+
end
|
16
|
+
|
17
|
+
def position=(coords)
|
18
|
+
@position = coords
|
19
|
+
@x = (@margin.nil? || @margin == 0) ? coords[0] : (@margin + coords[0])
|
20
|
+
@y = coords[1]
|
21
|
+
end
|
22
|
+
|
23
|
+
def justification=(just)
|
24
|
+
Justification.validate_justification just
|
25
|
+
@justification = just
|
26
|
+
end
|
27
|
+
|
28
|
+
def justification
|
29
|
+
@justification || Justification::LEFT
|
30
|
+
end
|
31
|
+
|
32
|
+
def margin=(margin)
|
33
|
+
@margin = margin || 0
|
34
|
+
end
|
35
|
+
|
36
|
+
def rotation=(rot)
|
37
|
+
Rotation.validate_rotation rot
|
38
|
+
@rotation = rot
|
39
|
+
end
|
40
|
+
|
41
|
+
def rotation
|
42
|
+
@rotation || Rotation::NO_ROTATION
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def has_data?
|
48
|
+
true
|
49
|
+
end
|
50
|
+
|
51
|
+
def check_attributes
|
52
|
+
raise MissingAttributeError.new("the X value is not given") unless @x
|
53
|
+
raise MissingAttributeError.new("the Y value is not given") unless @y
|
54
|
+
raise MissingAttributeError.new("the data to be printed is not given") unless @data || !has_data?
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "zebra/zpl/printable"
|
2
|
+
|
3
|
+
module Zebra
|
4
|
+
module Zpl
|
5
|
+
class Qrcode
|
6
|
+
include Printable
|
7
|
+
|
8
|
+
class InvalidScaleFactorError < StandardError; end
|
9
|
+
class InvalidCorrectionLevelError < StandardError; end
|
10
|
+
|
11
|
+
attr_reader :scale_factor, :correction_level
|
12
|
+
|
13
|
+
def scale_factor=(value)
|
14
|
+
raise InvalidScaleFactorError unless (1..99).include?(value.to_i)
|
15
|
+
@scale_factor = value
|
16
|
+
end
|
17
|
+
|
18
|
+
def correction_level=(value)
|
19
|
+
raise InvalidCorrectionLevelError unless %w[L M Q H].include?(value.to_s)
|
20
|
+
@correction_level = value
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_zpl
|
24
|
+
check_attributes
|
25
|
+
["b#{x}", y, "Q", "s#{scale_factor}", "e#{correction_level}", "\"#{data}\""].join(",")
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def check_attributes
|
31
|
+
super
|
32
|
+
raise MissingAttributeError.new("the scale factor to be used is not given") unless @scale_factor
|
33
|
+
raise MissingAttributeError.new("the error correction level to be used is not given") unless @correction_level
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Zebra
|
2
|
+
module Zpl
|
3
|
+
module Rotation
|
4
|
+
class InvalidRotationError < StandardError; end
|
5
|
+
|
6
|
+
NO_ROTATION = 'N'
|
7
|
+
DEGREES_90 = 'R'
|
8
|
+
DEGREES_180 = 'I'
|
9
|
+
DEGREES_270 = 'B'
|
10
|
+
|
11
|
+
def self.valid_rotation?(rotation)
|
12
|
+
[NO_ROTATION, DEGREES_90, DEGREES_180, DEGREES_270].include? rotation
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.validate_rotation(rotation)
|
16
|
+
raise InvalidRotationError unless valid_rotation?(rotation)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require "zebra/zpl/printable"
|
2
|
+
|
3
|
+
module Zebra
|
4
|
+
module Zpl
|
5
|
+
class Text
|
6
|
+
include Printable
|
7
|
+
|
8
|
+
attr_reader :font_size, :font_type, :width
|
9
|
+
|
10
|
+
def font_size=(f)
|
11
|
+
FontSize.validate_font_size f
|
12
|
+
@font_size = f
|
13
|
+
end
|
14
|
+
|
15
|
+
def width=(width)
|
16
|
+
unless (margin.nil? || margin < 1)
|
17
|
+
@width = (width - (margin*2))
|
18
|
+
else
|
19
|
+
@width = width || 0
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def font_type=(type)
|
24
|
+
FontType.validate_font_type type
|
25
|
+
@font_type = type
|
26
|
+
end
|
27
|
+
|
28
|
+
def font_type
|
29
|
+
@font_type || FontType::TYPE_0
|
30
|
+
end
|
31
|
+
|
32
|
+
def print_mode=(mode)
|
33
|
+
PrintMode.validate_mode mode
|
34
|
+
@print_mode = mode
|
35
|
+
end
|
36
|
+
|
37
|
+
def print_mode
|
38
|
+
@print_mode || PrintMode::NORMAL
|
39
|
+
end
|
40
|
+
|
41
|
+
def h_multiplier
|
42
|
+
@h_multiplier || HorizontalMultiplier::VALUE_1
|
43
|
+
end
|
44
|
+
|
45
|
+
def v_multiplier
|
46
|
+
@v_multiplier || VerticalMultiplier::VALUE_1
|
47
|
+
end
|
48
|
+
|
49
|
+
def print_mode
|
50
|
+
@print_mode || PrintMode::NORMAL
|
51
|
+
end
|
52
|
+
|
53
|
+
def h_multiplier=(multiplier)
|
54
|
+
HorizontalMultiplier.validate_multiplier multiplier
|
55
|
+
@h_multiplier = multiplier
|
56
|
+
end
|
57
|
+
|
58
|
+
def v_multiplier=(multiplier)
|
59
|
+
VerticalMultiplier.validate_multiplier multiplier
|
60
|
+
@v_multiplier = multiplier
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_zpl
|
64
|
+
check_attributes
|
65
|
+
# ["A#{x}", y, rotation, font_size, h_multiplier, v_multiplier, print_mode, "\"#{data}\""].join(",")
|
66
|
+
# "^FO25,25^FB600,100,0,C,0^FDFoo^FS"
|
67
|
+
|
68
|
+
# "^CF#{font_type},#{font_size}^FO#{x},#{y}^FB609,4,0,#{justification},0^FD#{data}^FS"
|
69
|
+
"^FW#{rotation}^CF#{font_type},#{font_size}^CI28^FO#{x},#{y}^FB#{width},4,0,#{justification},0^FD#{data}^FS"
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def check_attributes
|
75
|
+
super
|
76
|
+
raise MissingAttributeError.new("the font_size to be used is not given") unless @font_size
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/zebra/zpl.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require "cups"
|
2
|
+
require "tempfile"
|
3
|
+
require "zebra/zpl/version"
|
4
|
+
require "zebra/zpl/language"
|
5
|
+
require "zebra/zpl/country_code"
|
6
|
+
require "zebra/zpl/character_set"
|
7
|
+
require "zebra/zpl/rotation"
|
8
|
+
require "zebra/zpl/multipliers"
|
9
|
+
require "zebra/zpl/print_mode"
|
10
|
+
require "zebra/zpl/font"
|
11
|
+
require "zebra/zpl/box"
|
12
|
+
require "zebra/zpl/label"
|
13
|
+
require "zebra/zpl/text"
|
14
|
+
require "zebra/zpl/barcode"
|
15
|
+
require "zebra/zpl/barcode_type"
|
16
|
+
require "zebra/print_job"
|
17
|
+
require "zebra/zpl/qrcode"
|
18
|
+
require "zebra/zpl/justification"
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
|
8
|
+
require "zebra/zpl"
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
12
|
+
config.run_all_when_everything_filtered = true
|
13
|
+
config.filter_run :focus
|
14
|
+
|
15
|
+
# Run specs in random order to surface order dependencies. If you find an
|
16
|
+
# order dependency and want to debug it, you can fix the order by providing
|
17
|
+
# the seed, which is printed after each run.
|
18
|
+
# --seed 1234
|
19
|
+
config.order = 'random'
|
20
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Zebra::PrintJob do
|
4
|
+
before do
|
5
|
+
Cups.stub(:show_destinations).and_return(["Zebra", "Foobar"])
|
6
|
+
end
|
7
|
+
|
8
|
+
it "receives the name of a printer" do
|
9
|
+
described_class.new("Zebra").printer.should == "Zebra"
|
10
|
+
end
|
11
|
+
|
12
|
+
it "raises an error if the printer does not exists" do
|
13
|
+
expect {
|
14
|
+
described_class.new("Wrong")
|
15
|
+
}.to raise_error(Zebra::PrintJob::UnknownPrinter)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#print" do
|
19
|
+
let(:label) { stub :persist => tempfile }
|
20
|
+
let(:cups_job) { stub :print => true }
|
21
|
+
let(:tempfile) { stub(:path => "/foo/bar").as_null_object }
|
22
|
+
|
23
|
+
subject(:print_job) { described_class.new "Zebra" }
|
24
|
+
|
25
|
+
before { print_job.stub(:` => true) }
|
26
|
+
|
27
|
+
it "creates a cups print job with the correct arguments" do
|
28
|
+
print_job.print label
|
29
|
+
end
|
30
|
+
|
31
|
+
it "prints the label" do
|
32
|
+
print_job.should_receive(:`).with("lpr -P Zebra -o raw /foo/bar")
|
33
|
+
print_job.print label
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|