Commit 19f83876 authored by Anton Akhmerov's avatar Anton Akhmerov

Merge branch 'pylibdmtx-datamatrix-generation' into 'master'

Use pylibdmtx for datamatrix generation and fix datamatrix consistency

Closes #323 and #319

See merge request !158
parents bc760028 40e9257d
import sys
import os
from io import BytesIO
from reportlab.pdfgen import canvas
import PIL
from wand.image import Image
from wand.color import Color
from pystrich.datamatrix import DataMatrixEncoder
sys.path.append(os.getcwd())
def generate_datamatrix(exam_id, page_num, copy_num):
data = f'{exam_id}/{copy_num:04d}/{page_num:02d}'
from zesje.pdf_generation import generate_datamatrix # noqa: E402
from zesje.database import token_length # noqa: E402
image_bytes = DataMatrixEncoder(data).get_imagedata(cellsize=2)
return PIL.Image.open(BytesIO(image_bytes))
exam_token = "A" * token_length
copy_num = 1559
page_num = 0
datamatrix = generate_datamatrix(0, 0, 0)
datamatrix_x = datamatrix_y = 0
fontsize = 8
margin = 3
fontsize = 12
datamatrix_x = 0
datamatrix_y = fontsize
datamatrix = generate_datamatrix(0, 0, 0000)
imagesize = (datamatrix.width, 3 + fontsize + datamatrix.height)
datamatrix = generate_datamatrix(exam_token, page_num, copy_num)
imagesize = (datamatrix.width, fontsize + datamatrix.height)
result_pdf = BytesIO()
canv = canvas.Canvas(result_pdf, pagesize=imagesize)
canv.drawInlineImage(datamatrix, 0, 3 + fontsize)
canv.drawInlineImage(datamatrix, datamatrix_x, datamatrix_y)
canv.setFont('Helvetica', fontsize)
canv.drawString(0, 3, f" # 1519")
canv.drawString(datamatrix_x, datamatrix_y - (fontsize * 0.66),
f" # {copy_num}")
canv.showPage()
canv.save()
......@@ -36,7 +39,7 @@ canv.save()
result_pdf.seek(0)
# From https://stackoverflow.com/questions/27826854/python-wand-convert-pdf-to-png-disable-transparent-alpha-channel
with Image(file=result_pdf, resolution=80) as img:
with Image(width=img.width, height=img.height, background=Color("white")) as bg:
with Image(file=result_pdf, resolution=72) as img:
with Image(width=imagesize[0], height=imagesize[1], background=Color("white")) as bg:
bg.composite(img, 0, 0)
bg.save(filename="client/components/barcode_example.png")
client/components/barcode_example.png

383 Bytes | W: | H:

client/components/barcode_example.png

453 Bytes | W: | H:

