Class: QRCode::Encoder::Code

Inherits:
Object
  • Object
show all
Defined in:
lib/qrcode/encoder/code.rb

Overview

Creation

QRCode objects expect only one required constructor parameter and an optional hash of any other. Here’s a few examples:

qr = QRCode::Encoder::Code.new('hello world')
qr = QRCode::Encoder::Code.new('hello world', size: 1, level: :m, mode: :alphanumeric)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(segments, level: :h, size: nil, max_size: nil) ⇒ Code

Simple constructor that takes an array of segments



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/qrcode/encoder/code.rb', line 59

def initialize(segments, level: :h, size: nil, max_size: nil)
	@segments = Array(segments)
	@error_correction_level = ERROR_CORRECTION_LEVEL[level]
	
	unless @error_correction_level
		raise ArgumentError, "Unknown error correction level `#{level.inspect}`"
	end
	
	max_size ||= Encoder::Util.max_size
	calculated_size = size || minimum_version(limit: max_size)
	
	if calculated_size > max_size
		raise ArgumentError, "Given size greater than maximum possible size of #{max_size}"
	end
	
	@version = calculated_size
	@module_count = @version * 4 + POSITION_PATTERN_LENGTH
	@modules = Array.new(@module_count)
	@data_cache = nil
	make
end

Instance Attribute Details

#module_countObject (readonly) Also known as: size

Returns the value of attribute module_count.



38
39
40
# File 'lib/qrcode/encoder/code.rb', line 38

def module_count
  @module_count
end

#modulesObject (readonly)

Returns the value of attribute modules.



38
39
40
# File 'lib/qrcode/encoder/code.rb', line 38

def modules
  @modules
end

#segmentsObject (readonly)

Returns the value of attribute segments.



38
39
40
# File 'lib/qrcode/encoder/code.rb', line 38

def segments
  @segments
end

#versionObject (readonly)

Returns the value of attribute version.



38
39
40
# File 'lib/qrcode/encoder/code.rb', line 38

def version
  @version
end

Class Method Details

.build(data, level: :h, mode: :auto, size: nil, max_size: nil) ⇒ Object

Factory method to build QR code from data



49
50
51
52
# File 'lib/qrcode/encoder/code.rb', line 49

def self.build(data, level: :h, mode: :auto, size: nil, max_size: nil)
	segments = Segment.build(data, mode: mode)
	new(segments, level: level, size: size, max_size: max_size)
end

.count_max_data_bits(rs_blocks) ⇒ Object

:nodoc:



349
350
351
352
353
354
355
# File 'lib/qrcode/encoder/code.rb', line 349

def count_max_data_bits(rs_blocks) # :nodoc:
	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

:nodoc:



374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
# File 'lib/qrcode/encoder/code.rb', line 374

def create_bytes(buffer, rs_blocks) # :nodoc:
	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 = Encoder::Util.get_error_correct_polynomial(ec_count)
		raw_poly = Encoder::Polynomial.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_correction_level, segments) ⇒ Object

:nodoc:



357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# File 'lib/qrcode/encoder/code.rb', line 357

def create_data(version, error_correction_level, segments) # :nodoc:
	rs_blocks = Encoder::ErrorCorrectionBlock.for(version, error_correction_level)
	max_data_bits = Code.count_max_data_bits(rs_blocks)
	buffer = Encoder::BitBuffer.new(version)
	
	segments.each {|segment| segment.write(buffer)}
	buffer.end_of_message(max_data_bits)
	
	if buffer.get_length_in_bits > max_data_bits
		raise RuntimeError, "code length overflow. (#{buffer.get_length_in_bits}>#{max_data_bits}). (Try a larger size!)"
	end
	
	buffer.pad_until(max_data_bits)
	
	Code.create_bytes(buffer, rs_blocks)
end

Instance Method Details

#checked?(row, col) ⇒ Boolean

checked? is called with a col and row parameter. This will return true or false based on whether that coordinate exists in the matrix returned. It would normally be called while iterating through modules. A simple example would be:

instance.checked?( 10, 10 ) => true

Returns:

  • (Boolean)


88
89
90
91
92
93
# File 'lib/qrcode/encoder/code.rb', line 88

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

#error_correction_levelObject

Return a symbol for current error connection level



145
146
147
# File 'lib/qrcode/encoder/code.rb', line 145

def error_correction_level
	ERROR_CORRECTION_LEVEL.invert[@error_correction_level]
end

#inspectObject

Public overide as default inspect is very verbose

QRCode::Encoder::Code.new('my string to generate', size: 4, level: :h)
=> QRCodeCore: @data='my string to generate', @error_correction_level=2, @version=4, @module_count=33


140
141
142
# File 'lib/qrcode/encoder/code.rb', line 140

def inspect
	"QRCodeCore: @segments=#{@segments.size} segments, @error_correction_level=#{@error_correction_level}, @version=#{@version}, @module_count=#{@module_count}"
end

#modeObject

Return the primary mode used (first segment’s mode)



155
156
157
# File 'lib/qrcode/encoder/code.rb', line 155

def mode
	@segments.first&.mode || :mode_8bit_byte
end

#multi_segment?Boolean

Return true if this QR Code includes multiple encoded segments

Returns:

  • (Boolean)


150
151
152
# File 'lib/qrcode/encoder/code.rb', line 150

def multi_segment?
	@segments.size > 1
end

#to_s(*args) ⇒ Object

This is a public method that returns the QR Code you have generated as a string. It will not be able to be read in this format by a QR Code reader, but will give you an idea if the final outout. It takes two optional args :dark and :light which are there for you to choose how the output looks. Here’s an example of it’s use:

instance.to_s =>
xxxxxxx x  x x   x x  xx  xxxxxxx
x     x  xxx  xxxxxx xxx  x     x
x xxx x  xxxxx x       xx x xxx x

instance.to_s( dark: 'E', light: 'Q' ) =>
EEEEEEEQEQQEQEQQQEQEQQEEQQEEEEEEE
EQQQQQEQQEEEQQEEEEEEQEEEQQEQQQQQE
EQEEEQEQQEEEEEQEQQQQQQQEEQEQEEEQE


112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/qrcode/encoder/code.rb', line 112

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