escper 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -3,3 +3,7 @@ pkg/*
3
3
  .bundle
4
4
  *.*~
5
5
  *~
6
+ debian/ruby-escper
7
+ *.log
8
+ files
9
+ *.substvars
data/README.md CHANGED
@@ -9,15 +9,15 @@ Installation
9
9
  Introduction
10
10
  ------------
11
11
 
12
- Escper is a collection of essential tools that make printing of plain text and images to one or many serial thermal printers easy. Both USB and serial (RS232) printers are supported and detected automatically. Escper is useful for Ruby based Point of Sale systems that want to print receipts or tickets.
12
+ Escper is a collection of tools that make printing of plain text and images to one or several serial thermal printers easy. USB, serial (RS232) and TCP/IP based printers are supported. Escper is useful for Ruby-based Point of Sale (POS) systems that want to print receipts, tickets or labels.
13
13
 
14
- While the actual printing is just writing a string to a device node inside of `/dev`, there is some preprocessing necessary. Thermal printers usually have a narrow character set, do not support UTF-8, only ASCII-8BIT. Escper makes it possible to just conveniently pass an UTF-8 string to the printing method, and it does all the conversion work under the covers. For special characters, Escper will map UTF-8 characters to the ASCII-8BIT codes that are actually supported by the currently set codepage on the printer (have a look at the user manual of your printer). The file `lib/escper/codepages.yml` is an example for matching UTF-8 codes to ASCII codes of the standard codepage of the commonly available Espon and Metapace printers.
14
+ While the actual printing is just writing a bytearray to a device node located inside of `/dev`, there is some preprocessing necessary. Thermal printers usually have a narrow and custom character set, do not support UTF-8, only ASCII-8BIT. However, Escper makes it possible to conveniently pass an UTF-8 string to the printing method, and it does all the conversion work under the hood. For special characters, Escper will map UTF-8 characters to the ASCII-8BIT codes that are actually supported by the currently enabled codepage on the printer (have a look at the user manual of your printer). The file `lib/escper/codepages.yml` is an example for matching UTF-8 codes to ASCII codes of the standard codepage of the commonly available Espon and Metapace printers.
15
15
 
16
16
  Another tricky usecase is where text is mixed with images. Images are transformed into ESCPOS compatible printing data, which is supported by the majority of thermal printers. When mixing text and images in one print 'document', Escper will still transform special UTF-8 characters according to the above mentioned codepages.yml file, but leave the image data raw i.e. unchanged.
17
17
 
18
- Escper only supports printers which support plain data copy to their device node living under `/dev`. Printers for which the Kernel does not create a device node that can be opened as a file or as a Serial Port are not supported. Escper does not care about the styling of the text with special printer commands; it is up to the user to pass those commands as part of the printing string. An exception are images; those are converted to ESCPOS code.
18
+ Escper only supports printers which support plain data-copy to their device node living under `/dev` or via a TCP socket. Printers for which the Linux Kernel does not create a device node that can be opened as a file or as a Serial Port, or non-plain-TCP printers are not supported. Escper does not care about the formatting of the text; it is up to the user to pass those formatting commands as part of the printing string. An exception are images; those are converted to ESCPOS code always.
19
19
 
20
- Some Point of Sale systems, especially those for restaurants, have to send tickets to several printers at the same time (e.g. kitchen, bar, etc.). Escper makes this easy. Have a look at the usage examples below.
20
+ Some Point of Sale systems, especially those for restaurants, have to send tickets to several printers/locations at the same time (e.g. kitchen, bar, etc.). Escper makes this easy. Have a look at the usage examples below.
21
21
 
22
22
  Usecase: Convert image to ESCPOS code
23
23
  ------------
@@ -30,11 +30,11 @@ The source of the image can be a file:
30
30
 
31
31
  escpos_code = Escper::Img.new('/path/to/test.png', :file).to_s
32
32
 
33
- The source of the image can also be data which is uploaded from a HTML form. Here, the variable `data` is a variable containing the image data of a multipart HTML form:
33
+ The source of the image can also be data which is uploaded via a HTML form. Here, the variable `data` is a variable containing the image data of a multipart HTML form. The following code would work in Ruby on Rails:
34
34
 
35
35
  escpos_code = Escper::Img.new(data.read, :blob).to_s
36
36
 
37
- Alternatively, the image source can also be an ImageMagick canvas:
37
+ Alternatively, the image source can also be a dynamically created ImageMagick canvas:
38
38
 
39
39
  canvas = Magick::Image.new(512, 128)
40
40
  gc = Magick::Draw.new
@@ -52,21 +52,21 @@ Alternatively, the image source can also be an ImageMagick canvas:
52
52
 
53
53
  For optimal visual results, when using a file or a blob, the image should previously be converted to an indexed, black and white 1-bit palette image. In Gimp, click on "Image -> Mode -> Indexed..." and select "Use black and white (1-bit) palette". For dithering, choose "Floyd-Steinberg (reduced color bleeding)". The image size depends on the resolution of the printer.
54
54
 
55
- To send an image directly to a thermal receipt printer in just one line:
55
+ To print an image directly on a thermal receipt printer, in just one line:
56
56
 
57
- File.open('/dev/usb/lp0','w') { |f| f.write Escper::Img.new('/path/to/image.png').to_s }
57
+ File.open('/dev/usb/lp0','w') { |f| f.write Escper::Img.new('/path/to/image.png', :file).to_s }
58
58
 
59
59
 
60
60
  Usecase: Print UTF-8 text to several printers at the same time
61
61
  ------------
62
62
 
63
- First, create `VendorPrinter` objects which are simply containers for configuration data about the printer. If you develop your application in a framework like Rails, you also can use the models from the Rails application instead of creating them from within Escper. The only requirements are that the objects respond to the methods `id`, `name`, `path`, `copies`, `codepage` and `baudrate`.
63
+ First, in Ruby, create objects of the class named `VendorPrinter` which are simply containers for configuration data about the printer. If you develop your application in a framework like Ruby on Rails, you also can use the models from the Rails application instead of creating them from within Escper. The only requirements are that the objects respond to the methods `id`, `name`, `path`, `copies`, `codepage` and `baudrate`. Here we are creating 3 printers of the types USB, RS232 and TCP/IP:
64
64
 
65
65
  vp1 = Escper::VendorPrinter.new :id => 1, :name => 'Printer 1 USB', :path => '/dev/usb/lp0', :copies => 1
66
- vp2 = Escper::VendorPrinter.new :id => 2, :name => 'Printer 2 USB', :path => '/dev/usb/lp0', :copies => 1
67
- vp3 = Escper::VendorPrinter.new :id => 3, :name => 'Printer 3 RS232', :path => '/dev/ttyUSB0', :copies => 1
66
+ vp2 = Escper::VendorPrinter.new :id => 2, :name => 'Printer 2 RS232', :path => '/dev/ttyUSB0', :copies => 1
67
+ vp3 = Escper::VendorPrinter.new :id => 3, :name => 'Printer 3 TCP/IP', :path => '192.168.0.201:9100', :copies => 1
68
68
 
69
- `id` must be unique integers which will be needed later during printing. `name` is an arbitrary string which is only used for logging. `path` is the path to a regular file or the device node of the thermal printer which usually lives under `/dev`. Device nodes can be of the kinds USB or serial port (RS232). `copies` are the number of duplications of pages that the printer should print. Optionally, you can pass in the key `codepage` which is a number that must correspond to one of the YAML keys in the file `codepages.yml`. By making the `codepage` a parameter of the printer model, it is possible to use several different printers from different manufacturers with different character sets at the same time. `baudrate` is an optional integer to set the speed of the transmission (the default is 9600, this setting is only effective when using RS232 communication).
69
+ `id` must be unique integers which will be needed later during printing. `name` is an arbitrary string which is only used for logging. `path` is the path to a regular file, serial device node or `IP:port` of the thermal printer (with a colon). Device nodes can be of the type USB, serial port (RS232) or TCP/IP. `copies` are the number of duplications of pages that the printer should print. Optionally, you can pass in the key `codepage` which is a number that must correspond to one of the YAML keys in the file `codepages.yml`. By making the `codepage` a parameter of the printer model, it is possible to use several different printers from different manufacturers with different character sets at the same time. `baudrate` is an optional integer to set the speed of the transmission (the default is 9600, this setting is only effective when using RS232 communication).
70
70
 
71
71
  Next, initialize the printing engine of Escper by passing it an array of the VendorPrinter instances. It is also possible to pass a single VendorPrinter instance instead of an Array. As mentioned earlier, you also can pass instances or Arrays of instances of a class that is named differently (e.g. ActiveRecord queries), as longs as it responds to the afore mentioned attributes:
72
72
 
@@ -76,32 +76,32 @@ Now, open all device nodes as specified in `new`:
76
76
 
77
77
  print_engine.open
78
78
 
79
- Once all device nodes are openend for writing, you can print text. Text must be UTF-8 encoded. The fist parameter is the `id` of the printer object that should be printed to. The second parameter, the text, will be printed immediately:
79
+ After this, you can finally print text and images. Text must be UTF-8 encoded. The fist parameter is the `id` of the printer object that should be printed to. The second parameter is the actual text:
80
80
 
81
81
  print_engine.print 1, 'print text to printer 1'
82
82
  print_engine.print 2, 'print text to printer 2'
83
83
  print_engine.print 3, 'print text to printer 3'
84
84
 
85
85
  The `print` method will return an array which contains the number of bytes actually written to the device node, as well as the raw text that was written to the device node.
86
-
86
+
87
87
  After printing is finished, don't forget to close the device nodes which were openened during the `open` call:
88
88
 
89
89
  print_engine.close
90
90
 
91
91
 
92
- Usecase: Print UTF8 text mixed with binary images
92
+ Usecase: Print UTF-8 text mixed with binary images
93
93
  ------------
94
94
 
95
95
  Create a printer object:
96
96
 
97
97
  vp1 = Escper::VendorPrinter.new :id => 1, :name => 'Printer 1 USB', :path => '/dev/usb/lp0', :copies => 1
98
98
 
99
- Render images into ESCPOS, stored in variables:
99
+ Render images into ESCPOS code, stored in variables:
100
100
 
101
101
  image_escpos1 = Escper::Img.new('/path/to/test1.png', :file).to_s
102
102
  image_escpos2 = Escper::Img.new('/path/to/test2.png', :file).to_s
103
103
 
104
- This raw image data now must be stored in a hash, whith a unique key that gives the image a unique name:
104
+ This raw image data now must be stored in a hash, whith a unique key that gives the image a unique name. This is necessary so that the image code will not be distorted by the codepage transformation.
105
105
 
106
106
  raw_images = {:image1 => image_escpos1, :image2 => image_escpos2}
107
107
 
@@ -115,9 +115,9 @@ Open the printer device nodes:
115
115
 
116
116
  Print text and image at the same time:
117
117
 
118
- print_engine.print 1, 'print text and image1 {::escper}image1{:/} and image 2 {::escper}image1{:/} to printer 1', raw_images
118
+ print_engine.print 1, "print text and image1 {::escper}image1{:/} and image 2 {::escper}image1{:/} to printer 1", raw_images
119
119
 
120
- Note that the magic tag `{::escper}image_key{:/}` will be replaced with the image that is stored in the hash `raw_images` with the key `image_key`.
120
+ Note that the special tag `{::escper}image_key{:/}` will be replaced with the image that is stored in the hash `raw_images` with the key `image_key`.
121
121
 
122
122
  After printing is done, close the device nodes again:
123
123
 
@@ -127,7 +127,7 @@ After printing is done, close the device nodes again:
127
127
  Fallback mode
128
128
  ----------------------
129
129
 
130
- If a device node is busy or not writable, Escper will create fallback files instead and append the print data to that file. The fallback files will have the name of the printers and will by default be saved in `/tmp`, or, when you include Escper from Rails, in the `tmp` folder of the Rails app source.
130
+ If a device node is busy or not writable, Escper will create fallback files instead and append the print data to that file. The fallback files will have the name of the printers and will by default be saved in `/tmp`, or, when you include Escper from Rails, in the `tmp` folder of the Rails app source. A connection to an IP address (a TCP socket) must succeed within 2 seconds, otherwise the fallback mode becomes enabled.
131
131
 
132
132
  Configuration
133
133
  ----------------------
@@ -142,7 +142,7 @@ You can configure Escper by calling in your project:
142
142
 
143
143
  `codepage_file` specifies the path to `codepages.yml`. (for an explanation see above). If not specified, the file `codepages.yml` that is part of this gem distribution will be used.
144
144
 
145
- `use_safe_device_path` can be set to `true` when you are running Escper on a remote server and no actual writes to physical printers should occur. In this case, all print data will be stored in regular files in the path `safe_device_path` with safe/escaped file names, which can be further processed or served by other programs.
145
+ `use_safe_device_path` can be set to `true` for security reasons when you are running Escper on a remote server and no actual writes to physical printers should occur. In this case, all print data will always be stored in regular files in the path `safe_device_path` with safe/escaped file names, which can be further processed or served by other programs.
146
146
 
147
147
  Additional Features
148
148
  ----------------------
@@ -171,15 +171,15 @@ Ask for support or additional features!
171
171
 
172
172
  Red (E) Tools Ltd.
173
173
 
174
- office@red-e.eu
174
+ office@thebigrede.net
175
175
 
176
- www.red-e.eu
176
+ www.thebigrede.net
177
177
 
178
178
 
179
179
  Licence
180
180
  ----------------------
181
181
 
182
- Copyright (C) 2011-2013 Red (E) Tools Ltd. <office@red-e.eu>
182
+ Copyright (C) 2011-2013 Red (E) Tools Ltd. <office@thebigrede.net>
183
183
 
184
184
  Permission is hereby granted, free of charge, to any person obtaining
185
185
  a copy of this software and associated documentation files (the
@@ -9,8 +9,8 @@ Gem::Specification.new do |s|
9
9
  s.authors = ["Red (E) Tools Ltd."]
10
10
  s.email = ["office@red-e.eu"]
11
11
  s.homepage = "http://red-e.eu"
12
- s.summary = %q{Collection of essential tools that make printing of plain text and images to one or many serial thermal printers easy.}
13
- s.description = %q{Collection of essential tools that make printing of plain text and images to one or many serial thermal printers easy. Both USB and serial (RS232) printers are supported and detected automatically. Escper is useful for Ruby based Point of Sale systems that want to print receipts or tickets.}
12
+ s.summary = %q{Collection of tools that make printing of plain text and images to one or many serial thermal printers easy.}
13
+ s.description = %q{Collection of tools that make printing of plain text and images to one or many serial thermal printers easy. USB, serial (RS232) and TCP/IP printers are supported. Escper is useful for Ruby based Point of Sale systems that want to print receipts or tickets, but also suitable for stand-alone applications.}
14
14
 
15
15
  #s.rubyforge_project = "escper"
16
16
 
@@ -1,6 +1,6 @@
1
1
  require 'RMagick'
2
2
  require 'yaml'
3
- #require 'active_record'
3
+ require 'timeout'
4
4
 
5
5
  dir = File.dirname(__FILE__)
6
6
  Dir[File.expand_path("#{dir}/escper/*.rb")].uniq.each do |file|
@@ -54,16 +54,13 @@ module Escper
54
54
  temp = 0
55
55
  end
56
56
  end
57
- result = bits.collect{ |b| b.chr }.join
57
+ result = bits.pack("C*")
58
+ p_cmd = "\x1D\x76\x30\x00"
59
+ hdr = [@x, (@y*8)].pack("SS")
58
60
  escpos = ''
59
61
  escpos.encode! 'ASCII-8BIT'
60
- escpos += "\x1D\x76\x30\x00" +
61
- @x.chr +
62
- "\x00" +
63
- (@y*8).chr +
64
- "\x00" +
65
- result
62
+ escpos += p_cmd + hdr + result
66
63
  return escpos
67
64
  end
68
65
  end
69
- end
66
+ end
@@ -1,9 +1,9 @@
1
1
  module Escper
2
2
  def self.log(text)
3
3
  if defined?(ActiveRecord)
4
- ActiveRecord::Base.logger.info text
4
+ ActiveRecord::Base.logger.info "[ESCPER] #{ text }"
5
5
  else
6
- puts text
6
+ puts "[ESCPER] #{ text }"
7
7
  end
8
8
  end
9
9
  end
@@ -1,54 +1,78 @@
1
1
  module Escper
2
2
  class Printer
3
- # mode can be local or sass
4
- # vendor_printers can either be a single VendorPrinter object, or an Array of VendorPrinter objects, or an ActiveRecord Relation containing VendorPrinter objects.
5
- def initialize(mode='local', vendor_printers=nil, subdirectory=nil)
3
+
4
+ # Creates a new Printer object.
5
+ # +mode+:: can be either "local" or any other string. Currently only "local" is recognized. If set to anything else than "local", printing to TCP/IP based printers will be disabled.
6
+ # +vendor_printers+:: can either be a single object of class VendorPrinter, or an Array of objects of class VendorPrinter, or an ActiveRecord Relation containing objects which respond to the methods +id+, +path+, +name+, +copies+ and +codepage+.
7
+ # +subdirectory+:: If the Escper module variable +use_safe_device_path+ is other than nil, it will not be printed to the path gived by the +path+ attribute of the printers, but +subdirectory+ will be the prefix for the path. This way, printing data are saved to regular files in a regular directory. This is useful if this printing data is processed and served by a webserver rather than being sent to a real printer immmediately.
8
+ def initialize(mode="local", vendor_printers=nil, subdirectory=nil)
6
9
  @mode = mode
7
10
  @subdirectory = subdirectory
8
- @open_printers = Hash.new
11
+ @open_printers = {}
9
12
  @codepages_lookup = YAML::load(File.read(Escper.codepage_file))
10
13
  @file_mode = 'wb'
14
+
11
15
  if defined?(Rails)
12
16
  @fallback_root_path = Rails.root
13
17
  else
14
18
  @fallback_root_path = '/'
15
19
  end
20
+
16
21
  if vendor_printers.kind_of?(Array) or (defined?(ActiveRecord) == 'constant' and vendor_printers.kind_of?(ActiveRecord::Relation))
17
22
  @vendor_printers = vendor_printers
18
23
  elsif vendor_printers.kind_of?(VendorPrinter) or vendor_printers.kind_of?(::VendorPrinter)
19
24
  @vendor_printers = [vendor_printers]
20
25
  else
21
26
  # If no available VendorPrinters are initialized, create a set of temporary VendorPrinters with usual device paths.
22
- Escper.log "No VendorPrinters specified. Creating a set of temporary printers with common device paths"
23
- paths = ['/dev/ttyUSB0', '/dev/ttyUSB1', '/dev/ttyUSB2', '/dev/usb/lp0', '/dev/usb/lp1', '/dev/usb/lp2', '/dev/salor-hospitality-front', '/dev/salor-hospitality-top', '/dev/salor-hospitality-back-top-left', '/dev/salor-hospitality-back-top-right', '/dev/salor-hospitality-back-bottom-left', '/dev/salor-hospitality-back-bottom-right']
27
+ Escper.log "[initialize] No VendorPrinters specified. Creating a set of temporary printers with common device paths"
28
+ paths = ['/dev/ttyUSB0', '/dev/ttyUSB1', '/dev/ttyUSB2', '/dev/usb/lp0', '/dev/usb/lp1', '/dev/usb/lp2']
24
29
  @vendor_printers = Array.new
25
30
  paths.size.times do |i|
26
- @vendor_printers << VendorPrinter.new(:name => paths[i].gsub(/^.*\//,''), :path => paths[i], :copies => 1, :codepage => 0)
31
+ vp = VendorPrinter.new
32
+ vp.name = paths[i].gsub(/^.*\//,'')
33
+ vp.path = paths[i]
34
+ vp.copies = 1
35
+ vp.codepage = 0
27
36
  end
28
37
  end
29
38
  end
30
39
 
40
+ # Outputs text to the printing device (File, SerialPort or TCPSocket)
41
+ # +printer_id+:: The id of the printer which was passed to +new()+
42
+ # +text+:: UTF-8 encoded string. UTF-8 will be converted to ASCII-8BIT encoding according to the +codepage+ attribute of a specified printer. Codepage lookup tables are in the file +codepages.yml+, included in this gem. +text+ may include tags in the format {::escper}my_tag{:/}.For example, this tag "my_tag" will be replaced by the value of the key "my_tag" in the +raw_text_insertations+ hash. No character conversion will be done for these insertations.
43
+ # +raw_text_insertations+:: A hash specifying ASCII-8BIT encoded text for the keys given in the {::escper}{:/} tags. This is useful to send binary data to the printer (e.g. ESCPOS-encoded bitmaps), without being 'damaged' by the UTF-8 to ASCII-8BIT conversion.
31
44
  def print(printer_id, text, raw_text_insertations={})
32
- return if @open_printers == {}
33
- Escper.log "[PRINTING]============"
34
- Escper.log "[PRINTING]PRINTING..."
45
+ if @open_printers == {}
46
+ Escper.log "[print] No printers have been opened. Not printing anything"
47
+ return 0, ""
48
+ end
49
+
35
50
  printer = @open_printers[printer_id]
36
- raise 'Mismatch between open_printers and printer_id' if printer.nil?
51
+ if printer.nil?
52
+ Escper.log "[print] No printer with id #{ printer_id } has been opened."
53
+ return 0, ""
54
+ end
37
55
 
38
56
  codepage = printer[:codepage]
39
57
  codepage ||= 0
58
+
40
59
  output_text = Printer.merge_texts(text, raw_text_insertations, codepage)
41
60
 
42
- Escper.log "[PRINTING] Printing on #{ printer[:name] } @ #{ printer[:device].inspect }."
61
+ Escper.log "[print] Printing on #{ printer[:name] } @ #{ printer[:device].inspect }."
62
+
43
63
  bytes_written = nil
44
64
  printer[:copies].times do |i|
45
- # The method .write works both for SerialPort object and File object, so we don't have to distinguish here.
65
+ # The method .write works for SerialPort, File and TCPSocket, so we don't have to distinguish here.
46
66
  bytes_written = @open_printers[printer_id][:device].write output_text
47
- Escper.log "[PRINTING]ERROR: Byte count mismatch: sent #{text.length} written #{bytes_written}" unless output_text.length == bytes_written
67
+ if output_text.length != bytes_written
68
+ Escper.log "[print] WARN: Byte count mismatch: sent #{text.length} bytes, actually written #{bytes_written} bytes"
69
+ end
48
70
  end
49
- # The method .flush works both for SerialPort object and File object, so we don't have to distinguish here. It is not really neccessary, since the close method will theoretically flush also.
71
+
72
+ # The method .flush works for SerialPort, File and TCPSocket, so we don't have to distinguish here. It is not really neccessary, since the close method will theoretically flush also.
50
73
  @open_printers[printer_id][:device].flush
51
- Escper.log "[PRINTING] #{ output_text[0..60] }"
74
+
75
+ Escper.log "[print] Written text: #{ output_text[0..60] }"
52
76
  return bytes_written, output_text
53
77
  end
54
78
 
@@ -62,13 +86,15 @@ module Escper
62
86
  return asciified_text
63
87
  end
64
88
 
89
+ # Open a set of usual printer device paths, print example text, then close the printers.
90
+ # +chartest+:: Can be +true+ or +nil+. If true, a character test will be sent to the printer. If false, a test page containing the printer name and printer path will be sent to the printer.
65
91
  def identify(chartest=nil)
66
- Escper.log "[PRINTING]============"
67
- Escper.log "[PRINTING]TESTING Printers..."
68
- open
92
+ Escper.log "[identify] ============"
93
+ self.open
69
94
  @open_printers.each do |id, value|
70
95
  init = "\e@"
71
96
  cut = "\n\n\n\n\n\n" + "\x1D\x56\x00"
97
+
72
98
  testtext =
73
99
  "\e!\x38" + # double tall, double wide, bold
74
100
  "#{ I18n.t :printing_test }\r\n" +
@@ -76,20 +102,21 @@ module Escper
76
102
  "#{ value[:name] }\r\n" +
77
103
  "#{ value[:device].inspect }"
78
104
 
79
- Escper.log "[PRINTING] Testing #{value[:device].inspect }"
80
105
  if chartest
106
+ Escper.log "[identify] Printing all possible characters"
81
107
  print(id, init + Escper::Asciifier.all_chars + cut)
82
108
  else
109
+ Escper.log "[identify] Printing infos about this printer"
83
110
  ascifiier = Escper::Asciifier.new(value[:codepage])
84
111
  print(id, init + ascifiier.process(testtext) + cut)
85
112
  end
86
113
  end
87
- close
114
+ self.close
88
115
  end
89
116
 
117
+ # Opens all printers as passed to +new+
90
118
  def open
91
- Escper.log "[PRINTING]============"
92
- Escper.log "[PRINTING]OPEN Printers..."
119
+ Escper.log "[open] ============"
93
120
  @vendor_printers.size.times do |i|
94
121
  p = @vendor_printers[i]
95
122
  name = p.name
@@ -104,60 +131,136 @@ module Escper
104
131
  @file_mode = 'ab'
105
132
  end
106
133
 
107
- Escper.log "[PRINTING] Trying to open #{ name }@#{ path }@#{ baudrate }bps ..."
108
- pid = p.id ? p.id : i
134
+ Escper.log "[open] Trying to open #{ name }@#{ path }@#{ baudrate }bps ..."
135
+ pid = p.id ? p.id : i # assign incrementing id if none given
136
+
137
+ # ================ TCPSOCKET PRINTERS =============================
138
+ if @mode == "local"
139
+ # Writing to IP Addresses is only supported in local mode
140
+ if /\d+\.\d+\.\d+\.\d+:\d+/.match(path)
141
+ ip_addr = /(\d+\.\d+\.\d+\.\d+)/.match(path)[1]
142
+ port = /\d+\.\d+\.\d+\.\d+:(\d+)/.match(path)[1]
143
+ Escper.log "[open] Parsed IP #{ ip_addr} on port #{ port }"
144
+
145
+ begin
146
+ printer = nil
147
+ Escper.log "[open] Attempting to open TCPSocket at #{ ip_addr} on port #{ port } ... "
148
+ Timeout.timeout(2) do
149
+ printer = TCPSocket.new ip_addr, port
150
+ end
151
+ Escper.log "[open] Success for TCPSocket: #{ printer.inspect }"
152
+ @open_printers.merge! pid => {
153
+ :name => name,
154
+ :path => path,
155
+ :copies => p.copies,
156
+ :device => printer,
157
+ :codepage => codepage
158
+ }
159
+ next
160
+ rescue Errno::ECONNREFUSED
161
+ Escper.log "[open] TCPSocket ERROR: Connection refused at IP #{ ip_addr} on port #{ port }. Skipping this printer."
162
+ next
163
+ rescue Timeout::Error
164
+ Escper.log "[open] TCPSocket ERROR: Timeout #{ ip_addr} on port #{ port }. Skipping this printer."
165
+ next
166
+ rescue => e
167
+ Escper.log "[open] TCPSocket ERROR: Failed to open: #{ e.inspect }"
168
+ next
169
+ end
170
+ else
171
+ Escper.log "[open] Path #{ path } is not in IP:port format. Not trying to open printer as TCPSocket."
172
+ end
173
+ else
174
+ Escper.log "[open] Mode is #{ @mode }. Not trying to open printer as TCPSocket."
175
+ end
176
+
177
+ # ================ SERIALPORT PRINTERS =============================
109
178
  begin
110
179
  printer = SerialPort.new path, baudrate
111
- @open_printers.merge! pid => { :name => name, :path => path, :copies => p.copies, :device => printer, :codepage => codepage }
112
- Escper.log "[PRINTING] Success for SerialPort: #{ printer.inspect }"
180
+ @open_printers.merge! pid => {
181
+ :name => name,
182
+ :path => path,
183
+ :copies => p.copies,
184
+ :device => printer,
185
+ :codepage => codepage
186
+ }
187
+ Escper.log "[open] Success for SerialPort: #{ printer.inspect }"
113
188
  next
114
- rescue Exception => e
115
- Escper.log "[PRINTING] Failed to open as SerialPort: #{ e.inspect }"
189
+ rescue => e
190
+ Escper.log "[open] Failed to open as SerialPort: #{ e.inspect }"
116
191
  end
117
192
 
193
+
194
+ # ================ FILE PRINTERS =============================
118
195
  begin
119
196
  printer = File.open path, @file_mode
120
- @open_printers.merge! pid => { :name => name, :path => path, :copies => p.copies, :device => printer, :codepage => codepage }
121
- Escper.log "[PRINTING] Success for File: #{ printer.inspect }"
197
+ @open_printers.merge! pid => {
198
+ :name => name,
199
+ :path => path,
200
+ :copies => p.copies,
201
+ :device => printer,
202
+ :codepage => codepage
203
+ }
204
+ Escper.log "[open] Success for File: #{ printer.inspect }"
122
205
  next
123
206
  rescue Errno::EBUSY
124
- Escper.log "[PRINTING] The File #{ path } is already open."
125
- Escper.log "[PRINTING] Trying to reuse already opened printers."
207
+ # This happens when there are 2 printes with the same path
208
+ Escper.log "[open] The File #{ path } is already open."
209
+ Escper.log "[open] Trying to reuse already opened printers."
126
210
  previously_opened_printers = @open_printers.clone
127
211
  previously_opened_printers.each do |key, val|
128
- Escper.log "[PRINTING] Trying to reuse already opened File #{ key }: #{ val.inspect }"
212
+ Escper.log "[open] Trying to reuse already opened File #{ key }: #{ val.inspect }"
129
213
  if val[:path] == p[:path] and val[:device].class == File
130
- Escper.log "[PRINTING] Reused."
131
- @open_printers.merge! pid => { :name => name, :path => path, :copies => p.copies, :device => val[:device], :codepage => codepage }
214
+ Escper.log "[open] Reused."
215
+ @open_printers.merge! pid => {
216
+ :name => name,
217
+ :path => path,
218
+ :copies => p.copies,
219
+ :device => val[:device],
220
+ :codepage => codepage
221
+ }
132
222
  break
133
223
  end
134
224
  end
135
225
  unless @open_printers.has_key? p.id
136
226
  path = File.join(@fallback_root_path, 'tmp')
137
227
  printer = File.open(File.join(path, "#{ p.id }-#{ name }-fallback-busy.salor"), @file_mode)
138
- @open_printers.merge! pid => { :name => name, :path => path, :copies => p.copies, :device => printer, :codepage => codepage }
139
- Escper.log "[PRINTING] Failed to open as either SerialPort or USB File and resource IS busy. This should not have happened. Created #{ printer.inspect } instead."
228
+ @open_printers.merge! pid => {
229
+ :name => name,
230
+ :path => path,
231
+ :copies => p.copies,
232
+ :device => printer,
233
+ :codepage => codepage
234
+ }
235
+ Escper.log "[open] Failed to open as either SerialPort or USB File and resource IS busy. This should not have happened. Created #{ printer.inspect } instead."
140
236
  end
141
237
  next
142
- rescue Exception => e
238
+ rescue => e
143
239
  path = File.join(@fallback_root_path, 'tmp')
144
240
  printer = File.open(File.join(path, "#{ p.id }-#{ name }-fallback-notbusy.salor"), @file_mode)
145
- @open_printers.merge! pid => { :name => name, :path => path, :copies => p.copies, :device => printer, :codepage => codepage }
146
- Escper.log "[PRINTING] Failed to open as either SerialPort or USB File and resource is NOT busy. Created #{ printer.inspect } instead."
241
+ @open_printers.merge! pid => {
242
+ :name => name,
243
+ :path => path,
244
+ :copies => p.copies,
245
+ :device => printer,
246
+ :codepage => codepage
247
+ }
248
+ Escper.log "[open] Failed to open as either SerialPort or USB File and resource is NOT busy. Created #{ printer.inspect } instead."
147
249
  end
148
250
  end
149
251
  end
150
252
 
253
+ # Closes all opened printers
151
254
  def close
152
- Escper.log "[PRINTING]============"
153
- Escper.log "[PRINTING]CLOSING Printers..."
255
+ Escper.log "[close] ============"
154
256
  @open_printers.each do |key, value|
155
257
  begin
258
+ # File, SerialPort, and TCPSocket all have the close method
156
259
  value[:device].close
157
- Escper.log "[PRINTING] Closing #{ value[:name] } @ #{ value[:device].inspect }"
260
+ Escper.log "[close] Closing #{ value[:name] } @ #{ value[:device].inspect }"
158
261
  @open_printers.delete(key)
159
- rescue Exception => e
160
- Escper.log "[PRINTING] Error during closing of #{ value[:device] }: #{ e.inspect }"
262
+ rescue => e
263
+ Escper.log "[close] Error during closing of #{ value[:device] }: #{ e.inspect }"
161
264
  end
162
265
  end
163
266
  end
@@ -1,3 +1,3 @@
1
1
  module Escper
2
- VERSION = "1.2.1"
2
+ VERSION = "1.2.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: escper
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.2.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-07 00:00:00.000000000 Z
12
+ date: 2014-05-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rmagick
@@ -43,10 +43,10 @@ dependencies:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
- description: Collection of essential tools that make printing of plain text and images
47
- to one or many serial thermal printers easy. Both USB and serial (RS232) printers
48
- are supported and detected automatically. Escper is useful for Ruby based Point
49
- of Sale systems that want to print receipts or tickets.
46
+ description: Collection of tools that make printing of plain text and images to one
47
+ or many serial thermal printers easy. USB, serial (RS232) and TCP/IP printers are
48
+ supported. Escper is useful for Ruby based Point of Sale systems that want to print
49
+ receipts or tickets, but also suitable for stand-alone applications.
50
50
  email:
51
51
  - office@red-e.eu
52
52
  executables: []
@@ -90,6 +90,6 @@ rubyforge_project:
90
90
  rubygems_version: 1.8.23
91
91
  signing_key:
92
92
  specification_version: 3
93
- summary: Collection of essential tools that make printing of plain text and images
94
- to one or many serial thermal printers easy.
93
+ summary: Collection of tools that make printing of plain text and images to one or
94
+ many serial thermal printers easy.
95
95
  test_files: []