diff --git a/app/main/views.py b/app/main/views.py
index 469786635d03c95d8ca88ee35e049677b1a2c372..5faf01d950627bacdc9f73cbbfb89c5910323b95 100644
--- a/app/main/views.py
+++ b/app/main/views.py
@@ -12,6 +12,7 @@ This module implements the main blueprint.
 from flask import (Blueprint, render_template, jsonify)
 from flask_login import login_required
 from ..extensions import db
+from ..models import Action, Vendor, Model, Location, Status
 from .. import utils
 
 bp = Blueprint('main', __name__)
@@ -54,3 +55,16 @@ def retrieve_items():
 @login_required
 def index():
     return render_template('index.html')
+
+
+@bp.route('/qrcodes')
+@login_required
+def qrcodes():
+    codes = {}
+    for model in (Action, Vendor, Model, Location, Status):
+        items = db.session.query(model).order_by(model.name)
+        images = [{'name': item.name,
+                   'data': utils.image_to_base64(item.image())}
+                  for item in items]
+        codes[model.__name__] = images
+    return render_template('qrcodes.html', codes=codes)
diff --git a/app/templates/_helpers.html b/app/templates/_helpers.html
new file mode 100644
index 0000000000000000000000000000000000000000..efe2ae652c54d95be8b64caa4c6bd0d64e6391bf
--- /dev/null
+++ b/app/templates/_helpers.html
@@ -0,0 +1,3 @@
+{% macro nav_li(active) -%}
+<li {% if active %}class="active"{% endif %}>
+{%- endmacro %}
diff --git a/app/templates/base.html b/app/templates/base.html
index 0bb69b516cf61b9e0545070fcce1ccafd578db0b..4c13148d3c0fb88f913f1e0013b8c21ece4e11f9 100644
--- a/app/templates/base.html
+++ b/app/templates/base.html
@@ -1,5 +1,6 @@
 {%- extends "bootstrap/base.html" %}
 {% import "bootstrap/utils.html" as utils %}
+{% from "_helpers.html" import nav_li %}
 
 {% block head %}
   <meta charset="utf-8">
@@ -32,6 +33,8 @@
       <div class="navbar-collapse collapse">
         <ul class="nav navbar-nav">
           {% set path = request.path %}
+          {{ nav_li(path in ("/", "/index", "/index/")) }}<a href="{{ url_for('main.index') }}">Index</a></li>
+	  {{ nav_li(path == "/qrcodes") }}<a href="{{ url_for('main.qrcodes') }}">QR Codes</a></li>
           {% if current_user.is_authenticated and current_user.is_admin %}
             <li><a href="{{ url_for('admin.index') }}">Admin</a></li>
           {% endif %}
diff --git a/app/templates/qrcodes.html b/app/templates/qrcodes.html
new file mode 100644
index 0000000000000000000000000000000000000000..de29285b9629929defa970f05d155e9701d640c4
--- /dev/null
+++ b/app/templates/qrcodes.html
@@ -0,0 +1,22 @@
+{%- extends "base.html" %}
+{% import "bootstrap/wtf.html" as wtf %}
+
+{% block title %}QR Codes{% endblock %}
+
+{% block main %}
+  {% for name, images in codes.items() %}
+  <div class="row">
+    <h2>{{ name }} codes</h2>
+    {% for image in images %}
+    <div class="col-md-3">
+      <div class="thumbnail">
+        <img src="data:image/png;base64,{{ image.data }}"/>
+        <div class="caption">
+          <h3>{{ image.name }}</h3>
+        </div>
+      </div>
+    </div>
+    {% endfor %}
+  </div>
+  {% endfor %}
+{%- endblock %}
diff --git a/app/utils.py b/app/utils.py
index b93c5ba26edd69cbee2fe1afbeebfbd26a1fb571..779a6f5621409e6dd06b552d00176e40d8e59d3b 100644
--- a/app/utils.py
+++ b/app/utils.py
@@ -9,6 +9,8 @@ This module implements utility functions.
 :license: BSD 2-Clause, see LICENSE for more details.
 
 """
+import base64
+import io
 import hashlib
 import uuid
 
@@ -39,3 +41,15 @@ class InventoryError(Exception):
 def compute_hash(string):
     md5 = hashlib.md5(string.encode()).hexdigest()
     return uuid.UUID(md5)
+
+
+def image_to_base64(img, format='PNG'):
+    """Convert a Pillow image to a base64 string
+
+    :param img: Pillow image
+    :param format: format of the image to use
+    :returns str: image as base64 string
+    """
+    buf = io.BytesIO()
+    img.save(buf, format=format)
+    return base64.b64encode(buf.getvalue()).decode('ascii')