[RAILS] [Ruby] Générer un code QR concaténé avec rqrcode (pratique)

Modifier le rqrcode

À propos de la structure de bibliothèque de rqrcode

Ajouter une méthode pour écrire la partie d'en-tête du code QR concaténé

rqrcode_core/qrcode/qr_bit_buffer.rb


module RQRCodeCore
  class QRBitBuffer
    #Omission
    def byte_with_connected_encoding_start(length, page_number, last_page_number, parity)
      put(3, 4) #MODE indiquant le code QR concaténé= 0b0011
      put(page_number, 4) #Numéro de séquence(0〜15)
      put(last_page_number, 4) #Dernier numéro de séquence(0〜15)
      put(parity, 8) #Valeur de parité(Valeur XOR de toutes les données)
      put(QRMODE[:mode_8bit_byte], 4) # 8bit_valeur du mode octet
      put(length, QRUtil.get_length_in_bits(QRMODE[:mode_8bit_byte], @version)) #Longueur des données
    end

Créer une classe pour le code QR concaténé

rqrcode_core/qrcode/qr_8bit_byte_with_connected.rb


# frozen_string_literal: true

module RQRCodeCore
  class QR8BitByteWithConnected
    attr_reader :mode, :page_number, :last_page_number, :parity

    def initialize(data, page_number, last_page_number, parity)
      @mode = QRMODE[:mode_8bit_byte]
      @data = data
      @page_number = page_number
      @last_page_number = last_page_number
      @parity = parity
    end

    def get_length
      @data.bytesize
    end

    def write(buffer)
      buffer.byte_with_connected_encoding_start(get_length, @page_number, @last_page_number, @parity)
      @data.each_byte do |b|
        buffer.put(b, 8)
      end
    end
  end
end

Ajouter une option de code QR concaténé à la classe QRCode

rqrcode_core/qrcode/qr_code.rb


module RQRCodeCore
  #Omission
  class QRCode
    attr_reader :modules, :module_count, :version
    #Omission
    def initialize( string, *args )
      if !string.is_a? String
        raise QRCodeArgumentError, "The passed data is #{string.class}, not String"
      end

      options               = extract_options!(args)
      level                 = (options[:level] || :h).to_sym
      #Ajout du jugement d'option pour le code QR concaténé
      with_connected = options[:connected] || false

      #Omission

      # :byte_Erreur si un code QR concaténé est spécifié autre que 8 bits(La mise en œuvre est facultative)
      if with_connected && mode != QRMODE_NAME[:byte_8bit]
        raise QRCodeArgumentError, 'Argument error.(Connected QRCode is byte_8bit mode only)'
      end

      max_size_array        = QRMAXDIGITS[level][mode]
      size                  = options[:size] || smallest_size_for(string, max_size_array)

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

      #Omission
      @data_list =
        case mode
        when :mode_number
          QRNumeric.new( @data )
        when :mode_alpha_numk
          QRAlphanumeric.new( @data )
        else
          #S'il s'agit d'un code QR concaténé, modifiez la classe générée
          if with_connected
            page_number = options[:page_number]
            last_page_number = options[:last_page_number]
            parity = options[:parity]
            QR8BitByteWithConnected.new(@data, page_number, last_page_number, parity)
          else
            QR8bitByte.new(@data)
          end
        end

      @data_cache           = nil
      self.make
    end

Sortie du code QR concaténé

JAHIS7
1,1,1234567,13,Clinique de médecine interne de Kita
2,999-9999,99-999 Bâtiment d'essai 9F, Kita Shinagawa, Shinagawa-ku, Tokyo
3,03-9999-9991,03-9999-9992,
4,1,,Médecine interne
5,,,Médecin Taro
11,,Patient Hanako,Kanja Hanako
12,2
13,20000103
21,1
22,01010016
23,symbole,nombre,2,
51,20200818
81,1,,
81,2,,Ceci est une colonne de remarques pour les prescriptions.
101,1,3,,1
111,1,1,,Sur les jambes,
201,1,1,1,7,2619803XAZZZ,[Général] Solution externe contenant de l'alcool pour la désinfection,4,1,mL
101,2,1,,5
111,2,1,,Une fois par jour après le dîner,
201,2,1,1,7,1124022F2ZZZ,[Général] Comprimés de lorazépam 1 mg,1,1,Fermer à clé
101,3,1,,28
111,3,1,,3 fois par jour après chaque repas,
201,3,1,1,7,3136004F2ZZZ,[Général] Comprimés de mécobalamine à 0,5 mg,3,1,Fermer à clé
201,3,2,1,7,2171017F2ZZZ,[Général] Comprimés de Nicolanzil 5 mg,3,1,Fermer à clé
201,3,3,1,7,3962001F1ZZZ,[Général] Comprimés de chlorhydrate de buformine à 50 mg,3,1,Fermer à clé
201,3,4,1,7,1124022F1ZZZ,[Général] Comprimés de lorazépam 0,5 mg,3,1,Fermer à clé
201,3,5,1,7,1124026F1ZZZ,[Général] Comprimés de Tophisopam à 50 mg,3,1,Fermer à clé
201,3,6,1,2,612140503,,3,1,Fermer à clé
101,4,1,,28
111,4,1,,3 fois par jour après chaque repas,
201,4,1,1,7,2344009F2ZZZ,[Général] Comprimé d'oxyde de magnésium 330 mg,6,1,Fermer à clé
101,5,3,,1
111,5,1,,Sur les jambes,
201,5,1,1,7,2619803XAZZZ,[Général] Solution externe contenant de l'alcool pour la désinfection,4,1,mL
101,6,1,,28
111,6,1,,3 fois par jour après chaque repas,
201,6,1,1,7,3136004F2ZZZ,[Général] Comprimés de mécobalamine à 0,5 mg,3,1,Fermer à clé
201,6,2,1,7,2171017F2ZZZ,[Général] Comprimés de Nicolanzil 5 mg,3,1,Fermer à clé
201,6,3,1,7,3962001F1ZZZ,[Général] Comprimés de chlorhydrate de buformine à 50 mg,3,1,Fermer à clé
201,6,4,1,7,1124022F1ZZZ,[Général] Comprimés de lorazépam 0,5 mg,3,1,Fermer à clé
201,6,5,1,7,1124026F1ZZZ,[Général] Comprimés de Tophisopam à 50 mg,3,1,Fermer à clé
201,6,6,1,2,612140503,,3,1,Fermer à clé

