Generating Basic QR Codes in Swift 3.0
QR codes are a type of 2D barcode that was originally developed for use in the Japanese car industry. Encoding URLs, promoting virtual stores, accessing cryptocurrency wallets, adding new contacts to messaging platforms ā QR codes (or some variants of them) provide a streamlined approach to working with various types of data.
Lets look at using static data to create our code ā for example, a String.
In the code above weāve created a function called generateQRCode(from:)
which returns an optional UIImage.
In this function, we first want to convert our string to a Data object (which is simply a MutableCollection of bytes). This object will contain our stringās representation using some given encoding. In this case, we use ISO Latin 1; however, ASCII or UTF-8 works too.
Now, create an instance of CoreImage filter using the parameter name āCIQRCodeGenerator.ā
Essentially, weāve initialized a CIFilter
object, one for the specific filter called āCIQRCodeGenerator.ā This parameter name lets us reference Swiftās built-in filter for QR code generation through the Core Image framework. After creating a filter with the CIFilter
method in Swift, you must call setDefaults()
or setValue(_:forKey:)
to set parameters individually.
After creating a filter with the CIFilter
method in Swift, you must call setDefaults()
or setValue(_:forKey:)
to set parameters individually.
This might seem esoteric, to some degree, and it probably should, given the underlying levels of complexity. Take a closer look at the next line:
Here, we pass our data
constant ā which is simply an encoded version of our string ā to set the value for the key āinputMessage.ā This step is crucial and it works in this manner because the parameters of a CIFilter
object are set and retrieved through the use of key-value pairs.
Done! Well, not quite.
To recap, weāve passed our generateQRCode(from:)
function a string which weāve then encoded into a data object. Then, weāve created a CIFilter
object of the specific kind āCIQRCodeGenerator.ā Finally, weāve used our data object to set the value for the key āinputMessageā which represents the data input used in our QR code generation. Essentially, weāve retrieved a specific template, gathered all of the necessary components, but still havenāt returned anything.
Donāt worry about the transform nonsense; weāll get to that in just a moment (weāre using it to get rid of the blur in our resulting QR code).
Focus on unwrapping the output. Why are we doing this? Itās because filter ā which is our CIFilter
ā returns an optional CIImage (again, feel free to disregard the .applying(transform)
at the end there, for now).
In this particular case, CIFilter
ultimately produces a CIImage object using a string as an input. In order to have the image properly displayed in the imageView
outlet, we cast it as a UIImage. Finally, we get the following:
Oh no! Why is our QR code so freaking blurry? Since our CIImage is made up of points, the resulting UIImage is scaled to fit our UIImageView
, which results in a lack of clarity. This is where the transform part comes in!
We create an affine transformation matrix which we will use to scale our QR code. This is simply a struct
used in drawing 2D graphics. In short, this matrix links two coordinate systems by specifying how points in one coordinate system map to points in another. Then, we apply it when we unwrap the resulting optional CIImage.
The key here are the two scale values ā x and y. Weāve set them both to 1, and this is precisely the reason why weāve created a QR code of such exceptionally poor quality. What if we try changing both values (scaleX
and scaleY
) to 100?
Weāve successfully scaled up our UIImage. To be honest, weāve simply used an arbitrarily large number. If we want to be more elaborate with the scaling, we can figure out our desired scaling factor programmatically. So what is this scaling factor?
Well, actually, itās always equal to the ratio of an image viewās width and the original QR codeās width. In our example, this translates to:
Weāve added three new lines of code. First, weāve created a CIImage object by calling outputImage
on our CIFilter
object. Since this method returns an optional value, weāve unwrapped it using a guard statement. Next, weāve set up two constants for our two axes (x and y). As mentioned above, scaleX
and scaleY
are simply equal to the ratios of our image viewās width and height and our QR codeās width and height, respectively. Finally, weāve passed these two ratios as parameters to CGAffineTransform
to get an adequately scaled affine transformation matrix (i.e. transform
). We then call applying(transform)
on our outputImage
to get the following result:
Another thing we couldāve done during our QR code generation is set the value for error correction. This is done via the key āinputCorrectionLevel.ā
This parameter controls the amount of additional data encoded in the output image to provide error correction. It is equal to āMā by default, and changing this parameter affects the resulting QR code shape. Higher levels result in larger output images but allow larger areas of the code to be damaged.
Thatās it for the basics! You have now mastered QR code generation in Swift.
Thereās a lot more to QR codes in Swift, but this is it for our tutorial. Thank you for reading this simple overview of QR generation in Swift!
Here are some useful references: