CODEX

Exporting QR Codes in Flutter

Alex Nekrasov
Jan 12 · 4 min read

QR codes are an easy way to exchange small amounts of data between smartphones (data reader) and any media (data provider). They are easy to generate and to scan, you can customize them, add logos, change colors, and make them “yours”.

Image for post
Image for post
Photo by Albert Hu on Unsplash

Two smartphones with Flutter apps can easily generate and scan QR codes, but generating QR codes for export is a little bit trickier.

Scanning QR codes with Flutter

Let’s start with scanning. Any iOS or Android device with a camera can scan and decode QR codes. As an example, we’ll use the flutter_qr_bar_scanner.

It provides a widget showing the camera feed — QRBarScannerCamera. You see what you scan and you get a callback when the code is recognized:

QRBarScannerCamera(
onError: (context, error) => Text(
error.toString(),
style: TextStyle(color: Colors.red),
),
qrCodeCallback: (code) {
_qrCallback(code);
},
)

The example above is from the official page of the scanner library.

Showing QR codes with Flutter

Showing QR codes on the screen is even easier. The library qr_flutter includes a widget, which can show any QR code with only 3 lines of code:

QrImage(
data: 'Any text here',
)

You can insert this widget into a container of any size, you can add a logo and do other customizations.

But what if we need to save the QR code to the gallery or send it to a printer? One option is to take a screenshot, either using hardware buttons or using Flutter methods. But the quality of the picture we’ll get depends on the screen size. Small smartphones will give us worse quality pictures than an iPad Pro, for example. You can guess that it is not what we want.

Saving QR codes to files

Let’s generate a PNG file with a QR code and save it to a temporary file. It’s not a documented function, so we’ll have to be creative. This is our QR code string:

String qr = 'Any text here';

Import qr_flutter library:

import 'package:qr_flutter/qr_flutter.dart';

First, we need to validate the code. As a result, we’ll get either aQrCode structure or an error:

final qrValidationResult = QrValidator.validate(
data: qr,
version: QrVersions.auto,
errorCorrectionLevel: QrErrorCorrectLevel.L,
);

We can confirm that the code is valid:

qrValidationResult.status == QrValidationStatus.valid

and show an error if necessary:

qrValidationResult.error

If the verification is successful, we get our QrCode:

final qrCode = qrValidationResult.qrCode;

The next step is to create a Painter, in our case, it will be QrPainter. It’s a subclass of CustomPainter. In Flutter CustomPainter is a very powerful tool allowing you to create your own components, not as a combination of existing widgets, but drawing them basically by pixels.

final painter = QrPainter.withQr(
qr: qrCode,
color: const Color(0xFF000000),
gapless: true,
embeddedImageStyle: null,
embeddedImage: null,
);

As you can see, you can change colors or imbed images into QR codes. At this point, we don’t set image sizes. CustomPainter is supposed to be flexible, it can be embedded into a container of any size, so we get the final image at a later stage.

Now let’s get a random file name:

Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
final ts = DateTime.now().millisecondsSinceEpoch.toString();
String path = '$tempPath/$ts.png';

To get a temporary directory we use the function getTemporaryDirectory from the path_provider library. The file name is a current timestamp in milliseconds with apng extension.

Alternatively, you can give the file a name matching the QR code, but don’t forget that some symbols are not allowed, so you need either to remove them from the name or escape.

Now we’re ready to export a QR code image to a file:

final picData = await painter.toImageData(2048, format: ui.ImageByteFormat.png);
await writeToFile(picData, path);

Separately we need to add awriteToFile function:

Future<void> writeToFile(ByteData data, String path) async {
final buffer = data.buffer;
await File(path).writeAsBytes(
buffer.asUint8List(data.offsetInBytes, data.lengthInBytes)
);
}

Congratulations! The file path contains a 2048x2048 PNG file with your QR code.

Sharing your file

Now that you have a file you can share it. Sharing is not only sending it to social networks or messengers, it’s also printing, saving to files, and other actions.

For this, we will use theshare library. Let’s assume that our previous code is a function with the name createQrPicture and it returns String with image path:

Future<String> createQrPicture(String qr) async {
...
return path;
}

We can share our image with this code:

String path = await createQrPicture(qr);

await Share.shareFiles(
[path],
mimeTypes: ["image/png"],
subject: 'My QR code',
text: 'Please scan me'
);

Saving to Gallery

If you need to save your image to the Gallery (Photo Library) without interaction with the user, it can be done using thegallery_saver library.

String path = await createQrPicture(qr);

final success = await GallerySaver.saveImage(path);

Scaffold.of(context).showSnackBar(SnackBar(
content: success ? Text('Image saved to Gallery') : Text('Error saving image'),
));

That’s it! I hope you enjoyed it. If so, don’t forget to clap and see you next time!

CodeX

Everything connected with Code & Tech!

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store