#elixir

Extract data from a QR code in Elixir

Atul Bhosale's avatar

Atul Bhosale

After I had finished working on writing a QR code generator using Elixir for one of our clients, there was a requirement to extract the data from a QR code and storing it. This post is about how I learned to extract the data from a QR code in Elixir.

I came across zbar while searching for a tool to read a QR code. Since I will be using this tool to read the QR code image I will have to use System.cmd() in my code to run the zbar binary.

	defmodule Sample do
	  def qr_string(image_path) do
	    System.cmd("zbarimg", [image_path], stderr_to_stdout: true)
	  end
	end

When the stderr_to_stdout option is set to true, the error details will be included in the tuple returned by Sysmtem.cmd.

I generated a QR code with Hello world as the data.

screenshot1

When I run the above code I get the following:

screenshot1

I just need the QR data i.e. Hello world in this case, but it returns a tuple with first value as string & second as 0. I was curious to know why 0 is returned.

I tried scanning an invalid QR code image like the Codemancers logo.

screenshot1

screenshot1

Notice that now it returns 4. For invalid or non-QR code images, the zbarimg library will return 4.

what about an invalid file type?

screenshot1

We can extract the data for 0, return "No QR code present" for 4 and return "Invalid file" for anything else.

    defmodule Sample

      require Logger

      def qr_string(image_path) do
        case System.cmd("zbarimg", [image_path], stderr_to_stdout: true) do
          {data, 0} ->
            data

          {data, 4} ->
            raise Logger.info("No QR code present. msg: #{data}")

          {data, _} ->
            raise Logger.info("Invalid file. msg: #{data}")
        end
      end
    end

We still need to extract the QR code data from the string.

screenshot1

We can split the string & find the data.

screenshot1

I came across <> operator which can be used for string pattern matching, using which I could find the data in the string.

screenshot1

The existing code can be updated to:

    case System.cmd("zbarimg", [image_path], stderr_to_stdout: true) do

      {data, 0} ->
        "QR-Code:" <> result =
          data
          |> String.split("\n")
          |> List.first()

        result

      {data, 4} ->
        raise Logger.info("No QR code present. msg: #{data}")

      {data, _} ->
        raise Logger.info("Invalid file. msg: #{data}")
    end

I was able to extract the QR code data from a QR code image. Following is the screenshot of the data extracted from a QR code image.

screenshot1

Update: I received a recommendation about parsing QR code data from Antonin Kral, which is as follows:

In case the data stored in QR code consists of multiple lines, its recommended to use --xml option while using zbarimg

screenshot1

The Elixir code will be:

    args = ["--xml", image_path]
    System.cmd("zbarimg", args, stderr_to_stdout: true)

Note: In our client's requirement, the QR code data didn't span multiple lines hence I haven't used --xml option in my examples.