Méthode de calcul de la parité

    def create_total_text_parity(data)
      data.each_byte.inject(0) { |parity, b| parity ^ b }
    end

Méthode de fractionnement des données

    #Ajoutez un require pour RQRCodeCore si nécessaire.
    LIMIT_OF_CONNECTED_QRCODE_LENGTH = 16
    CAPACITY_GAP_FOR_CONNECTED = 2

    def slice_data_for_connected_qrcode(data, options)
      capacity = binary_qrcode_capacity_from(options[:level], options[:size]) - CAPACITY_GAP_FOR_CONNECTED

      sliced =
        if options[:adjust_for_sjis]
          slice_sjis_data(data, capacity: capacity)
        else
          slice_data(data, capacity: capacity)
        end

      fail 'data for connect QRCode too many length.' if sliced.length > LIMIT_OF_CONNECTED_QRCODE_LENGTH
      sliced
    end

    def binary_qrcode_capacity_from(level, size)
      RQRCodeCore::QRMAXDIGITS[level][:mode_8bit_byte][size - 1]
    end

    def slice_sjis_data(sjis_data, capacity:)
      is_first_char = ->(char) { (char >= 129 && char <= 159) || (char >= 224 && char <= 239) }

      bytes = sjis_data.each_byte
      sliced_list = []
      while bytes.present?
        next_bytes = bytes.take(capacity)
        if is_first_char.call(next_bytes.last) && next_bytes.length != bytes
          next_bytes = bytes.take(capacity - 1)
        end

        sliced_list << next_bytes.pack('c*')
        bytes = bytes.drop(next_bytes.length)
      end

      sliced_list
    end

    def slice_data(data, capacity:)
      data.each_byte.each_slice(capacity).map { |sliced| sliced.pack('c*') }
    end

Une méthode qui divise et génère automatiquement un code QR

    # Generate connected QRCode. (binary mode only)
    #
    #   # data   - the string you wish to encode
    #   # args
    #   #   size   - the size of the qrcode (default 4)
    #   #   level  - the error correction level
    #   #   adjust_for_sjis - true: no split sjis multi byte character
    #
    # qrcode_list = RQRCode::ConnectedQRCodeUtil.generate_binary_connected_qrcodes('hello world', size: 1, level: :m)
    def generate_binary_connected_qrcodes(data, *args)
      options = extract_options!(args)
      #S'il tient dans un code QR, il sera généré avec un code QR normal.
      return [RQRCode::QRCode.new(data, options)] if fits_in_single_qrcode?(data, options)

      #Diviser les données
      sliced_text = slice_data_for_connected_qrcode(data, options)
      #Générer la parité
      parity = create_total_text_parity(data)
      #Générer un code QR basé sur les données divisées
      sliced_text.map.with_index do |text, number|
        extend_args = { page_number: number, last_page_number: sliced_text.length - 1, connected: true, parity: parity }
        RQRCode::QRCode.new(text, options.merge(extend_args))
      end
    end

    def extract_options!(arr)
      arr.last.is_a?(::Hash) ? arr.pop : {}
    end

    def fits_in_single_qrcode?(data, options)
      data.each_byte.to_a.length <= binary_qrcode_capacity_from(options[:level], options[:size])
    end

Sortie réelle


  QRCODE_SIZE = 16 # Size of QRCODE
  QRCODE_LEVEL = :l # Error correction level (L = 7%)
  MODULE_PIXEL_SIZE = 2 # Size of Pixel

  def create_qrcode_png_files_from(csv_data)
    qrcodes = RQRCode::ConnectedQRCodeUtil.generate_binary_connected_qrcodes(
      csv_data,
      size: QRCODE_SIZE,
      level: QRCODE_LEVEL,
      adjust_for_sjis: true
    )
    qrcodes.map.with_index do |qrcode, index|
      file_path = File.join('tmp', "qrcode_#{index}.png ")
      qrcode.as_png(module_px_size: MODULE_PIXEL_SIZE, file: file_path)
    end
  end

Résumé

Les références

Cet article a été rédigé en référence aux informations suivantes.

Journal des modifications

Recommended Posts

[Ruby] Générer un code QR concaténé avec rqrcode (pratique)
[Ruby] Générer un code QR concaténé avec rqrcode (Knowledge)
Formater Ruby avec VS Code
Lire et générer un code QR [Android]
Faites un jeu de frappe avec ruby
J'ai fait une mort risquée avec Ruby
Extraire une partie d'une chaîne en Ruby
Mémorandum pour nettoyer le code Ruby
Création d'un outil d'automatisation de navigateur avec Ruby + Selenium
J'ai créé Code Pipeline avec AWS CDK.
[Ruby] Comment générer une chaîne de caractères d'alphabet aléatoire
Essayez de déboguer un programme Java avec VS Code
J'ai fait un portfolio avec Ruby On Rails
Créer un environnement de développement Java avec VS Code