Class: QrCodeMaker::QRCode

Inherits:
Object
  • Object
show all
Defined in:
lib/qr_code_maker/encoder.rb,
lib/qr_code_maker/renderer.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data, *args) ⇒ QRCode

Returns a new instance of QRCode.



668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
# File 'lib/qr_code_maker/encoder.rb', line 668

def initialize(data, *args)
  options = extract_options!(args)

  level = (options[:level] || :h).to_sym
  max_size = options[:max_size] || QRUtil.max_size

  @data = case data
  when String
    QRSegment.new(data: data, mode: options[:mode])
  when Array
    raise QRCodeArgumentError, "Array must contain Hashes with :data and :mode keys" unless data.all? { |seg| seg.is_a?(Hash) && %i[data mode].all? { |s| seg.key? s } }
    data.map { |seg| QRSegment.new(**seg) }
  when QRSegment
    data
  else
    raise QRCodeArgumentError, "data must be a String, QRSegment, or an Array"
  end
  @error_correct_level = QRERRORCORRECTLEVEL[level]

  unless @error_correct_level
    raise QRCodeArgumentError, "Unknown error correction level `#{level.inspect}`"
  end

  size = options[:size] || minimum_version(limit: max_size)

  if size > max_size
    raise QRCodeArgumentError, "Given size greater than maximum possible size of #{QRUtil.max_size}"
  end

  @version = size
  @module_count = @version * 4 + QRPOSITIONPATTERNLENGTH
  @modules = Array.new(@module_count)
  @data_list = multi_segment? ? QRMulti.new(@data) : @data.writer
  @data_cache = nil
  make
end

Instance Attribute Details

#module_countObject (readonly)

Returns the value of attribute module_count.



666
667
668
# File 'lib/qr_code_maker/encoder.rb', line 666

def module_count
  @module_count
end

#modulesObject (readonly)

Returns the value of attribute modules.



666
667
668
# File 'lib/qr_code_maker/encoder.rb', line 666

def modules
  @modules
end

#versionObject (readonly)

Returns the value of attribute version.



666
667
668
# File 'lib/qr_code_maker/encoder.rb', line 666

def version
  @version
end

Class Method Details

.count_max_data_bits(rs_blocks) ⇒ Object



947
948
949
950
951
952
# File 'lib/qr_code_maker/encoder.rb', line 947

def count_max_data_bits(rs_blocks)
  max_data_bytes = rs_blocks.reduce(0) do |sum, rs_block|
    sum + rs_block.data_count
  end
  max_data_bytes * 8
end

.create_bytes(buffer, rs_blocks) ⇒ Object



970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
# File 'lib/qr_code_maker/encoder.rb', line 970

def create_bytes(buffer, rs_blocks)
  offset = 0
  max_dc_count = 0
  max_ec_count = 0
  dcdata = Array.new(rs_blocks.size)
  ecdata = Array.new(rs_blocks.size)

  rs_blocks.each_with_index do |rs_block, r|
    dc_count = rs_block.data_count
    ec_count = rs_block.total_count - dc_count
    max_dc_count = [max_dc_count, dc_count].max
    max_ec_count = [max_ec_count, ec_count].max

    dcdata_block = Array.new(dc_count)
    dcdata_block.size.times do |i|
      dcdata_block[i] = 0xff & buffer.buffer[i + offset]
    end
    dcdata[r] = dcdata_block

    offset += dc_count
    rs_poly = QRUtil.get_error_correct_polynomial(ec_count)
    raw_poly = QRPolynomial.new(dcdata[r], rs_poly.get_length - 1)
    mod_poly = raw_poly.mod(rs_poly)

    ecdata_block = Array.new(rs_poly.get_length - 1)
    ecdata_block.size.times do |i|
      mod_index = i + mod_poly.get_length - ecdata_block.size
      ecdata_block[i] = (mod_index >= 0) ? mod_poly.get(mod_index) : 0
    end
    ecdata[r] = ecdata_block
  end

  total_code_count = rs_blocks.reduce(0) do |sum, rs_block|
    sum + rs_block.total_count
  end

  data = Array.new(total_code_count)
  index = 0

  max_dc_count.times do |i|
    rs_blocks.size.times do |r|
      if i < dcdata[r].size
        data[index] = dcdata[r][i]
        index += 1
      end
    end
  end

  max_ec_count.times do |i|
    rs_blocks.size.times do |r|
      if i < ecdata[r].size
        data[index] = ecdata[r][i]
        index += 1
      end
    end
  end

  data
end

