pax_global_header00006660000000000000000000000064130176501440014513gustar00rootroot0000000000000052 comment=de57705062081c3039db331f832bd7d2e514cc08 barby-0.6.5/000077500000000000000000000000001301765014400126225ustar00rootroot00000000000000barby-0.6.5/.gitignore000066400000000000000000000000221301765014400146040ustar00rootroot00000000000000*.swp Gemfile.lockbarby-0.6.5/CHANGELOG000066400000000000000000000032331301765014400140350ustar00rootroot00000000000000* 0.6.1 * Fix single-pixel error with RMagick [James Brink] * 0.6 * Add automatic character set to Code128 * Fix test for HtmlOutputter * 0.5.1 * Fix some encoding issues (ruby 2.0 & 1.9) * Rewrite HtmlOutputter. Not entirely backwards compatible with the previous version. * 0.5.0 * Require requirement of barcode symbologies in the same way outputters must be required before being used * 0.4.4 * Use Gemfile for dependency management [Ken Collins] * Move to MiniTest [Ken Collins] * HTML outputter [Ken Collins] * Various 1.9 fixes [Ken Collins, Dominique Ribaut] * 0.4.3 * 2- and 5-digit UPC supplements * Use ChunkyPNG for PngOutputter * 0.4.2 * ChunkyPngOutputter now renders 2D barcodes not upside down [Thanks Scient] * 0.4.1 * ChunkyPngOutputter - ChunkyPNG is a pure-Ruby PNG library * 0.4.0 * Can you tell I'm just making up version numbers as I go along? * DataMatrix (not required automatically, requires the 'semacode' gem) * Refactored PrawnOutputter a little. No more stupid options hashes + unbleed attribute * 0.3.2 * Fix bug where Code128 extras choke on newlines [Wayne Conrad] * Don't allow Code128 with empty data strings [Wayne Conrad] * Allow custom :size for QrCodes * 0.3.1 * Add support for PDF417, using Pdf417lib (JRuby only) [Aslak Hellesøy] * 0.3.0 * Make compatible with Ruby 1.9 [Chris Mowforth] * Add SvgOutputter for outputting SVGs without dependencies [Peter H. Li] * 0.2.1 * Allow QR Codes with sizes up to 40 * 0.2.0 * Added support for 2D barcodes * Updated all outputters to support 2D barcodes * Added support for QR Code * 0.1.2 * Added CairoOutputter [Kouhei Sutou] * 0.1.1 * Added PngOutputter that uses "png" gem barby-0.6.5/LICENSE000066400000000000000000000020401301765014400136230ustar00rootroot00000000000000Copyright (c) 2008 Tore Darell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. barby-0.6.5/README.md000066400000000000000000000106151301765014400141040ustar00rootroot00000000000000# Barby Barby is a Ruby library that generates barcodes in a variety of symbologies. Its functionality is split into _barcode_ and "_outputter_" objects: * [`Barby::Barcode` objects] [symbologies] turn data into a binary representation for a given symbology. * [`Barby::Outputter`] [outputters] then takes this representation and turns it into images, PDF, etc. You can easily add a symbology without having to worry about graphical representation. If it can be represented as the usual 1D or 2D matrix of lines or squares, outputters will do that for you. Likewise, you can easily add an outputter for a format that doesn't have one yet, and it will work with all existing symbologies. For more information, check out [the Barby wiki] [wiki]. ### New require policy Barcode symbologies are no longer required automatically, so you'll have to require the ones you need. If you need EAN-13, `require 'barby/barcode/ean_13'`. Full list of symbologies and filenames below. ## Example ```ruby require 'barby' require 'barby/barcode/code_128' require 'barby/outputter/ascii_outputter' barcode = Barby::Code128B.new('BARBY') puts barcode.to_ascii #Implicitly uses the AsciiOutputter ## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ## ## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ## ## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ## ## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ## ## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ## ## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ## ## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ## ## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ## ## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ## ## # # # # ## # # ## ## # ### # # ## ### ## # ## ### ### ## ### # ## B A R B Y ``` ## Supported symbologies ```ruby require 'barby/barcode/' ``` | Name | Filename | Dependencies | | ----------------------------------- | --------------------- | ------------- | | Code 25 | `code_25` | ─ | | ├─ Interleaved | `code_25_interleaved` | ─ | | └─ IATA | `code_25_iata` | ─ | | Code 39 | `code_39` | ─ | | └─ Extended | `code_39` | ─ | | Code 93 | `code_93` | ─ | | Code 128 (A, B, and C) | `code_128` | ─ | | └─ GS1 128 | `gs1_128` | ─ | | EAN-13 | `ean_13` | ─ | | ├─ Bookland | `bookland` | ─ | | └─ UPC-A | `ean_13` | ─ | | EAN-8 | `ean_8` | ─ | | UPC/EAN supplemental, 2 & 5 digits | `upc_supplemental` | ─ | | QR Code | `qr_code` | `rqrcode` | | DataMatrix (Semacode) | `data_matrix` | `semacode` | | PDF417 | `pdf_417` | JRuby | ## Outputters ```ruby require 'barby/outputter/_outputter' ``` | filename | dependencies | | ----------- | ------------- | | `ascii` | ─ | | `cairo` | cairo | | `html` | ─ | | `pdfwriter` | ─ | | `png` | chunky_png | | `prawn` | prawn | | `rmagick` | rmagick | | `svg` | ─ | ### Formats supported by outputters * Text (mostly for testing) * PNG, JPEG, GIF * PS, EPS * SVG * PDF * HTML --- For more information, check out [the Barby wiki] [wiki]. [wiki]: https://github.com/toretore/barby/wiki [symbologies]: https://github.com/toretore/barby/wiki/Symbologies [outputters]: https://github.com/toretore/barby/wiki/Outputters barby-0.6.5/Rakefile000066400000000000000000000004631301765014400142720ustar00rootroot00000000000000require 'rake' require 'rake/testtask' require 'rdoc/task' Rake::TestTask.new do |t| t.libs = ['lib','test'] t.test_files = Dir.glob("test/**/*_test.rb").sort t.verbose = true end RDoc::Task.new do |rdoc| rdoc.main = "README" rdoc.rdoc_files.include("README", "lib") rdoc.rdoc_dir = 'doc' end barby-0.6.5/barby.gemspec000066400000000000000000000013371301765014400152720ustar00rootroot00000000000000$:.push File.expand_path("../lib", __FILE__) require "barby/version" Gem::Specification.new do |s| s.name = "barby" s.version = Barby::VERSION::STRING s.platform = Gem::Platform::RUBY s.summary = "The Ruby barcode generator" s.email = "toredarell@gmail.com" s.homepage = "http://toretore.github.com/barby" s.description = "Barby creates barcodes." s.authors = ['Tore Darell'] s.rubyforge_project = "barby" s.has_rdoc = true s.extra_rdoc_files = ["README.md"] s.files = Dir['CHANGELOG', 'README.md', 'LICENSE', 'lib/**/*', 'vendor/**/*', 'bin/*'] #s.executables = ['barby'] #WIP, doesn't really work that well s.require_paths = ["lib"] end barby-0.6.5/bin/000077500000000000000000000000001301765014400133725ustar00rootroot00000000000000barby-0.6.5/bin/barby000077500000000000000000000024341301765014400144220ustar00rootroot00000000000000#!/usr/bin/env ruby #encoding: UTF-8 require 'optparse' require 'rubygems' #$: << File.join(File.dirname(__FILE__), '..', 'lib') require 'barby' options = { :outputter => 'Ascii', :outputter_method => 'to_ascii', :barcode => 'Code128B' } ARGV.options do |o| o.banner = " Usage: #{File.basename(__FILE__)} [OPTIONS] data" o.define_head ' Generates barcodes and prints the generated output to STDOUT' o.separator '' o.separator ' EXPERIMENTAL' o.separator '' o.on('-b', '--barcode=ClassName', String, 'Barcode type (Code128B)'){|v| options[:barcode] = v } o.on('-o', '--outputter=ClassName', String, 'Outputter (Ascii)'){|v| options[:outputter] = v } o.on('-m', '--method=method_name', String, 'Outputter method (to_ascii)'){|v| options[:outputter_method] = v } o.on_tail("-h", "--help", "Show this help message.") { puts o; exit } o.parse! end #p STDIN.read #exit require "barby/outputter/#{options[:outputter].gsub(/[A-Z]/){|c| '_'+c.downcase }[1..-1]}_outputter" barcode_class = Barby.const_get(options[:barcode]) barcode = barcode_class.new($*.empty? ? STDIN.read.chomp : $*[0]) outputter_class = Barby.const_get("#{options[:outputter]}Outputter") outputter = outputter_class.new(barcode) print eval("outputter.#{options[:outputter_method]}(#{ENV['OPTIONS']})") barby-0.6.5/lib/000077500000000000000000000000001301765014400133705ustar00rootroot00000000000000barby-0.6.5/lib/barby.rb000066400000000000000000000001411301765014400150100ustar00rootroot00000000000000require 'barby/vendor' require 'barby/version' require 'barby/barcode' require 'barby/outputter' barby-0.6.5/lib/barby/000077500000000000000000000000001301765014400144675ustar00rootroot00000000000000barby-0.6.5/lib/barby/barcode.rb000066400000000000000000000054511301765014400164200ustar00rootroot00000000000000module Barby #The base class for all barcodes. It includes some method_missing magic #that is used to find registered outputters. # #The only interface requirement of a barcode class is that is has an encoding #method that returns a string consisting of 1s and 0s representing the barcode's #"black" and "white" parts. One digit is the width of the "X dimension"; that is, #"101100" represents a single-width bar followed by a single-width space, then #a bar and a space twice that width. # #Example implementation: # # class StaticBarcode < Barby::Barcode1D # def encoding # '101100111000111100001' # end # end # # require 'barby/outputter/ascii_outputter' # puts StaticBarcode.new.to_ascii(:height => 3) # # # ## ### #### # # # ## ### #### # # # ## ### #### # # #2D implementation: # # class Static2DBarcode < Barby::Barcode2D # def encoding # ['1010101', '010101110', '0001010100'] # end # end class Barcode #Every barcode must have an encoding method. This method returns #a string containing a series of 1 and 0, representing bars and #spaces. One digit is the width of one "module" or X dimension. # #If the barcode is 2D, it returns an array of strings representing #each line in the barcode def encoding raise NotImplementedError, 'Every barcode should implement this method' end #Is this barcode valid? def valid? false end def to_s self.class.name.split('::').last end #Is this barcode 2D? def two_dimensional? is_a? Barcode2D end def method_missing(name, *args, &b)#:nodoc: #See if an outputter has registered this method if self.class.outputters.include?(name) klass, method_name = self.class.outputters[name] klass.new(self).send(method_name, *args, &b) else super end end #Returns an instantiated outputter for +name+ if any outputter #has registered that name def outputter_for(name, *a, &b) outputter_class_for(name).new(self, *a, &b) end #Get the outputter class object for +name+ def outputter_class_for(name) self.class.outputters[name].first end class << self def outputters @@outputters ||= {} end #Registers an outputter with +name+ so that a call to #+name+ on a Barcode instance will be delegated to this outputter def register_outputter(name, klass, method_name) outputters[name] = [klass, method_name] end end end #Most barcodes are one-dimensional. They have bars. class Barcode1D < Barcode end #2D barcodes are 1D barcodes stacked on top of each other. #Their encoding method must return an array of strings class Barcode2D < Barcode end end barby-0.6.5/lib/barby/barcode/000077500000000000000000000000001301765014400160665ustar00rootroot00000000000000barby-0.6.5/lib/barby/barcode/bookland.rb000066400000000000000000000065701301765014400202140ustar00rootroot00000000000000#encoding: ASCII require 'barby/barcode/ean_13' module Barby # Bookland barcodes are EAN-13 barcodes with number system # 978/979 (hence "Bookland"). The data they encode is an ISBN # with its check digit removed. This is a convenience class # that takes an ISBN number instead of "pure" EAN-13 data. # # #These are all the same: # barcode = Bookland.new('978-0-306-40615-7') # barcode = Bookland.new('978-0-306-40615') # barcode = Bookland.new('0-306-40615-7') # barcode = Bookland.new('0-306-40615') # # If a prefix is not given, a default of 978 is used. class Bookland < EAN13 # isbn should be an ISBN number string, with or without an EAN prefix and an ISBN checksum # non-number formatting like hyphens or spaces are ignored # # If a prefix is not given, a default of 978 is used. def initialize(isbn) self.isbn = isbn raise ArgumentError, 'data not valid' unless valid? end def data isbn.isbn end def isbn=(isbn) @isbn = ISBN.new(isbn) end #An instance of ISBN def isbn @isbn end # Encapsulates an ISBN number # # isbn = ISBN.new('978-0-306-40615') class ISBN DEFAULT_PREFIX = '978' PATTERN = /\A(?\d\d\d)?(?\d{9})(?\d)?\Z/ attr_reader :number # Takes one argument, which is the ISBN string with or without prefix and/or check digit. # Non-digit characters like hyphens and spaces are ignored. # # Prefix is 978 if not given. def initialize(isbn) self.isbn = isbn end def isbn=(isbn) if match = PATTERN.match(isbn.gsub(/\D/, '')) @number = match[:number] @prefix = match[:prefix] else raise ArgumentError, "Not a valid ISBN: #{isbn}" end end def isbn "#{prefix}#{number}" end def isbn_with_checksum "#{isbn}#{checksum}" end def isbn_10 number end def isbn_10_with_checksum "#{number}#{checksum}" end def formatted_isbn "#{prefix}-#{number}-#{checksum}" end def formatted_isbn_10 "#{number}-#{checksum}" end def prefix @prefix || DEFAULT_PREFIX end def digits (prefix+number).split('').map(&:to_i) end def isbn_10_digits number.split('').map(&:to_i) end # Calculates the ISBN 13-digit checksum following the algorithm from: # http://en.wikipedia.org/wiki/International_Standard_Book_Number#ISBN-13_check_digit_calculation def checksum (10 - (digits.each_with_index.inject(0) do |sum, (digit, index)| sum + (digit * (index.even? ? 1 : 3)) end % 10)) % 10 end ISBN_10_CHECKSUM_MULTIPLIERS = [10,9,8,7,6,5,4,3,2] # Calculates the ISBN 10-digit checksum following the algorithm from: # http://en.wikipedia.org/wiki/International_Standard_Book_Number#ISBN-10_check_digit_calculation def isbn_10_checksum isbn_10_digits.zip(ISBN_10_CHECKSUM_MULTIPLIERS).inject(0) do |sum, (digit, multiplier)| sum + (digit * multiplier) end end def to_s isbn_with_checksum end def inspect "#<#{self.class}:0x#{'%014x' % object_id} #{formatted_isbn}>" end end#class ISBN end#class Bookland end#module Barby barby-0.6.5/lib/barby/barcode/code_128.rb000066400000000000000000000447451301765014400177350ustar00rootroot00000000000000#encoding: ASCII require 'barby/barcode' module Barby #Code 128 barcodes # #Note that you must provide a type for each object, either by passing a string #as a second parameter to Code128.new or by instantiating one of the child classes. # #You can switch type by using the CODEA, CODEB and CODEC characters: # # "\305" => A # "\306" => B # "\307" => C # #As an example, here's one that starts out as type A and then switches to B and then C: # # Code128A.new("ABC123\306def\3074567") # # #GS1-128/EAN-128/UCC-128 # #To make a GS1-128 code, prefix the data with FNC1 and the Application Identifier: # # #AI=00, data=12345 # Code128.new("#{Code128::FNC1}0012345") class Code128 < Barcode1D FNC1 = "\xc1" FNC2 = "\xc2" FNC3 = "\xc3" FNC4 = "\xc4" CODEA = "\xc5" CODEB = "\xc6" CODEC = "\xc7" SHIFT = "\xc8" STARTA = "\xc9" STARTB = "\xca" STARTC = "\xcb" STOP = '11000111010' TERMINATE = '11' ENCODINGS = { 0 => "11011001100", 1 => "11001101100", 2 => "11001100110", 3 => "10010011000", 4 => "10010001100", 5 => "10001001100", 6 => "10011001000", 7 => "10011000100", 8 => "10001100100", 9 => "11001001000", 10 => "11001000100", 11 => "11000100100", 12 => "10110011100", 13 => "10011011100", 14 => "10011001110", 15 => "10111001100", 16 => "10011101100", 17 => "10011100110", 18 => "11001110010", 19 => "11001011100", 20 => "11001001110", 21 => "11011100100", 22 => "11001110100", 23 => "11101101110", 24 => "11101001100", 25 => "11100101100", 26 => "11100100110", 27 => "11101100100", 28 => "11100110100", 29 => "11100110010", 30 => "11011011000", 31 => "11011000110", 32 => "11000110110", 33 => "10100011000", 34 => "10001011000", 35 => "10001000110", 36 => "10110001000", 37 => "10001101000", 38 => "10001100010", 39 => "11010001000", 40 => "11000101000", 41 => "11000100010", 42 => "10110111000", 43 => "10110001110", 44 => "10001101110", 45 => "10111011000", 46 => "10111000110", 47 => "10001110110", 48 => "11101110110", 49 => "11010001110", 50 => "11000101110", 51 => "11011101000", 52 => "11011100010", 53 => "11011101110", 54 => "11101011000", 55 => "11101000110", 56 => "11100010110", 57 => "11101101000", 58 => "11101100010", 59 => "11100011010", 60 => "11101111010", 61 => "11001000010", 62 => "11110001010", 63 => "10100110000", 64 => "10100001100", 65 => "10010110000", 66 => "10010000110", 67 => "10000101100", 68 => "10000100110", 69 => "10110010000", 70 => "10110000100", 71 => "10011010000", 72 => "10011000010", 73 => "10000110100", 74 => "10000110010", 75 => "11000010010", 76 => "11001010000", 77 => "11110111010", 78 => "11000010100", 79 => "10001111010", 80 => "10100111100", 81 => "10010111100", 82 => "10010011110", 83 => "10111100100", 84 => "10011110100", 85 => "10011110010", 86 => "11110100100", 87 => "11110010100", 88 => "11110010010", 89 => "11011011110", 90 => "11011110110", 91 => "11110110110", 92 => "10101111000", 93 => "10100011110", 94 => "10001011110", 95 => "10111101000", 96 => "10111100010", 97 => "11110101000", 98 => "11110100010", 99 => "10111011110", 100 => "10111101110", 101 => "11101011110", 102 => "11110101110", 103 => "11010000100", 104 => "11010010000", 105 => "11010011100" } VALUES = { 'A' => { 0 => " ", 1 => "!", 2 => "\"", 3 => "#", 4 => "$", 5 => "%", 6 => "&", 7 => "'", 8 => "(", 9 => ")", 10 => "*", 11 => "+", 12 => ",", 13 => "-", 14 => ".", 15 => "/", 16 => "0", 17 => "1", 18 => "2", 19 => "3", 20 => "4", 21 => "5", 22 => "6", 23 => "7", 24 => "8", 25 => "9", 26 => ":", 27 => ";", 28 => "<", 29 => "=", 30 => ">", 31 => "?", 32 => "@", 33 => "A", 34 => "B", 35 => "C", 36 => "D", 37 => "E", 38 => "F", 39 => "G", 40 => "H", 41 => "I", 42 => "J", 43 => "K", 44 => "L", 45 => "M", 46 => "N", 47 => "O", 48 => "P", 49 => "Q", 50 => "R", 51 => "S", 52 => "T", 53 => "U", 54 => "V", 55 => "W", 56 => "X", 57 => "Y", 58 => "Z", 59 => "[", 60 => "\\", 61 => "]", 62 => "^", 63 => "_", 64 => "\000", 65 => "\001", 66 => "\002", 67 => "\003", 68 => "\004", 69 => "\005", 70 => "\006", 71 => "\a", 72 => "\b", 73 => "\t", 74 => "\n", 75 => "\v", 76 => "\f", 77 => "\r", 78 => "\016", 79 => "\017", 80 => "\020", 81 => "\021", 82 => "\022", 83 => "\023", 84 => "\024", 85 => "\025", 86 => "\026", 87 => "\027", 88 => "\030", 89 => "\031", 90 => "\032", 91 => "\e", 92 => "\034", 93 => "\035", 94 => "\036", 95 => "\037", 96 => FNC3, 97 => FNC2, 98 => SHIFT, 99 => CODEC, 100 => CODEB, 101 => FNC4, 102 => FNC1, 103 => STARTA, 104 => STARTB, 105 => STARTC }.invert, 'B' => { 0 => " ", 1 => "!", 2 => "\"", 3 => "#", 4 => "$", 5 => "%", 6 => "&", 7 => "'", 8 => "(", 9 => ")", 10 => "*", 11 => "+", 12 => ",", 13 => "-", 14 => ".", 15 => "/", 16 => "0", 17 => "1", 18 => "2", 19 => "3", 20 => "4", 21 => "5", 22 => "6", 23 => "7", 24 => "8", 25 => "9", 26 => ":", 27 => ";", 28 => "<", 29 => "=", 30 => ">", 31 => "?", 32 => "@", 33 => "A", 34 => "B", 35 => "C", 36 => "D", 37 => "E", 38 => "F", 39 => "G", 40 => "H", 41 => "I", 42 => "J", 43 => "K", 44 => "L", 45 => "M", 46 => "N", 47 => "O", 48 => "P", 49 => "Q", 50 => "R", 51 => "S", 52 => "T", 53 => "U", 54 => "V", 55 => "W", 56 => "X", 57 => "Y", 58 => "Z", 59 => "[", 60 => "\\", 61 => "]", 62 => "^", 63 => "_", 64 => "`", 65 => "a", 66 => "b", 67 => "c", 68 => "d", 69 => "e", 70 => "f", 71 => "g", 72 => "h", 73 => "i", 74 => "j", 75 => "k", 76 => "l", 77 => "m", 78 => "n", 79 => "o", 80 => "p", 81 => "q", 82 => "r", 83 => "s", 84 => "t", 85 => "u", 86 => "v", 87 => "w", 88 => "x", 89 => "y", 90 => "z", 91 => "{", 92 => "|", 93 => "}", 94 => "~", 95 => "\177", 96 => FNC3, 97 => FNC2, 98 => SHIFT, 99 => CODEC, 100 => FNC4, 101 => CODEA, 102 => FNC1, 103 => STARTA, 104 => STARTB, 105 => STARTC, }.invert, 'C' => { 0 => "00", 1 => "01", 2 => "02", 3 => "03", 4 => "04", 5 => "05", 6 => "06", 7 => "07", 8 => "08", 9 => "09", 10 => "10", 11 => "11", 12 => "12", 13 => "13", 14 => "14", 15 => "15", 16 => "16", 17 => "17", 18 => "18", 19 => "19", 20 => "20", 21 => "21", 22 => "22", 23 => "23", 24 => "24", 25 => "25", 26 => "26", 27 => "27", 28 => "28", 29 => "29", 30 => "30", 31 => "31", 32 => "32", 33 => "33", 34 => "34", 35 => "35", 36 => "36", 37 => "37", 38 => "38", 39 => "39", 40 => "40", 41 => "41", 42 => "42", 43 => "43", 44 => "44", 45 => "45", 46 => "46", 47 => "47", 48 => "48", 49 => "49", 50 => "50", 51 => "51", 52 => "52", 53 => "53", 54 => "54", 55 => "55", 56 => "56", 57 => "57", 58 => "58", 59 => "59", 60 => "60", 61 => "61", 62 => "62", 63 => "63", 64 => "64", 65 => "65", 66 => "66", 67 => "67", 68 => "68", 69 => "69", 70 => "70", 71 => "71", 72 => "72", 73 => "73", 74 => "74", 75 => "75", 76 => "76", 77 => "77", 78 => "78", 79 => "79", 80 => "80", 81 => "81", 82 => "82", 83 => "83", 84 => "84", 85 => "85", 86 => "86", 87 => "87", 88 => "88", 89 => "89", 90 => "90", 91 => "91", 92 => "92", 93 => "93", 94 => "94", 95 => "95", 96 => "96", 97 => "97", 98 => "98", 99 => "99", 100 => CODEB, 101 => CODEA, 102 => FNC1, 103 => STARTA, 104 => STARTB, 105 => STARTC }.invert } CONTROL_CHARACTERS = VALUES['A'].invert.values_at(*(64..95).to_a) attr_reader :type def initialize(data, type=nil) if type self.type = type self.data = "#{data}" else self.type, self.data = self.class.determine_best_type_for_data("#{data}") end raise ArgumentError, 'Data not valid' unless valid? end def type=(type) type = type.upcase raise ArgumentError, 'type must be A, B or C' unless type =~ /^[ABC]$/ @type = type end def to_s full_data end def data @data end #Returns the data for this barcode plus that for the entire extra chain, #excluding all change codes def full_data data + full_extra_data end #Returns the data for this barcode plus that for the entire extra chain, #including all change codes prefixing each extra def full_data_with_change_codes data + full_extra_data_with_change_code end #Returns the full_data for the extra or an empty string if there is no extra def full_extra_data return '' unless extra extra.full_data end #Returns the full_data for the extra with the change code for the extra #prepended. If there is no extra, an empty string is returned def full_extra_data_with_change_code return '' unless extra change_code_for(extra) + extra.full_data_with_change_codes end #Set the data for this barcode. If the barcode changes #character set, an extra will be created. def data=(data) data, *extra = data.split(/([#{CODEA+CODEB+CODEC}])/n) @data = data || '' self.extra = extra.join unless extra.empty? end #An "extra" is present if the barcode changes character set. If #a 128A barcode changes to C, the extra will be an instance of #Code128C. Extras can themselves have an extra if the barcode #changes character set again. It's like a linked list, and when #there are no more extras, the barcode ends with that object. #Most barcodes probably don't change charsets and don't have extras. def extra return @extra if defined?(@extra) @extra = nil end #Set the extra for this barcode. The argument is a string starting with the #"change character set" symbol. The string may contain several character #sets, in which case the extra will itself have an extra. def extra=(extra) raise ArgumentError, "Extra must begin with \\305, \\306 or \\307" unless extra =~ /^[#{CODEA+CODEB+CODEC}]/n type, data = extra[0,1], extra[1..-1] @extra = class_for(type).new(data) end #Get an array of the individual characters for this barcode. Special #characters like FNC1 will be present. Characters from extras are not #present. def characters chars = data.split(//n) if type == 'C' result = [] count = 0 while count < chars.size if chars[count] =~ /^\d$/ #If encountering a digit, next char/byte *must* be second digit in pair. I.e. if chars[count] is 5, #chars[count+1] must be /[0-9]/, otherwise it's not valid result << "#{chars[count]}#{chars[count+1]}" count += 2 else result << chars[count] count += 1 end end result else chars end end #Return the encoding of this barcode as a string of 1 and 0 def encoding start_encoding+data_encoding+extra_encoding+checksum_encoding+stop_encoding end #Returns the encoding for the data part of this barcode, without any extras def data_encoding characters.map do |char| encoding_for char end.join end #Returns the data encoding of this barcode and extras. def data_encoding_with_extra_encoding data_encoding+extra_encoding end #Returns the data encoding of this barcode's extra and its #extra until the barcode ends. def extra_encoding return '' unless extra change_code_encoding_for(extra) + extra.data_encoding + extra.extra_encoding end #Calculate the checksum for the data in this barcode. The data includes #data from extras. def checksum pos = 0 (numbers+extra_numbers).inject(start_num) do |sum,number| pos += 1 sum + (number * pos) end % 103 end #Get the encoding for the checksum def checksum_encoding encodings[checksum] end #protected #Returns the numeric values for the characters in the barcode in an array def numbers characters.map do |char| values[char] end end #Returns the numeric values for extras def extra_numbers return [] unless extra [change_code_number_for(extra)] + extra.numbers + extra.extra_numbers end def encodings ENCODINGS end #The start encoding starts the barcode def stop_encoding STOP+TERMINATE end #Find the encoding for the specified character for this barcode def encoding_for(char) encodings[values[char]] end def change_code_for_class(klass) {Code128A => CODEA, Code128B => CODEB, Code128C => CODEC}[klass] end #Find the character that changes the character set to the one #represented in +barcode+ def change_code_for(barcode) change_code_for_class(barcode.class) end #Find the numeric value for the character that changes the character #set to the one represented in +barcode+ def change_code_number_for(barcode) values[change_code_for(barcode)] end #Find the encoding to change to the character set in +barcode+ def change_code_encoding_for(barcode) encodings[change_code_number_for(barcode)] end def class_for(character) self.class.class_for(character) end #Is the data in this barcode valid? Does a lookup of every character #and checks if it exists in the character set. An empty data string #will also be reported as invalid. def valid? characters.any? && characters.all?{|c| values.include?(c) } end def values VALUES[type] end def start_character case type when 'A' then STARTA when 'B' then STARTB when 'C' then STARTC end end def start_num values[start_character] end def start_encoding encodings[start_num] end CTRL_RE = /#{CONTROL_CHARACTERS.join('|')}/ LOWR_RE = /[a-z]/ DGTS_RE = /\d{4,}/ # pairs of digits and FNC1 characters CODEC_CHARS_RE = /(?:\d{2}|#{FNC1}){2,}/ class << self def class_for(character) case character when 'A' then Code128A when 'B' then Code128B when 'C' then Code128C when CODEA then Code128A when CODEB then Code128B when CODEC then Code128C end end #Insert code shift and switch characters where appropriate to get the #shortest encoding possible def apply_shortest_encoding_for_data(data) extract_codec(data).map do |block| if codec_segment?(block) "#{CODEC}#{block}" else if control_before_lowercase?(block) handle_code_a(block) else handle_code_b(block) end end end.join end def determine_best_type_for_data(data) data = apply_shortest_encoding_for_data(data) type = case data.slice!(0) when CODEA then 'A' when CODEB then 'B' when CODEC then 'C' end [type, data] end private #Extract all CODEC segments from the data. 4 or more evenly numbered contiguous digits. # # # C A or B C A or B # extract_codec("12345abc678910DEF11") => ["1234", "5abc", "678910", "DEF11"] def extract_codec(data) data.split(/ (^(?:#{CODEC_CHARS_RE})) # matches digits that appear at the beginning of the barcode | ((?:#{CODEC_CHARS_RE})(?!\d)) # matches digits that appear later in the barcode /x).reject(&:empty?) end def codec_segment?(data) data =~ /\A#{CODEC_CHARS_RE}\Z/ end def control_character?(char) char =~ CTRL_RE end def lowercase_character?(char) char =~ LOWR_RE end #Handle a Code A segment which may contain Code B parts, but may not #contain any Code C parts. def handle_code_a(data) indata = data.dup outdata = CODEA.dup #We know it'll be A while char = indata.slice!(0) if lowercase_character?(char) #Found a lower case character (Code B) if control_before_lowercase?(indata) outdata << SHIFT << char #Control character appears before a new lowercase, use shift else outdata << handle_code_b(char+indata) #Switch to Code B break end else outdata << char end end#while outdata end #Handle a Code B segment which may contain Code A parts, but may not #contain any Code C parts. def handle_code_b(data) indata = data.dup outdata = CODEB.dup #We know this is going to start with Code B while char = indata.slice!(0) if control_character?(char) #Found a control character (Code A) if control_before_lowercase?(indata) #There is another control character before any lowercase, so outdata << handle_code_a(char+indata) #switch over to Code A. break else outdata << SHIFT << char #Can use a shift to only encode this char as Code A end else outdata << char end end#while outdata end #Test str to see if a control character (Code A) appears #before a lower case character (Code B). # #Returns true only if it contains a control character and a lower case #character doesn't appear before it. def control_before_lowercase?(str) ctrl = str =~ CTRL_RE char = str =~ LOWR_RE ctrl && (!char || ctrl < char) end end#class << self end#class Code128 class Code128A < Code128 def initialize(data) super(data, 'A') end end class Code128B < Code128 def initialize(data) super(data, 'B') end end class Code128C < Code128 def initialize(data) super(data, 'C') end end end barby-0.6.5/lib/barby/barcode/code_25.rb000066400000000000000000000074521301765014400176430ustar00rootroot00000000000000require 'barby/barcode' module Barby #Standard/Industrial 2 of 5, non-interleaved # #Checksum not included by default, to include it, #set include_checksum = true class Code25 < Barcode1D WIDE = W = true NARROW = N = false START_ENCODING = [W,W,N] STOP_ENCODING = [W,N,W] ENCODINGS = { 0 => [N,N,W,W,N], 1 => [W,N,N,N,W], 2 => [N,W,N,N,W], 3 => [W,W,N,N,N], 4 => [N,N,W,N,W], 5 => [W,N,W,N,N], 6 => [N,W,W,N,N], 7 => [N,N,N,W,W], 8 => [W,N,N,W,N], 9 => [N,W,N,W,N] } attr_accessor :include_checksum attr_writer :narrow_width, :wide_width, :space_width attr_reader :data def initialize(data) self.data = data @narrow_width, @wide_width, @space_width = nil end def data_encoding digit_encodings.join end def data_encoding_with_checksum digit_encodings_with_checksum.join end def encoding start_encoding+(include_checksum? ? data_encoding_with_checksum : data_encoding)+stop_encoding end def characters data.split(//) end def characters_with_checksum characters.push(checksum.to_s) end def digits characters.map{|c| c.to_i } end def digits_with_checksum digits.push(checksum) end def even_and_odd_digits alternater = false digits.reverse.partition{ alternater = !alternater } end def digit_encodings raise_invalid unless valid? digits.map{|d| encoding_for(d) } end alias character_encodings digit_encodings def digit_encodings_with_checksum raise_invalid unless valid? digits_with_checksum.map{|d| encoding_for(d) } end alias character_encodings_with_checksum digit_encodings_with_checksum #Returns the encoding for a single digit def encoding_for(digit) encoding_for_bars(ENCODINGS[digit]) end #Generate encoding for an array of W,N def encoding_for_bars(*bars) wide, narrow, space = wide_encoding, narrow_encoding, space_encoding bars.flatten.inject '' do |enc,bar| enc + (bar == WIDE ? wide : narrow) + space end end def encoding_for_bars_without_end_space(*a) encoding_for_bars(*a).gsub(/0+$/, '') end #Mod10 def checksum evens, odds = even_and_odd_digits sum = odds.inject(0){|s,d| s + d } + evens.inject(0){|s,d| s + (d*3) } sum %= 10 sum.zero? ? 0 : 10-sum end def checksum_encoding encoding_for(checksum) end #The width of a narrow bar in xdims def narrow_width @narrow_width || 1 end #The width of a wide bar in xdims #By default three times as wide as a narrow bar def wide_width @wide_width || narrow_width*3 end #The width of the space between the bars in xdims #By default the same width as a narrow bar # #A space serves only as a separator for the bars, #there is no encoded meaning in them def space_width @space_width || narrow_width end #2 of 5 doesn't require a checksum, but you can include a Mod10 checksum #by setting +include_checksum+ to true def include_checksum? include_checksum end def data=(data) @data = "#{data}" end def start_encoding encoding_for_bars(START_ENCODING) end def stop_encoding encoding_for_bars_without_end_space(STOP_ENCODING) end def narrow_encoding '1' * narrow_width end def wide_encoding '1' * wide_width end def space_encoding '0' * space_width end def valid? data =~ /^[0-9]*$/ end def to_s (include_checksum? ? characters_with_checksum : characters).join end private def raise_invalid raise ArgumentError, "data not valid" end end end barby-0.6.5/lib/barby/barcode/code_25_iata.rb000066400000000000000000000007671301765014400206430ustar00rootroot00000000000000require 'barby/barcode/code_25' module Barby #The IATA version of 2 of 5 is identical to its parent except for different #start and stop codes. This is the one used on the tags they put on your #luggage when you check it in at the airport. class Code25IATA < Code25 START_ENCODING = [N,N] STOP_ENCODING = [W,N] def start_encoding encoding_for_bars(START_ENCODING) end def stop_encoding encoding_for_bars_without_end_space(STOP_ENCODING) end end end barby-0.6.5/lib/barby/barcode/code_25_interleaved.rb000066400000000000000000000034471301765014400222250ustar00rootroot00000000000000require 'barby/barcode/code_25' module Barby #Code 2 of 5 interleaved. Same as standard 2 of 5, but spaces are used #for encoding as well as the bars. Each pair of numbers get interleaved, #that is, the first is encoded in the bars and the second is encoded #in the spaced. This means an interleaved 2/5 barcode must have an even #number of digits. class Code25Interleaved < Code25 START_ENCODING = [N,N,N,N] STOP_ENCODING = [W,N,N] def digit_pairs(d=nil) (d || digits).inject [] do |ary,i| ary << [] if !ary.last || ary.last.size == 2 ary.last << i ary end end def digit_pairs_with_checksum digit_pairs(digits_with_checksum) end def digit_encodings raise_invalid unless valid? digit_pairs.map{|p| encoding_for_pair(p) } end def digit_encodings_with_checksum digit_pairs_with_checksum.map{|p| encoding_for_pair(p) } end def encoding_for_pair(pair) bars, spaces = ENCODINGS[pair.first], ENCODINGS[pair.last] encoding_for_interleaved(bars.zip(spaces)) end #Encodes an array of interleaved W or N bars and spaces #ex: [W,N,W,W,N,N] => "111011100010" def encoding_for_interleaved(*bars_and_spaces) bar = false#starts with bar bars_and_spaces.flatten.inject '' do |enc,bar_or_space| bar = !bar enc << (bar ? '1' : '0') * (bar_or_space == WIDE ? wide_width : narrow_width) end end def start_encoding encoding_for_interleaved(START_ENCODING) end def stop_encoding encoding_for_interleaved(STOP_ENCODING) end def valid? # When checksum is included, it's included when determining "evenness" super && digits.size % 2 == (include_checksum? ? 1 : 0) end end end barby-0.6.5/lib/barby/barcode/code_39.rb000066400000000000000000000177631301765014400176560ustar00rootroot00000000000000#encoding: ASCII require 'barby/barcode' module Barby class Code39 < Barcode1D WIDE = W = true NARROW = N = false ENCODINGS = { ' ' => [N,W,W,N,N,N,W,N,N], '$' => [N,W,N,W,N,W,N,N,N], '%' => [N,N,N,W,N,W,N,W,N], '+' => [N,W,N,N,N,W,N,W,N], '-' => [N,W,N,N,N,N,W,N,W], '.' => [W,W,N,N,N,N,W,N,N], '/' => [N,W,N,W,N,N,N,W,N], '0' => [N,N,N,W,W,N,W,N,N], '1' => [W,N,N,W,N,N,N,N,W], '2' => [N,N,W,W,N,N,N,N,W], '3' => [W,N,W,W,N,N,N,N,N], '4' => [N,N,N,W,W,N,N,N,W], '5' => [W,N,N,W,W,N,N,N,N], '6' => [N,N,W,W,W,N,N,N,N], '7' => [N,N,N,W,N,N,W,N,W], '8' => [W,N,N,W,N,N,W,N,N], '9' => [N,N,W,W,N,N,W,N,N], 'A' => [W,N,N,N,N,W,N,N,W], 'B' => [N,N,W,N,N,W,N,N,W], 'C' => [W,N,W,N,N,W,N,N,N], 'D' => [N,N,N,N,W,W,N,N,W], 'E' => [W,N,N,N,W,W,N,N,N], 'F' => [N,N,W,N,W,W,N,N,N], 'G' => [N,N,N,N,N,W,W,N,W], 'H' => [W,N,N,N,N,W,W,N,N], 'I' => [N,N,W,N,N,W,W,N,N], 'J' => [N,N,N,N,W,W,W,N,N], 'K' => [W,N,N,N,N,N,N,W,W], 'L' => [N,N,W,N,N,N,N,W,W], 'M' => [W,N,W,N,N,N,N,W,N], 'N' => [N,N,N,N,W,N,N,W,W], 'O' => [W,N,N,N,W,N,N,W,N], 'P' => [N,N,W,N,W,N,N,W,N], 'Q' => [N,N,N,N,N,N,W,W,W], 'R' => [W,N,N,N,N,N,W,W,N], 'S' => [N,N,W,N,N,N,W,W,N], 'T' => [N,N,N,N,W,N,W,W,N], 'U' => [W,W,N,N,N,N,N,N,W], 'V' => [N,W,W,N,N,N,N,N,W], 'W' => [W,W,W,N,N,N,N,N,N], 'X' => [N,W,N,N,W,N,N,N,W], 'Y' => [W,W,N,N,W,N,N,N,N], 'Z' => [N,W,W,N,W,N,N,N,N] } #In extended mode, each character is replaced with two characters from the "normal" encoding EXTENDED_ENCODINGS = { "\000" => '%U', " " => " ", "@" => "%V", "`" => "%W", "\001" => '$A', "!" => "/A", "A" => "A", "a" => "+A", "\002" => '$B', '"' => "/B", "B" => "B", "b" => "+B", "\003" => '$C', "#" => "/C", "C" => "C", "c" => "+C", "\004" => '$D', "$" => "/D", "D" => "D", "d" => "+D", "\005" => '$E', "%" => "/E", "E" => "E", "e" => "+E", "\006" => '$F', "&" => "/F", "F" => "F", "f" => "+F", "\007" => '$G', "'" => "/G", "G" => "G", "g" => "+G", "\010" => '$H', "(" => "/H", "H" => "H", "h" => "+H", "\011" => '$I', ")" => "/I", "I" => "I", "i" => "+I", "\012" => '$J', "*" => "/J", "J" => "J", "j" => "+J", "\013" => '$K', "+" => "/K", "K" => "K", "k" => "+K", "\014" => '$L', "," => "/L", "L" => "L", "l" => "+L", "\015" => '$M', "-" => "-", "M" => "M", "m" => "+M", "\016" => '$N', "." => ".", "N" => "N", "n" => "+N", "\017" => '$O', "/" => "/O", "O" => "O", "o" => "+O", "\020" => '$P', "0" => "0", "P" => "P", "p" => "+P", "\021" => '$Q', "1" => "1", "Q" => "Q", "q" => "+Q", "\022" => '$R', "2" => "2", "R" => "R", "r" => "+R", "\023" => '$S', "3" => "3", "S" => "S", "s" => "+S", "\024" => '$T', "4" => "4", "T" => "T", "t" => "+T", "\025" => '$U', "5" => "5", "U" => "U", "u" => "+U", "\026" => '$V', "6" => "6", "V" => "V", "v" => "+V", "\027" => '$W', "7" => "7", "W" => "W", "w" => "+W", "\030" => '$X', "8" => "8", "X" => "X", "x" => "+X", "\031" => '$Y', "9" => "9", "Y" => "Y", "y" => "+Y", "\032" => '$Z', ":" => "/Z", "Z" => "Z", "z" => "+Z", "\033" => '%A', ";" => "%F", "[" => "%K", "{" => "%P", "\034" => '%B', "<" => "%G", "\\" => "%L", "|" => "%Q", "\035" => '%C', "=" => "%H", "]" => "%M", "}" => "%R", "\036" => '%D', ">" => "%I", "^" => "%N", "~" => "%S", "\037" => '%E', "?" => "%J", "_" => "%O", "\177" => "%T" } CHECKSUM_VALUES = { '0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6, '7' => 7, '8' => 8, '9' => 9, 'A' => 10, 'B' => 11, 'C' => 12, 'D' => 13, 'E' => 14, 'F' => 15, 'G' => 16, 'H' => 17, 'I' => 18, 'J' => 19, 'K' => 20, 'L' => 21, 'N' => 23, 'M' => 22, 'O' => 24, 'P' => 25, 'Q' => 26, 'R' => 27, 'S' => 28, 'T' => 29, 'U' => 30, 'V' => 31, 'W' => 32, 'X' => 33, 'Y' => 34, 'Z' => 35, '-' => 36, '.' => 37, ' ' => 38, '$' => 39, '/' => 40, '+' => 41, '%' => 42 } START_ENCODING = [N,W,N,N,W,N,W,N,N] # * STOP_ENCODING = [N,W,N,N,W,N,W,N,N] # * attr_accessor :data, :extended, :include_checksum attr_writer :spacing, :narrow_width, :wide_width # Do not surround "data" with the mandatory "*" as is this is done automically for you. # So instead of passing "*123456*" as "data", just pass "123456". def initialize(data, extended=false) self.data = data self.extended = extended raise(ArgumentError, "data is not valid (extended=#{extended?})") unless valid? yield self if block_given? end #Returns the characters that were passed in, no matter it they're part of #the extended charset or if they're already encodable, "normal" characters def raw_characters data.split(//) end #Returns the encodable characters. If extended mode is enabled, each character will #first be replaced by two characters from the encodable charset def characters chars = raw_characters extended ? chars.map{|c| EXTENDED_ENCODINGS[c].split(//) }.flatten : chars end def characters_with_checksum characters + [checksum_character] end def encoded_characters characters.map{|c| encoding_for(c) } end def encoded_characters_with_checksum encoded_characters + [checksum_encoding] end #The data part of the encoding (no start+stop characters) def data_encoding encoded_characters.join(spacing_encoding) end def data_encoding_with_checksum encoded_characters_with_checksum.join(spacing_encoding) end def encoding return encoding_with_checksum if include_checksum? start_encoding+spacing_encoding+data_encoding+spacing_encoding+stop_encoding end def encoding_with_checksum start_encoding+spacing_encoding+data_encoding_with_checksum+spacing_encoding+stop_encoding end #Checksum is optional def checksum characters.inject(0) do |sum,char| sum + CHECKSUM_VALUES[char] end % 43 end def checksum_character CHECKSUM_VALUES.invert[checksum] end def checksum_encoding encoding_for(checksum_character) end #Set include_checksum to true to make +encoding+ include the checksum def include_checksum? include_checksum end #Takes an array of WIDE/NARROW values and returns the string representation for #those bars and spaces, using wide_width and narrow_width def encoding_for_bars(*bars_and_spaces) bar = false bars_and_spaces.flatten.map do |width| bar = !bar (bar ? '1' : '0') * (width == WIDE ? wide_width : narrow_width) end.join end #Returns the string representation for a single character def encoding_for(character) encoding_for_bars(ENCODINGS[character]) end #Spacing between the characters in xdims. Spacing will be inserted #between each character in the encoding def spacing @spacing ||= 1 end def spacing_encoding '0' * spacing end def narrow_width @narrow_width ||= 1 end def wide_width @wide_width ||= 2 end def extended? extended end def start_encoding encoding_for_bars(START_ENCODING) end def stop_encoding encoding_for_bars(STOP_ENCODING) end def valid? if extended? raw_characters.all?{|c| EXTENDED_ENCODINGS.include?(c) } else raw_characters.all?{|c| ENCODINGS.include?(c) } end end def to_s data end end end barby-0.6.5/lib/barby/barcode/code_93.rb000066400000000000000000000166761301765014400176600ustar00rootroot00000000000000#encoding: ASCII require 'barby/barcode' module Barby class Code93 < Barcode1D SHIFT_DOLLAR = "\301" # ($) SHIFT_PERCENT = "\302" # (%) SHIFT_SLASH = "\303" # (/) SHIFT_PLUS = "\304" # (+) SHIFT_CHARACTERS = [SHIFT_DOLLAR, SHIFT_PERCENT, SHIFT_SLASH, SHIFT_PLUS] ENCODINGS = { "0" => "100010100", "1" => "101001000", "2" => "101000100", "3" => "101000010", "4" => "100101000", "5" => "100100100", "6" => "100100010", "7" => "101010000", "8" => "100010010", "9" => "100001010", "A" => "110101000", "B" => "110100100", "C" => "110100010", "D" => "110010100", "E" => "110010010", "F" => "110001010", "G" => "101101000", "H" => "101100100", "I" => "101100010", "J" => "100110100", "K" => "100011010", "L" => "101011000", "M" => "101001100", "N" => "101000110", "O" => "100101100", "P" => "100010110", "Q" => "110110100", "R" => "110110010", "S" => "110101100", "T" => "110100110", "U" => "110010110", "V" => "110011010", "W" => "101101100", "X" => "101100110", "Y" => "100110110", "Z" => "100111010", "-" => "100101110", "." => "111010100", " " => "111010010", "$" => "111001010", "/" => "101101110", "+" => "101110110", "%" => "110101110", SHIFT_DOLLAR => "100100110", SHIFT_PERCENT => "111011010", SHIFT_SLASH => "111010110", SHIFT_PLUS => "100110010" } EXTENDED_MAPPING = { "\000" => "\302U", " " => " ", "@" => "\302V", "`" => "\302W", "\001" => "\301A", "!" => "\303A", "A" => "A", "a" => "\304A", "\002" => "\301B", '"' => "\303B", "B" => "B", "b" => "\304B", "\003" => "\301C", "#" => "\303C", "C" => "C", "c" => "\304C", "\004" => "\301D", "$" => "\303D", "D" => "D", "d" => "\304D", "\005" => "\301E", "%" => "\303E", "E" => "E", "e" => "\304E", "\006" => "\301F", "&" => "\303F", "F" => "F", "f" => "\304F", "\007" => "\301G", "'" => "\303G", "G" => "G", "g" => "\304G", "\010" => "\301H", "(" => "\303H", "H" => "H", "h" => "\304H", "\011" => "\301I", ")" => "\303I", "I" => "I", "i" => "\304I", "\012" => "\301J", "*" => "\303J", "J" => "J", "j" => "\304J", "\013" => "\301K", "/" => "\303K", "K" => "K", "k" => "\304K", "\014" => "\301L", "," => "\303L", "L" => "L", "l" => "\304L", "\015" => "\301M", "-" => "-", "M" => "M", "m" => "\304M", "\016" => "\301N", "." => ".", "N" => "N", "n" => "\304N", "\017" => "\301O", "+" => "\303O", "O" => "O", "o" => "\304O", "\020" => "\301P", "0" => "0", "P" => "P", "p" => "\304P", "\021" => "\301Q", "1" => "1", "Q" => "Q", "q" => "\304Q", "\022" => "\301R", "2" => "2", "R" => "R", "r" => "\304R", "\023" => "\301S", "3" => "3", "S" => "S", "s" => "\304S", "\024" => "\301T", "4" => "4", "T" => "T", "t" => "\304T", "\025" => "\301U", "5" => "5", "U" => "U", "u" => "\304U", "\026" => "\301V", "6" => "6", "V" => "V", "v" => "\304V", "\027" => "\301W", "7" => "7", "W" => "W", "w" => "\304W", "\030" => "\301X", "8" => "8", "X" => "X", "x" => "\304X", "\031" => "\301Y", "9" => "9", "Y" => "Y", "y" => "\304Y", "\032" => "\301Z", ":" => "\303Z", "Z" => "Z", "z" => "\304Z", "\033" => "\302A", ";" => "\302F", "[" => "\302K", "{" => "\302P", "\034" => "\302B", "<" => "\302G", "\\" => "\302L", "|" => "\302Q", "\035" => "\302C", "=" => "\302H", "]" => "\302M", "}" => "\302R", "\036" => "\302D", ">" => "\302I", "^" => "\302N", "~" => "\302S", "\037" => "\302E", "?" => "\302J", "_" => "\302O", "\177" => "\302T" } EXTENDED_CHARACTERS = EXTENDED_MAPPING.keys - ENCODINGS.keys CHARACTERS = { 0 => "0", 1 => "1", 2 => "2", 3 => "3", 4 => "4", 5 => "5", 6 => "6", 7 => "7", 8 => "8", 9 => "9", 10 => "A", 11 => "B", 12 => "C", 13 => "D", 14 => "E", 15 => "F", 16 => "G", 17 => "H", 18 => "I", 19 => "J", 20 => "K", 21 => "L", 22 => "M", 23 => "N", 24 => "O", 25 => "P", 26 => "Q", 27 => "R", 28 => "S", 29 => "T", 30 => "U", 31 => "V", 32 => "W", 33 => "X", 34 => "Y", 35 => "Z", 36 => "-", 37 => ".", 38 => " ", 39 => "$", 40 => "/", 41 => "+", 42 => "%", 43 => SHIFT_DOLLAR, 44 => SHIFT_PERCENT, 45 => SHIFT_SLASH, 46 => SHIFT_PLUS } VALUES = CHARACTERS.invert START_ENCODING = '101011110' # * STOP_ENCODING = '101011110' TERMINATE_ENCODING = '1' attr_accessor :data def initialize(data) self.data = data end def extended? raw_characters.any?{|c| EXTENDED_CHARACTERS.include?(c) } end def raw_characters data.split(//) end def characters raw_characters.map{|c| EXTENDED_MAPPING[c].split(//) }.flatten end def encoded_characters characters.map{|c| ENCODINGS[c] } end alias character_encodings encoded_characters def start_encoding START_ENCODING end #The stop encoding includes the termination bar def stop_encoding STOP_ENCODING+TERMINATE_ENCODING end def encoding start_encoding+data_encoding_with_checksums+stop_encoding end def data_encoding character_encodings.join end def data_encoding_with_checksums (character_encodings + checksum_encodings).join end def checksum_encodings checksum_characters.map{|c| ENCODINGS[c] } end def checksum_encoding checksum_encodings.join end def checksums [c_checksum, k_checksum] end def checksum_characters checksums.map{|s| CHARACTERS[s] } end #Returns the values used for computing the C checksum #in the "right" order (i.e. reversed) def checksum_values characters.map{|c| VALUES[c] }.reverse end #Returns the normal checksum plus the c_checksum #This is used for calculating the k_checksum def checksum_values_with_c_checksum [c_checksum] + checksum_values end #Calculates the C checksum based on checksum_values def c_checksum sum = 0 checksum_values.each_with_index do |value, index| sum += ((index % 20) + 1) * value end sum % 47 end def c_checksum_character CHARACTERS[c_checksum] end def c_checksum_encoding ENCODINGS[c_checksum_character] end #Calculates the K checksum based on checksum_values_with_c_checksum def k_checksum sum = 0 checksum_values_with_c_checksum.each_with_index do |value, index| sum += ((index % 15) + 1) * value end sum % 47 end def k_checksum_character CHARACTERS[k_checksum] end def k_checksum_encoding ENCODINGS[k_checksum_character] end def valid? characters.all?{|c| ENCODINGS.include?(c) } end def to_s data end end end barby-0.6.5/lib/barby/barcode/data_matrix.rb000066400000000000000000000012731301765014400207130ustar00rootroot00000000000000require 'semacode' #Ruby 1.8: gem install semacode - Ruby 1.9: gem install semacode-ruby19 require 'barby/barcode' module Barby #Uses the semacode library (gem install semacode) to encode DataMatrix barcodes class DataMatrix < Barcode2D attr_reader :data def initialize(data) self.data = data end def data=(data) @data = data @encoder = nil end def encoder @encoder ||= ::DataMatrix::Encoder.new(data) end def encoding encoder.data.map{|a| a.map{|b| b ? '1' : '0' }.join } end def semacode? #TODO: Not sure if this is right data =~ /^http:\/\// end def to_s data end end end barby-0.6.5/lib/barby/barcode/ean_13.rb000066400000000000000000000076631301765014400174750ustar00rootroot00000000000000require 'barby/barcode' module Barby #EAN-13, aka UPC-A, barcodes are the ones you can see at your local #supermarket, in your house and, well, everywhere.. # #To use this for a UPC barcode, just add a 0 to the front class EAN13 < Barcode1D LEFT_ENCODINGS_ODD = { 0 => '0001101', 1 => '0011001', 2 => '0010011', 3 => '0111101', 4 => '0100011', 5 => '0110001', 6 => '0101111', 7 => '0111011', 8 => '0110111', 9 => '0001011' } LEFT_ENCODINGS_EVEN = { 0 => '0100111', 1 => '0110011', 2 => '0011011', 3 => '0100001', 4 => '0011101', 5 => '0111001', 6 => '0000101', 7 => '0010001', 8 => '0001001', 9 => '0010111' } RIGHT_ENCODINGS = { 0 => '1110010', 1 => '1100110', 2 => '1101100', 3 => '1000010', 4 => '1011100', 5 => '1001110', 6 => '1010000', 7 => '1000100', 8 => '1001000', 9 => '1110100' } #Describes whether the left-hand encoding should use #LEFT_ENCODINGS_ODD or LEFT_ENCODINGS_EVEN, based on the #first digit in the number system (and the barcode as a whole) LEFT_PARITY_MAPS = { 0 => [:odd, :odd, :odd, :odd, :odd, :odd], #UPC-A 1 => [:odd, :odd, :even, :odd, :even, :even], 2 => [:odd, :odd, :even, :even, :odd, :even], 3 => [:odd, :odd, :even, :even, :even, :odd], 4 => [:odd, :even, :odd, :odd, :even, :even], 5 => [:odd, :even, :even, :odd, :odd, :even], 6 => [:odd, :even, :even, :even, :odd, :odd], 7 => [:odd, :even, :odd, :even, :odd, :even], 8 => [:odd, :even, :odd, :even, :even, :odd], 9 => [:odd, :even, :even, :odd, :even, :odd] } #These are the lines that "stick down" in the graphical representation START = '101' CENTER = '01010' STOP = '101' #EAN-13 barcodes have 12 digits + check digit FORMAT = /^\d{12}$/ attr_accessor :data def initialize(data) self.data = data raise ArgumentError, 'data not valid' unless valid? end def characters data.split(//) end def numbers characters.map{|s| s.to_i } end def odd_and_even_numbers alternater = false numbers.reverse.partition{ alternater = !alternater } end #Numbers that are encoded to the left of the center #The first digit is not included def left_numbers numbers[1,6] end #Numbers that are encoded to the right of the center #The checksum is included here def right_numbers numbers_with_checksum[7,6] end def numbers_with_checksum numbers + [checksum] end def data_with_checksum data + checksum.to_s end def left_encodings left_parity_map.zip(left_numbers).map do |parity,number| parity == :odd ? LEFT_ENCODINGS_ODD[number] : LEFT_ENCODINGS_EVEN[number] end end def right_encodings right_numbers.map{|n| RIGHT_ENCODINGS[n] } end def left_encoding left_encodings.join end def right_encoding right_encodings.join end def encoding start_encoding+left_encoding+center_encoding+right_encoding+stop_encoding end #The parities to use for encoding left-hand numbers def left_parity_map LEFT_PARITY_MAPS[numbers.first] end def weighted_sum odds, evens = odd_and_even_numbers odds.map!{|n| n * 3 } (odds+evens).inject(0){|s,n| s+n } end #Mod10 def checksum mod = weighted_sum % 10 mod.zero? ? 0 : 10-mod end def checksum_encoding RIGHT_ENCODINGS[checksum] end def valid? data =~ FORMAT end def to_s data_with_checksum end #Is this a UPC-A barcode? #UPC barcodes are EAN codes that start with 0 def upc? numbers.first.zero? end def start_encoding START end def center_encoding CENTER end def stop_encoding STOP end end class UPCA < EAN13 def data '0' + super end end end barby-0.6.5/lib/barby/barcode/ean_8.rb000066400000000000000000000006671301765014400174160ustar00rootroot00000000000000require 'barby/barcode/ean_13' module Barby #EAN-8 is a sub-set of EAN-13, with only 7 (8) digits class EAN8 < EAN13 FORMAT = /^\d{7}$/ def left_numbers numbers[0,4] end def right_numbers numbers_with_checksum[4,4] end #Left-hand digits are all encoded using odd parity def left_parity_map [:odd, :odd, :odd, :odd] end def valid? data =~ FORMAT end end end barby-0.6.5/lib/barby/barcode/gs1_128.rb000066400000000000000000000015511301765014400175010ustar00rootroot00000000000000require 'barby/barcode/code_128' module Barby #DEPRECATED - Use the Code128 class directly instead: # # Code128.new("#{Code128::FNC1}#{application_identifier}#{data}") # #AKA EAN-128, UCC-128 class GS1128 < Code128 attr_accessor :application_identifier def initialize(data, type, ai) warn "DEPRECATED: The GS1128 class has been deprecated, use Code128 directly instead (called from #{caller[0]})" self.application_identifier = ai super(data, type) end def data FNC1+application_identifier+super end def partial_data @data end def application_identifier_number values[application_identifier] end def application_identifier_encoding encodings[application_identifier_number] end def to_s "(#{application_identifier}) #{partial_data}" end end end barby-0.6.5/lib/barby/barcode/pdf_417.rb000066400000000000000000000032271301765014400175630ustar00rootroot00000000000000require 'barby/barcode' require 'java' require 'Pdf417lib' import 'Pdf417lib' module Barby class Pdf417 < Barcode2D DEFAULT_OPTIONS = { :options => 0, :y_height => 3, :aspect_ratio => 0.5, :error_level => 0, :len_codewords => 0, :code_rows => 0, :code_columns => 0 } # Creates a new Pdf417 barcode. The +options+ argument # can use the same keys as DEFAULT_OPTIONS. Please consult # the source code of Pdf417lib.java for details about values # that can be used. def initialize(data, options={}) @pdf417 = Java::Pdf417lib.new self.data = data DEFAULT_OPTIONS.merge(options).each{|k,v| send("#{k}=", v) } end def options=(options) @options = options end def y_height=(y_height) @pdf417.setYHeight(y_height) end def aspect_ratio=(aspect_ratio) @pdf417.setAspectRatio(aspect_ratio) end def error_level=(error_level) @pdf417.setErrorLevel(error_level) end def len_codewords=(len_codewords) @pdf417.setLenCodewords(len_codewords) end def code_rows=(code_rows) @pdf417.setCodeRows(code_rows) end def code_columns=(code_columns) @pdf417.setCodeColumns(code_columns) end def data=(data) @pdf417.setText(data) end def encoding @pdf417.paintCode() cols = (@pdf417.getBitColumns() - 1) / 8 + 1 enc = [] row = nil @pdf417.getOutBits.each_with_index do |byte, n| if n%cols == 0 row = "" enc << row end row << sprintf("%08b", (byte & 0xff) | 0x100) end enc end end endbarby-0.6.5/lib/barby/barcode/qr_code.rb000066400000000000000000000054531301765014400200360ustar00rootroot00000000000000require 'rqrcode' require 'barby/barcode' module Barby #QrCode is a thin wrapper around the RQRCode library class QrCode < Barcode2D #Maximum sizes for each correction level for binary data #It's an array SIZES = { #L M Q H 1 => [17, 14, 11, 7], 2 => [32, 26, 20, 14], 3 => [53, 42, 32, 24], 4 => [78, 62, 46, 34], 5 => [106, 84, 60, 44], 6 => [134, 106, 74, 58], 7 => [154, 122, 86, 64], 8 => [192, 152, 108, 84], 9 => [230, 180, 130, 98], 10 => [271, 213, 151, 119], 11 => [321, 251, 177, 137], 12 => [367, 287, 203, 155], 13 => [425, 331, 241, 177], 14 => [458, 362, 258, 194], 15 => [520, 412, 292, 220], 16 => [586, 450, 322, 250], 17 => [644, 504, 364, 280], 18 => [718, 560, 394, 310], 19 => [792, 624, 442, 338], 20 => [858, 666, 482, 382], 21 => [929, 711, 509, 403], 22 => [1003, 779, 565, 439], 23 => [1091, 857, 611, 461], 24 => [1171, 911, 661, 511], 25 => [1273, 997, 715, 535], 26 => [1367, 1059, 751, 593], 27 => [1465, 1125, 805, 625], 28 => [1528, 1190, 868, 658], 29 => [1628, 1264, 908, 698], 30 => [1732, 1370, 982, 742], 31 => [1840, 1452, 1030, 790], 32 => [1952, 1538, 1112, 842], 33 => [2068, 1628, 1168, 898], 34 => [2188, 1722, 1228, 958], 35 => [2303, 1809, 1283, 983], 36 => [2431, 1911, 1351, 1051], 37 => [2563, 1989, 1423, 1093], 38 => [2699, 2099, 1499, 1139], 39 => [2809, 2213, 1579, 1219], 40 => [2953, 2331, 1663, 1273] }.sort LEVELS = { :l => 0, :m => 1, :q => 2, :h => 3 } attr_reader :data attr_writer :level, :size def initialize(data, options={}) self.data = data @level, @size = nil options.each{|k,v| send("#{k}=", v) } raise(ArgumentError, "data too large") unless size end def data=(data) @data = data end def encoding rqrcode.modules.map{|r| r.inject(''){|s,m| s << (m ? '1' : '0') } } end #Error correction level #Can be one of [:l, :m, :q, :h] (7%, 15%, 25%, 30%) def level @level || :l end def size #@size is only used for manual override, if it's not set #manually the size is always dynamic, calculated from the #length of the data return @size if @size level_index = LEVELS[level] length = data.bytesize found_size = nil SIZES.each do |size,max_values| if max_values[level_index] >= length found_size = size break end end found_size end def to_s data[0,20] end private #Generate an RQRCode object with the available values def rqrcode RQRCode::QRCode.new(data, :level => level, :size => size) end end end barby-0.6.5/lib/barby/barcode/upc_supplemental.rb000066400000000000000000000047501301765014400220010ustar00rootroot00000000000000require 'barby/barcode' require 'barby/barcode/ean_13' module Barby class UPCSupplemental < Barby::Barcode1D attr_accessor :data FORMAT = /^\d\d\d\d\d$|^\d\d$/ START = '1011' SEPARATOR = '01' ODD = :odd EVEN = :even PARITY_MAPS = { 2 => { 0 => [ODD, ODD], 1 => [ODD, EVEN], 2 => [EVEN, ODD], 3 => [EVEN, EVEN] }, 5 => { 0 => [EVEN, EVEN, ODD, ODD, ODD], 1 => [EVEN, ODD, EVEN, ODD, ODD], 2 => [EVEN, ODD, ODD, EVEN, ODD], 3 => [EVEN, ODD, ODD, ODD, EVEN], 4 => [ODD, EVEN, EVEN, ODD, ODD], 5 => [ODD, ODD, EVEN, EVEN, ODD], 6 => [ODD, ODD, ODD, EVEN, EVEN], 7 => [ODD, EVEN, ODD, EVEN, ODD], 8 => [ODD, EVEN, ODD, ODD, EVEN], 9 => [ODD, ODD, EVEN, ODD, EVEN] } } ENCODINGS = { ODD => EAN13::LEFT_ENCODINGS_ODD, EVEN => EAN13::LEFT_ENCODINGS_EVEN } def initialize(data) self.data = data end def size data.size end def two_digit? size == 2 end def five_digit? size == 5 end def characters data.split(//) end def digits characters.map{|c| c.to_i } end #Odd and even methods are only useful for 5 digits def odd_digits alternater = false digits.reverse.select{ alternater = !alternater } end def even_digits alternater = true digits.reverse.select{ alternater = !alternater } end def odd_sum odd_digits.inject(0){|s,d| s + d * 3 } end def even_sum even_digits.inject(0){|s,d| s + d * 9 } end #Checksum is different for 2 and 5 digits #2-digits don't really have a checksum, just a remainder to look up the parity def checksum if two_digit? data.to_i % 4 elsif five_digit? (odd_sum + even_sum) % 10 end end #Parity maps are different for 2 and 5 digits def parity_map PARITY_MAPS[size][checksum] end def encoded_characters parity_map.zip(digits).map do |parity, digit| ENCODINGS[parity][digit] end end def encoding START + encoded_characters.join(SEPARATOR) end def valid? data =~ FORMAT end def to_s data end NO_PRICE = new('90000') #The book doesn't have a suggested retail price COMPLIMENTARY = new('99991') #The book is complimentary (~free) USED = new('99990') #The book is marked as used end end barby-0.6.5/lib/barby/outputter.rb000066400000000000000000000073551301765014400171010ustar00rootroot00000000000000require 'barby/barcode' module Barby #An Outputter creates something from a barcode. That something can be #anything, but is most likely a graphical representation of the barcode. #Outputters can register methods on barcodes that will be associated with #them. # #The basic structure of an outputter class: # # class FooOutputter < Barby::Outputter # register :to_foo # def to_too # do_something_with(barcode.encoding) # end # end # #Barcode#to_foo will now be available to all barcodes class Outputter attr_accessor :barcode #An outputter instance will have access to a Barcode def initialize(barcode) self.barcode = barcode end #Register one or more handler methods with this outputter #Barcodes will then be able to use these methods to get the output #from the outputter. For example, if you have an ImageOutputter, #you could do: # #register :to_png, :to_gif # #You could then do aBarcode.to_png and get the result of that method. #The class which registers the method will receive the barcode as the only #argument, and the default implementation of initialize puts that into #the +barcode+ accessor. # #You can also have different method names on the barcode and the outputter #by providing a hash: # #register :to_png => :create_png, :to_gif => :create_gif def self.register(*method_names) if method_names.first.is_a? Hash method_names.first.each do |name, method_name| Barcode.register_outputter(name, self, method_name) end else method_names.each do |name| Barcode.register_outputter(name, self, name) end end end def two_dimensional? barcode.respond_to?(:two_dimensional?) && barcode.two_dimensional? end #Converts the barcode's encoding (a string containing 1s and 0s) #to true and false values (1 == true == "black bar") # #If the barcode is 2D, each line will be converted to an array #in the same way def booleans(reload=false)#:doc: if two_dimensional? encoding(reload).map{|l| l.split(//).map{|c| c == '1' } } else encoding(reload).split(//).map{|c| c == '1' } end end #Returns the barcode's encoding. The encoding #is cached and can be reloaded by passing true def encoding(reload=false)#:doc: @encoding = barcode.encoding if reload @encoding ||= barcode.encoding end #Collects continuous groups of bars and spaces (1 and 0) #into arrays where the first item is true or false (1 or 0) #and the second is the size of the group # #For example, "1100111000" becomes [[true,2],[false,2],[true,3],[false,3]] def boolean_groups(reload=false) if two_dimensional? encoding(reload).map do |line| line.scan(/1+|0+/).map do |group| [group[0,1] == '1', group.size] end end else encoding(reload).scan(/1+|0+/).map do |group| [group[0,1] == '1', group.size] end end end private #Takes a hash and temporarily sets properties on self (the outputter object) #corresponding with the keys to their values. When the block exits, the #properties are reset to their original values. Returns whatever the block returns. def with_options(options={}) original_options = options.inject({}) do |origs,pair| if respond_to?(pair.first) && respond_to?("#{pair.first}=") origs[pair.first] = send(pair.first) send("#{pair.first}=", pair.last) end origs end rv = yield original_options.each do |attribute,value| send("#{attribute}=", value) end rv end end end barby-0.6.5/lib/barby/outputter/000077500000000000000000000000001301765014400165425ustar00rootroot00000000000000barby-0.6.5/lib/barby/outputter/ascii_outputter.rb000066400000000000000000000016171301765014400223170ustar00rootroot00000000000000require 'barby/outputter' module Barby #Outputs an ASCII representation of the barcode. This is mostly useful for printing #the barcode directly to the terminal for testing. # #Registers to_ascii class AsciiOutputter < Outputter register :to_ascii def to_ascii(opts={}) default_opts = {:height => 10, :xdim => 1, :bar => '#', :space => ' '} default_opts.update(:height => 1, :bar => ' X ', :space => ' ') if barcode.two_dimensional? opts = default_opts.merge(opts) if barcode.two_dimensional? booleans.map do |bools| line_to_ascii(bools, opts) end.join("\n") else line_to_ascii(booleans, opts) end end private def line_to_ascii(booleans, opts) Array.new( opts[:height], booleans.map{|b| (b ? opts[:bar] : opts[:space]) * opts[:xdim] }.join ).join("\n") end end end barby-0.6.5/lib/barby/outputter/cairo_outputter.rb000066400000000000000000000111631301765014400223210ustar00rootroot00000000000000require 'barby/outputter' require 'cairo' require 'stringio' module Barby #Uses Cairo to render a barcode to a number of formats: PNG, PS, EPS, PDF and SVG # #Registers methods render_to_cairo_context, to_png, to_ps, to_eps, to_pdf and to_svg class CairoOutputter < Outputter register :render_to_cairo_context register :to_png if Cairo.const_defined?(:PSSurface) register :to_ps register :to_eps if Cairo::PSSurface.method_defined?(:eps=) end register :to_pdf if Cairo.const_defined?(:PDFSurface) register :to_svg if Cairo.const_defined?(:SVGSurface) attr_writer :x, :y, :xdim, :height, :margin def initialize(*) super @x, @y, @xdim, @height, @margin = nil end #Render the barcode onto a Cairo context def render_to_cairo_context(context, options={}) if context.respond_to?(:have_current_point?) and context.have_current_point? current_x, current_y = context.current_point else current_x = x(options) || margin(options) current_y = y(options) || margin(options) end _xdim = xdim(options) _height = height(options) original_current_x = current_x context.save do context.set_source_color(:black) context.fill do if barcode.two_dimensional? boolean_groups.each do |groups| groups.each do |bar,amount| current_width = _xdim * amount if bar context.rectangle(current_x, current_y, current_width, _xdim) end current_x += current_width end current_x = original_current_x current_y += _xdim end else boolean_groups.each do |bar,amount| current_width = _xdim * amount if bar context.rectangle(current_x, current_y, current_width, _height) end current_x += current_width end end end end context end #Render the barcode to a PNG image def to_png(options={}) output_to_string_io do |io| Cairo::ImageSurface.new(options[:format], full_width(options), full_height(options)) do |surface| render(surface, options) surface.write_to_png(io) end end end #Render the barcode to a PS document def to_ps(options={}) output_to_string_io do |io| Cairo::PSSurface.new(io, full_width(options), full_height(options)) do |surface| surface.eps = options[:eps] if surface.respond_to?(:eps=) render(surface, options) end end end #Render the barcode to an EPS document def to_eps(options={}) to_ps(options.merge(:eps => true)) end #Render the barcode to a PDF document def to_pdf(options={}) output_to_string_io do |io| Cairo::PDFSurface.new(io, full_width(options), full_height(options)) do |surface| render(surface, options) end end end #Render the barcode to an SVG document def to_svg(options={}) output_to_string_io do |io| Cairo::SVGSurface.new(io, full_width(options), full_height(options)) do |surface| render(surface, options) end end end def x(options={}) @x || options[:x] end def y(options={}) @y || options[:y] end def width(options={}) (barcode.two_dimensional? ? encoding.first.length : encoding.length) * xdim(options) end def height(options={}) if barcode.two_dimensional? encoding.size * xdim(options) else @height || options[:height] || 50 end end def full_width(options={}) width(options) + (margin(options) * 2) end def full_height(options={}) height(options) + (margin(options) * 2) end def xdim(options={}) @xdim || options[:xdim] || 1 end def margin(options={}) @margin || options[:margin] || 10 end private def output_to_string_io io = StringIO.new yield(io) io.rewind io.read end def render(surface, options) context = Cairo::Context.new(surface) yield(context) if block_given? context.set_source_color(options[:background] || :white) context.paint render_to_cairo_context(context, options) context end end end barby-0.6.5/lib/barby/outputter/html_outputter.rb000066400000000000000000000042161301765014400221710ustar00rootroot00000000000000require 'barby/outputter' module Barby # Outputs an HTML containing cells for each module in the barcode. # # This does NOT include any styling, you're expected to add the relevant # CSS yourself. The markup is simple: One
with class 'barby-barcode', # one or more inside a each containing # ', '', '', ''], @outputter.cells_for([true, false, false, true]) end it 'should build the expected rows' do assert_equal( [ "#{@outputter.cells_for([true, false]).join}", "#{@outputter.cells_for([false, true]).join}", ], @outputter.rows_for([[true, false],[false, true]]) ) end it 'should have the expected rows' do barcode = MockCode.new('101100') outputter = HtmlOutputter.new(barcode) assert_equal outputter.rows_for([[true, false, true, true, false, false]]), outputter.rows barcode = MockCode.new(['101', '010']) outputter = HtmlOutputter.new(barcode) assert_equal outputter.rows_for([[true, false, true], [false, true, false]]), outputter.rows end it 'should have the expected html' do assert_equal @outputter.start + @outputter.rows.join + @outputter.stop, @outputter.to_html end end barby-0.6.5/test/outputter/pdfwriter_outputter_test.rb000066400000000000000000000016651301765014400234110ustar00rootroot00000000000000unless RUBY_VERSION >= '1.9' require 'test_helper' require 'pdf/writer' class PDFWriterOutputterTest < Barby::TestCase before do load_outputter('pdfwriter') @barcode = Barcode.new def @barcode.encoding; '101100111000'; end @outputter = PDFWriterOutputter.new(@barcode) @pdf = PDF::Writer.new end it "should have registered annotate_pdf" do Barcode.outputters.must_include(:annotate_pdf) end it "should have defined the annotate_pdf method" do @outputter.must_respond_to(:annotate_pdf) end it "should return the pdf object it was given in annotate_pdf" do @barcode.annotate_pdf(@pdf).object_id.must_equal @pdf.object_id end it "should have x, y, height and xdim attributes" do @outputter.must_respond_to(:x) @outputter.must_respond_to(:y) @outputter.must_respond_to(:height) @outputter.must_respond_to(:xdim) end end end barby-0.6.5/test/outputter/png_outputter_test.rb000066400000000000000000000024601301765014400221610ustar00rootroot00000000000000require 'test_helper' class PngTestBarcode < Barby::Barcode def initialize(data) @data = data end def encoding @data end end class PngOutputterTest < Barby::TestCase before do load_outputter('png') @barcode = PngTestBarcode.new('10110011100011110000') @outputter = PngOutputter.new(@barcode) end it "should register to_png and to_image" do Barcode.outputters.must_include(:to_png) Barcode.outputters.must_include(:to_image) end it "should return a ChunkyPNG::Datastream on to_datastream" do @barcode.to_datastream.must_be_instance_of(ChunkyPNG::Datastream) end it "should return a string on to_png" do @barcode.to_png.must_be_instance_of(String) end it "should return a ChunkyPNG::Image on to_canvas" do @barcode.to_image.must_be_instance_of(ChunkyPNG::Image) end it "should have a width equal to Xdim * barcode_string.length" do @outputter.width.must_equal @outputter.barcode.encoding.length * @outputter.xdim end it "should have a full_width which is the sum of width + (margin*2)" do @outputter.full_width.must_equal @outputter.width + (@outputter.margin*2) end it "should have a full_height which is the sum of height + (margin*2)" do @outputter.full_height.must_equal @outputter.height + (@outputter.margin*2) end end barby-0.6.5/test/outputter/prawn_outputter_test.rb000066400000000000000000000044261301765014400225300ustar00rootroot00000000000000require 'test_helper' class PrawnOutputterTest < Barby::TestCase before do load_outputter('prawn') @barcode = Barcode.new def @barcode.encoding; '10110011100011110000'; end @outputter = PrawnOutputter.new(@barcode) end it "should register to_pdf and annotate_pdf" do Barcode.outputters.must_include(:to_pdf) Barcode.outputters.must_include(:annotate_pdf) end it "should have a to_pdf method" do @outputter.must_respond_to(:to_pdf) end it "should return a PDF document in a string on to_pdf" do @barcode.to_pdf.must_be_instance_of(String) end it "should return the same Prawn::Document on annotate_pdf" do doc = Prawn::Document.new @barcode.annotate_pdf(doc).object_id.must_equal doc.object_id end it "should default x and y to margin value" do @outputter.margin = 123 @outputter.x.must_equal 123 @outputter.y.must_equal 123 end it "should default ydim to xdim value" do @outputter.xdim = 321 @outputter.ydim.must_equal 321 end it "should be able to calculate width required" do @outputter.width.must_equal @barcode.encoding.length @outputter.xdim = 2 @outputter.width.must_equal @barcode.encoding.length * 2 @outputter.full_width.must_equal @barcode.encoding.length * 2 @outputter.margin = 5 @outputter.full_width.must_equal((@barcode.encoding.length * 2) + 10) #2D barcode = Barcode2D.new def barcode.encoding; ['111', '000', '111'] end outputter = PrawnOutputter.new(barcode) outputter.width.must_equal 3 outputter.xdim = 2 outputter.margin = 5 outputter.width.must_equal 6 outputter.full_width.must_equal 16 end it "should be able to calculate height required" do @outputter.full_height.must_equal @outputter.height @outputter.margin = 5 @outputter.full_height.must_equal @outputter.height + 10 #2D barcode = Barcode2D.new def barcode.encoding; ['111', '000', '111'] end outputter = PrawnOutputter.new(barcode) outputter.height.must_equal 3 outputter.xdim = 2 #ydim defaults to xdim outputter.margin = 5 outputter.height.must_equal 6 outputter.full_height.must_equal 16 outputter.ydim = 3 #ydim overrides xdim when set outputter.height.must_equal 9 outputter.full_height.must_equal 19 end end barby-0.6.5/test/outputter/rmagick_outputter_test.rb000066400000000000000000000045361301765014400230200ustar00rootroot00000000000000require 'test_helper' class RmagickTestBarcode < Barby::Barcode def initialize(data) @data = data end def encoding @data end end class RmagickOutputterTest < Barby::TestCase before do load_outputter('rmagick') @barcode = RmagickTestBarcode.new('10110011100011110000') @outputter = RmagickOutputter.new(@barcode) end it "should register to_png, to_gif, to_jpg, to_image" do Barcode.outputters.must_include(:to_png) Barcode.outputters.must_include(:to_gif) Barcode.outputters.must_include(:to_jpg) Barcode.outputters.must_include(:to_image) end it "should have defined to_png, to_gif, to_jpg, to_image" do @outputter.must_respond_to(:to_png) @outputter.must_respond_to(:to_gif) @outputter.must_respond_to(:to_jpg) @outputter.must_respond_to(:to_image) end it "should return a string on to_png and to_gif" do @outputter.to_png.must_be_instance_of(String) @outputter.to_gif.must_be_instance_of(String) end it "should return a Magick::Image instance on to_image" do @outputter.to_image.must_be_instance_of(Magick::Image) end it "should have a width equal to the length of the barcode encoding string * x dimension" do @outputter.xdim.must_equal 1#Default @outputter.width.must_equal @outputter.barcode.encoding.length @outputter.xdim = 2 @outputter.width.must_equal @outputter.barcode.encoding.length * 2 end it "should have a full_width equal to the width + left and right margins" do @outputter.xdim.must_equal 1 @outputter.margin.must_equal 10 @outputter.full_width.must_equal (@outputter.width + 10 + 10) end it "should have a default height of 100" do @outputter.height.must_equal 100 @outputter.height = 200 @outputter.height.must_equal 200 end it "should have a full_height equal to the height + top and bottom margins" do @outputter.full_height.must_equal @outputter.height + (@outputter.margin * 2) end describe "#to_image" do before do @barcode = RmagickTestBarcode.new('10110011100011110000') @outputter = RmagickOutputter.new(@barcode) @image = @outputter.to_image end it "should have a width and height equal to the outputter's full_width and full_height" do @image.columns.must_equal @outputter.full_width @image.rows.must_equal @outputter.full_height end end end barby-0.6.5/test/outputter/svg_outputter_test.rb000066400000000000000000000050511301765014400221730ustar00rootroot00000000000000require 'test_helper' class SvgBarcode < Barby::Barcode attr_accessor :data, :two_d def initialize(data, two_d=false) self.data, self.two_d = data, two_d end def encoding data end def two_dimensional? two_d end def to_s data end end class SvgOutputterTest < Barby::TestCase before do load_outputter('svg') @barcode = SvgBarcode.new('10110011100011110000') @outputter = SvgOutputter.new(@barcode) end it 'should register to_svg, bars_to_rects, and bars_to_path' do Barcode.outputters.must_include :to_svg Barcode.outputters.must_include :bars_to_rects Barcode.outputters.must_include :bars_to_path end it 'should return a string on to_svg' do @barcode.to_svg.must_be_instance_of String end it 'should return a string on bars_to_rects' do @barcode.bars_to_rects.must_be_instance_of String end it 'should return a string on bars_to_path' do @barcode.bars_to_path.must_be_instance_of String end it 'should produce one rect for each bar' do @barcode.bars_to_rects.scan(/ :my_quux Barcode.outputters.must_include(:quux) end describe "Outputter instances" do before do @barcode = Barcode.new class << @barcode; attr_accessor :encoding; end @barcode.encoding = '101100111000' @outputter = Outputter.new(@barcode) end it "should have a method 'booleans' which converts the barcode encoding to an array of true,false values" do @outputter.send(:booleans).length.must_equal @barcode.encoding.length t, f = true, false @outputter.send(:booleans).must_equal [t,f,t,t,f,f,t,t,t,f,f,f] end it "should convert 2D encodings with 'booleans'" do barcode = Barcode2D.new def barcode.encoding; ['101100','110010']; end outputter = Outputter.new(barcode) outputter.send(:booleans).length.must_equal barcode.encoding.length t, f = true, false outputter.send(:booleans).must_equal [[t,f,t,t,f,f], [t,t,f,f,t,f]] end it "should have an 'encoding' attribute" do @outputter.send(:encoding).must_equal @barcode.encoding end it "should cache encoding" do @outputter.send(:encoding).must_equal @barcode.encoding previous_encoding = @barcode.encoding @barcode.encoding = '101010' @outputter.send(:encoding).must_equal previous_encoding @outputter.send(:encoding, true).must_equal @barcode.encoding end it "should have a boolean_groups attribute which collects continuous bars and spaces" do t, f = true, false # 1 0 11 00 111 000 @outputter.send(:boolean_groups).must_equal [[t,1],[f,1],[t,2],[f,2],[t,3],[f,3]] barcode = Barcode2D.new def barcode.encoding; ['1100', '111000']; end outputter = Outputter.new(barcode) outputter.send(:boolean_groups).must_equal [[[t,2],[f,2]],[[t,3],[f,3]]] end it "should have a with_options method which sets the instance's attributes temporarily while the block gets yielded" do class << @outputter; attr_accessor :foo, :bar; end @outputter.foo, @outputter.bar = 'humbaba', 'scorpion man' @outputter.send(:with_options, :foo => 'horse', :bar => 'donkey') do @outputter.foo.must_equal 'horse' @outputter.bar.must_equal 'donkey' end @outputter.foo.must_equal 'humbaba' @outputter.bar.must_equal 'scorpion man' end it "should return the block value on with_options" do @outputter.send(:with_options, {}){ 'donkey' }.must_equal 'donkey' end it "should have a two_dimensional? method which returns true if the barcode is 2d" do refute Outputter.new(Barcode1D.new).send(:two_dimensional?) assert Outputter.new(Barcode2D.new).send(:two_dimensional?) end it "should not require the barcode object to respond to two_dimensional?" do barcode = Object.new def barcode.encoding; "101100111000"; end outputter = Outputter.new(barcode) assert outputter.send(:booleans) assert outputter.send(:boolean_groups) end end describe "Barcode instances" do before do @outputter = Class.new(Outputter) @outputter.register :foo @outputter.register :bar => :my_bar @outputter.class_eval{ def foo; 'foo'; end; def my_bar; 'bar'; end } @barcode = Barcode.new end it "should respond to registered output methods" do @barcode.foo.must_equal 'foo' @barcode.bar.must_equal 'bar' end it "should send arguments to registered method on outputter class" do @outputter.class_eval{ def foo(*a); a; end; def my_bar(*a); a; end } @barcode.foo(1,2,3).must_equal [1,2,3] @barcode.bar('humbaba').must_equal ['humbaba'] end it "should pass block to registered methods" do @outputter.class_eval{ def foo(*a, &b); b.call(*a); end } @barcode.foo(1,2,3){|*a| a }.must_equal [1,2,3] end it "should be able to get an instance of a specific outputter" do @barcode.outputter_for(:foo).must_be_instance_of(@outputter) end it "should be able to get a specific outputter class" do @barcode.outputter_class_for(:foo).must_equal @outputter end end end barby-0.6.5/test/pdf_417_test.rb000066400000000000000000000046071301765014400163400ustar00rootroot00000000000000if defined? JRUBY_VERSION require 'test_helper' require 'barby/barcode/pdf_417' class Pdf417Test < Barby::TestCase it "should produce a nice code" do enc = Pdf417.new('Ereshkigal').encoding enc.must_equal [ "111111111101010100101111010110011110100111010110001110100011101101011100100001111111101000110100100", "111111111101010100101111010110000100100110100101110000101011111110101001111001111111101000110100100", "111111111101010100101101010111111000100100011100110011111010101100001111100001111111101000110100100", "111111111101010100101111101101111110110100010100011101111011010111110111111001111111101000110100100", "111111111101010100101101011110000010100110010101110010100011101101110001110001111111101000110100100", "111111111101010100101111101101110000110101101100000011110011110110111110111001111111101000110100100", "111111111101010100101101001111001111100110001101001100100010100111101110100001111111101000110100100", "111111111101010100101111110110010111100111100100101000110010101111111001111001111111101000110100100", "111111111101010100101010011101111100100101111110001110111011111101001110110001111111101000110100100", "111111111101010100101010001111011100100100111110111110111010100101100011100001111111101000110100100", "111111111101010100101101001111000010100110001101110000101011101100111001110001111111101000110100100", "111111111101010100101101000110011111100101111111011101100011111110100011100101111111101000110100100", "111111111101010100101010000101010000100100011100001100101010100100110000111001111111101000110100100", "111111111101010100101111010100100001100100010100111100101011110110001001100001111111101000110100100", "111111111101010100101111010100011110110110011111101001100010100100001001111101111111101000110100100" ] enc.length.must_equal 15 enc[0].length.must_equal 99 end it "should produce a 19x135 code with default aspect_ratio" do enc = Pdf417.new('qwertyuiopasdfghjklzxcvbnm'*3).encoding enc.length.must_equal 19 enc[0].length.must_equal 135 end it "should produce a 29x117 code with 0.7 aspect_ratio" do enc = Pdf417.new('qwertyuiopasdfghjklzxcvbnm'*3, :aspect_ratio => 0.7).encoding enc.length.must_equal 29 enc[0].length.must_equal 117 end end end barby-0.6.5/test/qr_code_test.rb000066400000000000000000000043421301765014400166040ustar00rootroot00000000000000require 'test_helper' require 'barby/barcode/qr_code' class QrCodeTest < Barby::TestCase before do @data = 'Ereshkigal' @code = QrCode.new(@data) end it "should have the expected data" do @code.data.must_equal @data end it "should have the expected encoding" do # Should be an array of strings, where each string represents a "line" @code.encoding.must_equal(rqrcode(@code).modules.map do |line| line.inject(''){|s,m| s << (m ? '1' : '0') } end) end it "should be able to change its data and output a different encoding" do @code.data = 'hades' @code.data.must_equal 'hades' @code.encoding.must_equal(rqrcode(@code).modules.map do |line| line.inject(''){|s,m| s << (m ? '1' : '0') } end) end it "should have a 'level' accessor" do @code.must_respond_to :level @code.must_respond_to :level= end it "should set size according to size of data" do QrCode.new('1'*15, :level => :l).size.must_equal 1 QrCode.new('1'*15, :level => :m).size.must_equal 2 QrCode.new('1'*15, :level => :q).size.must_equal 2 QrCode.new('1'*15, :level => :h).size.must_equal 3 QrCode.new('1'*30, :level => :l).size.must_equal 2 QrCode.new('1'*30, :level => :m).size.must_equal 3 QrCode.new('1'*30, :level => :q).size.must_equal 3 QrCode.new('1'*30, :level => :h).size.must_equal 4 QrCode.new('1'*270, :level => :l).size.must_equal 10 end it "should allow size to be set manually" do code = QrCode.new('1'*15, :level => :l, :size => 2) code.size.must_equal 2 code.encoding.must_equal(rqrcode(code).modules.map do |line| line.inject(''){|s,m| s << (m ? '1' : '0') } end) end it "should raise ArgumentError when data too large" do assert QrCode.new('1'*2953, :level => :l) lambda{ QrCode.new('1'*2954, :level => :l) }.must_raise ArgumentError end it "should return the original data on to_s" do @code.to_s.must_equal 'Ereshkigal' end it "should include at most 20 characters on to_s" do QrCode.new('123456789012345678901234567890').to_s.must_equal '12345678901234567890' end private def rqrcode(code) RQRCode::QRCode.new(code.data, :level => code.level, :size => code.size) end end barby-0.6.5/test/test_helper.rb000066400000000000000000000006541301765014400164510ustar00rootroot00000000000000require 'rubygems' require 'barby' require 'minitest/autorun' require 'minitest/spec' module Barby class TestCase < MiniTest::Spec include Barby private # So we can register outputter during an full test suite run. def load_outputter(outputter) @loaded_outputter ||= load "barby/outputter/#{outputter}_outputter.rb" end def ruby_19_or_greater? RUBY_VERSION >= '1.9' end end end barby-0.6.5/test/upc_supplemental_test.rb000066400000000000000000000076031301765014400205530ustar00rootroot00000000000000require 'test_helper' require 'barby/barcode/upc_supplemental' class UpcSupplementalTest < Barby::TestCase it 'should be valid with 2 or 5 digits' do assert UPCSupplemental.new('12345').valid? assert UPCSupplemental.new('12').valid? end it 'should not be valid with any number of digits other than 2 or 5' do refute UPCSupplemental.new('1234').valid? refute UPCSupplemental.new('123').valid? refute UPCSupplemental.new('1').valid? refute UPCSupplemental.new('123456').valid? refute UPCSupplemental.new('123456789012').valid? end it 'should not be valid with non-digit characters' do refute UPCSupplemental.new('abcde').valid? refute UPCSupplemental.new('ABC').valid? refute UPCSupplemental.new('1234e').valid? refute UPCSupplemental.new('!2345').valid? refute UPCSupplemental.new('ab').valid? refute UPCSupplemental.new('1b').valid? refute UPCSupplemental.new('a1').valid? end describe 'checksum for 5 digits' do it 'should have the expected odd_digits' do UPCSupplemental.new('51234').odd_digits.must_equal [4,2,5] UPCSupplemental.new('54321').odd_digits.must_equal [1,3,5] UPCSupplemental.new('99990').odd_digits.must_equal [0,9,9] end it 'should have the expected even_digits' do UPCSupplemental.new('51234').even_digits.must_equal [3,1] UPCSupplemental.new('54321').even_digits.must_equal [2,4] UPCSupplemental.new('99990').even_digits.must_equal [9,9] end it 'should have the expected odd and even sums' do UPCSupplemental.new('51234').odd_sum.must_equal 33 UPCSupplemental.new('54321').odd_sum.must_equal 27 UPCSupplemental.new('99990').odd_sum.must_equal 54 UPCSupplemental.new('51234').even_sum.must_equal 36 UPCSupplemental.new('54321').even_sum.must_equal 54 UPCSupplemental.new('99990').even_sum.must_equal 162 end it 'should have the expected checksum' do UPCSupplemental.new('51234').checksum.must_equal 9 UPCSupplemental.new('54321').checksum.must_equal 1 UPCSupplemental.new('99990').checksum.must_equal 6 end end describe 'checksum for 2 digits' do it 'should have the expected checksum' do UPCSupplemental.new('51').checksum.must_equal 3 UPCSupplemental.new('21').checksum.must_equal 1 UPCSupplemental.new('99').checksum.must_equal 3 end end describe 'encoding' do before do @data = '51234' @code = UPCSupplemental.new(@data) end it 'should have the expected encoding' do # START 5 1 2 3 4 UPCSupplemental.new('51234').encoding.must_equal '1011 0110001 01 0011001 01 0011011 01 0111101 01 0011101'.tr(' ', '') # 9 9 9 9 0 UPCSupplemental.new('99990').encoding.must_equal '1011 0001011 01 0001011 01 0001011 01 0010111 01 0100111'.tr(' ', '') # START 5 1 UPCSupplemental.new('51').encoding.must_equal '1011 0111001 01 0110011'.tr(' ', '') # 2 2 UPCSupplemental.new('22').encoding.must_equal '1011 0011011 01 0010011'.tr(' ', '') end it 'should be able to change its data' do prev_encoding = @code.encoding @code.data = '99990' @code.encoding.wont_equal prev_encoding # 9 9 9 9 0 @code.encoding.must_equal '1011 0001011 01 0001011 01 0001011 01 0010111 01 0100111'.tr(' ', '') prev_encoding = @code.encoding @code.data = '22' @code.encoding.wont_equal prev_encoding # 2 2 @code.encoding.must_equal '1011 0011011 01 0010011'.tr(' ', '') end end end barby-0.6.5/vendor/000077500000000000000000000000001301765014400141175ustar00rootroot00000000000000barby-0.6.5/vendor/Pdf417lib-java-0.91/000077500000000000000000000000001301765014400170575ustar00rootroot00000000000000barby-0.6.5/vendor/Pdf417lib-java-0.91/lib/000077500000000000000000000000001301765014400176255ustar00rootroot00000000000000barby-0.6.5/vendor/Pdf417lib-java-0.91/lib/Pdf417lib.jar000066400000000000000000001010451301765014400217600ustar00rootroot00000000000000PKΕ: META-INF/PKPKΕ:META-INF/MANIFEST.MFMLK-. K-*ϳR03r.JM,IMu +h8*x%irrPK'0_<<PKȕ:Pdf417lib$Segment.classMPMO@} ]jK"p$&4lb҄ { +bbկ1Gg9/yy3;?_zhiȡCEU j*Tl3(Ӄ``67JH; YrɽQ8J1:ݒ=ar>Dtzel Ņ/²`>VQ0PĎht ȫإ1@"%ե20q,bSu7wRE#Ӗ.hT:&Ǒbr ɦ)Z%Α'[)H)5ª e'2f&N9рPKyMaFPKȕ:Pdf417lib$SegmentList.classmkPǿm4kv?檦U|  eki I;@AA}>xn[}7s>sν q8`2J XĠ ,XrYUɱ>C3o;۞g>3Hd~*C¸~Rp얐oڮbHz!Ő2l׺;,rH6%fSE;Vk6]ϐӛR&='ɷ ^n2(۽kݱar.zS!"jf?ͪH"%ƐiT䰡,ΩX@]EuT 4qO T~P1,1eutfi>S'Xk7$4MM '%90 Lble2Br!//Ia>L߀L8`YPAbi+kRHg$2D+8;!_1I* R-CVZ:CRb'h#': Y˴3gB̷qfL 9-]RE,W}_PKY+-PKȕ:Pdf417lib.classԽw|E?sNo ܇HK0R"RDTEE@" HJ5 )EE@DWP EEly_ X>g)3kfΙu,o7ԉL `L4"&!|_B|G$ĆnP3S CMtƝvH1HqH zJ"E!Z ݌qF qm%HeI# A!@YzEGRMH* ӓhnTTT ȕUBA'D#WEj$?#W{ X\6.r]|^iI\hZ#6 pC5444m֡->aLD?H ~j;4liiZGZGEn? rs\/qv& k#bo0g6AHg.#GtNzB;1rO^ =>IsHD`W|$+>;.goy4ʓDԓhRwO:܀T)͓cz_|A}=ߍn^nɽɽBo7ԟx!nG8ޓ!G}}XߓsT\$O'n%J;ӛAGm #kQ #=iH]<#]H[1V!"@,!.w mpkF`|#vKi[D`s.*#XDP"`,b=iIE9*m"ZE myWq--ăN@ Ah]szoXGMLA6֓H!p<ɪB"O2XC$cyWcO Ci|[ߧG fYYxlã&Ƴ0]MEG-O|IŧD>h9g r)O;Q}([r(+Q'VB$JPO'{x[u%j"W!JЁUQe *V!@HU|7*vO`*VR5h|B2 SW'<8~B,TQ%3  Ll!@oU n!JoJIH!ͤl+r[> :(}^CI>2*2n37ʁr`z2qvRFj?ήXʨRK^vRT< |"f` z.Eݻx 5P=A+j>Tܐcx$0U;8W'"M_aa<-g1LWI4|3!iA.s3Ϩo |QnFO7Q(&JYDb#XReNw;MTeN2.Jc<MƮ4&6r*}aO3 }ha,>6 pϢN"F#^4(P%$B#hx  FJzT%,&z(Q(n;$zbAd?:IBg@')_( $Sspێa֠ |AOB!vAڏ4-TxuQK`"6o(muiCvE]u"򠺄H%g~"㫋TAԺsi RIԅ %@EǞ9-=sݳr2uف@T}NM!IM$FAMw"E:P :jr\)xul RƹHu76v.R}=[|[$~_+{6]혬(`6ƫ9Gm<`ڸm0Ø;( 0R8R@09yOÑf_AMq_OAvOƳ)Dl<l' .KƳxgm`[q~ 60]`N呛)ǯSyfq*F#7SSو xcQ7Jt@7B-:(ujЧ໎(s OqD)[&1|LcD({r(?e!1L=D9F(/eQ^&+DCcD(eQ%+DC{ Q%+DFW}n[7Dm"ݿQχSq6QW=)a=EYl=6|; mw=,|; mw6|k; mwo-|k1+xV`&Am?SHSJ!N=j/TJgJ npmp`K@Z;  N@nT)>C݊A|?C:t([ d+>< E | 3DYE' VAnDJlԪ>o6*'MȆT DT5pT < UM;.+Xbv^zAbQ1>qllgom ص m v g}? ؒ!n v!}Hx5H>H]  <cH3{w~`=s 9~<8yp [8H^-(B^΃ARK1ARHE:f"=!9_2ArD=Is8Խ9[Pr@} WfBP3!?' r {yu'(yx {v<@MnlM&7a ou:MOxƓ1qi'c OƸ4Ɠ1.qɁ]`Hyƫu)xp-#} ^8LH`|رGڈG:LF߇L g&ag$<&a,D;[Gvhn/{td$;t#iH>v:M'14!Iu IHd0 alHۑ'"FZ/IHCcWL_5g} m@Mw59 xzw,!bj1ȯzJ߳?___otV8c& McBHTHl>ӄk‚*d Oֳj%n=K7_Fkx8而~=;WQ7T^G3Q\bqb]f f¤~bZo3#^ 8*<|OkÛ :&#ț c #cxitN4d W7n7c4 Tn2cK p9p[ͨnpf5ínғ;QqhJ t|D5u߁l$ 09q=Ùx/{ovsz 'ݸx1v?aw c{=Fz {}=B__<-Sx|so9Fz|<þ 9|0Ai;qy ؝f4{(GiMQvӶ|vӖO[>mbxbۊ.n+ydM0H`TJ% i%H-x"|[EhZbeMrlx4ǣ9 3Wx{,Xuf$UIW#ԓ<~#)W4n= I[ ,c̟^Lfcb 1^2ދ5ʼn^ FLz#HV­w0ir07JResg 85 d&[JfƷg`|KyF׃Unv=*bRA/$PR虄zj$T&҂HZ~a~*ѝ;|2c~n"QXǘy)F3/ŨJ1_0e_\~~Jq&H# p-xGOk3vs;vX?bzS8ka|XK0~:Q?0G{0>E +D@D ;vc(b*e6)FBA$t@R)i$]rJ L#ydK%$>݄)A"$DoBЄ$'G&$y>jB瓨&$ INmZ۴ i>ykoJ`Bj#RJ`YO y$A֓/Hz$7x>Ѩh|>n ѐ I!44TR_H)ѐ)TNc*g4d=U*YO|;Q`5d>&xZO5-1ƣxK1J8l=[O5m>m7cWVBocs|~ZϗH7FW(Bb)G(X )@|Gjqr(Y-N΋ؠ$$βK+,{r4@*=ʊW )Y x`G>b-t,|\:wb[nSR%7%kJ**`ܔTǸv;RQT4%_!;Y~ר/T|7IR&X@*$0N>bR1$5ŮvcxSj^c\5%ycxT_j| . o 5mc6c /woP)n9RG!Qq(ewx+^|.b?b`K~q,] ..ªMge`Yƣ,t>]B`!.g ~ 9un:k`!`3̼37cmz0}%̼Y0s&G#}18Fd{<A FJ۸Hk ׮_n5f쟙kM\a5;jsmuԺ[NZܭcm3m)2{`n^2r䬹ХM;Zѻ4ocZkJ]2][wO)ygAG(wѭuǎk}[vtdM"ת[qo8?okݱsm;Ҽ}Yۣ_^kbz x8袕nסWoۿ_+f#(:7:4ܹu~y;up^-QPuj{g.%I6Dqd5nAvnjy[wȏC-;w!>plN-vnC:ԶMggZ#)vTK;yrK.XT1:4oڹA󘠡[=>x?]niݱmsm|ʚӎa;Q \Ú(wn~A|Y>:/|"Q`߲]N~T]w _P-0з1{È:Іf |H-Ϸ%fdz 5ay7بe;q5Oݗ]ʸIܬVY3됙9 +/+Ǐ_sX~jEtk{S^y>@?!3'\Kķt70`ezf9f^VkVevN_)l֨DgL^i˳Z۶ 82{BÏ0GfnkW?i41d됝k&Z0^C *yUdB@f~iFdմyCYVK280;/GV@o/Hc|y8y$~e^k^x\pH둙e7(/OyeeչKnfi :w@,ԭ]YGI)ƱqhkuKw{N<Ql+d'?0 }\sYi ;{`^bkrwTAcik ~ +/;Z¹f 0V}}Qɾ?+0O^N\DQiW<6!4O5N]~9j=_@8L?A<LLDBEFdb5Md L?(A]+Hd]ek׹ջ~*j4|u+j]uez{ImԸ w}Oc*җH_Qժ79>"qw;dР으^t=P6Cyۖ~Y=p޾=oֲBo'[@yoE.܀s< owAT#R4n{R1epeRӡ\00 5+^b%O(w0k֪?ǃs; -[r)Awq}=Cy7e ;ɗ #$[h=jԳ6Ġy̞Y/uMٰ+cy g{}P}s^+-",2!;+sx ?|D>GE ^>듊z"zO._)E*^ZDiEO"L?^DO^?UD.gxgs>> KyE罞_Dsr<׍;J_p E&rG B}U!_]zG_7Vϯ8}%µ+4n)oǿsd2~۔4̖]^j ,4q|r/R޻otn7ΡB[a Ư0 Q?pz4;?r>1& 2fO)mr} Q+daގߞO߷WS/ŧ{wI G<4sPAKam]U S*oH=oz346_hsV8c`1Xa[jRB4zS^;w?Gͭf$<懽ܰ+f96JS|Ġu4o޹V.k\z4i)yL {mr^ Oy~ۡqzRI?y7n) MS(x4}MI/b>_ABeɡk]TՋMxms?S3Bjl ߽^l\[ؾ ]s]=ԫ^lzؚ٘+MYW/.9ŦogmM? Y1-U7.1mTg[nq|1 V+~bs R{SjA ]W'$DZ02/9.ZٷO;;|qV' J+rsy = zѰ=cd: >rZAƋVʷy+\dt%F1Pw?W1_T"*?Uؙzag]*>)O &r9c6+n-a0mijs\wズL=dj)T57c? 8դ*,28uT3aZr\E-Ivwl˧ߓ5'owƤMuu̿!iD[kM+uf1X3ƙ6PfKI?DߦIvp1?1 u񒻩:]+b0+ch1.FW= gxS>jN4eclj)fF;eg^gTa'6 rtq=2E2bMaG9o3< ?mWc gLAyﳼgy{gjFloyy>fxSb_ n%MStNI 9y')v2c.:XVns$ߌb|ĿlWL9.3k]O~+MGd{>ľaF:?Ͼ:f[B yS7vM߂ Nrl6*v "SƳKLIۛ5ePREfWJȕ^LE&ѳ ܋-1I Ƅ%pݬE ywfՙoj%7INUj&uGuOn)dx4+| +MfRg_a@ B*Q 'Xic:yqfڦ$u-V(+<T*)[lYab>sԋ jzPV0EfWq X`B LWlld]abχ֟2ksg'W0k1 + Sggѹ,"SE碳(p=;,n(O6j:?̮ M(/X$沾1)#Cڥy A D?+Lyj[&־ FdhTu}v;L4-fd؏?6kO{S|co~s_{&ۯ-o߳7=bQ6l3{'l=iٿR}מ?#fDoIޟRK+!1#J,I'=8zqd6ǤH?O}\_xY$'E1\:Y7M]0tTƓ$\QBIض! Kp1۹_ct]eF4IJdiڵlhiVV>t~Y~J6ed(MU15$\'y/2t^!cnS,p #shRs&`V|S"=))Pz[x~Qd?ƘXSA1Wxob9k5K=ˠ. )E& N ]kLіL7Yw4m4/\゛dsSW/]aj47?᧑~v]&%Zm54U>%bN{љE-ۜ%>=~E02s} ژC|/-_Ч!V|,oLBzR Brl P >28?[ Mҝ>@oT?=|f=! jN0XszO)6i?{G;0hŢ>5nMю{j2 CxrsX}<|ԞMۂ ĕ2V0i9cE1sLP/:s$_L7]˄qҝ䂆H.\ql+Kz:| 3+hozpƅc^xE84]Jq{B~||BqC-ij$1s'V,׾:ӄTO< G{Xtţ{Z"I'=-}hiO5:Rٞ&GxzYOKGLte<-iOS =M.BtGx}ӊѿzZ)^}+JVj=}˞^}W=:Ӛe֊irODWxzMtu<6뢯{Z/GxZ?u6QMOGImOF7x,7D7z<͞iO[Gz&7FyzStm{zst~iNOo}CO3=[ccO;Ex9.O<-G?>OF{zgsO~/='Fx-ݣ=͌G=x+zӬQO{GO}==}ѓ=ӁSfGtP?y/EtH7OthwOE=ӑ?=x6ZlZA.?ԆU Dm|xx jᏪ ''-Lmqd%S&- 6 V3ԖT \e'Ԗ? )eO-<|gV?r\iyj+竭_2|+^ _ |ڪVUmujjoj]mM?ւ6%u/ںW^ _:2௩\m} +6RZmcjPFm3Z7שm_M-om[mkm悔QMMj7ڿmߪ{j÷̀oW[;v|]j?T{|O]G]jj|j3៫BmOj{R?7k}R~X}o??oS ?vjsߩͅ6!Sjv(av#ῪMhc࿫}/ajT֨jES(DoԞU;|7|?# bU,|TC*}XcU oǩv o'QNT$>*࿝۩*࿝*࿝ۙ*}\OI>ۧU;KU;GϨYU<W.T".V>ۿy櫀MW?T o_R*}Ev o5.W ߮T*߮V*}CkTVT^o-߾ *}GUIU ov oS6nW*ݡTST ow#Sv o~TOU oP*JT o oQQ~c*=*=T oP)*I?T{F_* oP*_ /S%K /*ĩK /*࿄URL*࿔P%I*DUQ_Je*࿔V /eU)Ky_RTIU /KE_*RY+TR**TU /UIW*_jr /5UKm_ꨀr /uUVT*W / UiKc_Tf*ܠKs_ZRV*࿴V /7r /mUYN[TiK /TU*tR /]TMUC*ܩ]*ܭ=*ܫK7_K_zK,_zG*S>_W /TK /TK /*䩀2DT0_2B*࿌Rhu࿌Q˃yH/e:_Q8u࿌Wu<ԁ2Y/Sԁ2U/ԁ2]/3ԁ2S/ u<ԁ:_fe:_u<YYYԁWu<|u࿼:_^TKyY/Uu,U2u࿼YYy]/oe:_֪e:_֫Mu࿼ՁA/e:_6e:_UulU{٦y_/;ԁ:_ve:_>Tnu|cuQ^u|OՁ:_e:_>WR/_:_VAuRau|#9oՁrL/ՁrB/'Ձ:_W9ՁrZ/?gu_Ձ:_ΨwuK/VS:YuusRu࿋U8u࿋WuKT:Eԁ:Ww%Ձ.wwԁ.Y.SWFʪ]9u+w)wԁruKSWI*w:UQWM磌]:]w5ԁju࿫wԁ:Qkԁ:]wש]=u࿻^]ukwԁ:5QLnPBZ]+ukwmԁFu࿻Iڪukw]{uPw:uTNYﺨmw:ݡw]ՁNu࿻KV{ԁ^uwՁ.Sz]OuwY[]_uw_@uVA7Xrԁ.Wԁn:=wCՁn: W7RFiw51݃CX  n7^C࿛!=!M&iwiw5)T n7]C࿛!fiw593ݳ\ nM5p@f݂;wwwwww!=I!'HpΛ}^U;g^_55K՘/S3Ún܌@5*QӭnttjLPlnTPi\P\mdP<klP|otP,h|PB,lPO YE Y( Y8% YH YXe Yh Yx YɈ YŘU Yͨ Yø5 Yȡ Yءu Y衚   !M "( #8- $H %Xm &h 'x (Ɉ )Ř] *ͨ +ø= ,Ȣ -آ} .袚 /9 09 19C 29( 398# 49H 59Xc 69h 79x 89Ɉ۫1Z;1^;1bCֻ1fֻ1j{1n{1rC1v1z}1~}1}C؇ \lD6D6L]7n&2vLd 캙u3)f"S`DL]7n&2vLd 캙u3)f"S`DL]7n&2vLd 캙u3)f"S`DL]7n&2vLd 캙u3)f"S`DLjLjLݯԘ_1vQc ~]]N)S`5j55Z5jLݟԘԘ?1v׫1vQc M)S`5jL jLݍjLMjLjL-jLݭjLmjLjLjLݿԘ;՘Ԙ՘{Ԙ{՘Ԙ՘Ԙ՘Ԙ՘GԘG՘Ԙ՘'Ԙ'՘Ԙ՘gԘg՘Ԙ՘˛M݋%yW!C_.< y!oC+G<=y!C?,D<3y/!)J<y!Cǁw8yqq8<ǁ8Q>gy"?ǁW~ @"㣐$2>O@"㓐$2> @"㳐$2>D EHd| _DW UHd| _D@"&$2oC"!Hd|߃D!Hd?DƏ!Hd?D! Hd$2~ _A"א $2~ A"$29Hd@"84D<$2HdȔ )C"SD$2 LA"ӏ i|Hdj!B"$Hd&D!ǐ4 $2M LA"4$2M LSA"Ԑ4 $2M LA"4$2L3A"̐4 $2fD ivHdD inHdD i~HdZD iaHd)$2-LB"bȴ8$2-LKB"Rȴ4$2-LB"rDQJD1JDqJD JDIJD)JDiJDϔ;C3;K+w=pPJDܹJDJ]D܅J]DJ]DܥJ]DJ]Dܯ=pQJ]DUJN+%zV%zUJI=p+%zDߔ=pPJݠD܍JݤDJ%S`w)Mݮd P2vR2vw*LJ%S`w)Oݯd P2v*LJ%S`){L=d P2vO*LJ%S`){N=d d ^P2v/* /+A_QM ?J7 o*AR%J +A?PH %Jϔ +APO +%Jo *ASA )pQ*7J8^ >(G%pH ~\%p?|_p'PJ8)Oc%Ip'UL ~r%)pTJ ~j%ipUN ~z%pgTI ~f%Yp?lJ8+ϡ?\J8s+ϣ?|J8+/BJ8 +T ~eEqSƁ_\~ e%qRƁ_Z~eeqSƁ_^~eqWRƁ_Y~eUqWSƁ_]~ e5qRƁ_[~euqSƁ__~e q7RƁX~eMq7SƁ\~ e![+CQo N2~e!;+CwQ M2~e!{+CQ O2e!+CQ ?L2e!G+CQ ?N2e!'+COQ ?M2g3!g*CR\2_*CQ ?O2e!+C/Q_ L2 e!VF[e!S^ek!*C 2:e!+C 2o+C 2e!7+CoQߪ M2e!w*CR߭ G2>e!*CR? D21e'!O*CR? F29e+C_P I2eה!+C C2-e*CQ O2e!+C?Q L2 e!_*CR F2;eq2@~e2|q2|TƁO8Y(qUƁOG8+8U~ex)O?28?VƁD~Reɔq'WƁB~JeqVƁF~ZeqWƁA~FeqgVƁE'8*Ϧ?28s*ϥ?2<8*ϧ?28 */2OqQ_T~1UpP_R~)UpQ_V~9UpWP_Q~%UpWQ_U~5UpP_S~-UpQ_W~=Up7PP~#Up7QT~3UpPoJ ~*T ۫@wPI ~*T @PK ~*T @P?H *T @P?J *T ǫ@OP?I *T @?C ,U g@ *T @/P_H *T @PJkoT U_J;U P_F *?@SY /*@ *@oPߨI *T @PK .*{T @S߯@ !*GT @S?B )*gT Ϫ@S? *T /@_QM ?*7T o@R *T @?PH *T @PO +*oT ߪ@SA8B@qTרU *Ez =pYBHqUO7 =p =pU T聓 =p7 =pcz&QnRz&SnrzPnJzRnjzQnZzSnzzfPnFzfRnfzfQ'*ͪBl*ͮB*ͩB\*ͭB<*ͫB|*ͯB*-BB*-BOU[D#zՈ4nq[B#zԈ4ni[F#zՈ4ny[A#zVԈ4ne[E#zVՈ4nu[C#zԈ4nm[G#zՈ4n}@#z6Ԉ4ncD#z6Ո4nsB#AFm4o~; kA#AwF]4~7 kC#AF}4~? k?@#AFC40 k?B#AFc48 k?A#AOFS44 kF34, ?F_hFs4< k@#A/FK4_2vXsm&)l[Ӛ%C Z<7&޷/[q%5j2ZZLE:8жDvw^AEet?!?8.?hi:kKղZ_^֎_=nZR?ΒNo-3ﶤw6}knncҼ%RZPHvӽ7nԗv<.2Oǯն0Z- ZfnjHD*ډ84|Vnl'TNZMVQɫSTKiN蚺./KĸYoY-YHBb` ݥm8KlKkQ~_ۋ\tfyvmqmvص_]͵Y"^wm]7tf1ݵYJWwmr]eٵ_Oک}v,|vjx}2U*koWP-ZT;SuFg&OEBVKjgggQY-Z[;w vZM;_kͮW/lhU. WKhZ-ة]Emj"%%KG ;-ȍ7 &ܘC7n: fK{/3n,";ڍ {G: O}ߖ+2tx -ݭ VuCgY6 ; %uCgs WKQf ljAOڱpEk;Any7cSK8&n,']:Z^Z:`LvjY=rYZkl^Z\nRZmR-گ]5>Zuvtbj0h5xkUi׮ծS-Q]Z@h^vjqRB U j7nZ/rZk޼\nY-ݪ:yPnSm5UKikP-ݱ+w \-XݥZjkuݪ崻W kу`~jۇyݷ@~_-ӥ=S }P|j!C[A?mxh>~kn\D,W侧a)PqA*n*N*}MY^UT;0,8Z܀{/fu(9Jyh'')k d%y_rwSr|UKVKZQo\,ՂɒY+)(8O+s'Sp\dg)m6[nMYvMPpxf|_pvg+6vT{8FzvV,,+8&YQ+µbuWPq́+WoJdj!]YqWsRWskSs6!w5g]Y|tWsh^vK J9pvǾ~WlڄYn RԮ,ӯ8:kiH_pKPpfwgL]Y~cWp&  nǽ|_n,2?yrrCZ-7gjPqGUbѵ>e^ux6w| jF~bӭO}JɕTHw swurVwZu8~ƺ3wJ ;? gW/*;EM;ί *aJʢ%lK񫻴.d3+٤g~]oj JpuWU2_{T"ՕawM%]]+QOhYw]g`+j/-_^VɧuT?+9X-u7>wf[*1V&nZNP^Irw>_-vJ֢T2ܽhKmfݮ^]mR+vrmujﶜ}quw!N\->ֳ"vujC։{q$TיW}Ge,WSvjqwFdUu@Ndۉ\kcyqN\WwVG!`WE+?0olN\ _-ɵۊk hLNZl.ʲi~-x6[rI:e(e[ڷ/ _ꔕ ղmzaanVUH֯WWkTK5]}U0Z֖*Ulo-Ph$fnySڡM%f;]ecEnYtUֽo/Jtmv5tc{]}]dNW-U>ݪkwb~g٫_]-YV[ɞZпNY ]ã-z]D $J'-t ^V |vUf;]%ؿ~^v?h㥱|0j W+ŝz&1vgǀy59RJyص?W!sI+yNZIYtnzܘ?cz֘<&I+OߍIb7>^|rn~}:Ė> VdT݆wr¬YNޔ\ڇ;6ok%g$Bi%AhZx\?w/G3/GVJm+ Z1Xj\-'/D{]Z?uv?Y }0'&׭边O{ݠ_A6}F-57n6kdmYtynW%ݭwu?t N1loaau ru~2dv;%;Ws\sW4SGQsImage or a raw bitmap. * @author Paulo Soares (psoares@consiste.pt) */ public class Pdf417lib { /** Auto-size is made based on aspectRatio and yHeight. */ public static final int PDF417_USE_ASPECT_RATIO = 0; /** The size of the barcode will be at least codeColumns*codeRows. */ public static final int PDF417_FIXED_RECTANGLE = 1; /** The size will be at least codeColumns * with a variable number of codeRows. */ public static final int PDF417_FIXED_COLUMNS = 2; /** The size will be at least codeRows * with a variable number of codeColumns. */ public static final int PDF417_FIXED_ROWS = 4; /** The error level correction is set automatically according * to ISO 15438 recomendations. */ public static final int PDF417_AUTO_ERROR_LEVEL = 0; /** The error level correction is set by the user. It can be 0 to 8. */ public static final int PDF417_USE_ERROR_LEVEL = 16; /** No text interpretation is done and the content of codewords * is used directly. */ public static final int PDF417_USE_RAW_CODEWORDS = 64; /** Inverts the output bits of the raw bitmap that is normally * bit one for black. It has only effect for the raw bitmap. */ public static final int PDF417_INVERT_BITMAP = 128; protected int bitPtr; protected int cwPtr; protected SegmentList segmentList; /** Creates a new BarcodePDF417 with the default settings. */ public Pdf417lib() { setDefaultParameters(); } protected boolean checkSegmentType(Segment segment, char type) { if (segment == null) return false; return segment.type == type; } protected int getSegmentLength(Segment segment) { if (segment == null) return 0; return segment.end - segment.start; } /** Set the default settings that correspond to PDF417_USE_ASPECT_RATIO * and PDF417_AUTO_ERROR_LEVEL. */ public void setDefaultParameters() { options = 0; outBits = null; text = new byte[0]; yHeight = 3; aspectRatio = 0.5f; } protected void outCodeword17(int codeword) { int bytePtr = bitPtr / 8; int bit = bitPtr - bytePtr * 8; outBits[bytePtr++] |= codeword >> (9 + bit); outBits[bytePtr++] |= codeword >> (1 + bit); codeword <<= 8; outBits[bytePtr] |= codeword >> (1 + bit); bitPtr += 17; } protected void outCodeword18(int codeword) { int bytePtr = bitPtr / 8; int bit = bitPtr - bytePtr * 8; outBits[bytePtr++] |= codeword >> (10 + bit); outBits[bytePtr++] |= codeword >> (2 + bit); codeword <<= 8; outBits[bytePtr] |= codeword >> (2 + bit); if (bit == 7) outBits[++bytePtr] |= 0x80; bitPtr += 18; } protected void outCodeword(int codeword) { outCodeword17(codeword); } protected void outStopPattern() { outCodeword18(STOP_PATTERN); } protected void outStartPattern() { outCodeword17(START_PATTERN); } protected void outPaintCode() { int codePtr = 0; bitColumns = START_CODE_SIZE * (codeColumns + 3) + STOP_SIZE; int lenBits = ((bitColumns - 1) / 8 + 1) * codeRows; outBits = new byte[lenBits]; for (int row = 0; row < codeRows; ++row) { bitPtr = ((bitColumns - 1) / 8 + 1) * 8 * row; int rowMod = row % 3; int cluster[] = CLUSTERS[rowMod]; outStartPattern(); int edge = 0; switch (rowMod) { case 0: edge = 30 * (row / 3) + ((codeRows - 1) / 3); break; case 1: edge = 30 * (row / 3) + errorLevel * 3 + ((codeRows - 1) % 3); break; default: edge = 30 * (row / 3) + codeColumns - 1; break; } outCodeword(cluster[edge]); for (int column = 0; column < codeColumns; ++column) { outCodeword(cluster[codewords[codePtr++]]); } switch (rowMod) { case 0: edge = 30 * (row / 3) + codeColumns - 1; break; case 1: edge = 30 * (row / 3) + ((codeRows - 1) / 3); break; default: edge = 30 * (row / 3) + errorLevel * 3 + ((codeRows - 1) % 3); break; } outCodeword(cluster[edge]); outStopPattern(); } if ((options & PDF417_INVERT_BITMAP) != 0) { for (int k = 0; k < outBits.length; ++k) outBits[k] ^= 0xff; } } protected void calculateErrorCorrection(int dest) { if (errorLevel < 0 || errorLevel > 8) errorLevel = 0; int A[] = ERROR_LEVEL[errorLevel]; int Alength = 2 << errorLevel; for (int k = 0; k < Alength; ++k) codewords[dest + k] = 0; int lastE = Alength - 1; for (int k = 0; k < lenCodewords; ++k) { int t1 = codewords[k] + codewords[dest]; for (int e = 0; e <= lastE; ++e) { int t2 = (t1 * A[lastE - e]) % MOD; int t3 = MOD - t2; codewords[dest + e] = ((e == lastE ? 0 : codewords[dest + e + 1]) + t3) % MOD; } } for (int k = 0; k < Alength; ++k) codewords[dest + k] = (MOD - codewords[dest + k]) % MOD; } protected int getTextTypeAndValue(int maxLength, int idx) { if (idx >= maxLength) return 0; char c = (char)(text[idx] & 0xff); if (c >= 'A' && c <= 'Z') return (ALPHA + c - 'A'); if (c >= 'a' && c <= 'z') return (LOWER + c - 'a'); if (c == ' ') return (ALPHA + LOWER + MIXED + SPACE); int ms = MIXED_SET.indexOf(c); int ps = PUNCTUATION_SET.indexOf(c); if (ms < 0 && ps < 0) return (ISBYTE + c); if (ms == ps) return (MIXED + PUNCTUATION + ms); if (ms >= 0) return (MIXED + ms); return (PUNCTUATION + ps); } protected void textCompaction(int start, int length) { int dest[] = new int[ABSOLUTE_MAX_TEXT_SIZE * 2]; int mode = ALPHA; int ptr = 0; int fullBytes = 0; int v = 0; int k; int size; length += start; for (k = start; k < length; ++k) { v = getTextTypeAndValue(length, k); if ((v & mode) != 0) { dest[ptr++] = v & 0xff; continue; } if ((v & ISBYTE) != 0) { if ((ptr & 1) != 0) { dest[ptr++] = (mode & PUNCTUATION) != 0 ? PAL : PS; mode = (mode & PUNCTUATION) != 0 ? ALPHA : mode; } dest[ptr++] = BYTESHIFT; dest[ptr++] = v & 0xff; fullBytes += 2; continue; } switch (mode) { case ALPHA: if ((v & LOWER) != 0) { dest[ptr++] = LL; dest[ptr++] = v & 0xff; mode = LOWER; } else if ((v & MIXED) != 0) { dest[ptr++] = ML; dest[ptr++] = v & 0xff; mode = MIXED; } else if ((getTextTypeAndValue(length, k + 1) & getTextTypeAndValue(length, k + 2) & PUNCTUATION) != 0) { dest[ptr++] = ML; dest[ptr++] = PL; dest[ptr++] = v & 0xff; mode = PUNCTUATION; } else { dest[ptr++] = PS; dest[ptr++] = v & 0xff; } break; case LOWER: if ((v & ALPHA) != 0) { if ((getTextTypeAndValue(length, k + 1) & getTextTypeAndValue(length, k + 2) & ALPHA) != 0) { dest[ptr++] = ML; dest[ptr++] = AL; mode = ALPHA; } else { dest[ptr++] = AS; } dest[ptr++] = v & 0xff; } else if ((v & MIXED) != 0) { dest[ptr++] = ML; dest[ptr++] = v & 0xff; mode = MIXED; } else if ((getTextTypeAndValue(length, k + 1) & getTextTypeAndValue(length, k + 2) & PUNCTUATION) != 0) { dest[ptr++] = ML; dest[ptr++] = PL; dest[ptr++] = v & 0xff; mode = PUNCTUATION; } else { dest[ptr++] = PS; dest[ptr++] = v & 0xff; } break; case MIXED: if ((v & LOWER) != 0) { dest[ptr++] = LL; dest[ptr++] = v & 0xff; mode = LOWER; } else if ((v & ALPHA) != 0) { dest[ptr++] = AL; dest[ptr++] = v & 0xff; mode = ALPHA; } else if ((getTextTypeAndValue(length, k + 1) & getTextTypeAndValue(length, k + 2) & PUNCTUATION) != 0) { dest[ptr++] = PL; dest[ptr++] = v & 0xff; mode = PUNCTUATION; } else { dest[ptr++] = PS; dest[ptr++] = v & 0xff; } break; case PUNCTUATION: dest[ptr++] = PAL; mode = ALPHA; --k; break; } } if ((ptr & 1) != 0) dest[ptr++] = PS; size = (ptr + fullBytes) / 2; if (size + cwPtr > MAX_DATA_CODEWORDS) { throw new IndexOutOfBoundsException("The text is too big."); } length = ptr; ptr = 0; while (ptr < length) { v = dest[ptr++]; if (v >= 30) { codewords[cwPtr++] = v; codewords[cwPtr++] = dest[ptr++]; } else codewords[cwPtr++] = v * 30 + dest[ptr++]; } } protected void basicNumberCompaction(int start, int length) { int ret = cwPtr; int retLast = length / 3; int ni, k; cwPtr += retLast + 1; for (k = 0; k <= retLast; ++k) codewords[ret + k] = 0; codewords[ret + retLast] = 1; length += start; for (ni = start; ni < length; ++ni) { // multiply by 10 for (k = retLast; k >= 0; --k) codewords[ret + k] *= 10; // add the digit codewords[ret + retLast] += text[ni] - '0'; // propagate carry for (k = retLast; k > 0; --k) { codewords[ret + k - 1] += codewords[ret + k] / 900; codewords[ret + k] %= 900; } } } protected void numberCompaction(int start, int length) { int full = (length / 44) * 15; int size = length % 44; int k; if (size == 0) size = full; else size = full + size / 3 + 1; if (size + cwPtr > MAX_DATA_CODEWORDS) { throw new IndexOutOfBoundsException("The text is too big."); } length += start; for (k = start; k < length; k += 44) { size = length - k < 44 ? length - k : 44; basicNumberCompaction(k, size); } } protected void byteCompaction6(int start) { int length = 6; int ret = cwPtr; int retLast = 4; int ni, k; cwPtr += retLast + 1; for (k = 0; k <= retLast ; ++k) codewords[ret + k] = 0; length += start; for (ni = start; ni < length; ++ni) { // multiply by 256 for (k = retLast; k >= 0; --k) codewords[ret + k] *= 256; // add the digit codewords[ret + retLast] += (int)text[ni] & 0xff; // propagate carry for (k = retLast; k > 0; --k) { codewords[ret + k - 1] += codewords[ret + k] / 900; codewords[ret + k] %= 900; } } } void byteCompaction(int start, int length) { int k, j; int size = (length / 6) * 5 + (length % 6); if (size + cwPtr > MAX_DATA_CODEWORDS) { throw new IndexOutOfBoundsException("The text is too big."); } length += start; for (k = start; k < length; k += 6) { size = length - k < 44 ? length - k : 6; if (size < 6) { for (j = 0; j < size; ++j) codewords[cwPtr++] = (int)text[k + j] & 0xff; } else { byteCompaction6(k); } } } void breakString() { int textLength = text.length; int lastP = 0; int startN = 0; int nd = 0; char c = 0; int k, ptrS, j; boolean lastTxt, txt; Segment v; Segment vp; Segment vn; for (k = 0; k < textLength; ++k) { c = (char)(text[k] & 0xff); if (c >= '0' && c <= '9') { if (nd == 0) startN = k; ++nd; continue; } if (nd >= 13) { if (lastP != startN) { c = (char)(text[lastP] & 0xff); ptrS = lastP; lastTxt = (c >= ' ' && c < 127) || c == '\r' || c == '\n' || c == '\t'; for (j = lastP; j < startN; ++j) { c = (char)(text[j] & 0xff); txt = (c >= ' ' && c < 127) || c == '\r' || c == '\n' || c == '\t'; if (txt != lastTxt) { segmentList.add(lastTxt ? 'T' : 'B', lastP, j); lastP = j; lastTxt = txt; } } segmentList.add(lastTxt ? 'T' : 'B', lastP, startN); } segmentList.add('N', startN, k); lastP = k; } nd = 0; } if (nd < 13) startN = textLength; if (lastP != startN) { c = (char)(text[lastP] & 0xff); ptrS = lastP; lastTxt = (c >= ' ' && c < 127) || c == '\r' || c == '\n' || c == '\t'; for (j = lastP; j < startN; ++j) { c = (char)(text[j] & 0xff); txt = (c >= ' ' && c < 127) || c == '\r' || c == '\n' || c == '\t'; if (txt != lastTxt) { segmentList.add(lastTxt ? 'T' : 'B', lastP, j); lastP = j; lastTxt = txt; } } segmentList.add(lastTxt ? 'T' : 'B', lastP, startN); } if (nd >= 13) segmentList.add('N', startN, textLength); //optimize //merge short binary for (k = 0; k < segmentList.size(); ++k) { v = segmentList.get(k); vp = segmentList.get(k - 1); vn = segmentList.get(k + 1);; if (checkSegmentType(v, 'B') && getSegmentLength(v) == 1) { if (checkSegmentType(vp, 'T') && checkSegmentType(vn, 'T') && getSegmentLength(vp) + getSegmentLength(vn) >= 3) { vp.end = vn.end; segmentList.remove(k); segmentList.remove(k); k = -1; continue; } } } //merge text sections for (k = 0; k < segmentList.size(); ++k) { v = segmentList.get(k); vp = segmentList.get(k - 1); vn = segmentList.get(k + 1);; if (checkSegmentType(v, 'T') && getSegmentLength(v) >= 5) { boolean redo = false; if ((checkSegmentType(vp, 'B') && getSegmentLength(vp) == 1) || checkSegmentType(vp, 'T')) { redo = true; v.start = vp.start; segmentList.remove(k - 1); --k; } if ((checkSegmentType(vn, 'B') && getSegmentLength(vn) == 1) || checkSegmentType(vn, 'T')) { redo = true; v.end = vn.end; segmentList.remove(k + 1); } if (redo) { k = -1; continue; } } } //merge binary sections for (k = 0; k < segmentList.size(); ++k) { v = segmentList.get(k); vp = segmentList.get(k - 1); vn = segmentList.get(k + 1);; if (checkSegmentType(v, 'B')) { boolean redo = false; if ((checkSegmentType(vp, 'T') && getSegmentLength(vp) < 5) || checkSegmentType(vp, 'B')) { redo = true; v.start = vp.start; segmentList.remove(k - 1); --k; } if ((checkSegmentType(vn, 'T') && getSegmentLength(vn) < 5) || checkSegmentType(vn, 'B')) { redo = true; v.end = vn.end; segmentList.remove(k + 1); } if (redo) { k = -1; continue; } } } // check if all numbers if (segmentList.size() == 1 && (v = segmentList.get(0)).type == 'T' && getSegmentLength(v) >= 8) { for (k = v.start; k < v.end; ++k) { c = (char)(text[k] & 0xff); if (c < '0' || c > '9') break; } if (k == v.end) v.type = 'N'; } } protected void assemble() { int k; if (segmentList.size() == 0) return; cwPtr = 1; for (k = 0; k < segmentList.size(); ++k) { Segment v = segmentList.get(k); switch (v.type) { case 'T': if (k != 0) codewords[cwPtr++] = TEXT_MODE; textCompaction(v.start, getSegmentLength(v)); break; case 'N': codewords[cwPtr++] = NUMERIC_MODE; numberCompaction(v.start, getSegmentLength(v)); break; case 'B': codewords[cwPtr++] = (getSegmentLength(v) % 6) != 0 ? BYTE_MODE : BYTE_MODE_6; byteCompaction(v.start, getSegmentLength(v)); break; } } } protected static int maxPossibleErrorLevel(int remain) { int level = 8; int size = 512; while (level > 0) { if (remain >= size) return level; --level; size >>= 1; } return 0; } protected void dumpList() { if (segmentList.size() == 0) return; for (int k = 0; k < segmentList.size(); ++k) { Segment v = segmentList.get(k); int len = getSegmentLength(v); char c[] = new char[len]; for (int j = 0; j < len; ++j) { c[j] = (char)(text[v.start + j] & 0xff); if (c[j] == '\r') c[j] = '\n'; } System.out.println("" + v.type + new String(c)); } } protected int getMaxSquare() { if (codeColumns > 21) { codeColumns = 29; codeRows = 32; } else { codeColumns = 16; codeRows = 58; } return MAX_DATA_CODEWORDS + 2; } /** Paints the barcode. If no exception was thrown a valid barcode is available. */ public void paintCode() { int maxErr, lenErr, tot, pad; if ((options & PDF417_USE_RAW_CODEWORDS) != 0) { if (lenCodewords > MAX_DATA_CODEWORDS || lenCodewords < 1 || lenCodewords != codewords[0]) { throw new IllegalArgumentException("Invalid codeword size."); } } else { if (text == null) throw new NullPointerException("Text cannot be null."); if (text.length > ABSOLUTE_MAX_TEXT_SIZE) { throw new IndexOutOfBoundsException("The text is too big."); } segmentList = new SegmentList(); breakString(); //dumpList(); assemble(); segmentList = null; codewords[0] = lenCodewords = cwPtr; } maxErr = maxPossibleErrorLevel(MAX_DATA_CODEWORDS + 2 - lenCodewords); if ((options & PDF417_USE_ERROR_LEVEL) == 0) { if (lenCodewords < 41) errorLevel = 2; else if (lenCodewords < 161) errorLevel = 3; else if (lenCodewords < 321) errorLevel = 4; else errorLevel = 5; } if (errorLevel < 0) errorLevel = 0; else if (errorLevel > maxErr) errorLevel = maxErr; if (codeColumns < 1) codeColumns = 1; else if (codeColumns > 30) codeColumns = 30; if (codeRows < 3) codeRows = 3; else if (codeRows > 90) codeRows = 90; lenErr = 2 << errorLevel; boolean fixedColumn = (options & PDF417_FIXED_ROWS) == 0; boolean skipRowColAdjust = false; tot = lenCodewords + lenErr; if ((options & PDF417_FIXED_RECTANGLE) != 0) { tot = codeColumns * codeRows; if (tot > MAX_DATA_CODEWORDS + 2) { tot = getMaxSquare(); } if (tot < lenCodewords + lenErr) tot = lenCodewords + lenErr; else skipRowColAdjust = true; } else if ((options & (PDF417_FIXED_COLUMNS | PDF417_FIXED_ROWS)) == 0) { double c, b; fixedColumn = true; if (aspectRatio < 0.001) aspectRatio = 0.001f; else if (aspectRatio > 1000) aspectRatio = 1000; b = 73 * aspectRatio - 4; c = (-b + Math.sqrt(b * b + 4 * 17 * aspectRatio * (lenCodewords + lenErr) * yHeight)) / (2 * 17 * aspectRatio); codeColumns = (int)(c + 0.5); if (codeColumns < 1) codeColumns = 1; else if (codeColumns > 30) codeColumns = 30; } if (!skipRowColAdjust) { if (fixedColumn) { codeRows = (tot - 1) / codeColumns + 1; if (codeRows < 3) codeRows = 3; else if (codeRows > 90) { codeRows = 90; codeColumns = (tot - 1) / 90 + 1; } } else { codeColumns = (tot - 1) / codeRows + 1; if (codeColumns > 30) { codeColumns = 30; codeRows = (tot - 1) / 30 + 1; } } tot = codeRows * codeColumns; } if (tot > MAX_DATA_CODEWORDS + 2) { tot = getMaxSquare(); } errorLevel = maxPossibleErrorLevel(tot - lenCodewords); lenErr = 2 << errorLevel; pad = tot - lenErr - lenCodewords; cwPtr = lenCodewords; while (pad-- != 0) codewords[cwPtr++] = TEXT_MODE; codewords[0] = lenCodewords = cwPtr; calculateErrorCorrection(lenCodewords); lenCodewords = tot; outPaintCode(); } /** Gets the raw image bits of the barcode. The image will have to * be scaled in the Y direction by yHeight. * @return The raw barcode image */ public byte[] getOutBits() { return this.outBits; } /** Gets the number of X pixels of outBits. * @return the number of X pixels of outBits */ public int getBitColumns() { return this.bitColumns; } /** Gets the number of Y pixels of outBits. * It is also the number of rows in the barcode. * @return the number of Y pixels of outBits */ public int getCodeRows() { return this.codeRows; } /** Sets the number of barcode rows. This number may be changed * to keep the barcode valid. * @param codeRows the number of barcode rows */ public void setCodeRows(int codeRows) { this.codeRows = codeRows; } /** Gets the number of barcode data columns. * @return he number of barcode data columns */ public int getCodeColumns() { return this.codeColumns; } /** Sets the number of barcode data columns. * This number may be changed to keep the barcode valid. * @param codeColumns the number of barcode data columns */ public void setCodeColumns(int codeColumns) { this.codeColumns = codeColumns; } /** Gets the codeword array. This array is always 928 elements long. * It can be writen to if the option PDF417_USE_RAW_CODEWORDS * is set. * @return the codeword array */ public int[] getCodewords() { return this.codewords; } /** Gets the length of the codewords. * @return the length of the codewords */ public int getLenCodewords() { return this.lenCodewords; } /** Sets the length of the codewords. * @param lenCodewords the length of the codewords */ public void setLenCodewords(int lenCodewords) { this.lenCodewords = lenCodewords; } /** Gets the error level correction used for the barcode. It may different * from the previously set value. * @return the error level correction used for the barcode */ public int getErrorLevel() { return this.errorLevel; } /** Sets the error level correction for the barcode. * @param errorLevel the error level correction for the barcode */ public void setErrorLevel(int errorLevel) { this.errorLevel = errorLevel; } /** Gets the bytes that form the barcode. This bytes should * be interpreted in the codepage Cp437. * @return the bytes that form the barcode */ public byte[] getText() { return this.text; } /** Sets the bytes that form the barcode. This bytes should * be interpreted in the codepage Cp437. * @param text the bytes that form the barcode */ public void setText(byte[] text) { this.text = text; } /** Sets the text that will form the barcode. This text is converted * to bytes using the encoding Cp437. * @param s the text that will form the barcode * @throws UnsupportedEncodingException if the encoding Cp437 is not supported */ public void setText(String s) throws UnsupportedEncodingException { this.text = s.getBytes("Cp437"); } /** Gets the options to generate the barcode. * @return the options to generate the barcode */ public int getOptions() { return this.options; } /** Sets the options to generate the barcode. This can be all * the PDF417_* constants. * @param options the options to generate the barcode */ public void setOptions(int options) { this.options = options; } /** Gets the barcode aspect ratio. * @return the barcode aspect ratio */ public float getAspectRatio() { return this.aspectRatio; } /** Sets the barcode aspect ratio. A ratio or 0.5 will make the * barcode width twice as large as the height. * @param aspectRatio the barcode aspect ratio */ public void setAspectRatio(float aspectRatio) { this.aspectRatio = aspectRatio; } /** Gets the Y pixel height relative to X. * @return the Y pixel height relative to X */ public float getYHeight() { return this.yHeight; } /** Sets the Y pixel height relative to X. It is usually 3. * @param yHeight the Y pixel height relative to X */ public void setYHeight(float yHeight) { this.yHeight = yHeight; } protected static final int START_PATTERN = 0x1fea8; protected static final int STOP_PATTERN = 0x3fa29; protected static final int START_CODE_SIZE = 17; protected static final int STOP_SIZE = 18; protected static final int MOD = 929; protected static final int ALPHA = 0x10000; protected static final int LOWER = 0x20000; protected static final int MIXED = 0x40000; protected static final int PUNCTUATION = 0x80000; protected static final int ISBYTE = 0x100000; protected static final int BYTESHIFT = 913; protected static final int PL = 25; protected static final int LL = 27; protected static final int AS = 27; protected static final int ML = 28; protected static final int AL = 28; protected static final int PS = 29; protected static final int PAL = 29; protected static final int SPACE = 26; protected static final int TEXT_MODE = 900; protected static final int BYTE_MODE_6 = 924; protected static final int BYTE_MODE = 901; protected static final int NUMERIC_MODE = 902; protected static final int ABSOLUTE_MAX_TEXT_SIZE = 5420; protected static final int MAX_DATA_CODEWORDS = 926; static String MIXED_SET = "0123456789&\r\t,:#-.$/+%*=^"; static String PUNCTUATION_SET = ";<>@[\\]_`~!\r\t,:\n-.$/\"|*()?{}'"; static int CLUSTERS[][] = {{ 0x1d5c0, 0x1eaf0, 0x1f57c, 0x1d4e0, 0x1ea78, 0x1f53e, 0x1a8c0, 0x1d470, 0x1a860, 0x15040, 0x1a830, 0x15020, 0x1adc0, 0x1d6f0, 0x1eb7c, 0x1ace0, 0x1d678, 0x1eb3e, 0x158c0, 0x1ac70, 0x15860, 0x15dc0, 0x1aef0, 0x1d77c, 0x15ce0, 0x1ae78, 0x1d73e, 0x15c70, 0x1ae3c, 0x15ef0, 0x1af7c, 0x15e78, 0x1af3e, 0x15f7c, 0x1f5fa, 0x1d2e0, 0x1e978, 0x1f4be, 0x1a4c0, 0x1d270, 0x1e93c, 0x1a460, 0x1d238, 0x14840, 0x1a430, 0x1d21c, 0x14820, 0x1a418, 0x14810, 0x1a6e0, 0x1d378, 0x1e9be, 0x14cc0, 0x1a670, 0x1d33c, 0x14c60, 0x1a638, 0x1d31e, 0x14c30, 0x1a61c, 0x14ee0, 0x1a778, 0x1d3be, 0x14e70, 0x1a73c, 0x14e38, 0x1a71e, 0x14f78, 0x1a7be, 0x14f3c, 0x14f1e, 0x1a2c0, 0x1d170, 0x1e8bc, 0x1a260, 0x1d138, 0x1e89e, 0x14440, 0x1a230, 0x1d11c, 0x14420, 0x1a218, 0x14410, 0x14408, 0x146c0, 0x1a370, 0x1d1bc, 0x14660, 0x1a338, 0x1d19e, 0x14630, 0x1a31c, 0x14618, 0x1460c, 0x14770, 0x1a3bc, 0x14738, 0x1a39e, 0x1471c, 0x147bc, 0x1a160, 0x1d0b8, 0x1e85e, 0x14240, 0x1a130, 0x1d09c, 0x14220, 0x1a118, 0x1d08e, 0x14210, 0x1a10c, 0x14208, 0x1a106, 0x14360, 0x1a1b8, 0x1d0de, 0x14330, 0x1a19c, 0x14318, 0x1a18e, 0x1430c, 0x14306, 0x1a1de, 0x1438e, 0x14140, 0x1a0b0, 0x1d05c, 0x14120, 0x1a098, 0x1d04e, 0x14110, 0x1a08c, 0x14108, 0x1a086, 0x14104, 0x141b0, 0x14198, 0x1418c, 0x140a0, 0x1d02e, 0x1a04c, 0x1a046, 0x14082, 0x1cae0, 0x1e578, 0x1f2be, 0x194c0, 0x1ca70, 0x1e53c, 0x19460, 0x1ca38, 0x1e51e, 0x12840, 0x19430, 0x12820, 0x196e0, 0x1cb78, 0x1e5be, 0x12cc0, 0x19670, 0x1cb3c, 0x12c60, 0x19638, 0x12c30, 0x12c18, 0x12ee0, 0x19778, 0x1cbbe, 0x12e70, 0x1973c, 0x12e38, 0x12e1c, 0x12f78, 0x197be, 0x12f3c, 0x12fbe, 0x1dac0, 0x1ed70, 0x1f6bc, 0x1da60, 0x1ed38, 0x1f69e, 0x1b440, 0x1da30, 0x1ed1c, 0x1b420, 0x1da18, 0x1ed0e, 0x1b410, 0x1da0c, 0x192c0, 0x1c970, 0x1e4bc, 0x1b6c0, 0x19260, 0x1c938, 0x1e49e, 0x1b660, 0x1db38, 0x1ed9e, 0x16c40, 0x12420, 0x19218, 0x1c90e, 0x16c20, 0x1b618, 0x16c10, 0x126c0, 0x19370, 0x1c9bc, 0x16ec0, 0x12660, 0x19338, 0x1c99e, 0x16e60, 0x1b738, 0x1db9e, 0x16e30, 0x12618, 0x16e18, 0x12770, 0x193bc, 0x16f70, 0x12738, 0x1939e, 0x16f38, 0x1b79e, 0x16f1c, 0x127bc, 0x16fbc, 0x1279e, 0x16f9e, 0x1d960, 0x1ecb8, 0x1f65e, 0x1b240, 0x1d930, 0x1ec9c, 0x1b220, 0x1d918, 0x1ec8e, 0x1b210, 0x1d90c, 0x1b208, 0x1b204, 0x19160, 0x1c8b8, 0x1e45e, 0x1b360, 0x19130, 0x1c89c, 0x16640, 0x12220, 0x1d99c, 0x1c88e, 0x16620, 0x12210, 0x1910c, 0x16610, 0x1b30c, 0x19106, 0x12204, 0x12360, 0x191b8, 0x1c8de, 0x16760, 0x12330, 0x1919c, 0x16730, 0x1b39c, 0x1918e, 0x16718, 0x1230c, 0x12306, 0x123b8, 0x191de, 0x167b8, 0x1239c, 0x1679c, 0x1238e, 0x1678e, 0x167de, 0x1b140, 0x1d8b0, 0x1ec5c, 0x1b120, 0x1d898, 0x1ec4e, 0x1b110, 0x1d88c, 0x1b108, 0x1d886, 0x1b104, 0x1b102, 0x12140, 0x190b0, 0x1c85c, 0x16340, 0x12120, 0x19098, 0x1c84e, 0x16320, 0x1b198, 0x1d8ce, 0x16310, 0x12108, 0x19086, 0x16308, 0x1b186, 0x16304, 0x121b0, 0x190dc, 0x163b0, 0x12198, 0x190ce, 0x16398, 0x1b1ce, 0x1638c, 0x12186, 0x16386, 0x163dc, 0x163ce, 0x1b0a0, 0x1d858, 0x1ec2e, 0x1b090, 0x1d84c, 0x1b088, 0x1d846, 0x1b084, 0x1b082, 0x120a0, 0x19058, 0x1c82e, 0x161a0, 0x12090, 0x1904c, 0x16190, 0x1b0cc, 0x19046, 0x16188, 0x12084, 0x16184, 0x12082, 0x120d8, 0x161d8, 0x161cc, 0x161c6, 0x1d82c, 0x1d826, 0x1b042, 0x1902c, 0x12048, 0x160c8, 0x160c4, 0x160c2, 0x18ac0, 0x1c570, 0x1e2bc, 0x18a60, 0x1c538, 0x11440, 0x18a30, 0x1c51c, 0x11420, 0x18a18, 0x11410, 0x11408, 0x116c0, 0x18b70, 0x1c5bc, 0x11660, 0x18b38, 0x1c59e, 0x11630, 0x18b1c, 0x11618, 0x1160c, 0x11770, 0x18bbc, 0x11738, 0x18b9e, 0x1171c, 0x117bc, 0x1179e, 0x1cd60, 0x1e6b8, 0x1f35e, 0x19a40, 0x1cd30, 0x1e69c, 0x19a20, 0x1cd18, 0x1e68e, 0x19a10, 0x1cd0c, 0x19a08, 0x1cd06, 0x18960, 0x1c4b8, 0x1e25e, 0x19b60, 0x18930, 0x1c49c, 0x13640, 0x11220, 0x1cd9c, 0x1c48e, 0x13620, 0x19b18, 0x1890c, 0x13610, 0x11208, 0x13608, 0x11360, 0x189b8, 0x1c4de, 0x13760, 0x11330, 0x1cdde, 0x13730, 0x19b9c, 0x1898e, 0x13718, 0x1130c, 0x1370c, 0x113b8, 0x189de, 0x137b8, 0x1139c, 0x1379c, 0x1138e, 0x113de, 0x137de, 0x1dd40, 0x1eeb0, 0x1f75c, 0x1dd20, 0x1ee98, 0x1f74e, 0x1dd10, 0x1ee8c, 0x1dd08, 0x1ee86, 0x1dd04, 0x19940, 0x1ccb0, 0x1e65c, 0x1bb40, 0x19920, 0x1eedc, 0x1e64e, 0x1bb20, 0x1dd98, 0x1eece, 0x1bb10, 0x19908, 0x1cc86, 0x1bb08, 0x1dd86, 0x19902, 0x11140, 0x188b0, 0x1c45c, 0x13340, 0x11120, 0x18898, 0x1c44e, 0x17740, 0x13320, 0x19998, 0x1ccce, 0x17720, 0x1bb98, 0x1ddce, 0x18886, 0x17710, 0x13308, 0x19986, 0x17708, 0x11102, 0x111b0, 0x188dc, 0x133b0, 0x11198, 0x188ce, 0x177b0, 0x13398, 0x199ce, 0x17798, 0x1bbce, 0x11186, 0x13386, 0x111dc, 0x133dc, 0x111ce, 0x177dc, 0x133ce, 0x1dca0, 0x1ee58, 0x1f72e, 0x1dc90, 0x1ee4c, 0x1dc88, 0x1ee46, 0x1dc84, 0x1dc82, 0x198a0, 0x1cc58, 0x1e62e, 0x1b9a0, 0x19890, 0x1ee6e, 0x1b990, 0x1dccc, 0x1cc46, 0x1b988, 0x19884, 0x1b984, 0x19882, 0x1b982, 0x110a0, 0x18858, 0x1c42e, 0x131a0, 0x11090, 0x1884c, 0x173a0, 0x13190, 0x198cc, 0x18846, 0x17390, 0x1b9cc, 0x11084, 0x17388, 0x13184, 0x11082, 0x13182, 0x110d8, 0x1886e, 0x131d8, 0x110cc, 0x173d8, 0x131cc, 0x110c6, 0x173cc, 0x131c6, 0x110ee, 0x173ee, 0x1dc50, 0x1ee2c, 0x1dc48, 0x1ee26, 0x1dc44, 0x1dc42, 0x19850, 0x1cc2c, 0x1b8d0, 0x19848, 0x1cc26, 0x1b8c8, 0x1dc66, 0x1b8c4, 0x19842, 0x1b8c2, 0x11050, 0x1882c, 0x130d0, 0x11048, 0x18826, 0x171d0, 0x130c8, 0x19866, 0x171c8, 0x1b8e6, 0x11042, 0x171c4, 0x130c2, 0x171c2, 0x130ec, 0x171ec, 0x171e6, 0x1ee16, 0x1dc22, 0x1cc16, 0x19824, 0x19822, 0x11028, 0x13068, 0x170e8, 0x11022, 0x13062, 0x18560, 0x10a40, 0x18530, 0x10a20, 0x18518, 0x1c28e, 0x10a10, 0x1850c, 0x10a08, 0x18506, 0x10b60, 0x185b8, 0x1c2de, 0x10b30, 0x1859c, 0x10b18, 0x1858e, 0x10b0c, 0x10b06, 0x10bb8, 0x185de, 0x10b9c, 0x10b8e, 0x10bde, 0x18d40, 0x1c6b0, 0x1e35c, 0x18d20, 0x1c698, 0x18d10, 0x1c68c, 0x18d08, 0x1c686, 0x18d04, 0x10940, 0x184b0, 0x1c25c, 0x11b40, 0x10920, 0x1c6dc, 0x1c24e, 0x11b20, 0x18d98, 0x1c6ce, 0x11b10, 0x10908, 0x18486, 0x11b08, 0x18d86, 0x10902, 0x109b0, 0x184dc, 0x11bb0, 0x10998, 0x184ce, 0x11b98, 0x18dce, 0x11b8c, 0x10986, 0x109dc, 0x11bdc, 0x109ce, 0x11bce, 0x1cea0, 0x1e758, 0x1f3ae, 0x1ce90, 0x1e74c, 0x1ce88, 0x1e746, 0x1ce84, 0x1ce82, 0x18ca0, 0x1c658, 0x19da0, 0x18c90, 0x1c64c, 0x19d90, 0x1cecc, 0x1c646, 0x19d88, 0x18c84, 0x19d84, 0x18c82, 0x19d82, 0x108a0, 0x18458, 0x119a0, 0x10890, 0x1c66e, 0x13ba0, 0x11990, 0x18ccc, 0x18446, 0x13b90, 0x19dcc, 0x10884, 0x13b88, 0x11984, 0x10882, 0x11982, 0x108d8, 0x1846e, 0x119d8, 0x108cc, 0x13bd8, 0x119cc, 0x108c6, 0x13bcc, 0x119c6, 0x108ee, 0x119ee, 0x13bee, 0x1ef50, 0x1f7ac, 0x1ef48, 0x1f7a6, 0x1ef44, 0x1ef42, 0x1ce50, 0x1e72c, 0x1ded0, 0x1ef6c, 0x1e726, 0x1dec8, 0x1ef66, 0x1dec4, 0x1ce42, 0x1dec2, 0x18c50, 0x1c62c, 0x19cd0, 0x18c48, 0x1c626, 0x1bdd0, 0x19cc8, 0x1ce66, 0x1bdc8, 0x1dee6, 0x18c42, 0x1bdc4, 0x19cc2, 0x1bdc2, 0x10850, 0x1842c, 0x118d0, 0x10848, 0x18426, 0x139d0, 0x118c8, 0x18c66, 0x17bd0, 0x139c8, 0x19ce6, 0x10842, 0x17bc8, 0x1bde6, 0x118c2, 0x17bc4, 0x1086c, 0x118ec, 0x10866, 0x139ec, 0x118e6, 0x17bec, 0x139e6, 0x17be6, 0x1ef28, 0x1f796, 0x1ef24, 0x1ef22, 0x1ce28, 0x1e716, 0x1de68, 0x1ef36, 0x1de64, 0x1ce22, 0x1de62, 0x18c28, 0x1c616, 0x19c68, 0x18c24, 0x1bce8, 0x19c64, 0x18c22, 0x1bce4, 0x19c62, 0x1bce2, 0x10828, 0x18416, 0x11868, 0x18c36, 0x138e8, 0x11864, 0x10822, 0x179e8, 0x138e4, 0x11862, 0x179e4, 0x138e2, 0x179e2, 0x11876, 0x179f6, 0x1ef12, 0x1de34, 0x1de32, 0x19c34, 0x1bc74, 0x1bc72, 0x11834, 0x13874, 0x178f4, 0x178f2, 0x10540, 0x10520, 0x18298, 0x10510, 0x10508, 0x10504, 0x105b0, 0x10598, 0x1058c, 0x10586, 0x105dc, 0x105ce, 0x186a0, 0x18690, 0x1c34c, 0x18688, 0x1c346, 0x18684, 0x18682, 0x104a0, 0x18258, 0x10da0, 0x186d8, 0x1824c, 0x10d90, 0x186cc, 0x10d88, 0x186c6, 0x10d84, 0x10482, 0x10d82, 0x104d8, 0x1826e, 0x10dd8, 0x186ee, 0x10dcc, 0x104c6, 0x10dc6, 0x104ee, 0x10dee, 0x1c750, 0x1c748, 0x1c744, 0x1c742, 0x18650, 0x18ed0, 0x1c76c, 0x1c326, 0x18ec8, 0x1c766, 0x18ec4, 0x18642, 0x18ec2, 0x10450, 0x10cd0, 0x10448, 0x18226, 0x11dd0, 0x10cc8, 0x10444, 0x11dc8, 0x10cc4, 0x10442, 0x11dc4, 0x10cc2, 0x1046c, 0x10cec, 0x10466, 0x11dec, 0x10ce6, 0x11de6, 0x1e7a8, 0x1e7a4, 0x1e7a2, 0x1c728, 0x1cf68, 0x1e7b6, 0x1cf64, 0x1c722, 0x1cf62, 0x18628, 0x1c316, 0x18e68, 0x1c736, 0x19ee8, 0x18e64, 0x18622, 0x19ee4, 0x18e62, 0x19ee2, 0x10428, 0x18216, 0x10c68, 0x18636, 0x11ce8, 0x10c64, 0x10422, 0x13de8, 0x11ce4, 0x10c62, 0x13de4, 0x11ce2, 0x10436, 0x10c76, 0x11cf6, 0x13df6, 0x1f7d4, 0x1f7d2, 0x1e794, 0x1efb4, 0x1e792, 0x1efb2, 0x1c714, 0x1cf34, 0x1c712, 0x1df74, 0x1cf32, 0x1df72, 0x18614, 0x18e34, 0x18612, 0x19e74, 0x18e32, 0x1bef4 }, { 0x1f560, 0x1fab8, 0x1ea40, 0x1f530, 0x1fa9c, 0x1ea20, 0x1f518, 0x1fa8e, 0x1ea10, 0x1f50c, 0x1ea08, 0x1f506, 0x1ea04, 0x1eb60, 0x1f5b8, 0x1fade, 0x1d640, 0x1eb30, 0x1f59c, 0x1d620, 0x1eb18, 0x1f58e, 0x1d610, 0x1eb0c, 0x1d608, 0x1eb06, 0x1d604, 0x1d760, 0x1ebb8, 0x1f5de, 0x1ae40, 0x1d730, 0x1eb9c, 0x1ae20, 0x1d718, 0x1eb8e, 0x1ae10, 0x1d70c, 0x1ae08, 0x1d706, 0x1ae04, 0x1af60, 0x1d7b8, 0x1ebde, 0x15e40, 0x1af30, 0x1d79c, 0x15e20, 0x1af18, 0x1d78e, 0x15e10, 0x1af0c, 0x15e08, 0x1af06, 0x15f60, 0x1afb8, 0x1d7de, 0x15f30, 0x1af9c, 0x15f18, 0x1af8e, 0x15f0c, 0x15fb8, 0x1afde, 0x15f9c, 0x15f8e, 0x1e940, 0x1f4b0, 0x1fa5c, 0x1e920, 0x1f498, 0x1fa4e, 0x1e910, 0x1f48c, 0x1e908, 0x1f486, 0x1e904, 0x1e902, 0x1d340, 0x1e9b0, 0x1f4dc, 0x1d320, 0x1e998, 0x1f4ce, 0x1d310, 0x1e98c, 0x1d308, 0x1e986, 0x1d304, 0x1d302, 0x1a740, 0x1d3b0, 0x1e9dc, 0x1a720, 0x1d398, 0x1e9ce, 0x1a710, 0x1d38c, 0x1a708, 0x1d386, 0x1a704, 0x1a702, 0x14f40, 0x1a7b0, 0x1d3dc, 0x14f20, 0x1a798, 0x1d3ce, 0x14f10, 0x1a78c, 0x14f08, 0x1a786, 0x14f04, 0x14fb0, 0x1a7dc, 0x14f98, 0x1a7ce, 0x14f8c, 0x14f86, 0x14fdc, 0x14fce, 0x1e8a0, 0x1f458, 0x1fa2e, 0x1e890, 0x1f44c, 0x1e888, 0x1f446, 0x1e884, 0x1e882, 0x1d1a0, 0x1e8d8, 0x1f46e, 0x1d190, 0x1e8cc, 0x1d188, 0x1e8c6, 0x1d184, 0x1d182, 0x1a3a0, 0x1d1d8, 0x1e8ee, 0x1a390, 0x1d1cc, 0x1a388, 0x1d1c6, 0x1a384, 0x1a382, 0x147a0, 0x1a3d8, 0x1d1ee, 0x14790, 0x1a3cc, 0x14788, 0x1a3c6, 0x14784, 0x14782, 0x147d8, 0x1a3ee, 0x147cc, 0x147c6, 0x147ee, 0x1e850, 0x1f42c, 0x1e848, 0x1f426, 0x1e844, 0x1e842, 0x1d0d0, 0x1e86c, 0x1d0c8, 0x1e866, 0x1d0c4, 0x1d0c2, 0x1a1d0, 0x1d0ec, 0x1a1c8, 0x1d0e6, 0x1a1c4, 0x1a1c2, 0x143d0, 0x1a1ec, 0x143c8, 0x1a1e6, 0x143c4, 0x143c2, 0x143ec, 0x143e6, 0x1e828, 0x1f416, 0x1e824, 0x1e822, 0x1d068, 0x1e836, 0x1d064, 0x1d062, 0x1a0e8, 0x1d076, 0x1a0e4, 0x1a0e2, 0x141e8, 0x1a0f6, 0x141e4, 0x141e2, 0x1e814, 0x1e812, 0x1d034, 0x1d032, 0x1a074, 0x1a072, 0x1e540, 0x1f2b0, 0x1f95c, 0x1e520, 0x1f298, 0x1f94e, 0x1e510, 0x1f28c, 0x1e508, 0x1f286, 0x1e504, 0x1e502, 0x1cb40, 0x1e5b0, 0x1f2dc, 0x1cb20, 0x1e598, 0x1f2ce, 0x1cb10, 0x1e58c, 0x1cb08, 0x1e586, 0x1cb04, 0x1cb02, 0x19740, 0x1cbb0, 0x1e5dc, 0x19720, 0x1cb98, 0x1e5ce, 0x19710, 0x1cb8c, 0x19708, 0x1cb86, 0x19704, 0x19702, 0x12f40, 0x197b0, 0x1cbdc, 0x12f20, 0x19798, 0x1cbce, 0x12f10, 0x1978c, 0x12f08, 0x19786, 0x12f04, 0x12fb0, 0x197dc, 0x12f98, 0x197ce, 0x12f8c, 0x12f86, 0x12fdc, 0x12fce, 0x1f6a0, 0x1fb58, 0x16bf0, 0x1f690, 0x1fb4c, 0x169f8, 0x1f688, 0x1fb46, 0x168fc, 0x1f684, 0x1f682, 0x1e4a0, 0x1f258, 0x1f92e, 0x1eda0, 0x1e490, 0x1fb6e, 0x1ed90, 0x1f6cc, 0x1f246, 0x1ed88, 0x1e484, 0x1ed84, 0x1e482, 0x1ed82, 0x1c9a0, 0x1e4d8, 0x1f26e, 0x1dba0, 0x1c990, 0x1e4cc, 0x1db90, 0x1edcc, 0x1e4c6, 0x1db88, 0x1c984, 0x1db84, 0x1c982, 0x1db82, 0x193a0, 0x1c9d8, 0x1e4ee, 0x1b7a0, 0x19390, 0x1c9cc, 0x1b790, 0x1dbcc, 0x1c9c6, 0x1b788, 0x19384, 0x1b784, 0x19382, 0x1b782, 0x127a0, 0x193d8, 0x1c9ee, 0x16fa0, 0x12790, 0x193cc, 0x16f90, 0x1b7cc, 0x193c6, 0x16f88, 0x12784, 0x16f84, 0x12782, 0x127d8, 0x193ee, 0x16fd8, 0x127cc, 0x16fcc, 0x127c6, 0x16fc6, 0x127ee, 0x1f650, 0x1fb2c, 0x165f8, 0x1f648, 0x1fb26, 0x164fc, 0x1f644, 0x1647e, 0x1f642, 0x1e450, 0x1f22c, 0x1ecd0, 0x1e448, 0x1f226, 0x1ecc8, 0x1f666, 0x1ecc4, 0x1e442, 0x1ecc2, 0x1c8d0, 0x1e46c, 0x1d9d0, 0x1c8c8, 0x1e466, 0x1d9c8, 0x1ece6, 0x1d9c4, 0x1c8c2, 0x1d9c2, 0x191d0, 0x1c8ec, 0x1b3d0, 0x191c8, 0x1c8e6, 0x1b3c8, 0x1d9e6, 0x1b3c4, 0x191c2, 0x1b3c2, 0x123d0, 0x191ec, 0x167d0, 0x123c8, 0x191e6, 0x167c8, 0x1b3e6, 0x167c4, 0x123c2, 0x167c2, 0x123ec, 0x167ec, 0x123e6, 0x167e6, 0x1f628, 0x1fb16, 0x162fc, 0x1f624, 0x1627e, 0x1f622, 0x1e428, 0x1f216, 0x1ec68, 0x1f636, 0x1ec64, 0x1e422, 0x1ec62, 0x1c868, 0x1e436, 0x1d8e8, 0x1c864, 0x1d8e4, 0x1c862, 0x1d8e2, 0x190e8, 0x1c876, 0x1b1e8, 0x1d8f6, 0x1b1e4, 0x190e2, 0x1b1e2, 0x121e8, 0x190f6, 0x163e8, 0x121e4, 0x163e4, 0x121e2, 0x163e2, 0x121f6, 0x163f6, 0x1f614, 0x1617e, 0x1f612, 0x1e414, 0x1ec34, 0x1e412, 0x1ec32, 0x1c834, 0x1d874, 0x1c832, 0x1d872, 0x19074, 0x1b0f4, 0x19072, 0x1b0f2, 0x120f4, 0x161f4, 0x120f2, 0x161f2, 0x1f60a, 0x1e40a, 0x1ec1a, 0x1c81a, 0x1d83a, 0x1903a, 0x1b07a, 0x1e2a0, 0x1f158, 0x1f8ae, 0x1e290, 0x1f14c, 0x1e288, 0x1f146, 0x1e284, 0x1e282, 0x1c5a0, 0x1e2d8, 0x1f16e, 0x1c590, 0x1e2cc, 0x1c588, 0x1e2c6, 0x1c584, 0x1c582, 0x18ba0, 0x1c5d8, 0x1e2ee, 0x18b90, 0x1c5cc, 0x18b88, 0x1c5c6, 0x18b84, 0x18b82, 0x117a0, 0x18bd8, 0x1c5ee, 0x11790, 0x18bcc, 0x11788, 0x18bc6, 0x11784, 0x11782, 0x117d8, 0x18bee, 0x117cc, 0x117c6, 0x117ee, 0x1f350, 0x1f9ac, 0x135f8, 0x1f348, 0x1f9a6, 0x134fc, 0x1f344, 0x1347e, 0x1f342, 0x1e250, 0x1f12c, 0x1e6d0, 0x1e248, 0x1f126, 0x1e6c8, 0x1f366, 0x1e6c4, 0x1e242, 0x1e6c2, 0x1c4d0, 0x1e26c, 0x1cdd0, 0x1c4c8, 0x1e266, 0x1cdc8, 0x1e6e6, 0x1cdc4, 0x1c4c2, 0x1cdc2, 0x189d0, 0x1c4ec, 0x19bd0, 0x189c8, 0x1c4e6, 0x19bc8, 0x1cde6, 0x19bc4, 0x189c2, 0x19bc2, 0x113d0, 0x189ec, 0x137d0, 0x113c8, 0x189e6, 0x137c8, 0x19be6, 0x137c4, 0x113c2, 0x137c2, 0x113ec, 0x137ec, 0x113e6, 0x137e6, 0x1fba8, 0x175f0, 0x1bafc, 0x1fba4, 0x174f8, 0x1ba7e, 0x1fba2, 0x1747c, 0x1743e, 0x1f328, 0x1f996, 0x132fc, 0x1f768, 0x1fbb6, 0x176fc, 0x1327e, 0x1f764, 0x1f322, 0x1767e, 0x1f762, 0x1e228, 0x1f116, 0x1e668, 0x1e224, 0x1eee8, 0x1f776, 0x1e222, 0x1eee4, 0x1e662, 0x1eee2, 0x1c468, 0x1e236, 0x1cce8, 0x1c464, 0x1dde8, 0x1cce4, 0x1c462, 0x1dde4, 0x1cce2, 0x1dde2, 0x188e8, 0x1c476, 0x199e8, 0x188e4, 0x1bbe8, 0x199e4, 0x188e2, 0x1bbe4, 0x199e2, 0x1bbe2, 0x111e8, 0x188f6, 0x133e8, 0x111e4, 0x177e8, 0x133e4, 0x111e2, 0x177e4, 0x133e2, 0x177e2, 0x111f6, 0x133f6, 0x1fb94, 0x172f8, 0x1b97e, 0x1fb92, 0x1727c, 0x1723e, 0x1f314, 0x1317e, 0x1f734, 0x1f312, 0x1737e, 0x1f732, 0x1e214, 0x1e634, 0x1e212, 0x1ee74, 0x1e632, 0x1ee72, 0x1c434, 0x1cc74, 0x1c432, 0x1dcf4, 0x1cc72, 0x1dcf2, 0x18874, 0x198f4, 0x18872, 0x1b9f4, 0x198f2, 0x1b9f2, 0x110f4, 0x131f4, 0x110f2, 0x173f4, 0x131f2, 0x173f2, 0x1fb8a, 0x1717c, 0x1713e, 0x1f30a, 0x1f71a, 0x1e20a, 0x1e61a, 0x1ee3a, 0x1c41a, 0x1cc3a, 0x1dc7a, 0x1883a, 0x1987a, 0x1b8fa, 0x1107a, 0x130fa, 0x171fa, 0x170be, 0x1e150, 0x1f0ac, 0x1e148, 0x1f0a6, 0x1e144, 0x1e142, 0x1c2d0, 0x1e16c, 0x1c2c8, 0x1e166, 0x1c2c4, 0x1c2c2, 0x185d0, 0x1c2ec, 0x185c8, 0x1c2e6, 0x185c4, 0x185c2, 0x10bd0, 0x185ec, 0x10bc8, 0x185e6, 0x10bc4, 0x10bc2, 0x10bec, 0x10be6, 0x1f1a8, 0x1f8d6, 0x11afc, 0x1f1a4, 0x11a7e, 0x1f1a2, 0x1e128, 0x1f096, 0x1e368, 0x1e124, 0x1e364, 0x1e122, 0x1e362, 0x1c268, 0x1e136, 0x1c6e8, 0x1c264, 0x1c6e4, 0x1c262, 0x1c6e2, 0x184e8, 0x1c276, 0x18de8, 0x184e4, 0x18de4, 0x184e2, 0x18de2, 0x109e8, 0x184f6, 0x11be8, 0x109e4, 0x11be4, 0x109e2, 0x11be2, 0x109f6, 0x11bf6, 0x1f9d4, 0x13af8, 0x19d7e, 0x1f9d2, 0x13a7c, 0x13a3e, 0x1f194, 0x1197e, 0x1f3b4, 0x1f192, 0x13b7e, 0x1f3b2, 0x1e114, 0x1e334, 0x1e112, 0x1e774, 0x1e332, 0x1e772, 0x1c234, 0x1c674, 0x1c232, 0x1cef4, 0x1c672, 0x1cef2, 0x18474, 0x18cf4, 0x18472, 0x19df4, 0x18cf2, 0x19df2, 0x108f4, 0x119f4, 0x108f2, 0x13bf4, 0x119f2, 0x13bf2, 0x17af0, 0x1bd7c, 0x17a78, 0x1bd3e, 0x17a3c, 0x17a1e, 0x1f9ca, 0x1397c, 0x1fbda, 0x17b7c, 0x1393e, 0x17b3e, 0x1f18a, 0x1f39a, 0x1f7ba, 0x1e10a, 0x1e31a, 0x1e73a, 0x1ef7a, 0x1c21a, 0x1c63a, 0x1ce7a, 0x1defa, 0x1843a, 0x18c7a, 0x19cfa, 0x1bdfa, 0x1087a, 0x118fa, 0x139fa, 0x17978, 0x1bcbe, 0x1793c, 0x1791e, 0x138be, 0x179be, 0x178bc, 0x1789e, 0x1785e, 0x1e0a8, 0x1e0a4, 0x1e0a2, 0x1c168, 0x1e0b6, 0x1c164, 0x1c162, 0x182e8, 0x1c176, 0x182e4, 0x182e2, 0x105e8, 0x182f6, 0x105e4, 0x105e2, 0x105f6, 0x1f0d4, 0x10d7e, 0x1f0d2, 0x1e094, 0x1e1b4, 0x1e092, 0x1e1b2, 0x1c134, 0x1c374, 0x1c132, 0x1c372, 0x18274, 0x186f4, 0x18272, 0x186f2, 0x104f4, 0x10df4, 0x104f2, 0x10df2, 0x1f8ea, 0x11d7c, 0x11d3e, 0x1f0ca, 0x1f1da, 0x1e08a, 0x1e19a, 0x1e3ba, 0x1c11a, 0x1c33a, 0x1c77a, 0x1823a, 0x1867a, 0x18efa, 0x1047a, 0x10cfa, 0x11dfa, 0x13d78, 0x19ebe, 0x13d3c, 0x13d1e, 0x11cbe, 0x13dbe, 0x17d70, 0x1bebc, 0x17d38, 0x1be9e, 0x17d1c, 0x17d0e, 0x13cbc, 0x17dbc, 0x13c9e, 0x17d9e, 0x17cb8, 0x1be5e, 0x17c9c, 0x17c8e, 0x13c5e, 0x17cde, 0x17c5c, 0x17c4e, 0x17c2e, 0x1c0b4, 0x1c0b2, 0x18174, 0x18172, 0x102f4, 0x102f2, 0x1e0da, 0x1c09a, 0x1c1ba, 0x1813a, 0x1837a, 0x1027a, 0x106fa, 0x10ebe, 0x11ebc, 0x11e9e, 0x13eb8, 0x19f5e, 0x13e9c, 0x13e8e, 0x11e5e, 0x13ede, 0x17eb0, 0x1bf5c, 0x17e98, 0x1bf4e, 0x17e8c, 0x17e86, 0x13e5c, 0x17edc, 0x13e4e, 0x17ece, 0x17e58, 0x1bf2e, 0x17e4c, 0x17e46, 0x13e2e, 0x17e6e, 0x17e2c, 0x17e26, 0x10f5e, 0x11f5c, 0x11f4e, 0x13f58, 0x19fae, 0x13f4c, 0x13f46, 0x11f2e, 0x13f6e, 0x13f2c, 0x13f26 }, { 0x1abe0, 0x1d5f8, 0x153c0, 0x1a9f0, 0x1d4fc, 0x151e0, 0x1a8f8, 0x1d47e, 0x150f0, 0x1a87c, 0x15078, 0x1fad0, 0x15be0, 0x1adf8, 0x1fac8, 0x159f0, 0x1acfc, 0x1fac4, 0x158f8, 0x1ac7e, 0x1fac2, 0x1587c, 0x1f5d0, 0x1faec, 0x15df8, 0x1f5c8, 0x1fae6, 0x15cfc, 0x1f5c4, 0x15c7e, 0x1f5c2, 0x1ebd0, 0x1f5ec, 0x1ebc8, 0x1f5e6, 0x1ebc4, 0x1ebc2, 0x1d7d0, 0x1ebec, 0x1d7c8, 0x1ebe6, 0x1d7c4, 0x1d7c2, 0x1afd0, 0x1d7ec, 0x1afc8, 0x1d7e6, 0x1afc4, 0x14bc0, 0x1a5f0, 0x1d2fc, 0x149e0, 0x1a4f8, 0x1d27e, 0x148f0, 0x1a47c, 0x14878, 0x1a43e, 0x1483c, 0x1fa68, 0x14df0, 0x1a6fc, 0x1fa64, 0x14cf8, 0x1a67e, 0x1fa62, 0x14c7c, 0x14c3e, 0x1f4e8, 0x1fa76, 0x14efc, 0x1f4e4, 0x14e7e, 0x1f4e2, 0x1e9e8, 0x1f4f6, 0x1e9e4, 0x1e9e2, 0x1d3e8, 0x1e9f6, 0x1d3e4, 0x1d3e2, 0x1a7e8, 0x1d3f6, 0x1a7e4, 0x1a7e2, 0x145e0, 0x1a2f8, 0x1d17e, 0x144f0, 0x1a27c, 0x14478, 0x1a23e, 0x1443c, 0x1441e, 0x1fa34, 0x146f8, 0x1a37e, 0x1fa32, 0x1467c, 0x1463e, 0x1f474, 0x1477e, 0x1f472, 0x1e8f4, 0x1e8f2, 0x1d1f4, 0x1d1f2, 0x1a3f4, 0x1a3f2, 0x142f0, 0x1a17c, 0x14278, 0x1a13e, 0x1423c, 0x1421e, 0x1fa1a, 0x1437c, 0x1433e, 0x1f43a, 0x1e87a, 0x1d0fa, 0x14178, 0x1a0be, 0x1413c, 0x1411e, 0x141be, 0x140bc, 0x1409e, 0x12bc0, 0x195f0, 0x1cafc, 0x129e0, 0x194f8, 0x1ca7e, 0x128f0, 0x1947c, 0x12878, 0x1943e, 0x1283c, 0x1f968, 0x12df0, 0x196fc, 0x1f964, 0x12cf8, 0x1967e, 0x1f962, 0x12c7c, 0x12c3e, 0x1f2e8, 0x1f976, 0x12efc, 0x1f2e4, 0x12e7e, 0x1f2e2, 0x1e5e8, 0x1f2f6, 0x1e5e4, 0x1e5e2, 0x1cbe8, 0x1e5f6, 0x1cbe4, 0x1cbe2, 0x197e8, 0x1cbf6, 0x197e4, 0x197e2, 0x1b5e0, 0x1daf8, 0x1ed7e, 0x169c0, 0x1b4f0, 0x1da7c, 0x168e0, 0x1b478, 0x1da3e, 0x16870, 0x1b43c, 0x16838, 0x1b41e, 0x1681c, 0x125e0, 0x192f8, 0x1c97e, 0x16de0, 0x124f0, 0x1927c, 0x16cf0, 0x1b67c, 0x1923e, 0x16c78, 0x1243c, 0x16c3c, 0x1241e, 0x16c1e, 0x1f934, 0x126f8, 0x1937e, 0x1fb74, 0x1f932, 0x16ef8, 0x1267c, 0x1fb72, 0x16e7c, 0x1263e, 0x16e3e, 0x1f274, 0x1277e, 0x1f6f4, 0x1f272, 0x16f7e, 0x1f6f2, 0x1e4f4, 0x1edf4, 0x1e4f2, 0x1edf2, 0x1c9f4, 0x1dbf4, 0x1c9f2, 0x1dbf2, 0x193f4, 0x193f2, 0x165c0, 0x1b2f0, 0x1d97c, 0x164e0, 0x1b278, 0x1d93e, 0x16470, 0x1b23c, 0x16438, 0x1b21e, 0x1641c, 0x1640e, 0x122f0, 0x1917c, 0x166f0, 0x12278, 0x1913e, 0x16678, 0x1b33e, 0x1663c, 0x1221e, 0x1661e, 0x1f91a, 0x1237c, 0x1fb3a, 0x1677c, 0x1233e, 0x1673e, 0x1f23a, 0x1f67a, 0x1e47a, 0x1ecfa, 0x1c8fa, 0x1d9fa, 0x191fa, 0x162e0, 0x1b178, 0x1d8be, 0x16270, 0x1b13c, 0x16238, 0x1b11e, 0x1621c, 0x1620e, 0x12178, 0x190be, 0x16378, 0x1213c, 0x1633c, 0x1211e, 0x1631e, 0x121be, 0x163be, 0x16170, 0x1b0bc, 0x16138, 0x1b09e, 0x1611c, 0x1610e, 0x120bc, 0x161bc, 0x1209e, 0x1619e, 0x160b8, 0x1b05e, 0x1609c, 0x1608e, 0x1205e, 0x160de, 0x1605c, 0x1604e, 0x115e0, 0x18af8, 0x1c57e, 0x114f0, 0x18a7c, 0x11478, 0x18a3e, 0x1143c, 0x1141e, 0x1f8b4, 0x116f8, 0x18b7e, 0x1f8b2, 0x1167c, 0x1163e, 0x1f174, 0x1177e, 0x1f172, 0x1e2f4, 0x1e2f2, 0x1c5f4, 0x1c5f2, 0x18bf4, 0x18bf2, 0x135c0, 0x19af0, 0x1cd7c, 0x134e0, 0x19a78, 0x1cd3e, 0x13470, 0x19a3c, 0x13438, 0x19a1e, 0x1341c, 0x1340e, 0x112f0, 0x1897c, 0x136f0, 0x11278, 0x1893e, 0x13678, 0x19b3e, 0x1363c, 0x1121e, 0x1361e, 0x1f89a, 0x1137c, 0x1f9ba, 0x1377c, 0x1133e, 0x1373e, 0x1f13a, 0x1f37a, 0x1e27a, 0x1e6fa, 0x1c4fa, 0x1cdfa, 0x189fa, 0x1bae0, 0x1dd78, 0x1eebe, 0x174c0, 0x1ba70, 0x1dd3c, 0x17460, 0x1ba38, 0x1dd1e, 0x17430, 0x1ba1c, 0x17418, 0x1ba0e, 0x1740c, 0x132e0, 0x19978, 0x1ccbe, 0x176e0, 0x13270, 0x1993c, 0x17670, 0x1bb3c, 0x1991e, 0x17638, 0x1321c, 0x1761c, 0x1320e, 0x1760e, 0x11178, 0x188be, 0x13378, 0x1113c, 0x17778, 0x1333c, 0x1111e, 0x1773c, 0x1331e, 0x1771e, 0x111be, 0x133be, 0x177be, 0x172c0, 0x1b970, 0x1dcbc, 0x17260, 0x1b938, 0x1dc9e, 0x17230, 0x1b91c, 0x17218, 0x1b90e, 0x1720c, 0x17206, 0x13170, 0x198bc, 0x17370, 0x13138, 0x1989e, 0x17338, 0x1b99e, 0x1731c, 0x1310e, 0x1730e, 0x110bc, 0x131bc, 0x1109e, 0x173bc, 0x1319e, 0x1739e, 0x17160, 0x1b8b8, 0x1dc5e, 0x17130, 0x1b89c, 0x17118, 0x1b88e, 0x1710c, 0x17106, 0x130b8, 0x1985e, 0x171b8, 0x1309c, 0x1719c, 0x1308e, 0x1718e, 0x1105e, 0x130de, 0x171de, 0x170b0, 0x1b85c, 0x17098, 0x1b84e, 0x1708c, 0x17086, 0x1305c, 0x170dc, 0x1304e, 0x170ce, 0x17058, 0x1b82e, 0x1704c, 0x17046, 0x1302e, 0x1706e, 0x1702c, 0x17026, 0x10af0, 0x1857c, 0x10a78, 0x1853e, 0x10a3c, 0x10a1e, 0x10b7c, 0x10b3e, 0x1f0ba, 0x1e17a, 0x1c2fa, 0x185fa, 0x11ae0, 0x18d78, 0x1c6be, 0x11a70, 0x18d3c, 0x11a38, 0x18d1e, 0x11a1c, 0x11a0e, 0x10978, 0x184be, 0x11b78, 0x1093c, 0x11b3c, 0x1091e, 0x11b1e, 0x109be, 0x11bbe, 0x13ac0, 0x19d70, 0x1cebc, 0x13a60, 0x19d38, 0x1ce9e, 0x13a30, 0x19d1c, 0x13a18, 0x19d0e, 0x13a0c, 0x13a06, 0x11970, 0x18cbc, 0x13b70, 0x11938, 0x18c9e, 0x13b38, 0x1191c, 0x13b1c, 0x1190e, 0x13b0e, 0x108bc, 0x119bc, 0x1089e, 0x13bbc, 0x1199e, 0x13b9e, 0x1bd60, 0x1deb8, 0x1ef5e, 0x17a40, 0x1bd30, 0x1de9c, 0x17a20, 0x1bd18, 0x1de8e, 0x17a10, 0x1bd0c, 0x17a08, 0x1bd06, 0x17a04, 0x13960, 0x19cb8, 0x1ce5e, 0x17b60, 0x13930, 0x19c9c, 0x17b30, 0x1bd9c, 0x19c8e, 0x17b18, 0x1390c, 0x17b0c, 0x13906, 0x17b06, 0x118b8, 0x18c5e, 0x139b8, 0x1189c, 0x17bb8, 0x1399c, 0x1188e, 0x17b9c, 0x1398e, 0x17b8e, 0x1085e, 0x118de, 0x139de, 0x17bde, 0x17940, 0x1bcb0, 0x1de5c, 0x17920, 0x1bc98, 0x1de4e, 0x17910, 0x1bc8c, 0x17908, 0x1bc86, 0x17904, 0x17902, 0x138b0, 0x19c5c, 0x179b0, 0x13898, 0x19c4e, 0x17998, 0x1bcce, 0x1798c, 0x13886, 0x17986, 0x1185c, 0x138dc, 0x1184e, 0x179dc, 0x138ce, 0x179ce, 0x178a0, 0x1bc58, 0x1de2e, 0x17890, 0x1bc4c, 0x17888, 0x1bc46, 0x17884, 0x17882, 0x13858, 0x19c2e, 0x178d8, 0x1384c, 0x178cc, 0x13846, 0x178c6, 0x1182e, 0x1386e, 0x178ee, 0x17850, 0x1bc2c, 0x17848, 0x1bc26, 0x17844, 0x17842, 0x1382c, 0x1786c, 0x13826, 0x17866, 0x17828, 0x1bc16, 0x17824, 0x17822, 0x13816, 0x17836, 0x10578, 0x182be, 0x1053c, 0x1051e, 0x105be, 0x10d70, 0x186bc, 0x10d38, 0x1869e, 0x10d1c, 0x10d0e, 0x104bc, 0x10dbc, 0x1049e, 0x10d9e, 0x11d60, 0x18eb8, 0x1c75e, 0x11d30, 0x18e9c, 0x11d18, 0x18e8e, 0x11d0c, 0x11d06, 0x10cb8, 0x1865e, 0x11db8, 0x10c9c, 0x11d9c, 0x10c8e, 0x11d8e, 0x1045e, 0x10cde, 0x11dde, 0x13d40, 0x19eb0, 0x1cf5c, 0x13d20, 0x19e98, 0x1cf4e, 0x13d10, 0x19e8c, 0x13d08, 0x19e86, 0x13d04, 0x13d02, 0x11cb0, 0x18e5c, 0x13db0, 0x11c98, 0x18e4e, 0x13d98, 0x19ece, 0x13d8c, 0x11c86, 0x13d86, 0x10c5c, 0x11cdc, 0x10c4e, 0x13ddc, 0x11cce, 0x13dce, 0x1bea0, 0x1df58, 0x1efae, 0x1be90, 0x1df4c, 0x1be88, 0x1df46, 0x1be84, 0x1be82, 0x13ca0, 0x19e58, 0x1cf2e, 0x17da0, 0x13c90, 0x19e4c, 0x17d90, 0x1becc, 0x19e46, 0x17d88, 0x13c84, 0x17d84, 0x13c82, 0x17d82, 0x11c58, 0x18e2e, 0x13cd8, 0x11c4c, 0x17dd8, 0x13ccc, 0x11c46, 0x17dcc, 0x13cc6, 0x17dc6, 0x10c2e, 0x11c6e, 0x13cee, 0x17dee, 0x1be50, 0x1df2c, 0x1be48, 0x1df26, 0x1be44, 0x1be42, 0x13c50, 0x19e2c, 0x17cd0, 0x13c48, 0x19e26, 0x17cc8, 0x1be66, 0x17cc4, 0x13c42, 0x17cc2, 0x11c2c, 0x13c6c, 0x11c26, 0x17cec, 0x13c66, 0x17ce6, 0x1be28, 0x1df16, 0x1be24, 0x1be22, 0x13c28, 0x19e16, 0x17c68, 0x13c24, 0x17c64, 0x13c22, 0x17c62, 0x11c16, 0x13c36, 0x17c76, 0x1be14, 0x1be12, 0x13c14, 0x17c34, 0x13c12, 0x17c32, 0x102bc, 0x1029e, 0x106b8, 0x1835e, 0x1069c, 0x1068e, 0x1025e, 0x106de, 0x10eb0, 0x1875c, 0x10e98, 0x1874e, 0x10e8c, 0x10e86, 0x1065c, 0x10edc, 0x1064e, 0x10ece, 0x11ea0, 0x18f58, 0x1c7ae, 0x11e90, 0x18f4c, 0x11e88, 0x18f46, 0x11e84, 0x11e82, 0x10e58, 0x1872e, 0x11ed8, 0x18f6e, 0x11ecc, 0x10e46, 0x11ec6, 0x1062e, 0x10e6e, 0x11eee, 0x19f50, 0x1cfac, 0x19f48, 0x1cfa6, 0x19f44, 0x19f42, 0x11e50, 0x18f2c, 0x13ed0, 0x19f6c, 0x18f26, 0x13ec8, 0x11e44, 0x13ec4, 0x11e42, 0x13ec2, 0x10e2c, 0x11e6c, 0x10e26, 0x13eec, 0x11e66, 0x13ee6, 0x1dfa8, 0x1efd6, 0x1dfa4, 0x1dfa2, 0x19f28, 0x1cf96, 0x1bf68, 0x19f24, 0x1bf64, 0x19f22, 0x1bf62, 0x11e28, 0x18f16, 0x13e68, 0x11e24, 0x17ee8, 0x13e64, 0x11e22, 0x17ee4, 0x13e62, 0x17ee2, 0x10e16, 0x11e36, 0x13e76, 0x17ef6, 0x1df94, 0x1df92, 0x19f14, 0x1bf34, 0x19f12, 0x1bf32, 0x11e14, 0x13e34, 0x11e12, 0x17e74, 0x13e32, 0x17e72, 0x1df8a, 0x19f0a, 0x1bf1a, 0x11e0a, 0x13e1a, 0x17e3a, 0x1035c, 0x1034e, 0x10758, 0x183ae, 0x1074c, 0x10746, 0x1032e, 0x1076e, 0x10f50, 0x187ac, 0x10f48, 0x187a6, 0x10f44, 0x10f42, 0x1072c, 0x10f6c, 0x10726, 0x10f66, 0x18fa8, 0x1c7d6, 0x18fa4, 0x18fa2, 0x10f28, 0x18796, 0x11f68, 0x18fb6, 0x11f64, 0x10f22, 0x11f62, 0x10716, 0x10f36, 0x11f76, 0x1cfd4, 0x1cfd2, 0x18f94, 0x19fb4, 0x18f92, 0x19fb2, 0x10f14, 0x11f34, 0x10f12, 0x13f74, 0x11f32, 0x13f72, 0x1cfca, 0x18f8a, 0x19f9a, 0x10f0a, 0x11f1a, 0x13f3a, 0x103ac, 0x103a6, 0x107a8, 0x183d6, 0x107a4, 0x107a2, 0x10396, 0x107b6, 0x187d4, 0x187d2, 0x10794, 0x10fb4, 0x10792, 0x10fb2, 0x1c7ea }}; static int ERROR_LEVEL[][] = {{ 27, 917 }, { 522, 568, 723, 809 }, { 237, 308, 436, 284, 646, 653, 428, 379 }, { 274, 562, 232, 755, 599, 524, 801, 132, 295, 116, 442, 428, 295, 42, 176, 65 }, { 361, 575, 922, 525, 176, 586, 640, 321, 536, 742, 677, 742, 687, 284, 193, 517, 273, 494, 263, 147, 593, 800, 571, 320, 803, 133, 231, 390, 685, 330, 63, 410 }, { 539, 422, 6, 93, 862, 771, 453, 106, 610, 287, 107, 505, 733, 877, 381, 612, 723, 476, 462, 172, 430, 609, 858, 822, 543, 376, 511, 400, 672, 762, 283, 184, 440, 35, 519, 31, 460, 594, 225, 535, 517, 352, 605, 158, 651, 201, 488, 502, 648, 733, 717, 83, 404, 97, 280, 771, 840, 629, 4, 381, 843, 623, 264, 543 }, { 521, 310, 864, 547, 858, 580, 296, 379, 53, 779, 897, 444, 400, 925, 749, 415, 822, 93, 217, 208, 928, 244, 583, 620, 246, 148, 447, 631, 292, 908, 490, 704, 516, 258, 457, 907, 594, 723, 674, 292, 272, 96, 684, 432, 686, 606, 860, 569, 193, 219, 129, 186, 236, 287, 192, 775, 278, 173, 40, 379, 712, 463, 646, 776, 171, 491, 297, 763, 156, 732, 95, 270, 447, 90, 507, 48, 228, 821, 808, 898, 784, 663, 627, 378, 382, 262, 380, 602, 754, 336, 89, 614, 87, 432, 670, 616, 157, 374, 242, 726, 600, 269, 375, 898, 845, 454, 354, 130, 814, 587, 804, 34, 211, 330, 539, 297, 827, 865, 37, 517, 834, 315, 550, 86, 801, 4, 108, 539 }, { 524, 894, 75, 766, 882, 857, 74, 204, 82, 586, 708, 250, 905, 786, 138, 720, 858, 194, 311, 913, 275, 190, 375, 850, 438, 733, 194, 280, 201, 280, 828, 757, 710, 814, 919, 89, 68, 569, 11, 204, 796, 605, 540, 913, 801, 700, 799, 137, 439, 418, 592, 668, 353, 859, 370, 694, 325, 240, 216, 257, 284, 549, 209, 884, 315, 70, 329, 793, 490, 274, 877, 162, 749, 812, 684, 461, 334, 376, 849, 521, 307, 291, 803, 712, 19, 358, 399, 908, 103, 511, 51, 8, 517, 225, 289, 470, 637, 731, 66, 255, 917, 269, 463, 830, 730, 433, 848, 585, 136, 538, 906, 90, 2, 290, 743, 199, 655, 903, 329, 49, 802, 580, 355, 588, 188, 462, 10, 134, 628, 320, 479, 130, 739, 71, 263, 318, 374, 601, 192, 605, 142, 673, 687, 234, 722, 384, 177, 752, 607, 640, 455, 193, 689, 707, 805, 641, 48, 60, 732, 621, 895, 544, 261, 852, 655, 309, 697, 755, 756, 60, 231, 773, 434, 421, 726, 528, 503, 118, 49, 795, 32, 144, 500, 238, 836, 394, 280, 566, 319, 9, 647, 550, 73, 914, 342, 126, 32, 681, 331, 792, 620, 60, 609, 441, 180, 791, 893, 754, 605, 383, 228, 749, 760, 213, 54, 297, 134, 54, 834, 299, 922, 191, 910, 532, 609, 829, 189, 20, 167, 29, 872, 449, 83, 402, 41, 656, 505, 579, 481, 173, 404, 251, 688, 95, 497, 555, 642, 543, 307, 159, 924, 558, 648, 55, 497, 10 }, { 352, 77, 373, 504, 35, 599, 428, 207, 409, 574, 118, 498, 285, 380, 350, 492, 197, 265, 920, 155, 914, 299, 229, 643, 294, 871, 306, 88, 87, 193, 352, 781, 846, 75, 327, 520, 435, 543, 203, 666, 249, 346, 781, 621, 640, 268, 794, 534, 539, 781, 408, 390, 644, 102, 476, 499, 290, 632, 545, 37, 858, 916, 552, 41, 542, 289, 122, 272, 383, 800, 485, 98, 752, 472, 761, 107, 784, 860, 658, 741, 290, 204, 681, 407, 855, 85, 99, 62, 482, 180, 20, 297, 451, 593, 913, 142, 808, 684, 287, 536, 561, 76, 653, 899, 729, 567, 744, 390, 513, 192, 516, 258, 240, 518, 794, 395, 768, 848, 51, 610, 384, 168, 190, 826, 328, 596, 786, 303, 570, 381, 415, 641, 156, 237, 151, 429, 531, 207, 676, 710, 89, 168, 304, 402, 40, 708, 575, 162, 864, 229, 65, 861, 841, 512, 164, 477, 221, 92, 358, 785, 288, 357, 850, 836, 827, 736, 707, 94, 8, 494, 114, 521, 2, 499, 851, 543, 152, 729, 771, 95, 248, 361, 578, 323, 856, 797, 289, 51, 684, 466, 533, 820, 669, 45, 902, 452, 167, 342, 244, 173, 35, 463, 651, 51, 699, 591, 452, 578, 37, 124, 298, 332, 552, 43, 427, 119, 662, 777, 475, 850, 764, 364, 578, 911, 283, 711, 472, 420, 245, 288, 594, 394, 511, 327, 589, 777, 699, 688, 43, 408, 842, 383, 721, 521, 560, 644, 714, 559, 62, 145, 873, 663, 713, 159, 672, 729, 624, 59, 193, 417, 158, 209, 563, 564, 343, 693, 109, 608, 563, 365, 181, 772, 677, 310, 248, 353, 708, 410, 579, 870, 617, 841, 632, 860, 289, 536, 35, 777, 618, 586, 424, 833, 77, 597, 346, 269, 757, 632, 695, 751, 331, 247, 184, 45, 787, 680, 18, 66, 407, 369, 54, 492, 228, 613, 830, 922, 437, 519, 644, 905, 789, 420, 305, 441, 207, 300, 892, 827, 141, 537, 381, 662, 513, 56, 252, 341, 242, 797, 838, 837, 720, 224, 307, 631, 61, 87, 560, 310, 756, 665, 397, 808, 851, 309, 473, 795, 378, 31, 647, 915, 459, 806, 590, 731, 425, 216, 548, 249, 321, 881, 699, 535, 673, 782, 210, 815, 905, 303, 843, 922, 281, 73, 469, 791, 660, 162, 498, 308, 155, 422, 907, 817, 187, 62, 16, 425, 535, 336, 286, 437, 375, 273, 610, 296, 183, 923, 116, 667, 751, 353, 62, 366, 691, 379, 687, 842, 37, 357, 720, 742, 330, 5, 39, 923, 311, 424, 242, 749, 321, 54, 669, 316, 342, 299, 534, 105, 667, 488, 640, 672, 576, 540, 316, 486, 721, 610, 46, 656, 447, 171, 616, 464, 190, 531, 297, 321, 762, 752, 533, 175, 134, 14, 381, 433, 717, 45, 111, 20, 596, 284, 736, 138, 646, 411, 877, 669, 141, 919, 45, 780, 407, 164, 332, 899, 165, 726, 600, 325, 498, 655, 357, 752, 768, 223, 849, 647, 63, 310, 863, 251, 366, 304, 282, 738, 675, 410, 389, 244, 31, 121, 303, 263 }}; /** Holds value of property outBits. */ private byte[] outBits; /** Holds value of property bitColumns. */ private int bitColumns; /** Holds value of property codeRows. */ private int codeRows; /** Holds value of property codeColumns. */ private int codeColumns; /** Holds value of property codewords. */ private int[] codewords = new int[MAX_DATA_CODEWORDS + 2]; /** Holds value of property lenCodewords. */ private int lenCodewords; /** Holds value of property errorLevel. */ private int errorLevel; /** Holds value of property text. */ private byte[] text; /** Holds value of property options. */ private int options; /** Holds value of property aspectRatio. */ private float aspectRatio; /** Holds value of property yHeight. */ private float yHeight; protected class Segment { public char type; public int start; public int end; public Segment(char type, int start, int end) { this.type = type; this.start = start; this.end = end; } } protected class SegmentList { protected ArrayList list = new ArrayList(); public void add(char type, int start, int end) { list.add(new Segment(type, start, end)); } public Segment get(int idx) { if (idx < 0 || idx >= list.size()) return null; return (Segment)list.get(idx); } public void remove(int idx) { if (idx < 0 || idx >= list.size()) return; list.remove(idx); } public int size() { return list.size(); } } public static void main(String[] args) { if (args.length < 2) { System.out.println("PDF417 barcode postscript generator"); System.out.println("Usage: java Pdf417lib postscript_file_name barcode_text"); return; } try { Pdf417lib pd = new Pdf417lib(); pd.setText(args[1]); pd.setOptions(Pdf417lib.PDF417_INVERT_BITMAP); pd.paintCode(); java.io.PrintWriter pr = new java.io.PrintWriter(new java.io.FileOutputStream(args[0])); int cols = (pd.getBitColumns() - 1) / 8 + 1; pr.println("/Times findfont\n12 scalefont setfont\n100 80 moveto\n(A PDF417 example.)show"); pr.println("stroke\n100 100 translate\n" + pd.getBitColumns()/2.0 + " " + pd.getCodeRows() * 3/2.0 + " scale"); pr.print(pd.getBitColumns() + " " + pd.getCodeRows() + " 1 [" + pd.getBitColumns() + " 0 0 " + (-pd.getCodeRows()) + " 0 " + pd.getCodeRows() + "]{<"); byte out[] = pd.getOutBits(); for (int k = 0; k < out.length; ++k) { if ((k % cols) == 0) pr.println(); pr.print(Integer.toHexString((out[k] & 0xff) | 0x100).substring(1).toUpperCase()); } pr.println("\n>}image\nshowpage"); pr.close(); } catch (Exception e) { e.printStackTrace(); } } }
for each module with the additional class "on" or "off". # # Example, let's say the barcode.encoding == ['101', '010'] : # # # # # # # # # # # # # # #
# # You could then style this with: # # table.barby-barcode { border-spacing: 0; } # tr.barby-row {} # td.barby-cell { width: 3px; height: 3px; } # td.barby-cell.on { background: #000; } # # Options: # # :class_name - A class name that will be added to the in addition to barby-barcode class HtmlOutputter < Outputter register :to_html attr_accessor :class_name def to_html(options = {}) with_options options do start + rows.join + stop end end def rows if barcode.two_dimensional? rows_for(booleans) else rows_for([booleans]) end end def rows_for(boolean_groups) boolean_groups.map{|g| row_for(cells_for(g)) } end def cells_for(booleans) booleans.map{|b| b ? on_cell : off_cell } end def row_for(cells) "#{cells.join}" end def on_cell '' end def off_cell '' end def start '
' end def stop '
' end end end barby-0.6.5/lib/barby/outputter/pdfwriter_outputter.rb000066400000000000000000000033301301765014400232270ustar00rootroot00000000000000require 'barby/outputter' module Barby #Annotates a PDFWriter document with the barcode # #Registers the annotate_pdf method class PDFWriterOutputter < Outputter register :annotate_pdf attr_accessor :x, :y, :height, :xdim #Annotate a PDFWriter document with the barcode # #Valid options are: # #x, y - The point in the document to start rendering from #height - The height of the bars in PDF units #xdim - The X dimension in PDF units def annotate_pdf(pdf, options={}) with_options options do xpos, ypos = x, y orig_xpos = xpos if barcode.two_dimensional? boolean_groups.reverse_each do |groups| groups.each do |bar,amount| if bar pdf.move_to(xpos, ypos). line_to(xpos, ypos+xdim). line_to(xpos+(xdim*amount), ypos+xdim). line_to(xpos+(xdim*amount), ypos). line_to(xpos, ypos). fill end xpos += (xdim*amount) end xpos = orig_xpos ypos += xdim end else boolean_groups.each do |bar,amount| if bar pdf.move_to(xpos, ypos). line_to(xpos, ypos+height). line_to(xpos+(xdim*amount), ypos+height). line_to(xpos+(xdim*amount), ypos). line_to(xpos, ypos). fill end xpos += (xdim*amount) end end end pdf end def x @x || 10 end def y @y || 10 end def height @height || 50 end def xdim @xdim || 1 end end end barby-0.6.5/lib/barby/outputter/png_outputter.rb000066400000000000000000000046461301765014400220200ustar00rootroot00000000000000require 'barby/outputter' require 'chunky_png' module Barby #Renders the barcode to a PNG image using chunky_png (gem install chunky_png) # #Registers the to_png, to_datastream and to_canvas methods class PngOutputter < Outputter register :to_png, :to_image, :to_datastream attr_writer :xdim, :ydim, :width, :height, :margin def initialize(*) super @xdim, @height, @margin = nil end #Creates a PNG::Canvas object and renders the barcode on it def to_image(opts={}) with_options opts do canvas = ChunkyPNG::Image.new(full_width, full_height, ChunkyPNG::Color::WHITE) if barcode.two_dimensional? x, y = margin, margin booleans.each do |line| line.each do |bar| if bar x.upto(x+(xdim-1)) do |xx| y.upto y+(ydim-1) do |yy| canvas[xx,yy] = ChunkyPNG::Color::BLACK end end end x += xdim end y += ydim x = margin end else x, y = margin, margin booleans.each do |bar| if bar x.upto(x+(xdim-1)) do |xx| y.upto y+(height-1) do |yy| canvas[xx,yy] = ChunkyPNG::Color::BLACK end end end x += xdim end end canvas end end #Create a ChunkyPNG::Datastream containing the barcode image # # :constraints - Value is passed on to ChunkyPNG::Image#to_datastream # E.g. to_datastream(:constraints => {:color_mode => ChunkyPNG::COLOR_GRAYSCALE}) def to_datastream(*a) constraints = a.first && a.first[:constraints] ? [a.first[:constraints]] : [] to_image(*a).to_datastream(*constraints) end #Renders the barcode to a PNG image def to_png(*a) to_datastream(*a).to_s end def width length * xdim end def height barcode.two_dimensional? ? (ydim * encoding.length) : (@height || 100) end def full_width width + (margin * 2) end def full_height height + (margin * 2) end def xdim @xdim || 1 end def ydim @ydim || xdim end def margin @margin || 10 end def length barcode.two_dimensional? ? encoding.first.length : encoding.length end end end barby-0.6.5/lib/barby/outputter/prawn_outputter.rb000066400000000000000000000054451301765014400223610ustar00rootroot00000000000000require 'barby/outputter' require 'prawn' module Barby class PrawnOutputter < Outputter register :to_pdf, :annotate_pdf attr_writer :xdim, :ydim, :x, :y, :height, :margin, :unbleed def initialize(*) super @xdim, @ydim, @x, @y, @height, @margin, @unbleed = nil end def to_pdf(opts={}) doc_opts = opts.delete(:document) || {} doc_opts[:page_size] ||= 'A4' annotate_pdf(Prawn::Document.new(doc_opts), opts).render end def annotate_pdf(pdf, opts={}) with_options opts do xpos, ypos = x, y orig_xpos = xpos if barcode.two_dimensional? boolean_groups.reverse_each do |groups| groups.each do |bar,amount| if bar pdf.move_to(xpos+unbleed, ypos+unbleed) pdf.line_to(xpos+unbleed, ypos+ydim-unbleed) pdf.line_to(xpos+(xdim*amount)-unbleed, ypos+ydim-unbleed) pdf.line_to(xpos+(xdim*amount)-unbleed, ypos+unbleed) pdf.line_to(xpos+unbleed, ypos+unbleed) pdf.fill end xpos += (xdim*amount) end xpos = orig_xpos ypos += ydim end else boolean_groups.each do |bar,amount| if bar pdf.move_to(xpos+unbleed, ypos) pdf.line_to(xpos+unbleed, ypos+height) pdf.line_to(xpos+(xdim*amount)-unbleed, ypos+height) pdf.line_to(xpos+(xdim*amount)-unbleed, ypos) pdf.line_to(xpos+unbleed, ypos) pdf.fill end xpos += (xdim*amount) end end end pdf end def length two_dimensional? ? encoding.first.length : encoding.length end def width length * xdim end def height two_dimensional? ? (ydim * encoding.length) : (@height || 50) end def full_width width + (margin * 2) end def full_height height + (margin * 2) end #Margin is used for x and y if not given explicitly, effectively placing the barcode # points from the [left,bottom] of the page. #If you define x and y, there will be no margin. And if you don't define margin, it's 0. def margin @margin || 0 end def x @x || margin end def y @y || margin end def xdim @xdim || 1 end def ydim @ydim || xdim end #Defines an amount to reduce black bars/squares by to account for "ink bleed" #If xdim = 3, unbleed = 0.2, a single/width black bar will be 2.6 wide #For 2D, both x and y dimensions are reduced. def unbleed @unbleed || 0 end private def page_size(xdim, height, margin) [width(xdim,margin), height(height,margin)] end end end barby-0.6.5/lib/barby/outputter/rmagick_outputter.rb000066400000000000000000000057631301765014400226520ustar00rootroot00000000000000require 'barby/outputter' require 'rmagick' module Barby #Renders images from barcodes using RMagick # #Registers the to_png, to_gif, to_jpg and to_image methods class RmagickOutputter < Outputter register :to_png, :to_gif, :to_jpg, :to_image attr_writer :height, :xdim, :ydim, :margin def initialize(*) super @height, @xdim, @ydim, @margin = nil end #Returns a string containing a PNG image def to_png(*a) to_blob('png', *a) end #Returns a string containint a GIF image def to_gif(*a) to_blob('gif', *a) end #Returns a string containing a JPEG image def to_jpg(*a) to_blob('jpg', *a) end def to_blob(format, *a) img = to_image(*a) blob = img.to_blob{|i| i.format = format } #Release the memory used by RMagick explicitly. Ruby's GC #isn't aware of it and can't clean it up automatically img.destroy! if img.respond_to?(:destroy!) blob end #Returns an instance of Magick::Image def to_image(opts={}) with_options opts do canvas = Magick::Image.new(full_width, full_height) bars = Magick::Draw.new x1 = margin y1 = margin if barcode.two_dimensional? encoding.each do |line| line.split(//).map{|c| c == '1' }.each do |bar| if bar x2 = x1+(xdim-1) y2 = y1+(ydim-1) # For single pixels use point if x1 == x2 && y1 == y2 bars.point(x1,y1) else bars.rectangle(x1, y1, x2, y2) end end x1 += xdim end x1 = margin y1 += ydim end else booleans.each do |bar| if bar x2 = x1+(xdim-1) y2 = y1+(height-1) bars.rectangle(x1, y1, x2, y2) end x1 += xdim end end bars.draw(canvas) canvas end end #The height of the barcode in px #For 2D barcodes this is the number of "lines" * ydim def height barcode.two_dimensional? ? (ydim * encoding.length) : (@height || 100) end #The width of the barcode in px def width length * xdim end #Number of modules (xdims) on the x axis def length barcode.two_dimensional? ? encoding.first.length : encoding.length end #X dimension. 1X == 1px def xdim @xdim || 1 end #Y dimension. Only for 2D codes def ydim @ydim || xdim end #The margin of each edge surrounding the barcode in pixels def margin @margin || 10 end #The full width of the image. This is the width of the #barcode + the left and right margin def full_width width + (margin * 2) end #The height of the image. This is the height of the #barcode + the top and bottom margin def full_height height + (margin * 2) end end end barby-0.6.5/lib/barby/outputter/svg_outputter.rb000066400000000000000000000117611301765014400220270ustar00rootroot00000000000000require 'barby/outputter' module Barby #Renders the barcode to a simple SVG image using pure ruby # #Registers the to_svg, bars_to_path, and bars_to_rects method # #Bars can be rendered as a stroked path or as filled rectangles. Path #generally yields smaller files, but this doesn't render cleanly in Firefox #3 for odd xdims. My guess is that the renderer tries to put half a pixel #on one side of the path and half on the other, leading to fuzzy dithering #instead of sharp, clean b&w. # #Therefore, default behavior is to use a path for even xdims, and #rectangles for odd. This can be overridden by calling with explicit #:use => 'rects' or :use => 'path' options. class SvgOutputter < Outputter register :to_svg, :bars_to_rects, :bars_to_path attr_writer :title, :xdim, :ydim, :height, :rmargin, :lmargin, :tmargin, :bmargin, :xmargin, :ymargin, :margin def initialize(*) super @title, @xdim, @ydim, @height, @rmargin, @lmargin, @tmargin, @bmargin, @xmargin, @ymargin, @margin = nil end def to_svg(opts={}) with_options opts do case opts[:use] when 'rects' then bars = bars_to_rects when 'path' then bars = bars_to_path else xdim_odd = (xdim % 2 == 1) bars = xdim_odd ? bars_to_rects : bars_to_path end <<-"EOT" #{escape title} #{bars} EOT end end def bars_to_rects(opts={}) rects = '' with_options opts do x, y = lmargin, tmargin if barcode.two_dimensional? boolean_groups.each do |line| line.each do |bar, amount| bar_width = xdim * amount if bar rects << %Q|\n| end x += bar_width end y += ydim x = lmargin end else boolean_groups.each do |bar, amount| bar_width = xdim * amount if bar rects << %Q|\n| end x += bar_width end end end # with_options rects end def bars_to_path(opts={}) with_options opts do %Q|| end end def bars_to_path_data(opts={}) path_data = '' with_options opts do x, y = lmargin+(xdim/2), tmargin if barcode.two_dimensional? booleans.each do |line| line.each do |bar| if bar path_data << "M#{x} #{y}V #{y+ydim}" end x += xdim end y += ydim x = lmargin+(xdim/2) end else booleans.each do |bar| if bar path_data << "M#{x} #{y}V#{y+height}" end x += xdim end end end # with_options path_data end def title @title || barcode.to_s end def width length * xdim end def height barcode.two_dimensional? ? (ydim * encoding.length) : (@height || 100) end def full_width width + lmargin + rmargin end def full_height height + tmargin + bmargin end def xdim @xdim || 1 end def ydim @ydim || xdim end def lmargin @lmargin || _xmargin end def rmargin @rmargin || _xmargin end def tmargin @tmargin || _ymargin end def bmargin @bmargin || _ymargin end def xmargin return nil if @lmargin || @rmargin _margin end def ymargin return nil if @tmargin || @bmargin _margin end def margin return nil if @ymargin || @xmargin || @tmargin || @bmargin || @lmargin || @rmargin _margin end def length barcode.two_dimensional? ? encoding.first.length : encoding.length end def svg_width(opts={}) opts[:rot] ? full_height : full_width end def svg_height(opts={}) opts[:rot] ? full_width : full_height end def transform(opts={}) opts[:rot] ? %Q|transform="rotate(-90) translate(-#{full_width}, 0)"| : nil end private def _xmargin @xmargin || _margin end def _ymargin @ymargin || _margin end def _margin @margin || 10 end #Escape XML special characters <, & and > def escape(str) str.gsub('&', '&').gsub('<', '<').gsub('>', '>') end end end barby-0.6.5/lib/barby/vendor.rb000066400000000000000000000001401301765014400163040ustar00rootroot00000000000000Dir["#{File.dirname(__FILE__)}/../../vendor/*/lib"].each do |d| $: << File.expand_path(d) end barby-0.6.5/lib/barby/version.rb000066400000000000000000000002211301765014400164740ustar00rootroot00000000000000module Barby #:nodoc: module VERSION #:nodoc: MAJOR = 0 MINOR = 6 TINY = 5 STRING = [MAJOR, MINOR, TINY].join('.') end end barby-0.6.5/test/000077500000000000000000000000001301765014400136015ustar00rootroot00000000000000barby-0.6.5/test/barcodes.rb000066400000000000000000000005141301765014400157100ustar00rootroot00000000000000require 'code_128_test' require 'code_25_test' require 'code_25_interleaved_test' require 'code_25_iata_test' require 'code_39_test' require 'code_93_test' require 'ean13_test' require 'ean8_test' require 'bookland_test' require 'upc_supplemental_test' require 'data_matrix_test' require 'qr_code_test' #require 'pdf_417_test' barby-0.6.5/test/bookland_test.rb000066400000000000000000000025131301765014400167570ustar00rootroot00000000000000require 'test_helper' require 'barby/barcode/bookland' class BooklandTest < Barby::TestCase before do # Gr Publ Tit Checksum @isbn = '96-8261-240-3' @code = Bookland.new(@isbn) end it "should have the expected data" do @code.data.must_equal '978968261240' end it "should have the expected numbers" do @code.numbers.must_equal [9,7,8,9,6,8,2,6,1,2,4,0] end it "should have the expected checksum" do @code.checksum.must_equal 4 end it "should raise an error when data not valid" do lambda{ Bookland.new('1234') }.must_raise ArgumentError end describe 'ISBN conversion' do it "should accept ISBN with number system and check digit" do code = Bookland.new('978-82-92526-14-9') assert code.valid? code.data.must_equal '978829252614' code = Bookland.new('979-82-92526-14-9') assert code.valid? code.data.must_equal '979829252614' end it "should accept ISBN without number system but with check digit" do code = Bookland.new('82-92526-14-9') assert code.valid? code.data.must_equal '978829252614' #978 is the default prefix end it "should accept ISBN without number system or check digit" do code = Bookland.new('82-92526-14') assert code.valid? code.data.must_equal '978829252614' end end end barby-0.6.5/test/code_128_test.rb000066400000000000000000000472411301765014400165010ustar00rootroot00000000000000# encoding: UTF-8 require 'test_helper' require 'barby/barcode/code_128' class Code128Test < Barby::TestCase %w[CODEA CODEB CODEC FNC1 FNC2 FNC3 FNC4 SHIFT].each do |const| const_set const, Code128.const_get(const) end before do @data = 'ABC123' @code = Code128A.new(@data) end it "should have the expected stop encoding (including termination bar 11)" do @code.send(:stop_encoding).must_equal '1100011101011' end it "should find the right class for a character A, B or C" do @code.send(:class_for, 'A').must_equal Code128A @code.send(:class_for, 'B').must_equal Code128B @code.send(:class_for, 'C').must_equal Code128C end it "should find the right change code for a class" do @code.send(:change_code_for_class, Code128A).must_equal Code128::CODEA @code.send(:change_code_for_class, Code128B).must_equal Code128::CODEB @code.send(:change_code_for_class, Code128C).must_equal Code128::CODEC end it "should not allow empty data" do lambda{ Code128B.new("") }.must_raise(ArgumentError) end describe "single encoding" do before do @data = 'ABC123' @code = Code128A.new(@data) end it "should have the same data as when initialized" do @code.data.must_equal @data end it "should be able to change its data" do @code.data = '123ABC' @code.data.must_equal '123ABC' @code.data.wont_equal @data end it "should not have an extra" do assert @code.extra.nil? end it "should have empty extra encoding" do @code.extra_encoding.must_equal '' end it "should have the correct checksum" do @code.checksum.must_equal 66 end it "should return all data for to_s" do @code.to_s.must_equal @data end end describe "multiple encodings" do before do @data = binary_encode("ABC123\306def\3074567") @code = Code128A.new(@data) end it "should be able to return full_data which includes the entire extra chain excluding charset change characters" do @code.full_data.must_equal "ABC123def4567" end it "should be able to return full_data_with_change_codes which includes the entire extra chain including charset change characters" do @code.full_data_with_change_codes.must_equal @data end it "should not matter if extras were added separately" do code = Code128B.new("ABC") code.extra = binary_encode("\3071234") code.full_data.must_equal "ABC1234" code.full_data_with_change_codes.must_equal binary_encode("ABC\3071234") code.extra.extra = binary_encode("\306abc") code.full_data.must_equal "ABC1234abc" code.full_data_with_change_codes.must_equal binary_encode("ABC\3071234\306abc") code.extra.extra.data = binary_encode("abc\305DEF") code.full_data.must_equal "ABC1234abcDEF" code.full_data_with_change_codes.must_equal binary_encode("ABC\3071234\306abc\305DEF") code.extra.extra.full_data.must_equal "abcDEF" code.extra.extra.full_data_with_change_codes.must_equal binary_encode("abc\305DEF") code.extra.full_data.must_equal "1234abcDEF" code.extra.full_data_with_change_codes.must_equal binary_encode("1234\306abc\305DEF") end it "should have a Code B extra" do @code.extra.must_be_instance_of(Code128B) end it "should have a valid extra" do assert @code.extra.valid? end it "the extra should also have an extra of type C" do @code.extra.extra.must_be_instance_of(Code128C) end it "the extra's extra should be valid" do assert @code.extra.extra.valid? end it "should not have more than two extras" do assert @code.extra.extra.extra.nil? end it "should split extra data from string on data assignment" do @code.data = binary_encode("123\306abc") @code.data.must_equal '123' @code.extra.must_be_instance_of(Code128B) @code.extra.data.must_equal 'abc' end it "should be be able to change its extra" do @code.extra = binary_encode("\3071234") @code.extra.must_be_instance_of(Code128C) @code.extra.data.must_equal '1234' end it "should split extra data from string on extra assignment" do @code.extra = binary_encode("\306123\3074567") @code.extra.must_be_instance_of(Code128B) @code.extra.data.must_equal '123' @code.extra.extra.must_be_instance_of(Code128C) @code.extra.extra.data.must_equal '4567' end it "should not fail on newlines in extras" do code = Code128B.new(binary_encode("ABC\305\n")) code.data.must_equal "ABC" code.extra.must_be_instance_of(Code128A) code.extra.data.must_equal "\n" code.extra.extra = binary_encode("\305\n\n\n\n\n\nVALID") code.extra.extra.data.must_equal "\n\n\n\n\n\nVALID" end it "should raise an exception when extra string doesn't start with the special code character" do lambda{ @code.extra = '123' }.must_raise ArgumentError end it "should have the correct checksum" do @code.checksum.must_equal 84 end it "should have the expected encoding" do #STARTA A B C 1 2 3 @code.encoding.must_equal '11010000100101000110001000101100010001000110100111001101100111001011001011100'+ #CODEB d e f '10111101110100001001101011001000010110000100'+ #CODEC 45 67 '101110111101011101100010000101100'+ #CHECK=84 STOP '100111101001100011101011' end it "should return all data including extras, except change codes for to_s" do @code.to_s.must_equal "ABC123def4567" end end describe "128A" do before do @data = 'ABC123' @code = Code128A.new(@data) end it "should be valid when given valid data" do assert @code.valid? end it "should not be valid when given invalid data" do @code.data = 'abc123' refute @code.valid? end it "should have the expected characters" do @code.characters.must_equal %w(A B C 1 2 3) end it "should have the expected start encoding" do @code.start_encoding.must_equal '11010000100' end it "should have the expected data encoding" do @code.data_encoding.must_equal '101000110001000101100010001000110100111001101100111001011001011100' end it "should have the expected encoding" do @code.encoding.must_equal '11010000100101000110001000101100010001000110100111001101100111001011001011100100100001101100011101011' end it "should have the expected checksum encoding" do @code.checksum_encoding.must_equal '10010000110' end end describe "128B" do before do @data = 'abc123' @code = Code128B.new(@data) end it "should be valid when given valid data" do assert @code.valid? end it "should not be valid when given invalid data" do @code.data = binary_encode("abc£123") refute @code.valid? end it "should have the expected characters" do @code.characters.must_equal %w(a b c 1 2 3) end it "should have the expected start encoding" do @code.start_encoding.must_equal '11010010000' end it "should have the expected data encoding" do @code.data_encoding.must_equal '100101100001001000011010000101100100111001101100111001011001011100' end it "should have the expected encoding" do @code.encoding.must_equal '11010010000100101100001001000011010000101100100111001101100111001011001011100110111011101100011101011' end it "should have the expected checksum encoding" do @code.checksum_encoding.must_equal '11011101110' end end describe "128C" do before do @data = '123456' @code = Code128C.new(@data) end it "should be valid when given valid data" do assert @code.valid? end it "should not be valid when given invalid data" do @code.data = '123' refute @code.valid? @code.data = 'abc' refute @code.valid? end it "should have the expected characters" do @code.characters.must_equal %w(12 34 56) end it "should have the expected start encoding" do @code.start_encoding.must_equal '11010011100' end it "should have the expected data encoding" do @code.data_encoding.must_equal '101100111001000101100011100010110' end it "should have the expected encoding" do @code.encoding.must_equal '11010011100101100111001000101100011100010110100011011101100011101011' end it "should have the expected checksum encoding" do @code.checksum_encoding.must_equal '10001101110' end end describe "Function characters" do it "should retain the special symbols in the data accessor" do Code128A.new(binary_encode("\301ABC\301DEF")).data.must_equal binary_encode("\301ABC\301DEF") Code128B.new(binary_encode("\301ABC\302DEF")).data.must_equal binary_encode("\301ABC\302DEF") Code128C.new(binary_encode("\301123456")).data.must_equal binary_encode("\301123456") Code128C.new(binary_encode("12\30134\30156")).data.must_equal binary_encode("12\30134\30156") end it "should keep the special symbols as characters" do Code128A.new(binary_encode("\301ABC\301DEF")).characters.must_equal binary_encode_array(%W(\301 A B C \301 D E F)) Code128B.new(binary_encode("\301ABC\302DEF")).characters.must_equal binary_encode_array(%W(\301 A B C \302 D E F)) Code128C.new(binary_encode("\301123456")).characters.must_equal binary_encode_array(%W(\301 12 34 56)) Code128C.new(binary_encode("12\30134\30156")).characters.must_equal binary_encode_array(%W(12 \301 34 \301 56)) end it "should not allow FNC > 1 for Code C" do lambda{ Code128C.new("12\302") }.must_raise ArgumentError lambda{ Code128C.new("\30312") }.must_raise ArgumentError lambda{ Code128C.new("12\304") }.must_raise ArgumentError end it "should be included in the encoding" do a = Code128A.new(binary_encode("\301AB")) a.data_encoding.must_equal '111101011101010001100010001011000' a.encoding.must_equal '11010000100111101011101010001100010001011000101000011001100011101011' end end describe "Code128 with type" do #it "should raise an exception when not given a type" do # lambda{ Code128.new('abc') }.must_raise(ArgumentError) #end it "should raise an exception when given a non-existent type" do lambda{ Code128.new('abc', 'F') }.must_raise(ArgumentError) end it "should not fail on frozen type" do Code128.new('123456', 'C'.freeze) # not failing Code128.new('123456', 'c'.freeze) # not failing even when upcasing end it "should give the right encoding for type A" do code = Code128.new('ABC123', 'A') code.encoding.must_equal '11010000100101000110001000101100010001000110100111001101100111001011001011100100100001101100011101011' end it "should give the right encoding for type B" do code = Code128.new('abc123', 'B') code.encoding.must_equal '11010010000100101100001001000011010000101100100111001101100111001011001011100110111011101100011101011' end it "should give the right encoding for type B" do code = Code128.new('123456', 'C') code.encoding.must_equal '11010011100101100111001000101100011100010110100011011101100011101011' end end describe "Code128 automatic charset" do =begin 5.4.7.7. Use of Start, Code Set, and Shift Characters to Minimize Symbol Length (Informative) The same data may be represented by different GS1-128 barcodes through the use of different combinations of Start, code set, and shift characters. The following rules should normally be implemented in printer control software to minimise the number of symbol characters needed to represent a given data string (and, therefore, reduce the overall symbol length). * Determine the Start Character: - If the data consists of two digits, use Start Character C. - If the data begins with four or more numeric data characters, use Start Character C. - If an ASCII symbology element (e.g., NUL) occurs in the data before any lowercase character, use Start Character A. - Otherwise, use Start Character B. * If Start Character C is used and the data begins with an odd number of numeric data characters, insert a code set A or code set B character before the last digit, following rules 1c and 1d to determine between code sets A and B. * If four or more numeric data characters occur together when in code sets A or B and: - If there is an even number of numeric data characters, then insert a code set C character before the first numeric digit to change to code set C. - If there is an odd number of numeric data characters, then insert a code set C character immediately after the first numeric digit to change to code set C. * When in code set B and an ASCII symbology element occurs in the data: - If following that character, a lowercase character occurs in the data before the occurrence of another symbology element, then insert a shift character before the symbology element. - Otherwise, insert a code set A character before the symbology element to change to code set A. * When in code set A and a lowercase character occurs in the data: - If following that character, a symbology element occurs in the data before the occurrence of another lowercase character, then insert a shift character before the lowercase character. - Otherwise, insert a code set B character before the lowercase character to change to code set B. When in code set C and a non-numeric character occurs in the data, insert a code set A or code set B character before that character, and follow rules 1c and 1d to determine between code sets A and B. Note: In these rules, the term “lowercase” is used for convenience to mean any code set B character with Code 128 Symbol character values 64 to 95 (ASCII values 96 to 127) (e.g., all lowercase alphanumeric characters plus `{|}~DEL). The term “symbology element” means any code set A character with Code 128 Symbol character values 64 to 95 (ASCII values 00 to 31). Note 2: If the Function 1 Symbol Character (FNC1) occurs in the first position following the Start Character, or in an odd-numbered position in a numeric field, it should be treated as two digits for the purpose of determining the appropriate code set. =end it "should minimize symbol length according to GS1-128 guidelines" do # Determine the Start Character. Code128.apply_shortest_encoding_for_data("#{FNC1}10").must_equal "#{CODEC}#{FNC1}10" Code128.apply_shortest_encoding_for_data("#{FNC1}101234").must_equal "#{CODEC}#{FNC1}101234" Code128.apply_shortest_encoding_for_data("10\001LOT").must_equal "#{CODEA}10\001LOT" Code128.apply_shortest_encoding_for_data("lot1").must_equal "#{CODEB}lot1" # Switching to codeset B from codeset C Code128.apply_shortest_encoding_for_data("#{FNC1}101").must_equal "#{CODEC}#{FNC1}10#{CODEB}1" # Switching to codeset A from codeset C Code128.apply_shortest_encoding_for_data("#{FNC1}10\001a").must_equal "#{CODEC}#{FNC1}10#{CODEA}\001#{CODEB}a" # Switching to codeset C from codeset A Code128.apply_shortest_encoding_for_data("#{FNC1}10\001LOT1234").must_equal "#{CODEC}#{FNC1}10#{CODEA}\001LOT#{CODEC}1234" Code128.apply_shortest_encoding_for_data("#{FNC1}10\001LOT12345").must_equal "#{CODEC}#{FNC1}10#{CODEA}\001LOT1#{CODEC}2345" # Switching to codeset C from codeset B Code128.apply_shortest_encoding_for_data("#{FNC1}10LOT1234").must_equal "#{CODEC}#{FNC1}10#{CODEB}LOT#{CODEC}1234" Code128.apply_shortest_encoding_for_data("#{FNC1}10LOT12345").must_equal "#{CODEC}#{FNC1}10#{CODEB}LOT1#{CODEC}2345" # Switching to codeset A from codeset B Code128.apply_shortest_encoding_for_data("#{FNC1}10lot\001a").must_equal "#{CODEC}#{FNC1}10#{CODEB}lot#{SHIFT}\001a" Code128.apply_shortest_encoding_for_data("#{FNC1}10lot\001\001").must_equal "#{CODEC}#{FNC1}10#{CODEB}lot#{CODEA}\001\001" # Switching to codeset B from codeset A Code128.apply_shortest_encoding_for_data("#{FNC1}10\001l\001").must_equal "#{CODEC}#{FNC1}10#{CODEA}\001#{SHIFT}l\001" Code128.apply_shortest_encoding_for_data("#{FNC1}10\001ll").must_equal "#{CODEC}#{FNC1}10#{CODEA}\001#{CODEB}ll" # testing "Note 2" from the GS1 specification Code128.apply_shortest_encoding_for_data("#{FNC1}10LOT#{FNC1}0101").must_equal "#{CODEC}#{FNC1}10#{CODEB}LOT#{CODEC}#{FNC1}0101" Code128.apply_shortest_encoding_for_data("#{FNC1}10LOT#{FNC1}01010").must_equal "#{CODEC}#{FNC1}10#{CODEB}LOT#{FNC1}0#{CODEC}1010" Code128.apply_shortest_encoding_for_data("#{FNC1}10LOT01#{FNC1}0101").must_equal "#{CODEC}#{FNC1}10#{CODEB}LOT#{CODEC}01#{FNC1}0101" end it "should know how to extract CODEC segments properly from a data string" do Code128.send(:extract_codec, "1234abcd5678\r\n\r\n").must_equal ["1234", "abcd", "5678", "\r\n\r\n"] Code128.send(:extract_codec, "12345abc6").must_equal ["1234", "5abc6"] Code128.send(:extract_codec, "abcdef").must_equal ["abcdef"] Code128.send(:extract_codec, "123abcdef45678").must_equal ["123abcdef4", "5678"] Code128.send(:extract_codec, "abcd12345").must_equal ["abcd1", "2345"] Code128.send(:extract_codec, "abcd12345efg").must_equal ["abcd1", "2345", "efg"] Code128.send(:extract_codec, "12345").must_equal ["1234", "5"] Code128.send(:extract_codec, "12345abc").must_equal ["1234", "5abc"] Code128.send(:extract_codec, "abcdef1234567").must_equal ["abcdef1", "234567"] end it "should know how to most efficiently apply different encodings to a data string" do Code128.apply_shortest_encoding_for_data("123456").must_equal "#{CODEC}123456" Code128.apply_shortest_encoding_for_data("abcdef").must_equal "#{CODEB}abcdef" Code128.apply_shortest_encoding_for_data("ABCDEF").must_equal "#{CODEB}ABCDEF" Code128.apply_shortest_encoding_for_data("\n\t\r").must_equal "#{CODEA}\n\t\r" Code128.apply_shortest_encoding_for_data("123456abcdef").must_equal "#{CODEC}123456#{CODEB}abcdef" Code128.apply_shortest_encoding_for_data("abcdef123456").must_equal "#{CODEB}abcdef#{CODEC}123456" Code128.apply_shortest_encoding_for_data("1234567").must_equal "#{CODEC}123456#{CODEB}7" Code128.apply_shortest_encoding_for_data("123b456").must_equal "#{CODEB}123b456" Code128.apply_shortest_encoding_for_data("abc123def45678gh").must_equal "#{CODEB}abc123def4#{CODEC}5678#{CODEB}gh" Code128.apply_shortest_encoding_for_data("12345AB\nEEasdgr12EE\r\n").must_equal "#{CODEC}1234#{CODEA}5AB\nEE#{CODEB}asdgr12EE#{CODEA}\r\n" Code128.apply_shortest_encoding_for_data("123456QWERTY\r\n\tAAbbcc12XX34567").must_equal "#{CODEC}123456#{CODEA}QWERTY\r\n\tAA#{CODEB}bbcc12XX3#{CODEC}4567" Code128.apply_shortest_encoding_for_data("ABCdef\rGHIjkl").must_equal "#{CODEB}ABCdef#{SHIFT}\rGHIjkl" Code128.apply_shortest_encoding_for_data("ABC\rb\nDEF12gHI3456").must_equal "#{CODEA}ABC\r#{SHIFT}b\nDEF12#{CODEB}gHI#{CODEC}3456" Code128.apply_shortest_encoding_for_data("ABCdef\rGHIjkl\tMNop\nqRs").must_equal "#{CODEB}ABCdef#{SHIFT}\rGHIjkl#{SHIFT}\tMNop#{SHIFT}\nqRs" end it "should apply automatic charset when no charset is given" do b = Code128.new("123456QWERTY\r\n\tAAbbcc12XX34567") b.type.must_equal 'C' b.full_data_with_change_codes.must_equal "123456#{CODEA}QWERTY\r\n\tAA#{CODEB}bbcc12XX3#{CODEC}4567" end end private def binary_encode_array(datas) datas.each { |data| binary_encode(data) } end def binary_encode(data) ruby_19_or_greater? ? data.force_encoding('BINARY') : data end end barby-0.6.5/test/code_25_iata_test.rb000066400000000000000000000005751301765014400174120ustar00rootroot00000000000000require 'test_helper' require 'barby/barcode/code_25_iata' class Code25IATATest < Barby::TestCase before do @data = '0123456789' @code = Code25IATA.new(@data) end it "should have the expected start_encoding" do @code.start_encoding.must_equal '1010' end it "should have the expected stop_encoding" do @code.stop_encoding.must_equal '11101' end end barby-0.6.5/test/code_25_interleaved_test.rb000066400000000000000000000071141301765014400207720ustar00rootroot00000000000000require 'test_helper' require 'barby/barcode/code_25_interleaved' class Code25InterleavedTest < Barby::TestCase before do @data = '12345670' @code = Code25Interleaved.new(@data) end it "should have the expected digit_pairs" do @code.digit_pairs.must_equal [[1,2],[3,4],[5,6],[7,0]] end it "should have the expected digit_encodings" do @code.digit_encodings.must_equal %w(111010001010111000 111011101000101000 111010001110001010 101010001110001110) end it "should have the expected start_encoding" do @code.start_encoding.must_equal '1010' end it "should have the expected stop_encoding" do @code.stop_encoding.must_equal '11101' end it "should have the expected data_encoding" do @code.data_encoding.must_equal "111010001010111000111011101000101000111010001110001010101010001110001110" end it "should have the expected encoding" do @code.encoding.must_equal "101011101000101011100011101110100010100011101000111000101010101000111000111011101" end it "should be valid" do assert @code.valid? end it "should return the expected encoding for parameters passed to encoding_for_interleaved" do w, n = Code25Interleaved::WIDE, Code25Interleaved::NARROW # 1 2 1 2 1 2 1 2 1 2 digits 1 and 2 # B S B S B S B S B S bars and spaces @code.encoding_for_interleaved(w,n,n,w,n,n,n,n,w,w).must_equal '111010001010111000' # 3 4 3 4 3 4 3 4 3 4 digits 3 and 4 # B S B S B S B S B S bars and spaces @code.encoding_for_interleaved(w,n,w,n,n,w,n,n,n,w).must_equal '111011101000101000' end it "should return all characters in sequence for to_s" do @code.to_s.must_equal @code.characters.join end describe "with checksum" do before do @data = '1234567' @code = Code25Interleaved.new(@data) @code.include_checksum = true end it "should have the expected digit_pairs_with_checksum" do @code.digit_pairs_with_checksum.must_equal [[1,2],[3,4],[5,6],[7,0]] end it "should have the expected digit_encodings_with_checksum" do @code.digit_encodings_with_checksum.must_equal %w(111010001010111000 111011101000101000 111010001110001010 101010001110001110) end it "should have the expected data_encoding_with_checksum" do @code.data_encoding_with_checksum.must_equal "111010001010111000111011101000101000111010001110001010101010001110001110" end it "should have the expected encoding" do @code.encoding.must_equal "101011101000101011100011101110100010100011101000111000101010101000111000111011101" end it "should be valid" do assert @code.valid? end it "should return all characters including checksum in sequence on to_s" do @code.to_s.must_equal @code.characters_with_checksum.join end end describe "with invalid number of digits" do before do @data = '1234567' @code = Code25Interleaved.new(@data) end it "should not be valid" do refute @code.valid? end it "should raise ArgumentError on all encoding methods" do lambda{ @code.encoding }.must_raise(ArgumentError) lambda{ @code.data_encoding }.must_raise(ArgumentError) lambda{ @code.digit_encodings }.must_raise(ArgumentError) end it "should not raise ArgumentError on encoding methods that include checksum" do b = Code25Interleaved.new(@data) b.include_checksum = true b.encoding @code.data_encoding_with_checksum @code.digit_encodings_with_checksum end end end barby-0.6.5/test/code_25_test.rb000066400000000000000000000065371301765014400164200ustar00rootroot00000000000000require 'test_helper' require 'barby/barcode/code_25' class Code25Test < Barby::TestCase before do @data = "1234567" @code = Code25.new(@data) end it "should return the same data it was given" do @code.data.must_equal @data end it "should have the expected characters" do @code.characters.must_equal %w(1 2 3 4 5 6 7) end it "should have the expected characters_with_checksum" do @code.characters_with_checksum.must_equal %w(1 2 3 4 5 6 7 0) end it "should have the expected digits" do @code.digits.must_equal [1,2,3,4,5,6,7] end it "should have the expected digits_with_checksum" do @code.digits_with_checksum.must_equal [1,2,3,4,5,6,7,0] end it "should have the expected even_and_odd_digits" do @code.even_and_odd_digits.must_equal [[7,5,3,1], [6,4,2]] end it "should have the expected start_encoding" do @code.start_encoding.must_equal '1110111010' end it "should have the expected stop_encoding" do @code.stop_encoding.must_equal '111010111' end it "should have a default narrow_width of 1" do @code.narrow_width.must_equal 1 end it "should have a default wide_width equal to narrow_width * 3" do @code.wide_width.must_equal @code.narrow_width * 3 @code.narrow_width = 2 @code.wide_width.must_equal 6 end it "should have a default space_width equal to narrow_width" do @code.space_width.must_equal @code.narrow_width @code.narrow_width = 23 @code.space_width.must_equal 23 end it "should have the expected digit_encodings" do @code.digit_encodings.must_equal %w(11101010101110 10111010101110 11101110101010 10101110101110 11101011101010 10111011101010 10101011101110) end it "should have the expected digit_encodings_with_checksum" do @code.digit_encodings_with_checksum.must_equal %w(11101010101110 10111010101110 11101110101010 10101110101110 11101011101010 10111011101010 10101011101110 10101110111010) end it "should have the expected data_encoding" do @code.data_encoding.must_equal "11101010101110101110101011101110111010101010101110101110111010111010101011101110101010101011101110" end it "should have the expected checksum" do @code.checksum.must_equal 0 end it "should have the expected checksum_encoding" do @code.checksum_encoding.must_equal '10101110111010' end it "should have the expected encoding" do @code.encoding.must_equal "111011101011101010101110101110101011101110111010101010101110101110111010111010101011101110101010101011101110111010111" end it "should be valid" do assert @code.valid? end it "should not be valid" do @code.data = 'abc' refute @code.valid? end it "should raise on encoding methods that include data encoding if not valid" do @code.data = 'abc' lambda{ @code.encoding }.must_raise ArgumentError lambda{ @code.data_encoding }.must_raise ArgumentError lambda{ @code.data_encoding_with_checksum }.must_raise ArgumentError lambda{ @code.digit_encodings }.must_raise ArgumentError lambda{ @code.digit_encodings_with_checksum }.must_raise ArgumentError end it "should return all characters in sequence on to_s" do @code.to_s.must_equal @code.characters.join end it "should include checksum in to_s when include_checksum is true" do @code.include_checksum = true @code.to_s.must_equal @code.characters_with_checksum.join end end barby-0.6.5/test/code_39_test.rb000066400000000000000000000152471301765014400164230ustar00rootroot00000000000000#encoding: ASCII require 'test_helper' require 'barby/barcode/code_39' class Code39Test < Barby::TestCase before do @data = 'TEST8052' @code = Code39.new(@data) @code.spacing = 3 end it "should yield self on initialize" do c1 = nil c2 = Code39.new('TEST'){|c| c1 = c } c1.must_equal c2 end it "should have the expected data" do @code.data.must_equal @data end it "should have the expected characters" do @code.characters.must_equal @data.split(//) end it "should have the expected start_encoding" do @code.start_encoding.must_equal '100101101101' end it "should have the expected stop_encoding" do @code.stop_encoding.must_equal '100101101101' end it "should have the expected spacing_encoding" do @code.spacing_encoding.must_equal '000' end it "should have the expected encoded characters" do @code.encoded_characters.must_equal %w(101011011001 110101100101 101101011001 101011011001 110100101101 101001101101 110100110101 101100101011) end it "should have the expected data_encoding" do @code.data_encoding.must_equal '101011011001000110101100101000101101011001000101011011001000110100101101000101001101101000110100110101000101100101011' end it "should have the expected encoding" do @code.encoding.must_equal '100101101101000101011011001000110101100101000101101011001000101011011001000110100101101000101001101101000110100110101000101100101011000100101101101' end it "should be valid" do assert @code.valid? end it "should not be valid" do @code.data = "123\200456" refute @code.valid? end it "should raise an exception when data is not valid on initialization" do lambda{ Code39.new('abc') }.must_raise(ArgumentError) end it "should return all characters in sequence without checksum on to_s" do @code.to_s.must_equal @data end describe "Checksumming" do before do @code = Code39.new('CODE39') end it "should have the expected checksum" do @code.checksum.must_equal 32 end it "should have the expected checksum_character" do @code.checksum_character.must_equal 'W' end it "should have the expected checksum_encoding" do @code.checksum_encoding.must_equal '110011010101' end it "should have the expected characters_with_checksum" do @code.characters_with_checksum.must_equal %w(C O D E 3 9 W) end it "should have the expected encoded_characters_with_checksum" do @code.encoded_characters_with_checksum.must_equal %w(110110100101 110101101001 101011001011 110101100101 110110010101 101100101101 110011010101) end it "should have the expected data_encoding_with_checksum" do @code.data_encoding_with_checksum.must_equal "110110100101011010110100101010110010110110101100101011011001010101011001011010110011010101" end it "should have the expected encoding_with_checksum" do @code.encoding_with_checksum.must_equal "10010110110101101101001010110101101001010101100101101101011001010110110010101010110010110101100110101010100101101101" end it "should return the encoding with checksum when include_checksum == true" do @code.include_checksum = true @code.encoding.must_equal "10010110110101101101001010110101101001010101100101101101011001010110110010101010110010110101100110101010100101101101" end end describe "Normal encoding" do before do @data = 'ABC$%' @code = Code39.new(@data) end it "should have the expected characters" do @code.characters.must_equal %w(A B C $ %) end it "should have the expected encoded_characters" do @code.encoded_characters.must_equal %w(110101001011 101101001011 110110100101 100100100101 101001001001) end it "should have the expected data_encoding" do @code.data_encoding.must_equal '1101010010110101101001011011011010010101001001001010101001001001' end it "should not be valid" do @code.data = 'abc' refute @code.valid? end end describe "Extended encoding" do before do @data = '' @code = Code39.new(@data, true) end it "should return true on extended?" do assert @code.extended? end it "should have the expected characters" do @code.characters.must_equal %w(% G + A + B + C % I) end it "should have the expected encoded_characters" do @code.encoded_characters.must_equal %w(101001001001 101010011011 100101001001 110101001011 100101001001 101101001011 100101001001 110110100101 101001001001 101101001101) end it "should have the expected data_encoding" do @code.data_encoding.must_equal '101001001001010101001101101001010010010110101001011010010100100101011010010110100101001001011011010010101010010010010101101001101' end it "should have the expected encoding" do @code.encoding.must_equal '10010110110101010010010010101010011011010010100100101101010010110100101001001'+ '010110100101101001010010010110110100101010100100100101011010011010100101101101' end it "should take a second parameter on initialize indicating it is extended" do assert Code39.new('abc', true).extended? refute Code39.new('ABC', false).extended? refute Code39.new('ABC').extended? end it "should be valid" do assert @code.valid? end it "should not be valid" do @code.data = "abc\200123" refute @code.valid? end it "should return all characters in sequence without checksum on to_s" do @code.to_s.must_equal @data end end describe "Variable widths" do before do @data = 'ABC$%' @code = Code39.new(@data) @code.narrow_width = 2 @code.wide_width = 5 end it "should have the expected encoded_characters" do @code.encoded_characters.must_equal %w(111110011001100000110011111 110011111001100000110011111 111110011111001100000110011 110000011000001100000110011 110011000001100000110000011) end it "should have the expected data_encoding" do # A SB SC S$ S% @code.data_encoding.must_equal '1111100110011000001100111110110011111001100000110011111011111001111100110000011001101100000110000011000001100110110011000001100000110000011' @code.spacing = 3 # A S B S C S $ S % @code.data_encoding.must_equal '111110011001100000110011111000110011111001100000110011111000111110011111001100000110011000110000011000001100000110011000110011000001100000110000011' end end end barby-0.6.5/test/code_93_test.rb000066400000000000000000000104361301765014400164160ustar00rootroot00000000000000#encoding: ASCII require 'test_helper' require 'barby/barcode/code_93' class Code93Test < Barby::TestCase before do @data = 'TEST93' @code = Code93.new(@data) end it "should return the same data we put in" do @code.data.must_equal @data end it "should have the expected characters" do @code.characters.must_equal @data.split(//) end it "should have the expected start_encoding" do @code.start_encoding.must_equal '101011110' end it "should have the expected stop_encoding" do # STOP TERM @code.stop_encoding.must_equal '1010111101' end it "should have the expected encoded characters" do # T E S T 9 3 @code.encoded_characters.must_equal %w(110100110 110010010 110101100 110100110 100001010 101000010) end it "should have the expected data_encoding" do # T E S T 9 3 @code.data_encoding.must_equal "110100110110010010110101100110100110100001010101000010" end it "should have the expected data_encoding_with_checksums" do # T E S T 9 3 + (C) 6 (K) @code.data_encoding_with_checksums.must_equal "110100110110010010110101100110100110100001010101000010101110110100100010" end it "should have the expected encoding" do # START T E S T 9 3 + (C) 6 (K) STOP TERM @code.encoding.must_equal "1010111101101001101100100101101011001101001101000010101010000101011101101001000101010111101" end it "should have the expected checksum_values" do @code.checksum_values.must_equal [29, 14, 28, 29, 9, 3].reverse #! end it "should have the expected c_checksum" do @code.c_checksum.must_equal 41 #calculate this first! end it "should have the expected c_checksum_character" do @code.c_checksum_character.must_equal '+' end it "should have the expected c_checksum_encoding" do @code.c_checksum_encoding.must_equal '101110110' end it "should have the expected checksum_values_with_c_checksum" do @code.checksum_values_with_c_checksum.must_equal [29, 14, 28, 29, 9, 3, 41].reverse #! end it "should have the expected k_checksum" do @code.k_checksum.must_equal 6 #calculate this first! end it "should have the expected k_checksum_character" do @code.k_checksum_character.must_equal '6' end it "should have the expected k_checksum_encoding" do @code.k_checksum_encoding.must_equal '100100010' end it "should have the expected checksums" do @code.checksums.must_equal [41, 6] end it "should have the expected checksum_characters" do @code.checksum_characters.must_equal ['+', '6'] end it "should have the expected checksum_encodings" do @code.checksum_encodings.must_equal %w(101110110 100100010) end it "should have the expected checksum_encoding" do @code.checksum_encoding.must_equal '101110110100100010' end it "should be valid" do assert @code.valid? end it "should not be valid when not in extended mode" do @code.data = 'not extended' end it "should return data with no checksums on to_s" do @code.to_s.must_equal 'TEST93' end describe "Extended mode" do before do @data = "Extended!" @code = Code93.new(@data) end it "should be extended" do assert @code.extended? end it "should convert extended characters to special shift characters" do @code.characters.must_equal ["E", "\304", "X", "\304", "T", "\304", "E", "\304", "N", "\304", "D", "\304", "E", "\304", "D", "\303", "A"] end it "should have the expected data_encoding" do @code.data_encoding.must_equal '110010010100110010101100110100110010110100110100110010110010010'+ '100110010101000110100110010110010100100110010110010010100110010110010100111010110110101000' end it "should have the expected c_checksum" do @code.c_checksum.must_equal 9 end it "should have the expected k_checksum" do @code.k_checksum.must_equal 46 end it "should return the original data on to_s with no checksums" do @code.to_s.must_equal 'Extended!' end end end barby-0.6.5/test/data_matrix_test.rb000066400000000000000000000017161301765014400174670ustar00rootroot00000000000000require 'test_helper' require 'barby/barcode/data_matrix' class DataMatrixTest < Barby::TestCase before do @data = "humbaba" @code = Barby::DataMatrix.new(@data) end it "should have the expected encoding" do @code.encoding.must_equal ["1010101010101010", "1011111000011111", "1110111000010100", "1110100100000111", "1101111010101000", "1101111011110011", "1111111100000100", "1100101111110001", "1001000010001010", "1101010110111011", "1000000100011110", "1001010010000011", "1101100111011110", "1110111010000101", "1110010110001010", "1111111111111111"] end it "should return data on to_s" do @code.to_s.must_equal @data end it "should be able to change its data" do prev_encoding = @code.encoding @code.data = "after eight" @code.encoding.wont_equal prev_encoding end end barby-0.6.5/test/ean13_test.rb000066400000000000000000000105241301765014400160760ustar00rootroot00000000000000require 'test_helper' require 'barby/barcode/ean_13' class EAN13Test < Barby::TestCase describe 'validations' do before do @valid = EAN13.new('123456789012') end it "should be valid with 12 digits" do assert @valid.valid? end it "should not be valid with non-digit characters" do @valid.data = "The shit apple doesn't fall far from the shit tree" refute @valid.valid? end it "should not be valid with less than 12 digits" do @valid.data = "12345678901" refute @valid.valid? end it "should not be valid with more than 12 digits" do @valid.data = "1234567890123" refute @valid.valid? end it "should raise an exception when data is invalid" do lambda{ EAN13.new('123') }.must_raise(ArgumentError) end end describe 'data' do before do @data = '007567816412' @code = EAN13.new(@data) end it "should have the same data as was passed to it" do @code.data.must_equal @data end it "should have the expected characters" do @code.characters.must_equal @data.split(//) end it "should have the expected numbers" do @code.numbers.must_equal @data.split(//).map{|s| s.to_i } end it "should have the expected odd_and_even_numbers" do @code.odd_and_even_numbers.must_equal [[2,4,1,7,5,0], [1,6,8,6,7,0]] end it "should have the expected left_numbers" do #0=second number in number system code @code.left_numbers.must_equal [0,7,5,6,7,8] end it "should have the expected right_numbers" do @code.right_numbers.must_equal [1,6,4,1,2,5]#5=checksum end it "should have the expected numbers_with_checksum" do @code.numbers_with_checksum.must_equal @data.split(//).map{|s| s.to_i } + [5] end it "should have the expected data_with_checksum" do @code.data_with_checksum.must_equal @data+'5' end it "should return all digits and the checksum on to_s" do @code.to_s.must_equal '0075678164125' end end describe 'checksum' do before do @code = EAN13.new('007567816412') end it "should have the expected weighted_sum" do @code.weighted_sum.must_equal 85 @code.data = '007567816413' @code.weighted_sum.must_equal 88 end it "should have the correct checksum" do @code.checksum.must_equal 5 @code.data = '007567816413' @code.checksum.must_equal 2 end it "should have the correct checksum_encoding" do @code.checksum_encoding.must_equal '1001110' end end describe 'encoding' do before do @code = EAN13.new('750103131130') end it "should have the expected checksum" do @code.checksum.must_equal 9 end it "should have the expected checksum_encoding" do @code.checksum_encoding.must_equal '1110100' end it "should have the expected left_parity_map" do @code.left_parity_map.must_equal [:odd, :even, :odd, :even, :odd, :even] end it "should have the expected left_encodings" do @code.left_encodings.must_equal %w(0110001 0100111 0011001 0100111 0111101 0110011) end it "should have the expected right_encodings" do @code.right_encodings.must_equal %w(1000010 1100110 1100110 1000010 1110010 1110100) end it "should have the expected left_encoding" do @code.left_encoding.must_equal '011000101001110011001010011101111010110011' end it "should have the expected right_encoding" do @code.right_encoding.must_equal '100001011001101100110100001011100101110100' end it "should have the expected encoding" do #Start Left Center Right Stop @code.encoding.must_equal '101' + '011000101001110011001010011101111010110011' + '01010' + '100001011001101100110100001011100101110100' + '101' end end describe 'static data' do before :each do @code = EAN13.new('123456789012') end it "should have the expected start_encoding" do @code.start_encoding.must_equal '101' end it "should have the expected stop_encoding" do @code.stop_encoding.must_equal '101' end it "should have the expected center_encoding" do @code.center_encoding.must_equal '01010' end end end barby-0.6.5/test/ean8_test.rb000066400000000000000000000041011301765014400160140ustar00rootroot00000000000000require 'test_helper' require 'barby/barcode/ean_8' class EAN8Test < Barby::TestCase describe 'validations' do before do @valid = EAN8.new('1234567') end it "should be valid with 7 digits" do assert @valid.valid? end it "should not be valid with less than 7 digits" do @valid.data = '123456' refute @valid.valid? end it "should not be valid with more than 7 digits" do @valid.data = '12345678' refute @valid.valid? end it "should not be valid with non-digits" do @valid.data = 'abcdefg' refute @valid.valid? end end describe 'checksum' do before :each do @code = EAN8.new('5512345') end it "should have the expected weighted_sum" do @code.weighted_sum.must_equal 53 end it "should have the expected checksum" do @code.checksum.must_equal 7 end end describe 'data' do before :each do @data = '5512345' @code = EAN8.new(@data) end it "should have the expected data" do @code.data.must_equal @data end it "should have the expected odd_and_even_numbers" do @code.odd_and_even_numbers.must_equal [[5,3,1,5],[4,2,5]] end it "should have the expected left_numbers" do #EAN-8 includes the first character in the left-hand encoding, unlike EAN-13 @code.left_numbers.must_equal [5,5,1,2] end it "should have the expected right_numbers" do @code.right_numbers.must_equal [3,4,5,7] end it "should return the data with checksum on to_s" do @code.to_s.must_equal '55123457' end end describe 'encoding' do before :each do @code = EAN8.new('5512345') end it "should have the expected left_parity_map" do @code.left_parity_map.must_equal [:odd, :odd, :odd, :odd] end it "should have the expected left_encoding" do @code.left_encoding.must_equal '0110001011000100110010010011' end it "should have the expected right_encoding" do @code.right_encoding.must_equal '1000010101110010011101000100' end end end barby-0.6.5/test/outputter/000077500000000000000000000000001301765014400156545ustar00rootroot00000000000000barby-0.6.5/test/outputter/cairo_outputter_test.rb000066400000000000000000000070641301765014400224770ustar00rootroot00000000000000require 'test_helper' class CairoOutputterTest < Barby::TestCase def ps_available? Cairo.const_defined?(:PSSurface) end def eps_available? ps_available? and Cairo::PSSurface.method_defined?(:eps=) end def pdf_available? Cairo.const_defined?(:PDFSurface) end def svg_available? Cairo.const_defined?(:SVGSurface) end before do load_outputter('cairo') @barcode = Barby::Barcode.new def @barcode.encoding; '101100111000'; end @outputter = Barby::CairoOutputter.new(@barcode) @outputters = Barby::Barcode.outputters @surface = Cairo::ImageSurface.new(100, 100) @context = Cairo::Context.new(@surface) end it "should have defined the render_to_cairo_context method" do @outputters.must_include(:render_to_cairo_context) end it "should have defined the to_png method" do @outputters.must_include(:to_png) end it "should have defined the to_ps and to_eps method if available" do if ps_available? @outputters.must_include(:to_ps) if eps_available? @outputters.must_include(:to_eps) else @outputters.wont_include(:to_eps) end else @outputters.wont_include(:to_ps) @outputters.wont_include(:to_eps) end end it "should have defined the to_pdf method if available" do if pdf_available? @outputters.must_include(:to_pdf) else @outputters.wont_include(:to_pdf) end end it "should have defined the to_svg method if available" do if svg_available? @outputters.must_include(:to_svg) else @outputters.wont_include(:to_svg) end end it "should return the cairo context object it was given in render_to_cairo_context" do @barcode.render_to_cairo_context(@context).object_id.must_equal @context.object_id end it "should return PNG image by the to_png method" do png = @barcode.to_png data = ruby_19_or_greater? ? png.force_encoding('BINARY') : png data.must_match(/\A\x89PNG/n) end it "should return PS document by the to_ps method" do if ps_available? @barcode.to_ps.must_match(/\A%!PS-Adobe-[\d.]/) end end it "should return EPS document by the to_eps method" do if eps_available? @barcode.to_eps.must_match(/\A%!PS-Adobe-[\d.]+ EPSF-[\d.]+/) end end it "should return PDF document by the to_pdf method" do if pdf_available? pdf = @barcode.to_pdf data = ruby_19_or_greater? ? pdf.force_encoding('BINARY') : pdf data.must_match(/\A%PDF-[\d.]+/n) end end it "should return SVG document by the to_svg method" do if svg_available? @barcode.to_svg.must_match(/<\/svg>\s*\Z/m) end end it "should have x, y, width, height, full_width, full_height, xdim and margin attributes" do @outputter.must_respond_to(:x) @outputter.must_respond_to(:y) @outputter.must_respond_to(:width) @outputter.must_respond_to(:height) @outputter.must_respond_to(:full_width) @outputter.must_respond_to(:full_height) @outputter.must_respond_to(:xdim) @outputter.must_respond_to(:margin) end it "should not change attributes when given an options hash to render" do %w(x y height xdim).each do |m| @outputter.send("#{m}=", 10) @outputter.send(m).must_equal 10 end @outputter.render_to_cairo_context(@context, :x => 20, :y => 20, :height => 20, :xdim => 20) %w(x y height xdim).each{|m| @outputter.send(m).must_equal 10 } end end barby-0.6.5/test/outputter/html_outputter_test.rb000066400000000000000000000040221301765014400223350ustar00rootroot00000000000000require 'test_helper' require 'barby/barcode/code_128' #require 'barby/outputter/html_outputter' class HtmlOutputterTest < Barby::TestCase class MockCode attr_reader :encoding def initialize(e) @encoding = e end def two_dimensional? encoding.is_a? Array end end before do load_outputter('html') @barcode = Barby::Code128B.new('BARBY') @outputter = HtmlOutputter.new(@barcode) end it "should register to_html" do Barcode.outputters.must_include(:to_html) end it 'should have the expected start HTML' do assert_equal '', @outputter.start end it 'should be able to set additional class name' do @outputter.class_name = 'humbaba' assert_equal '
', @outputter.start end it 'should have the expected stop HTML' do assert_equal '
', @outputter.stop end it 'should build the expected cells' do assert_equal ['