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