.create_data(version, error_correct_level, data_list) ⇒ Object



954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
# File 'lib/qr_code_maker/encoder.rb', line 954

def create_data(version, error_correct_level, data_list)
  rs_blocks = QRRSBlock.get_rs_blocks(version, error_correct_level)
  max_data_bits = count_max_data_bits(rs_blocks)
  buffer = QRBitBuffer.new(version)

  data_list.write(buffer)
  buffer.end_of_message(max_data_bits)

  if buffer.get_length_in_bits > max_data_bits
    raise QRCodeRunTimeError, "code length overflow. (#{buffer.get_length_in_bits}>#{max_data_bits}). (Try a larger size!)"
  end

  buffer.pad_until(max_data_bits)
  create_bytes(buffer, rs_blocks)
end

Instance Method Details

#as_ascii(options = {}) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/qr_code_maker/renderer.rb', line 35

def as_ascii(options = {})
  dark = options[:dark] || "██"
  light = options[:light] || "  "
  margin = options[:margin] || 2

  rows = []
  margin.times { rows << (light * (@module_count + 2 * margin)) }

  @modules.each do |row|
    row_str = light * margin
    row.each do |col|
      row_str << (col ? dark : light)
    end
    row_str << (light * margin)
    rows << row_str
  end

  margin.times { rows << (light * (@module_count + 2 * margin)) }
  rows.join("\n")
end

#as_svg(options = {}) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/qr_code_maker/renderer.rb', line 5

def as_svg(options = {})
  color = options[:color] || "black"
  bg_color = options[:bg_color]
  bg_color = "white" if bg_color.nil?
  
  module_size = options[:module_size] || 10
  margin = options[:margin] || 4

  view_box_size = @module_count + 2 * margin
  total_size = view_box_size * module_size

  path_data = +""
  @modules.each_with_index do |row, r|
    row.each_with_index do |col, c|
      if col
        path_data << "M#{c + margin},#{r + margin}h1v1h-1z"
      end
    end
  end

  svg = []
  svg << %(<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 #{view_box_size} #{view_box_size}" width="#{total_size}" height="#{total_size}">)
  if bg_color && bg_color != "transparent" && bg_color != false
    svg << %(  <rect width="100%" height="100%" fill="#{bg_color}"/>)
  end
  svg << %(  <path d="#{path_data}" fill="#{color}" shape-rendering="crispEdges"/>)
  svg << %(</svg>)
  svg.join("\n")
end

#checked?(row, col) ⇒ Boolean Also known as: dark?

Returns:

  • (Boolean)


705
706
707
708
709
710
# File 'lib/qr_code_maker/encoder.rb', line 705

def checked?(row, col)
  if !row.between?(0, @module_count - 1) || !col.between?(0, @module_count - 1)
    raise QRCodeRunTimeError, "Invalid row/column pair: #{row}, #{col}"
  end
  @modules[row][col]
end

#error_correction_levelObject



739
740
741
# File 'lib/qr_code_maker/encoder.rb', line 739

def error_correction_level
  QRERRORCORRECTLEVEL.invert[@error_correct_level]
end

#inspectObject



735
736
737
# File 'lib/qr_code_maker/encoder.rb', line 735

def inspect
  "QRCodeMaker: @data='#{@data}', @error_correct_level=#{@error_correct_level}, @version=#{@version}, @module_count=#{@module_count}"
end

#modeObject



747
748
749
750
751
752
753
754
755
756
# File 'lib/qr_code_maker/encoder.rb', line 747

def mode
  case @data_list
  when QRNumeric
    :mode_number
  when QRAlphanumeric
    :mode_alpha_numk
  else
    :mode_8bit_byte
  end
end

#multi_segment?Boolean

Returns:

  • (Boolean)


743
744
745
# File 'lib/qr_code_maker/encoder.rb', line 743

def multi_segment?
  @data.is_a?(Array)
end

#to_s(*args) ⇒ Object



713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
# File 'lib/qr_code_maker/encoder.rb', line 713

def to_s(*args)
  options = extract_options!(args)
  dark = options[:dark] || "x"
  light = options[:light] || " "
  quiet_zone_size = options[:quiet_zone_size] || 0

  rows = []
  @modules.each do |row|
    cols = light * quiet_zone_size
    row.each do |col|
      cols += (col ? dark : light)
    end
    rows << cols
  end

  quiet_zone_size.times do
    rows.unshift(light * (rows.first.length / light.size))
    rows << light * (rows.first.length / light.size)
  end
  rows.join("\n")
end