diff --git a/src/pretix/base/pdf.py b/src/pretix/base/pdf.py index 5e9834ead..dd1541d26 100644 --- a/src/pretix/base/pdf.py +++ b/src/pretix/base/pdf.py @@ -822,6 +822,10 @@ class Renderer: kwargs = {} if o.get('nowhitespace', False): kwargs['barBorder'] = 0 + + if o.get('color'): + kwargs['barFillColor'] = Color(o['color'][0] / 255, o['color'][1] / 255, o['color'][2] / 255) + qrw = QrCodeWidget(content, barLevel=level, barHeight=reqs, barWidth=reqs, **kwargs) d = Drawing(reqs, reqs) d.add(qrw) diff --git a/src/pretix/control/templates/pretixcontrol/pdf/index.html b/src/pretix/control/templates/pretixcontrol/pdf/index.html index 72eaee686..1424ca3ff 100644 --- a/src/pretix/control/templates/pretixcontrol/pdf/index.html +++ b/src/pretix/control/templates/pretixcontrol/pdf/index.html @@ -322,6 +322,17 @@ id="toolbox-squaresize"> +
+
+
+
+ + + +
+
+
diff --git a/src/pretix/plugins/ticketoutputpdf/migrations/0012_alter_ticketlayout_layout.py b/src/pretix/plugins/ticketoutputpdf/migrations/0012_alter_ticketlayout_layout.py new file mode 100644 index 000000000..4bfa93ad3 --- /dev/null +++ b/src/pretix/plugins/ticketoutputpdf/migrations/0012_alter_ticketlayout_layout.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.17 on 2024-12-29 12:36 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ticketoutputpdf', '0011_sales_channels_remove_old_fields'), + ] + + operations = [ + migrations.AlterField( + model_name='ticketlayout', + name='layout', + field=models.TextField(default='[\n {\n "type": "barcodearea",\n "page": 1,\n "left": "130.40",\n "bottom": "204.50",\n "size": "64.00",\n "content": "secret",\n "text": "",\n "text_i18n": {},\n "nowhitespace": false,\n "color": [\n 0,\n 0,\n 0,\n 1\n ]\n },\n {\n "type": "poweredby",\n "page": 1,\n "left": "88.72",\n "bottom": "10.00",\n "size": "20.00",\n "content": "dark"\n },\n {\n "type": "textcontainer",\n "page": 1,\n "locale": "",\n "left": "16.35",\n "bottom": "272.09",\n "fontsize": "14.0",\n "lineheight": "1",\n "color": [\n 0,\n 0,\n 0,\n 1\n ],\n "fontfamily": "Open Sans",\n "bold": false,\n "italic": false,\n "width": "177.07",\n "height": "11.80",\n "content": "event_name",\n "text": "Sample event name",\n "text_i18n": {},\n "rotation": 0,\n "align": "left",\n "verticalalign": "middle",\n "autoresize": true,\n "splitlongwords": true\n },\n {\n "type": "textcontainer",\n "page": 1,\n "locale": "",\n "left": "16.35",\n "bottom": "261.77",\n "fontsize": "13.0",\n "lineheight": "1",\n "color": [\n 0,\n 0,\n 0,\n 1\n ],\n "fontfamily": "Open Sans",\n "bold": false,\n "italic": false,\n "width": "113.03",\n "height": "7.83",\n "content": "itemvar",\n "text": "Sample product – sample variation",\n "text_i18n": {},\n "rotation": 0,\n "align": "left",\n "verticalalign": "middle",\n "autoresize": true,\n "splitlongwords": true\n },\n {\n "type": "textcontainer",\n "page": 1,\n "locale": "",\n "left": "16.35",\n "bottom": "251.30",\n "fontsize": "13.0",\n "lineheight": "1",\n "color": [\n 0,\n 0,\n 0,\n 1\n ],\n "fontfamily": "Open Sans",\n "bold": false,\n "italic": false,\n "width": "113.03",\n "height": "7.83",\n "content": "attendee_name",\n "text": "Dr John Doe",\n "text_i18n": {},\n "rotation": 0,\n "align": "left",\n "verticalalign": "middle",\n "autoresize": true,\n "splitlongwords": true\n },\n {\n "type": "textcontainer",\n "page": 1,\n "locale": "",\n "left": "16.35",\n "bottom": "240.30",\n "fontsize": "13.0",\n "lineheight": "1",\n "color": [\n 0,\n 0,\n 0,\n 1\n ],\n "fontfamily": "Open Sans",\n "bold": false,\n "italic": false,\n "width": "113.03",\n "height": "7.83",\n "content": "event_begin",\n "text": "2017-05-31 20:00",\n "text_i18n": {},\n "rotation": 0,\n "align": "left",\n "verticalalign": "middle",\n "autoresize": true,\n "splitlongwords": true\n },\n {\n "type": "textcontainer",\n "page": 1,\n "locale": "",\n "left": "16.35",\n "bottom": "231.30",\n "fontsize": "13.0",\n "lineheight": "1",\n "color": [\n 0,\n 0,\n 0,\n 1\n ],\n "fontfamily": "Open Sans",\n "bold": false,\n "italic": false,\n "width": "113.03",\n "height": "7.83",\n "content": "seat",\n "text": "Ground floor, Row 3, Seat 4",\n "text_i18n": {},\n "rotation": 0,\n "align": "left",\n "verticalalign": "middle",\n "autoresize": true,\n "splitlongwords": true\n },\n {\n "type": "textcontainer",\n "page": 1,\n "locale": "",\n "left": "16.35",\n "bottom": "203.43",\n "fontsize": "13.0",\n "lineheight": "1",\n "color": [\n 0,\n 0,\n 0,\n 1\n ],\n "fontfamily": "Open Sans",\n "bold": false,\n "italic": false,\n "width": "113.03",\n "height": "25.70",\n "content": "event_location",\n "text": "Random City",\n "text_i18n": {},\n "rotation": 0,\n "align": "left",\n "verticalalign": "bottom",\n "autoresize": true,\n "splitlongwords": true\n },\n {\n "type": "textcontainer",\n "page": 1,\n "locale": "",\n "left": "101.50",\n "bottom": "193.33",\n "fontsize": "13.0",\n "lineheight": "1",\n "color": [\n 0,\n 0,\n 0,\n 1\n ],\n "fontfamily": "Open Sans",\n "bold": false,\n "italic": false,\n "width": "91.93",\n "height": "7.83",\n "content": "secret",\n "text": "tdmruoekvkpbv1o2mv8xccvqcikvr58u",\n "text_i18n": {},\n "rotation": 0,\n "align": "left",\n "verticalalign": "middle",\n "autoresize": true,\n "splitlongwords": true\n },\n {\n "type": "textcontainer",\n "page": 1,\n "locale": "",\n "left": "51.50",\n "bottom": "193.33",\n "fontsize": "13.0",\n "lineheight": "1",\n "color": [\n 0,\n 0,\n 0,\n 1\n ],\n "fontfamily": "Open Sans",\n "bold": false,\n "italic": false,\n "width": "47.38",\n "height": "7.83",\n "content": "price",\n "text": "123.45 EUR",\n "text_i18n": {},\n "rotation": 0,\n "align": "right",\n "verticalalign": "middle",\n "autoresize": true,\n "splitlongwords": true\n },\n {\n "type": "textcontainer",\n "page": 1,\n "locale": "",\n "left": "16.50",\n "bottom": "193.33",\n "fontsize": "13.0",\n "lineheight": "1",\n "color": [\n 0,\n 0,\n 0,\n 1\n ],\n "fontfamily": "Open Sans",\n "bold": false,\n "italic": false,\n "width": "32.32",\n "height": "7.83",\n "content": "order",\n "text": "A1B2C",\n "text_i18n": {},\n "rotation": 0,\n "align": "left",\n "verticalalign": "middle",\n "autoresize": true,\n "splitlongwords": true\n }\n]'), + ), + ] diff --git a/src/pretix/plugins/ticketoutputpdf/models.py b/src/pretix/plugins/ticketoutputpdf/models.py index 337e69d53..07f7fb9f3 100644 --- a/src/pretix/plugins/ticketoutputpdf/models.py +++ b/src/pretix/plugins/ticketoutputpdf/models.py @@ -37,7 +37,13 @@ DEFAULT_TICKET_LAYOUT = '''[ "content": "secret", "text": "", "text_i18n": {}, - "nowhitespace": false + "nowhitespace": false, + "color": [ + 0, + 0, + 0, + 1 + ] }, { "type": "poweredby", diff --git a/src/pretix/static/pretixcontrol/js/ui/editor.js b/src/pretix/static/pretixcontrol/js/ui/editor.js index c9474519d..d91f587a7 100644 --- a/src/pretix/static/pretixcontrol/js/ui/editor.js +++ b/src/pretix/static/pretixcontrol/js/ui/editor.js @@ -313,6 +313,7 @@ var editor = { content: o.content, }); } else if (o.type === "barcodearea") { + col = (new fabric.Color(o.fill))._source; d.push({ type: "barcodearea", page: editor.pdf_page_number, @@ -323,6 +324,7 @@ var editor = { text: o.text, text_i18n: o.text_i18n || {}, nowhitespace: o.nowhitespace || false, + color: col, }); } else if (o.type === "poweredby") { d.push({ @@ -349,6 +351,10 @@ var editor = { o.content = d.content; o.scaleToHeight(editor._mm2px(d.size)); o.nowhitespace = d.nowhitespace || false; + if (!d.color) { + d.color = [0, 0, 0, 1]; + } + o.set('fill', 'rgb(' + d.color[0] + ',' + d.color[1] + ',' + d.color[2] + ')'); if (d.content === "other") { o.text = d.text } else if (d.content === "other_i18n") { @@ -640,6 +646,8 @@ var editor = { })); }); } else if (o.type === "barcodearea") { + var col = (new fabric.Color(o.fill))._source; + $("#toolbox-qrcolor").val("#" + ((1 << 24) + (col[0] << 16) + (col[1] << 8) + col[2]).toString(16).slice(1)); $("#toolbox-squaresize").val(editor._px2mm(o.height * o.scaleY).toFixed(2)); $("#toolbox-qrwhitespace").prop("checked", o.nowhitespace || false); } else if (o.type === "imagearea") { @@ -742,6 +750,7 @@ var editor = { o.set('scaleX', 1); o.set('scaleY', 1); o.set('top', new_top) + o.set('fill', $("#toolbox-qrcolor").val()); o.nowhitespace = $("#toolbox-qrwhitespace").prop("checked") || false; $("#toolbox-content-other").toggle($("#toolbox-content").val() === "other"); @@ -1028,7 +1037,7 @@ var editor = { width: 100, height: 100, lockRotation: true, - fill: '#666', + fill: '#000', content: $(this).attr("data-content"), text: '', nowhitespace: true, diff --git a/src/pretix/static/schema/pdf-layout.schema.json b/src/pretix/static/schema/pdf-layout.schema.json index 98596fcb9..e501272c9 100644 --- a/src/pretix/static/schema/pdf-layout.schema.json +++ b/src/pretix/static/schema/pdf-layout.schema.json @@ -80,6 +80,17 @@ "nowhitespace": { "description": "Whether a barcode should be rendered without margins. Only used for type 'barcodearea'.", "type": "boolean" + }, + "color": { + "description": "QR color as a tuple of three integers in the 0-255 range and one float in the 0-1 range. The last value (alpha) is ignored by the current implementation but might be used in the future.", + "type": "array", + "items": { + "type": "number", + "minimum": 0, + "maximum": 255 + }, + "minItems": 3, + "maxItems": 4 } }, "additionalProperties": false