Skip to content

Commit

Permalink
Feat: QR code generator (#137)
Browse files Browse the repository at this point in the history
  • Loading branch information
thekaveman authored Sep 16, 2024
2 parents d9078c3 + ffaed3c commit a752e84
Show file tree
Hide file tree
Showing 11 changed files with 227 additions and 6 deletions.
5 changes: 3 additions & 2 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ RUN apt-get install -y ruby-full && gem install bundler
RUN python -m pip install --upgrade pip

RUN useradd --create-home --shell /bin/bash $USER && \
mkdir /home/$USER/site && \
chown -R $USER /home/$USER

WORKDIR /home/$USER/site
Expand All @@ -20,5 +21,5 @@ RUN bundle install
USER $USER
ENV PATH "$PATH:/home/$USER/.local/bin"

COPY .devcontainer/requirements.txt .devcontainer/requirements.txt
RUN pip install --no-cache-dir -r .devcontainer/requirements.txt
COPY LICENSE pyproject.toml README.md ./
RUN pip install -e .[dev,qr_codes]
5 changes: 4 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "compiler/datadonuts.la",
"dockerComposeFile": "compose.yml",
"dockerComposeFile": "../compose.yml",
"service": "site",
"workspaceFolder": "/home/compiler/site",
"postAttachCommand": ["/bin/bash", ".devcontainer/postAttach.sh"],
Expand All @@ -18,6 +18,9 @@
"eamodio.gitlens",
"esbenp.prettier-vscode",
"mhutchie.git-graph",
"ms-python.python",
"ms-python.black-formatter",
"ms-python.flake8",
"redhat.vscode-xml",
"sissel.shopify-liquid",
"tamasfe.even-better-toml"
Expand Down
1 change: 0 additions & 1 deletion .devcontainer/requirements.txt

This file was deleted.

2 changes: 2 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[flake8]
max-line-length = 127
66 changes: 66 additions & 0 deletions .github/workflows/generate-qr-code.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Generate QR code
on:
workflow_dispatch:
inputs:
data:
description: "The data for the QR code, e.g. a URL"
required: true
type: string
color:
description: "The color of the QR code (hex or name), defaults to black"
default: "#000000"
required: false
type: string
background:
description: "The background color of the QR code in hex format, defaults to transparent"
default: "transparent"
required: false
type: string
size:
description: "The size of the QR code from 1 (smallest) to 10 (largest), defaults to 4"
default: 4
required: false
type: choice
options:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10

jobs:
generate-qr-code:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
cache-dependency-path: "pyproject.toml"

- name: Install dependencies
run: pip install -e .[qr_codes]

- name: Generate QR code
run: |
python qr_codes/main.py \
--color="${{ inputs.color }}" \
--background="${{ inputs.background }}" \
--size="${{ inputs.size }}" \
${{ inputs.data }} \
qr-code.png
- name: Upload QR code as artifact
uses: actions/upload-artifact@v4
with:
name: qr-code.png
path: qr-code.png
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
.idea/
_site/
.DS_Store
qr_codes/*.png
!qr_codes/datadonuts.la.png
4 changes: 2 additions & 2 deletions .devcontainer/compose.yml → compose.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
services:
site:
build:
context: ..
context: .
dockerfile: .devcontainer/Dockerfile
command: sleep infinity
volumes:
- ..:/home/compiler/site
- .:/home/compiler/site
39 changes: 39 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
[project]
name = "data-donuts"
description = "Administrative tasks for the Data + Donuts team"
version = "1.0.0"
readme = "README.md"
license = { file = "LICENSE" }
classifiers = ["Programming Language :: Python :: 3 :: Only"]
requires-python = ">=3.11"
dependencies = []

[project.urls]
code = "https://github.com/compilerla/data-donuts"
tracker = "https://github.com/compilerla/data-donuts/issues"

[project.optional-dependencies]
dev = [
"black",
"build",
"flake8",
"ipykernel",
"pre-commit"
]
qr_codes = [
"pypng==0.20220715.0",
"qrcode[pil]==7.4.2",
"typing_extensions==4.12.2"
]

[build-system]
requires = ["setuptools>=65"]
build-backend = "setuptools.build_meta"

[tool.black]
line-length = 127
target-version = ['py311']
include = '\.pyi?$'

[tool.setuptools]
packages = []
42 changes: 42 additions & 0 deletions qr_codes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Generate QR codes

> Generate a QR code as an PNG file
## Run in GitHub

1. Go to the `Actions` tab at the top of this repository
1. In the left bar, select the `Generate QR code` workflow
1. Click the gray `Run workflow` button on the right side, providing inputs as-needed:

- `branch` should be left as `main`
- `data` is required, this is the URL the QR code should point to
- `color`, `background`, and `size` are optional

1. Click the green `Run workflow` button
1. Refresh the page to see the in-progress workflow run
1. When the workflow has completed (look for the green check mark), click the run
1. In the bottom pane under `Artifacts`, find a link to download the QR code image (downloads a ZIP file with the image inside)

## Run locally

1. Open this repository's devcontainer in VS Code
2. Change into the `qr_codes` directory
3. Run the helper script

```bash
$ python main.py -h
usage: main.py [-h] [--color COLOR] [--background BACKGROUND] [--size SIZE] data output

Generate a QR code as an PNG file

positional arguments:
data The data to encode as a QR code
output Path to an PNG file where the QR code is written

options:
-h, --help show this help message and exit
--color COLOR The color of the QR code in hex format, by default black
--background BACKGROUND
The background color of the QR code in hex format, by default transparent
--size SIZE The QR code size from 1-10, by default 4
```
Binary file added qr_codes/datadonuts.la.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
67 changes: 67 additions & 0 deletions qr_codes/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import argparse
import sys

from PIL import ImageColor
import qrcode
from qrcode.image.styledpil import StyledPilImage
from qrcode.image.styles.colormasks import SolidFillColorMask


def generate(args: argparse.Namespace):
qr = qrcode.QRCode(version=args.size, image_factory=StyledPilImage)
qr.add_data(args.data)
qr.make(fit=True)

# convert hex colors to RGB tuples, adding alpha channel to the front_color
# alpha = 0 means transparent
# alpha = 255 means opaque
front_color = ImageColor.getrgb(args.color) + (255,)
back_color = (
# convert the string "transparent" to RGBA with full transparency
(255, 255, 255, 0)
if args.background == "transparent"
# if we have a background color, it doesn't need transparency/alpha
else ImageColor.getrgb(args.background)
)
color_mask = SolidFillColorMask(back_color, front_color)

img = qr.make_image(color_mask=color_mask)
img.save(args.output)


def main(argv=None):
argv = argv if argv is not None else sys.argv[1:]
parser = argparse.ArgumentParser(
prog="main.py",
description="Generate a QR code as an PNG file",
)

parser.add_argument("data", help="The data to encode as a QR code")
parser.add_argument(
"output", help="Path to an PNG file where the QR code is written"
)
parser.add_argument(
"--color",
help="The color of the QR code in hex format, by default black",
default="#000000",
)
parser.add_argument(
"--background",
help="The background color of the QR code in hex format, by default transparent",
default="transparent",
)
parser.add_argument(
"--size",
help="The QR code size from 1-10, by default 4",
default=4,
)

args = parser.parse_args(argv)

generate(args)

return 0


if __name__ == "__main__":
raise SystemExit(main())

0 comments on commit a752e84

Please sign in to comment.