client/components/barcode_example.png
client/components/barcode_example.png
client/components/barcode_example.png
client/components/barcode_example.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -32,7 +32,6 @@ dependencies:
- reportlab
- Wand
- Pillow # also scan processing
- pyStrich # TODO: can we replace this with stuff from pylibdmtx?
# Scan processing
- opencv-python
......
......@@ -10,7 +10,7 @@ from werkzeug.datastructures import FileStorage
from sqlalchemy.orm import selectinload
from ..pdf_generation import generate_pdfs, output_pdf_filename_format, join_pdfs, page_is_size
from ..database import db, Exam, ExamWidget, Submission
from ..database import db, Exam, ExamWidget, Submission, token_length
PAGE_FORMATS = {
"A4": (595.276, 841.89),
......@@ -478,8 +478,8 @@ class ExamPreview(Resource):
generate_pdfs(
exam_path,
exam.token[:5] + 'PREVIEW',
[1519],
"A" * token_length,
[1559],
[output_file],
student_id_widget.x, student_id_widget.y,
barcode_widget.x, barcode_widget.y
......
from io import BytesIO
from tempfile import NamedTemporaryFile
import PIL
from pdfrw import PdfReader, PdfWriter, PageMerge
from pystrich.datamatrix import DataMatrixEncoder
from pylibdmtx.pylibdmtx import encode
from reportlab.lib.units import mm
from reportlab.pdfgen import canvas
......@@ -16,9 +15,9 @@ def generate_pdfs(exam_pdf_file, exam_id, copy_nums, output_paths, id_grid_x,
"""
Generate the final PDFs from the original exam PDF.
To maintain a consistent size of the DataMatrix codes, adhere to (# of
letters in exam ID) + 2 * (# of digits in exam ID) = C for a certain
constant C. The reason for this is that pyStrich encodes two digits in as
To ensure the page information fits into the datamatrix grid, adhere to
(# of letters in exam ID) + 2 * (# of digits in exam ID) = C for a certain
constant C. The reason for this is that libdmtx encodes two digits in as
much space as one letter.
If maximum interchangeability with version 1 QR codes is desired (error
......@@ -155,9 +154,9 @@ def generate_datamatrix(exam_id, page_num, copy_num):
"""
Generates a DataMatrix code to be used on a page.
To maintain a consistent size of the DataMatrix codes, adhere to (# of
letters in exam ID) + 2 * (# of digits in exam ID) = C for a certain
constant C. The reason for this is that pyStrich encodes two digits in as
To ensure the page information fits into the datamatrix grid, adhere to
(# of letters in exam ID) + 2 * (# of digits in exam ID) = C for a certain
constant C. The reason for this is that pylibdmtx encodes two digits in as
much space as one letter.
If maximum interchangeability with version 1 QR codes is desired (error
......@@ -182,8 +181,10 @@ def generate_datamatrix(exam_id, page_num, copy_num):
data = f'{exam_id}/{copy_num:04d}/{page_num:02d}'
image_bytes = DataMatrixEncoder(data).get_imagedata(cellsize=2)
return PIL.Image.open(BytesIO(image_bytes))
encoded = encode(data.encode('utf-8'), size='18x18')
datamatrix = PIL.Image.frombytes('RGB', (encoded.width, encoded.height), encoded.pixels)
datamatrix = datamatrix.resize((44, 44)).convert('L')
return datamatrix
def _generate_overlay(canv, pagesize, exam_id, copy_num, num_pages, id_grid_x,
......@@ -192,9 +193,9 @@ def _generate_overlay(canv, pagesize, exam_id, copy_num, num_pages, id_grid_x,
Generates an overlay ('watermark') PDF, which can then be overlaid onto
the exam PDF.
To maintain a consistent size of the DataMatrix codes in the overlay,
To ensure the page information fits into the datamatrix grid in the overlay,
adhere to (# of letters in exam ID) + 2 * (# of digits in exam ID) = C for
a certain constant C. The reason for this is that pyStrich encodes two
a certain constant C. The reason for this is that pylibdmtx encodes two
digits in as much space as one letter.
If maximum interchangeability with version 1 QR codes is desired (error
......@@ -223,16 +224,16 @@ def _generate_overlay(canv, pagesize, exam_id, copy_num, num_pages, id_grid_x,
The y coordinate where the DataMatrix codes should be placed
"""
# Font settings for the copy number (printed under the datamatrix)
fontsize = 8
canv.setFont('Helvetica', fontsize)
# transform y-cooridate to different origin location
id_grid_y = pagesize[1] - id_grid_y
# ID grid on first page only
generate_id_grid(canv, id_grid_x, id_grid_y)
# Font settings for the copy number (printed under the datamatrix)
fontsize = 12
canv.setFont('Helvetica', fontsize)
for page_num in range(num_pages):
_add_corner_markers_and_bottom_bar(canv, pagesize)
......@@ -243,7 +244,7 @@ def _generate_overlay(canv, pagesize, exam_id, copy_num, num_pages, id_grid_x,
canv.drawInlineImage(datamatrix, datamatrix_x, datamatrix_y_adjusted)
canv.drawString(
datamatrix_x, datamatrix_y_adjusted - fontsize,
datamatrix_x, datamatrix_y_adjusted - (fontsize * 0.66),
f" # {copy_num}"
)
canv.showPage()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment