Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e31449c99a | ||
|
|
ad78464341 | ||
|
|
ae639c69c1 | ||
|
|
959dcfa062 | ||
|
|
aa35c8feb0 | ||
|
|
6b1b83b4a5 | ||
|
|
3b16771cf7 | ||
|
|
29cd12358e | ||
|
|
5818bdf812 | ||
|
|
7cb0d7de12 | ||
|
|
7f60e01b9a | ||
|
|
f70b527f7c | ||
|
|
4f45656976 | ||
|
|
310f576108 |
@@ -0,0 +1,22 @@
|
|||||||
|
name: Publish to Comfy registry
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
paths:
|
||||||
|
- "pyproject.toml"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish-node:
|
||||||
|
name: Publish Custom Node to registry
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Publish Custom Node
|
||||||
|
uses: Comfy-Org/publish-node-action@main
|
||||||
|
with:
|
||||||
|
## Add your own personal access token to your Github Repository secrets and reference it here.
|
||||||
|
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
|
||||||
@@ -35,6 +35,7 @@ A dynamically sized QR code without any resampling scaled by the text length, th
|
|||||||
* `Quartile` - 25% error correction.
|
* `Quartile` - 25% error correction.
|
||||||
* `High` - 30% error correction.
|
* `High` - 30% error correction.
|
||||||
* `border` - The border size (In multiples of `module` widths)
|
* `border` - The border size (In multiples of `module` widths)
|
||||||
|
* `module_drawer` - The shape the QR code modules should be. The default is `square`, but see [Alternate Module Drawers](#alternate-module-drawers) below for new examples.
|
||||||
|
|
||||||
#### Outputs
|
#### Outputs
|
||||||
|
|
||||||
@@ -74,6 +75,7 @@ A QR code fixed to specific output dimensions through image resampling.
|
|||||||
* `Hamming` - Hamming interpolation
|
* `Hamming` - Hamming interpolation
|
||||||
* `Lanczos` - Lanczos interpolation
|
* `Lanczos` - Lanczos interpolation
|
||||||
* `Nearest` - Nearest Neighbor interpolation
|
* `Nearest` - Nearest Neighbor interpolation
|
||||||
|
* `module_drawer` - The shape the QR code modules should be. The default is `square`, but see [Alternate Module Drawers](#alternate-module-drawers) below for new examples.
|
||||||
|
|
||||||
#### Outputs
|
#### Outputs
|
||||||
|
|
||||||
@@ -129,6 +131,16 @@ And then aggressively increasing the strength of the ControlNet on only the erro
|
|||||||
|
|
||||||
Any workflow in the example that ends with "validated" (and a few image examples) assume the installation of the [scanning pack](https://gitlab.com/sofuego-comfy-nodes/ComfyQR-scanning-nodes) as well.
|
Any workflow in the example that ends with "validated" (and a few image examples) assume the installation of the [scanning pack](https://gitlab.com/sofuego-comfy-nodes/ComfyQR-scanning-nodes) as well.
|
||||||
|
|
||||||
|
## Alternate Module Drawers
|
||||||
|
|
||||||
|
The QR generation nodes now support alternate module styles. Experiment using different ones for greater flexibility during generation.
|
||||||
|
|
||||||
|
| Square | Gapped Square | Circle | Rounded | Vertical bars | Horizontal bars |
|
||||||
|
|:---: | :---: | :---: | :---: | :---: | :---: |
|
||||||
|
|  |  |  |  |  |  |
|
||||||
|
|
||||||
|
**Note** _Even unaltered non square styles will inherently register small deviations from RMSE values and possible minute deviations for correlations when using the [Mask QR Errors](#mask-qr-errors) node. When information is extracted, the `source_qr` values are rounded so that they can only be 0 or 1 (to allow alternate drawers to be used as inputs) and matched against the unrounded aggregation of the `modified_qr` values._
|
||||||
|
|
||||||
## Future updates
|
## Future updates
|
||||||
|
|
||||||
If the solution is clean enough and if it can definitively improve scannability, there may be additional plans for the seperation of alignment patterns (based on `module_size`, `border`, and `QR_VERSION`) for more advanced workflows.
|
If the solution is clean enough and if it can definitively improve scannability, there may be additional plans for the seperation of alignment patterns (based on `module_size`, `border`, and `QR_VERSION`) for more advanced workflows.
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 909 KiB After Width: | Height: | Size: 907 KiB |
|
Before Width: | Height: | Size: 961 KiB After Width: | Height: | Size: 961 KiB |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"last_node_id": 51,
|
"last_node_id": 52,
|
||||||
"last_link_id": 114,
|
"last_link_id": 117,
|
||||||
"nodes": [
|
"nodes": [
|
||||||
{
|
{
|
||||||
"id": 19,
|
"id": 19,
|
||||||
@@ -204,7 +204,7 @@
|
|||||||
],
|
],
|
||||||
"size": {
|
"size": {
|
||||||
"0": 210,
|
"0": 210,
|
||||||
"1": 82
|
"1": 106
|
||||||
},
|
},
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 1,
|
"order": 1,
|
||||||
@@ -212,31 +212,24 @@
|
|||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"name": "COMBO",
|
"name": "COMBO",
|
||||||
"type": "Http,Https,None",
|
"type": "COMBO",
|
||||||
"links": [
|
"links": [
|
||||||
46
|
46
|
||||||
],
|
],
|
||||||
"slot_index": 0,
|
"slot_index": 0,
|
||||||
"widget": {
|
"widget": {
|
||||||
"name": "protocol",
|
"name": "protocol"
|
||||||
"config": [
|
|
||||||
[
|
|
||||||
"Http",
|
|
||||||
"Https",
|
|
||||||
"None"
|
|
||||||
],
|
|
||||||
{
|
|
||||||
"default": "Https"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "Protocol",
|
"title": "Protocol",
|
||||||
"properties": {},
|
"properties": {
|
||||||
|
"Run widget replace on values": false
|
||||||
|
},
|
||||||
"widgets_values": [
|
"widgets_values": [
|
||||||
"Https",
|
"Https",
|
||||||
"fixed"
|
"fixed",
|
||||||
|
""
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -262,18 +255,14 @@
|
|||||||
],
|
],
|
||||||
"slot_index": 0,
|
"slot_index": 0,
|
||||||
"widget": {
|
"widget": {
|
||||||
"name": "text",
|
"name": "text"
|
||||||
"config": [
|
|
||||||
"STRING",
|
|
||||||
{
|
|
||||||
"multiline": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "URL",
|
"title": "URL",
|
||||||
"properties": {},
|
"properties": {
|
||||||
|
"Run widget replace on values": false
|
||||||
|
},
|
||||||
"widgets_values": [
|
"widgets_values": [
|
||||||
"gitlab.com/sofuego-comfy-nodes/comfy-qr-validation-nodes"
|
"gitlab.com/sofuego-comfy-nodes/comfy-qr-validation-nodes"
|
||||||
]
|
]
|
||||||
@@ -290,7 +279,7 @@
|
|||||||
"1": 46
|
"1": 46
|
||||||
},
|
},
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 12,
|
"order": 14,
|
||||||
"mode": 0,
|
"mode": 0,
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
@@ -326,10 +315,10 @@
|
|||||||
647.9219000000045,
|
647.9219000000045,
|
||||||
458.3673000000005
|
458.3673000000005
|
||||||
],
|
],
|
||||||
"size": [
|
"size": {
|
||||||
315,
|
"0": 315,
|
||||||
474.00000762939453
|
"1": 474
|
||||||
],
|
},
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 25,
|
"order": 25,
|
||||||
"mode": 0,
|
"mode": 0,
|
||||||
@@ -427,7 +416,7 @@
|
|||||||
"1": 106
|
"1": 106
|
||||||
},
|
},
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 13,
|
"order": 12,
|
||||||
"mode": 0,
|
"mode": 0,
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
@@ -435,16 +424,7 @@
|
|||||||
"type": "INT",
|
"type": "INT",
|
||||||
"link": 103,
|
"link": 103,
|
||||||
"widget": {
|
"widget": {
|
||||||
"name": "width",
|
"name": "width"
|
||||||
"config": [
|
|
||||||
"INT",
|
|
||||||
{
|
|
||||||
"default": 512,
|
|
||||||
"min": 1,
|
|
||||||
"max": 8192,
|
|
||||||
"step": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -452,16 +432,7 @@
|
|||||||
"type": "INT",
|
"type": "INT",
|
||||||
"link": 104,
|
"link": 104,
|
||||||
"widget": {
|
"widget": {
|
||||||
"name": "height",
|
"name": "height"
|
||||||
"config": [
|
|
||||||
"INT",
|
|
||||||
{
|
|
||||||
"default": 512,
|
|
||||||
"min": 1,
|
|
||||||
"max": 8192,
|
|
||||||
"step": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -503,20 +474,10 @@
|
|||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
"name": "protocol",
|
"name": "protocol",
|
||||||
"type": "Http,Https,None",
|
"type": "COMBO",
|
||||||
"link": 46,
|
"link": 46,
|
||||||
"widget": {
|
"widget": {
|
||||||
"name": "protocol",
|
"name": "protocol"
|
||||||
"config": [
|
|
||||||
[
|
|
||||||
"Http",
|
|
||||||
"Https",
|
|
||||||
"None"
|
|
||||||
],
|
|
||||||
{
|
|
||||||
"default": "Https"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -524,13 +485,7 @@
|
|||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"link": 47,
|
"link": 47,
|
||||||
"widget": {
|
"widget": {
|
||||||
"name": "text",
|
"name": "text"
|
||||||
"config": [
|
|
||||||
"STRING",
|
|
||||||
{
|
|
||||||
"multiline": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -591,7 +546,8 @@
|
|||||||
"#000000",
|
"#000000",
|
||||||
"#FFFFFF",
|
"#FFFFFF",
|
||||||
"High",
|
"High",
|
||||||
1
|
1,
|
||||||
|
"Square"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -647,7 +603,7 @@
|
|||||||
"1": 166
|
"1": 166
|
||||||
},
|
},
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 20,
|
"order": 19,
|
||||||
"mode": 0,
|
"mode": 0,
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
@@ -718,7 +674,7 @@
|
|||||||
{
|
{
|
||||||
"name": "destination",
|
"name": "destination",
|
||||||
"type": "MASK",
|
"type": "MASK",
|
||||||
"link": 91
|
"link": 115
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "source",
|
"name": "source",
|
||||||
@@ -783,113 +739,6 @@
|
|||||||
"Node name for S&R": "MaskToImage"
|
"Node name for S&R": "MaskToImage"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": 3,
|
|
||||||
"type": "comfy-qr-quantify-match",
|
|
||||||
"pos": [
|
|
||||||
97.9219000000007,
|
|
||||||
-111.63269999999997
|
|
||||||
],
|
|
||||||
"size": {
|
|
||||||
"0": 317.4000244140625,
|
|
||||||
"1": 238
|
|
||||||
},
|
|
||||||
"flags": {},
|
|
||||||
"order": 19,
|
|
||||||
"mode": 0,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "source_qr",
|
|
||||||
"type": "IMAGE",
|
|
||||||
"link": 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "modified_qr",
|
|
||||||
"type": "IMAGE",
|
|
||||||
"link": 5
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "PERCENT_ERROR",
|
|
||||||
"type": "FLOAT",
|
|
||||||
"links": null,
|
|
||||||
"shape": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "CORRELATION",
|
|
||||||
"type": "FLOAT",
|
|
||||||
"links": null,
|
|
||||||
"shape": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "RMSE",
|
|
||||||
"type": "FLOAT",
|
|
||||||
"links": null,
|
|
||||||
"shape": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "QR_ERROR_MASK",
|
|
||||||
"type": "MASK",
|
|
||||||
"links": [
|
|
||||||
91
|
|
||||||
],
|
|
||||||
"shape": 3,
|
|
||||||
"slot_index": 3
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"Node name for S&R": "comfy-qr-quantify-match"
|
|
||||||
},
|
|
||||||
"widgets_values": [
|
|
||||||
16,
|
|
||||||
"mean",
|
|
||||||
"mean",
|
|
||||||
"module_pattern",
|
|
||||||
0.5,
|
|
||||||
false
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 2,
|
|
||||||
"type": "LoadImage",
|
|
||||||
"pos": [
|
|
||||||
-288,
|
|
||||||
115
|
|
||||||
],
|
|
||||||
"size": {
|
|
||||||
"0": 315,
|
|
||||||
"1": 314.0000305175781
|
|
||||||
},
|
|
||||||
"flags": {},
|
|
||||||
"order": 3,
|
|
||||||
"mode": 0,
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "IMAGE",
|
|
||||||
"type": "IMAGE",
|
|
||||||
"links": [
|
|
||||||
5,
|
|
||||||
87
|
|
||||||
],
|
|
||||||
"shape": 3,
|
|
||||||
"slot_index": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "MASK",
|
|
||||||
"type": "MASK",
|
|
||||||
"links": null,
|
|
||||||
"shape": 3
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"Node name for S&R": "LoadImage"
|
|
||||||
},
|
|
||||||
"widgets_values": [
|
|
||||||
"unscannable_00001_ (1).png",
|
|
||||||
"image"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": 47,
|
"id": 47,
|
||||||
"type": "PrimitiveNode",
|
"type": "PrimitiveNode",
|
||||||
@@ -902,7 +751,7 @@
|
|||||||
"1": 82
|
"1": 82
|
||||||
},
|
},
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 4,
|
"order": 3,
|
||||||
"mode": 0,
|
"mode": 0,
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
@@ -914,21 +763,14 @@
|
|||||||
],
|
],
|
||||||
"slot_index": 0,
|
"slot_index": 0,
|
||||||
"widget": {
|
"widget": {
|
||||||
"name": "height",
|
"name": "height"
|
||||||
"config": [
|
|
||||||
"INT",
|
|
||||||
{
|
|
||||||
"default": 512,
|
|
||||||
"min": 1,
|
|
||||||
"max": 8192,
|
|
||||||
"step": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "Height",
|
"title": "Height",
|
||||||
"properties": {},
|
"properties": {
|
||||||
|
"Run widget replace on values": false
|
||||||
|
},
|
||||||
"widgets_values": [
|
"widgets_values": [
|
||||||
768,
|
768,
|
||||||
"fixed"
|
"fixed"
|
||||||
@@ -946,7 +788,7 @@
|
|||||||
"1": 82
|
"1": 82
|
||||||
},
|
},
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 5,
|
"order": 4,
|
||||||
"mode": 0,
|
"mode": 0,
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
@@ -958,21 +800,14 @@
|
|||||||
],
|
],
|
||||||
"slot_index": 0,
|
"slot_index": 0,
|
||||||
"widget": {
|
"widget": {
|
||||||
"name": "width",
|
"name": "width"
|
||||||
"config": [
|
|
||||||
"INT",
|
|
||||||
{
|
|
||||||
"default": 512,
|
|
||||||
"min": 1,
|
|
||||||
"max": 8192,
|
|
||||||
"step": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "Width",
|
"title": "Width",
|
||||||
"properties": {},
|
"properties": {
|
||||||
|
"Run widget replace on values": false
|
||||||
|
},
|
||||||
"widgets_values": [
|
"widgets_values": [
|
||||||
768,
|
768,
|
||||||
"fixed"
|
"fixed"
|
||||||
@@ -990,7 +825,7 @@
|
|||||||
"1": 82
|
"1": 82
|
||||||
},
|
},
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 6,
|
"order": 5,
|
||||||
"mode": 0,
|
"mode": 0,
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
@@ -1002,21 +837,14 @@
|
|||||||
],
|
],
|
||||||
"slot_index": 0,
|
"slot_index": 0,
|
||||||
"widget": {
|
"widget": {
|
||||||
"name": "x",
|
"name": "x"
|
||||||
"config": [
|
|
||||||
"INT",
|
|
||||||
{
|
|
||||||
"default": 0,
|
|
||||||
"min": 0,
|
|
||||||
"max": 8192,
|
|
||||||
"step": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "X Offset",
|
"title": "X Offset",
|
||||||
"properties": {},
|
"properties": {
|
||||||
|
"Run widget replace on values": false
|
||||||
|
},
|
||||||
"widgets_values": [
|
"widgets_values": [
|
||||||
16,
|
16,
|
||||||
"fixed"
|
"fixed"
|
||||||
@@ -1034,7 +862,7 @@
|
|||||||
"1": 82
|
"1": 82
|
||||||
},
|
},
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 7,
|
"order": 6,
|
||||||
"mode": 0,
|
"mode": 0,
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
@@ -1046,21 +874,14 @@
|
|||||||
],
|
],
|
||||||
"slot_index": 0,
|
"slot_index": 0,
|
||||||
"widget": {
|
"widget": {
|
||||||
"name": "y",
|
"name": "y"
|
||||||
"config": [
|
|
||||||
"INT",
|
|
||||||
{
|
|
||||||
"default": 0,
|
|
||||||
"min": 0,
|
|
||||||
"max": 8192,
|
|
||||||
"step": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "Y Offset",
|
"title": "Y Offset",
|
||||||
"properties": {},
|
"properties": {
|
||||||
|
"Run widget replace on values": false
|
||||||
|
},
|
||||||
"widgets_values": [
|
"widgets_values": [
|
||||||
16,
|
16,
|
||||||
"fixed"
|
"fixed"
|
||||||
@@ -1078,7 +899,7 @@
|
|||||||
"1": 106
|
"1": 106
|
||||||
},
|
},
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 14,
|
"order": 13,
|
||||||
"mode": 0,
|
"mode": 0,
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
@@ -1086,16 +907,7 @@
|
|||||||
"type": "INT",
|
"type": "INT",
|
||||||
"link": 105,
|
"link": 105,
|
||||||
"widget": {
|
"widget": {
|
||||||
"name": "width",
|
"name": "width"
|
||||||
"config": [
|
|
||||||
"INT",
|
|
||||||
{
|
|
||||||
"default": 512,
|
|
||||||
"min": 1,
|
|
||||||
"max": 8192,
|
|
||||||
"step": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1103,16 +915,7 @@
|
|||||||
"type": "INT",
|
"type": "INT",
|
||||||
"link": 106,
|
"link": 106,
|
||||||
"widget": {
|
"widget": {
|
||||||
"name": "height",
|
"name": "height"
|
||||||
"config": [
|
|
||||||
"INT",
|
|
||||||
{
|
|
||||||
"default": 512,
|
|
||||||
"min": 1,
|
|
||||||
"max": 8192,
|
|
||||||
"step": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -1167,16 +970,7 @@
|
|||||||
"type": "INT",
|
"type": "INT",
|
||||||
"link": 109,
|
"link": 109,
|
||||||
"widget": {
|
"widget": {
|
||||||
"name": "x",
|
"name": "x"
|
||||||
"config": [
|
|
||||||
"INT",
|
|
||||||
{
|
|
||||||
"default": 0,
|
|
||||||
"min": 0,
|
|
||||||
"max": 8192,
|
|
||||||
"step": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1184,16 +978,7 @@
|
|||||||
"type": "INT",
|
"type": "INT",
|
||||||
"link": 110,
|
"link": 110,
|
||||||
"widget": {
|
"widget": {
|
||||||
"name": "y",
|
"name": "y"
|
||||||
"config": [
|
|
||||||
"INT",
|
|
||||||
{
|
|
||||||
"default": 0,
|
|
||||||
"min": 0,
|
|
||||||
"max": 8192,
|
|
||||||
"step": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -1283,93 +1068,6 @@
|
|||||||
"Node name for S&R": "PreviewImage"
|
"Node name for S&R": "PreviewImage"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": 6,
|
|
||||||
"type": "ImageCompositeMasked",
|
|
||||||
"pos": [
|
|
||||||
-332.0780999999991,
|
|
||||||
-91.63270000000001
|
|
||||||
],
|
|
||||||
"size": {
|
|
||||||
"0": 315,
|
|
||||||
"1": 146
|
|
||||||
},
|
|
||||||
"flags": {},
|
|
||||||
"order": 17,
|
|
||||||
"mode": 0,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "destination",
|
|
||||||
"type": "IMAGE",
|
|
||||||
"link": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "source",
|
|
||||||
"type": "IMAGE",
|
|
||||||
"link": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "mask",
|
|
||||||
"type": "MASK",
|
|
||||||
"link": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "x",
|
|
||||||
"type": "INT",
|
|
||||||
"link": 107,
|
|
||||||
"widget": {
|
|
||||||
"name": "x",
|
|
||||||
"config": [
|
|
||||||
"INT",
|
|
||||||
{
|
|
||||||
"default": 0,
|
|
||||||
"min": 0,
|
|
||||||
"max": 8192,
|
|
||||||
"step": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "y",
|
|
||||||
"type": "INT",
|
|
||||||
"link": 108,
|
|
||||||
"widget": {
|
|
||||||
"name": "y",
|
|
||||||
"config": [
|
|
||||||
"INT",
|
|
||||||
{
|
|
||||||
"default": 0,
|
|
||||||
"min": 0,
|
|
||||||
"max": 8192,
|
|
||||||
"step": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "IMAGE",
|
|
||||||
"type": "IMAGE",
|
|
||||||
"links": [
|
|
||||||
4,
|
|
||||||
12,
|
|
||||||
111
|
|
||||||
],
|
|
||||||
"shape": 3,
|
|
||||||
"slot_index": 0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"Node name for S&R": "ImageCompositeMasked"
|
|
||||||
},
|
|
||||||
"widgets_values": [
|
|
||||||
16,
|
|
||||||
16,
|
|
||||||
false
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": 17,
|
"id": 17,
|
||||||
"type": "VAEDecode",
|
"type": "VAEDecode",
|
||||||
@@ -1492,7 +1190,7 @@
|
|||||||
"1": 58
|
"1": 58
|
||||||
},
|
},
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 8,
|
"order": 7,
|
||||||
"mode": 0,
|
"mode": 0,
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
@@ -1537,6 +1235,183 @@
|
|||||||
"widgets_values": [
|
"widgets_values": [
|
||||||
"ComfyUI"
|
"ComfyUI"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"type": "ImageCompositeMasked",
|
||||||
|
"pos": [
|
||||||
|
-332.0780999999991,
|
||||||
|
-91.63270000000001
|
||||||
|
],
|
||||||
|
"size": {
|
||||||
|
"0": 315,
|
||||||
|
"1": 146
|
||||||
|
},
|
||||||
|
"flags": {},
|
||||||
|
"order": 17,
|
||||||
|
"mode": 0,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "destination",
|
||||||
|
"type": "IMAGE",
|
||||||
|
"link": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "source",
|
||||||
|
"type": "IMAGE",
|
||||||
|
"link": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mask",
|
||||||
|
"type": "MASK",
|
||||||
|
"link": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "x",
|
||||||
|
"type": "INT",
|
||||||
|
"link": 107,
|
||||||
|
"widget": {
|
||||||
|
"name": "x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "y",
|
||||||
|
"type": "INT",
|
||||||
|
"link": 108,
|
||||||
|
"widget": {
|
||||||
|
"name": "y"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "IMAGE",
|
||||||
|
"type": "IMAGE",
|
||||||
|
"links": [
|
||||||
|
12,
|
||||||
|
111,
|
||||||
|
116
|
||||||
|
],
|
||||||
|
"shape": 3,
|
||||||
|
"slot_index": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Node name for S&R": "ImageCompositeMasked"
|
||||||
|
},
|
||||||
|
"widgets_values": [
|
||||||
|
16,
|
||||||
|
16,
|
||||||
|
false
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"type": "LoadImage",
|
||||||
|
"pos": [
|
||||||
|
-288,
|
||||||
|
115
|
||||||
|
],
|
||||||
|
"size": {
|
||||||
|
"0": 315,
|
||||||
|
"1": 314.0000305175781
|
||||||
|
},
|
||||||
|
"flags": {},
|
||||||
|
"order": 8,
|
||||||
|
"mode": 0,
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "IMAGE",
|
||||||
|
"type": "IMAGE",
|
||||||
|
"links": [
|
||||||
|
87,
|
||||||
|
117
|
||||||
|
],
|
||||||
|
"shape": 3,
|
||||||
|
"slot_index": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "MASK",
|
||||||
|
"type": "MASK",
|
||||||
|
"links": null,
|
||||||
|
"shape": 3
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Node name for S&R": "LoadImage"
|
||||||
|
},
|
||||||
|
"widgets_values": [
|
||||||
|
"unscannable_00001_ (1).png",
|
||||||
|
"image"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 52,
|
||||||
|
"type": "comfy-qr-mask_errors",
|
||||||
|
"pos": [
|
||||||
|
120,
|
||||||
|
-146
|
||||||
|
],
|
||||||
|
"size": {
|
||||||
|
"0": 317.4000244140625,
|
||||||
|
"1": 262
|
||||||
|
},
|
||||||
|
"flags": {},
|
||||||
|
"order": 20,
|
||||||
|
"mode": 0,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "source_qr",
|
||||||
|
"type": "IMAGE",
|
||||||
|
"link": 116
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "modified_qr",
|
||||||
|
"type": "IMAGE",
|
||||||
|
"link": 117
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "QR_ERROR_MASK",
|
||||||
|
"type": "MASK",
|
||||||
|
"links": [
|
||||||
|
115
|
||||||
|
],
|
||||||
|
"shape": 3,
|
||||||
|
"slot_index": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PERCENT_ERROR",
|
||||||
|
"type": "FLOAT",
|
||||||
|
"links": null,
|
||||||
|
"shape": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CORRELATION",
|
||||||
|
"type": "FLOAT",
|
||||||
|
"links": null,
|
||||||
|
"shape": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "RMSE",
|
||||||
|
"type": "FLOAT",
|
||||||
|
"links": null,
|
||||||
|
"shape": 6
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Node name for S&R": "comfy-qr-mask_errors"
|
||||||
|
},
|
||||||
|
"widgets_values": [
|
||||||
|
16,
|
||||||
|
"mean",
|
||||||
|
"mean",
|
||||||
|
"module_pattern",
|
||||||
|
0.5,
|
||||||
|
false,
|
||||||
|
2.2
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"links": [
|
"links": [
|
||||||
@@ -1564,22 +1439,6 @@
|
|||||||
0,
|
0,
|
||||||
"IMAGE"
|
"IMAGE"
|
||||||
],
|
],
|
||||||
[
|
|
||||||
4,
|
|
||||||
6,
|
|
||||||
0,
|
|
||||||
3,
|
|
||||||
0,
|
|
||||||
"IMAGE"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
5,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
3,
|
|
||||||
1,
|
|
||||||
"IMAGE"
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
7,
|
7,
|
||||||
8,
|
8,
|
||||||
@@ -1714,7 +1573,7 @@
|
|||||||
0,
|
0,
|
||||||
1,
|
1,
|
||||||
0,
|
0,
|
||||||
"Http,Https,None"
|
"COMBO"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
47,
|
47,
|
||||||
@@ -1748,14 +1607,6 @@
|
|||||||
1,
|
1,
|
||||||
"MASK"
|
"MASK"
|
||||||
],
|
],
|
||||||
[
|
|
||||||
91,
|
|
||||||
3,
|
|
||||||
3,
|
|
||||||
39,
|
|
||||||
0,
|
|
||||||
"MASK"
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
92,
|
92,
|
||||||
39,
|
39,
|
||||||
@@ -1883,6 +1734,30 @@
|
|||||||
23,
|
23,
|
||||||
0,
|
0,
|
||||||
"IMAGE"
|
"IMAGE"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
115,
|
||||||
|
52,
|
||||||
|
0,
|
||||||
|
39,
|
||||||
|
0,
|
||||||
|
"MASK"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
116,
|
||||||
|
6,
|
||||||
|
0,
|
||||||
|
52,
|
||||||
|
0,
|
||||||
|
"IMAGE"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
117,
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
52,
|
||||||
|
1,
|
||||||
|
"IMAGE"
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"groups": [],
|
"groups": [],
|
||||||
|
|||||||
@@ -342,7 +342,8 @@
|
|||||||
"#DDDDDD",
|
"#DDDDDD",
|
||||||
"High",
|
"High",
|
||||||
1,
|
1,
|
||||||
"Nearest"
|
"Nearest",
|
||||||
|
"Square"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -440,4 +441,4 @@
|
|||||||
"config": {},
|
"config": {},
|
||||||
"extra": {},
|
"extra": {},
|
||||||
"version": 0.4
|
"version": 0.4
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -477,7 +477,8 @@
|
|||||||
"#000000",
|
"#000000",
|
||||||
"#FFFFFF",
|
"#FFFFFF",
|
||||||
"Medium",
|
"Medium",
|
||||||
1
|
1,
|
||||||
|
"Square"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -524,7 +524,8 @@
|
|||||||
"#000000",
|
"#000000",
|
||||||
"#FFFFFF",
|
"#FFFFFF",
|
||||||
"High",
|
"High",
|
||||||
1
|
1,
|
||||||
|
"Square"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -394,7 +394,8 @@
|
|||||||
"#000000",
|
"#000000",
|
||||||
"#FFFFFF",
|
"#FFFFFF",
|
||||||
"High",
|
"High",
|
||||||
1
|
1,
|
||||||
|
"Square"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -357,7 +357,8 @@
|
|||||||
"#000000",
|
"#000000",
|
||||||
"#FFFFFF",
|
"#FFFFFF",
|
||||||
"High",
|
"High",
|
||||||
1
|
1,
|
||||||
|
"Square"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -423,4 +424,4 @@
|
|||||||
"config": {},
|
"config": {},
|
||||||
"extra": {},
|
"extra": {},
|
||||||
"version": 0.4
|
"version": 0.4
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,8 @@
|
|||||||
"FF0",
|
"FF0",
|
||||||
"High",
|
"High",
|
||||||
1,
|
1,
|
||||||
"Nearest"
|
"Nearest",
|
||||||
|
"Circle"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -88,4 +89,4 @@
|
|||||||
"config": {},
|
"config": {},
|
||||||
"extra": {},
|
"extra": {},
|
||||||
"version": 0.4
|
"version": 0.4
|
||||||
}
|
}
|
||||||
|
|||||||
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1,16 @@
|
|||||||
|
[project]
|
||||||
|
name = "comfyqr"
|
||||||
|
description = "QR generation within ComfyUI. Contains nodes suitable for workflows from generating basic QR images to techniques with advanced QR masking."
|
||||||
|
version = "0.4.1"
|
||||||
|
license = "LICENSE"
|
||||||
|
dependencies = ["qrcode >= 7.1"]
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
Repository = "https://github.com/coreyryanhanson/ComfyQR"
|
||||||
|
# Used by Comfy Registry https://comfyregistry.org
|
||||||
|
|
||||||
|
[tool.comfy]
|
||||||
|
PublisherId = "coreyryanhanson"
|
||||||
|
DisplayName = "ComfyQR"
|
||||||
|
Icon = ""
|
||||||
|
|
||||||
@@ -1,6 +1,13 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import qrcode
|
import qrcode
|
||||||
from qrcode.compat.pil import Image
|
from qrcode.image.styles.moduledrawers import (GappedSquareModuleDrawer,
|
||||||
|
CircleModuleDrawer,
|
||||||
|
RoundedModuleDrawer,
|
||||||
|
VerticalBarsDrawer,
|
||||||
|
HorizontalBarsDrawer)
|
||||||
|
from qrcode.image.styledpil import StyledPilImage
|
||||||
|
from qrcode.image.styles.colormasks import SolidFillColorMask
|
||||||
|
from PIL import Image
|
||||||
import torch
|
import torch
|
||||||
import torch.nn.functional as F
|
import torch.nn.functional as F
|
||||||
|
|
||||||
@@ -27,11 +34,19 @@ class QRBase:
|
|||||||
out_image = np.array(img, dtype=np.uint8).astype(np.float32) / 255
|
out_image = np.array(img, dtype=np.uint8).astype(np.float32) / 255
|
||||||
return torch.from_numpy(out_image).unsqueeze(0)
|
return torch.from_numpy(out_image).unsqueeze(0)
|
||||||
|
|
||||||
def _make_qr(self, qr, fill_hexcolor, back_hexcolor):
|
def _make_qr(self, qr, fill_hexcolor, back_hexcolor, module_drawer):
|
||||||
self.fill = self._parse_hexcolor_string(fill_hexcolor, "fill_hexcolor")
|
self.fill = self._parse_hexcolor_string(fill_hexcolor, "fill_hexcolor")
|
||||||
self.back = self._parse_hexcolor_string(back_hexcolor, "back_hexcolor")
|
self.back = self._parse_hexcolor_string(back_hexcolor, "back_hexcolor")
|
||||||
qr.make(fit=True)
|
qr.make(fit=True)
|
||||||
return qr.make_image(fill_color=self.fill, back_color=self.back)
|
if module_drawer == "Square":
|
||||||
|
# Keeps using Square QR generation the old way for faster speeds.
|
||||||
|
return qr.make_image(fill_color=self.fill, back_color=self.back)
|
||||||
|
color_mask = SolidFillColorMask(back_color=self.back,
|
||||||
|
front_color=self.fill)
|
||||||
|
module_drawing_method = self._select_module_drawer(module_drawer)
|
||||||
|
return qr.make_image(image_factory=StyledPilImage,
|
||||||
|
color_mask=color_mask,
|
||||||
|
module_drawer=module_drawing_method)
|
||||||
|
|
||||||
def _parse_hexcolor_string(self, s, parameter):
|
def _parse_hexcolor_string(self, s, parameter):
|
||||||
if s.startswith("#"):
|
if s.startswith("#"):
|
||||||
@@ -45,11 +60,31 @@ class QRBase:
|
|||||||
try:
|
try:
|
||||||
return tuple(int(channel, 16) for channel in rgb)
|
return tuple(int(channel, 16) for channel in rgb)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ValueError(f"{parameter} contains invalid hexadecimal characters")
|
raise ValueError(f"{parameter} contains invalid hexadecimal "
|
||||||
|
f"characters")
|
||||||
|
|
||||||
def _validate_qr_size(self, size, max_size):
|
def _validate_qr_size(self, size, max_size):
|
||||||
if size > max_size:
|
if size > max_size:
|
||||||
raise RuntimeError(f"QR dimensions of {size} exceed max size of {max_size}.")
|
raise RuntimeError(f"QR dimensions of {size} exceed max size of "
|
||||||
|
f"{max_size}.")
|
||||||
|
|
||||||
|
def _select_module_drawer(self, module_drawer_string):
|
||||||
|
"""Square is not included in the results, for a speed optimization
|
||||||
|
applying color masks. Current version of python-qr code suffers a
|
||||||
|
slowdown when using custom colors combined with custom module drawers.
|
||||||
|
By bypassing square QRs, non standard colors will load faster."""
|
||||||
|
if module_drawer_string == "Gapped square":
|
||||||
|
return GappedSquareModuleDrawer()
|
||||||
|
if module_drawer_string == "Circle":
|
||||||
|
return CircleModuleDrawer()
|
||||||
|
if module_drawer_string == "Rounded":
|
||||||
|
return RoundedModuleDrawer()
|
||||||
|
if module_drawer_string == "Vertical bars":
|
||||||
|
return VerticalBarsDrawer()
|
||||||
|
if module_drawer_string == "Horizontal bars":
|
||||||
|
return HorizontalBarsDrawer()
|
||||||
|
raise ValueError(f"Module drawing method of {module_drawer_string} "
|
||||||
|
f"not supported")
|
||||||
|
|
||||||
def update_text(self, protocol, text):
|
def update_text(self, protocol, text):
|
||||||
"""This function takes input from a text box and a chosen internet
|
"""This function takes input from a text box and a chosen internet
|
||||||
@@ -79,12 +114,34 @@ class QRByImageSize(QRBase):
|
|||||||
"required": {
|
"required": {
|
||||||
"protocol": (["Http", "Https", "None"], {"default": "Https"}),
|
"protocol": (["Http", "Https", "None"], {"default": "Https"}),
|
||||||
"text": ("STRING", {"multiline": True}),
|
"text": ("STRING", {"multiline": True}),
|
||||||
"image_size": ("INT", {"default": 512, "min": 64, "max": 4096, "step": 64}),
|
"image_size": ("INT", {"default": 512,
|
||||||
"fill_hexcolor": ("STRING", {"multiline": False, "default": "#000000"}),
|
"min": 64,
|
||||||
"back_hexcolor": ("STRING", {"multiline": False, "default": "#FFFFFF"}),
|
"max": 4096,
|
||||||
"error_correction": (["Low", "Medium", "Quartile", "High"], {"default": "High"}),
|
"step": 64}),
|
||||||
"border": ("INT", {"default": 1, "min": 0, "max": 100, "step": 1}),
|
"fill_hexcolor": ("STRING", {"multiline": False,
|
||||||
"resampling": (["Bicubic", "Bilinear", "Box", "Hamming", "Lanczos", "Nearest"], {"default": "Nearest"}),
|
"default": "#000000"}),
|
||||||
|
"back_hexcolor": ("STRING", {"multiline": False,
|
||||||
|
"default": "#FFFFFF"}),
|
||||||
|
"error_correction": (["Low", "Medium", "Quartile", "High"],
|
||||||
|
{"default": "High"}),
|
||||||
|
"border": ("INT", {"default": 1,
|
||||||
|
"min": 0,
|
||||||
|
"max": 100,
|
||||||
|
"step": 1}),
|
||||||
|
"resampling": (["Bicubic",
|
||||||
|
"Bilinear",
|
||||||
|
"Box",
|
||||||
|
"Hamming",
|
||||||
|
"Lanczos",
|
||||||
|
"Nearest"
|
||||||
|
], {"default": "Nearest"}),
|
||||||
|
"module_drawer": (["Square",
|
||||||
|
"Gapped square",
|
||||||
|
"Circle",
|
||||||
|
"Rounded",
|
||||||
|
"Vertical bars",
|
||||||
|
"Horizontal bars"
|
||||||
|
], {"default": "Square"})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +161,8 @@ class QRByImageSize(QRBase):
|
|||||||
return Image.BOX
|
return Image.BOX
|
||||||
if resampling_string == "Hamming":
|
if resampling_string == "Hamming":
|
||||||
return Image.HAMMING
|
return Image.HAMMING
|
||||||
raise ValueError(f"Resampling method of {resampling_string} not supported")
|
raise ValueError(f"Resampling method of {resampling_string} not "
|
||||||
|
f"supported")
|
||||||
|
|
||||||
def generate_qr(
|
def generate_qr(
|
||||||
self,
|
self,
|
||||||
@@ -115,18 +173,18 @@ class QRByImageSize(QRBase):
|
|||||||
back_hexcolor,
|
back_hexcolor,
|
||||||
error_correction,
|
error_correction,
|
||||||
border,
|
border,
|
||||||
resampling
|
resampling,
|
||||||
|
module_drawer
|
||||||
):
|
):
|
||||||
resampling_method = self._select_resampling_method(resampling)
|
resampling_method = self._select_resampling_method(resampling)
|
||||||
error_level = self._get_error_correction_constant(error_correction)
|
error_level = self._get_error_correction_constant(error_correction)
|
||||||
self.update_text(protocol, text)
|
self.update_text(protocol, text)
|
||||||
qr = qrcode.QRCode(
|
qr = qrcode.QRCode(
|
||||||
error_correction=error_level,
|
error_correction=error_level,
|
||||||
box_size=1,
|
box_size=16,
|
||||||
border=border)
|
border=border)
|
||||||
qr.add_data(self.text)
|
qr.add_data(self.text)
|
||||||
img = self._make_qr(qr, fill_hexcolor, back_hexcolor)
|
img = self._make_qr(qr, fill_hexcolor, back_hexcolor, module_drawer)
|
||||||
self._validate_qr_size(img.pixel_size, image_size)
|
|
||||||
img = img.resize((image_size, image_size), resample=resampling_method)
|
img = img.resize((image_size, image_size), resample=resampling_method)
|
||||||
return (self._img_to_tensor(img), qr.version)
|
return (self._img_to_tensor(img), qr.version)
|
||||||
|
|
||||||
@@ -139,12 +197,31 @@ class QRByModuleSize(QRBase):
|
|||||||
"required": {
|
"required": {
|
||||||
"protocol": (["Http", "Https", "None"], {"default": "Https"}),
|
"protocol": (["Http", "Https", "None"], {"default": "Https"}),
|
||||||
"text": ("STRING", {"multiline": True}),
|
"text": ("STRING", {"multiline": True}),
|
||||||
"module_size": ("INT", {"default": 16, "min": 1, "max": 64, "step": 1}),
|
"module_size": ("INT", {"default": 16,
|
||||||
"max_image_size": ("INT", {"default": 512, "min": 64, "max": 4096, "step": 64}),
|
"min": 1,
|
||||||
"fill_hexcolor": ("STRING", {"multiline": False, "default": "#000000"}),
|
"max": 64,
|
||||||
"back_hexcolor": ("STRING", {"multiline": False, "default": "#FFFFFF"}),
|
"step": 1}),
|
||||||
"error_correction": (["Low", "Medium", "Quartile", "High"], {"default": "High"}),
|
"max_image_size": ("INT", {"default": 512,
|
||||||
"border": ("INT", {"default": 1, "min": 0, "max": 100, "step": 1}),
|
"min": 64,
|
||||||
|
"max": 4096,
|
||||||
|
"step": 64}),
|
||||||
|
"fill_hexcolor": ("STRING", {"multiline": False,
|
||||||
|
"default": "#000000"}),
|
||||||
|
"back_hexcolor": ("STRING", {"multiline": False,
|
||||||
|
"default": "#FFFFFF"}),
|
||||||
|
"error_correction": (["Low", "Medium", "Quartile", "High"],
|
||||||
|
{"default": "High"}),
|
||||||
|
"border": ("INT", {"default": 1,
|
||||||
|
"min": 0,
|
||||||
|
"max": 100,
|
||||||
|
"step": 1}),
|
||||||
|
"module_drawer": (["Square",
|
||||||
|
"Gapped square",
|
||||||
|
"Circle",
|
||||||
|
"Rounded",
|
||||||
|
"Vertical bars",
|
||||||
|
"Horizontal bars"
|
||||||
|
], {"default": "Square"})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +237,8 @@ class QRByModuleSize(QRBase):
|
|||||||
fill_hexcolor,
|
fill_hexcolor,
|
||||||
back_hexcolor,
|
back_hexcolor,
|
||||||
error_correction,
|
error_correction,
|
||||||
border
|
border,
|
||||||
|
module_drawer
|
||||||
):
|
):
|
||||||
self.update_text(protocol, text)
|
self.update_text(protocol, text)
|
||||||
error_level = self._get_error_correction_constant(error_correction)
|
error_level = self._get_error_correction_constant(error_correction)
|
||||||
@@ -169,7 +247,7 @@ class QRByModuleSize(QRBase):
|
|||||||
box_size=module_size,
|
box_size=module_size,
|
||||||
border=border)
|
border=border)
|
||||||
qr.add_data(self.text)
|
qr.add_data(self.text)
|
||||||
img = self._make_qr(qr, fill_hexcolor, back_hexcolor)
|
img = self._make_qr(qr, fill_hexcolor, back_hexcolor, module_drawer)
|
||||||
self._validate_qr_size(img.pixel_size, max_image_size)
|
self._validate_qr_size(img.pixel_size, max_image_size)
|
||||||
return (self._img_to_tensor(img), qr.version, img.pixel_size)
|
return (self._img_to_tensor(img), qr.version, img.pixel_size)
|
||||||
|
|
||||||
@@ -182,17 +260,41 @@ class QRByModuleSizeSplitFunctionPatterns(QRBase):
|
|||||||
"required": {
|
"required": {
|
||||||
"protocol": (["Http", "Https", "None"], {"default": "Https"}),
|
"protocol": (["Http", "Https", "None"], {"default": "Https"}),
|
||||||
"text": ("STRING", {"multiline": True}),
|
"text": ("STRING", {"multiline": True}),
|
||||||
"module_size": ("INT", {"default": 16, "min": 1, "max": 64, "step": 1}),
|
"module_size": ("INT", {"default": 16,
|
||||||
"max_image_size": ("INT", {"default": 512, "min": 64, "max": 4096, "step": 64}),
|
"min": 1,
|
||||||
"fill_hexcolor": ("STRING", {"multiline": False, "default": "#000000"}),
|
"max": 64,
|
||||||
"back_hexcolor": ("STRING", {"multiline": False, "default": "#FFFFFF"}),
|
"step": 1}),
|
||||||
"error_correction": (["Low", "Medium", "Quartile", "High"], {"default": "High"}),
|
"max_image_size": ("INT", {"default": 512,
|
||||||
"border": ("INT", {"default": 1, "min": 0, "max": 100, "step": 1}),
|
"min": 64,
|
||||||
|
"max": 4096,
|
||||||
|
"step": 64}),
|
||||||
|
"fill_hexcolor": ("STRING", {"multiline": False,
|
||||||
|
"default": "#000000"}),
|
||||||
|
"back_hexcolor": ("STRING", {"multiline": False,
|
||||||
|
"default": "#FFFFFF"}),
|
||||||
|
"error_correction": (["Low", "Medium", "Quartile", "High"],
|
||||||
|
{"default": "High"}),
|
||||||
|
"border": ("INT", {"default": 1,
|
||||||
|
"min": 0,
|
||||||
|
"max": 100,
|
||||||
|
"step": 1}),
|
||||||
|
"module_drawer": (["Square",
|
||||||
|
"Gapped square",
|
||||||
|
"Circle",
|
||||||
|
"Rounded",
|
||||||
|
"Vertical bars",
|
||||||
|
"Horizontal bars"
|
||||||
|
], {"default": "Square"})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = ("IMAGE", "IMAGE", "IMAGE", "MASK", "INT", "INT")
|
RETURN_TYPES = ("IMAGE", "IMAGE", "IMAGE", "MASK", "INT", "INT")
|
||||||
RETURN_NAMES = ("QR_CODE", "MODULE_LAYER", "FINDER_LAYER", "FINDER_MASK", "QR_VERSION", "IMAGE_SIZE")
|
RETURN_NAMES = ("QR_CODE",
|
||||||
|
"MODULE_LAYER",
|
||||||
|
"FINDER_LAYER",
|
||||||
|
"FINDER_MASK",
|
||||||
|
"QR_VERSION",
|
||||||
|
"IMAGE_SIZE")
|
||||||
|
|
||||||
def _generate_finder_pattern_ranges(self, module_size, border_size):
|
def _generate_finder_pattern_ranges(self, module_size, border_size):
|
||||||
outer = module_size * border_size
|
outer = module_size * border_size
|
||||||
@@ -205,9 +307,16 @@ class QRByModuleSizeSplitFunctionPatterns(QRBase):
|
|||||||
(-inner, far_outer, outer, inner)
|
(-inner, far_outer, outer, inner)
|
||||||
]
|
]
|
||||||
|
|
||||||
def _generate_finder_pattern_mask(self, pixel_size, module_size, border_size):
|
def _generate_finder_pattern_mask(self,
|
||||||
|
pixel_size,
|
||||||
|
module_size,
|
||||||
|
border_size):
|
||||||
mask = np.zeros((pixel_size, pixel_size), dtype=bool)
|
mask = np.zeros((pixel_size, pixel_size), dtype=bool)
|
||||||
for x_min, x_max, y_min, y_max in self._generate_finder_pattern_ranges(module_size, border_size):
|
for (x_min,
|
||||||
|
x_max,
|
||||||
|
y_min,
|
||||||
|
y_max) in self._generate_finder_pattern_ranges(module_size,
|
||||||
|
border_size):
|
||||||
mask[y_min:y_max, x_min:x_max] = True
|
mask[y_min:y_max, x_min:x_max] = True
|
||||||
return mask
|
return mask
|
||||||
|
|
||||||
@@ -219,7 +328,7 @@ class QRByModuleSizeSplitFunctionPatterns(QRBase):
|
|||||||
|
|
||||||
def _mask_to_tensor(self, mask):
|
def _mask_to_tensor(self, mask):
|
||||||
out_image = mask.astype(np.float32)
|
out_image = mask.astype(np.float32)
|
||||||
return torch.from_numpy(out_image)
|
return torch.from_numpy(out_image).unsqueeze(0)
|
||||||
|
|
||||||
def generate_qr(
|
def generate_qr(
|
||||||
self,
|
self,
|
||||||
@@ -230,7 +339,8 @@ class QRByModuleSizeSplitFunctionPatterns(QRBase):
|
|||||||
fill_hexcolor,
|
fill_hexcolor,
|
||||||
back_hexcolor,
|
back_hexcolor,
|
||||||
error_correction,
|
error_correction,
|
||||||
border
|
border,
|
||||||
|
module_drawer
|
||||||
):
|
):
|
||||||
self.update_text(protocol, text)
|
self.update_text(protocol, text)
|
||||||
error_level = self._get_error_correction_constant(error_correction)
|
error_level = self._get_error_correction_constant(error_correction)
|
||||||
@@ -239,10 +349,12 @@ class QRByModuleSizeSplitFunctionPatterns(QRBase):
|
|||||||
box_size=module_size,
|
box_size=module_size,
|
||||||
border=border)
|
border=border)
|
||||||
qr.add_data(self.text)
|
qr.add_data(self.text)
|
||||||
img = self._make_qr(qr, fill_hexcolor, back_hexcolor)
|
img = self._make_qr(qr, fill_hexcolor, back_hexcolor, module_drawer)
|
||||||
pixel_size = img.pixel_size
|
pixel_size = img.pixel_size
|
||||||
self._validate_qr_size(pixel_size, max_image_size)
|
self._validate_qr_size(pixel_size, max_image_size)
|
||||||
mask = self._generate_finder_pattern_mask(pixel_size, module_size, border)
|
mask = self._generate_finder_pattern_mask(pixel_size,
|
||||||
|
module_size,
|
||||||
|
border)
|
||||||
module_image = self._apply_fill_to_mask(img, mask)
|
module_image = self._apply_fill_to_mask(img, mask)
|
||||||
function_image = self._apply_fill_to_mask(img, ~mask)
|
function_image = self._apply_fill_to_mask(img, ~mask)
|
||||||
return (
|
return (
|
||||||
@@ -265,6 +377,7 @@ class QRErrorMasker:
|
|||||||
CATEGORY = "ComfyQR"
|
CATEGORY = "ComfyQR"
|
||||||
RETURN_TYPES = ("MASK", "FLOAT", "FLOAT", "FLOAT")
|
RETURN_TYPES = ("MASK", "FLOAT", "FLOAT", "FLOAT")
|
||||||
RETURN_NAMES = ("QR_ERROR_MASK", "PERCENT_ERROR", "CORRELATION", "RMSE")
|
RETURN_NAMES = ("QR_ERROR_MASK", "PERCENT_ERROR", "CORRELATION", "RMSE")
|
||||||
|
OUTPUT_IS_LIST = (False, True, True, True)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(cls):
|
def INPUT_TYPES(cls):
|
||||||
@@ -272,13 +385,24 @@ class QRErrorMasker:
|
|||||||
"required": {
|
"required": {
|
||||||
"source_qr": ("IMAGE",),
|
"source_qr": ("IMAGE",),
|
||||||
"modified_qr": ("IMAGE",),
|
"modified_qr": ("IMAGE",),
|
||||||
"module_size": ("INT", {"default": 16, "min": 1, "max": 64, "step": 1}),
|
"module_size": ("INT", {"default": 16,
|
||||||
"grayscale_method": (["mean", "luminance"], {"default": "luminance"}),
|
"min": 1,
|
||||||
|
"max": 64,
|
||||||
|
"step": 1}),
|
||||||
|
"grayscale_method": (["mean", "luminance"],
|
||||||
|
{"default": "luminance"}),
|
||||||
"aggregate_method": (["mean",], {"default": "mean"}),
|
"aggregate_method": (["mean",], {"default": "mean"}),
|
||||||
"evaluate": (["full_qr", "module_pattern", "finder_pattern"], {"default": "module_pattern"}),
|
"evaluate": (["full_qr", "module_pattern", "finder_pattern"],
|
||||||
"error_difficulty": ("FLOAT", {"default": 0, "min": 0, "max": 1, "step": .01}),
|
{"default": "module_pattern"}),
|
||||||
|
"error_difficulty": ("FLOAT", {"default": 0,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": .01}),
|
||||||
"inverted_pattern": ("BOOLEAN", {"default": False}),
|
"inverted_pattern": ("BOOLEAN", {"default": False}),
|
||||||
"gamma": ("FLOAT", {"default": 2.2, "min": .1, "max": 2.8, "step": .1}),
|
"gamma": ("FLOAT", {"default": 2.2,
|
||||||
|
"min": .1,
|
||||||
|
"max": 2.8,
|
||||||
|
"step": .1}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,10 +412,13 @@ class QRErrorMasker:
|
|||||||
indices = torch.nonzero(module_pixels, as_tuple=True)
|
indices = torch.nonzero(module_pixels, as_tuple=True)
|
||||||
# The viewer patterns will guarentee a module pixel in the upper left
|
# The viewer patterns will guarentee a module pixel in the upper left
|
||||||
# The bottom right does not have that guarentee so max is used.
|
# The bottom right does not have that guarentee so max is used.
|
||||||
return indices[0][0], indices[0].max() + 1, indices[1][0], indices[1].max() + 1
|
return (indices[0][0],
|
||||||
|
indices[0].max() + 1,
|
||||||
|
indices[1][0], indices[1].max() + 1)
|
||||||
|
|
||||||
def _extract_pattern_from_bounds(self, tensor):
|
def _extract_pattern_from_bounds(self, tensor):
|
||||||
return tensor[self.qr_bounds[0]:self.qr_bounds[1], self.qr_bounds[2]:self.qr_bounds[3]]
|
return tensor[self.qr_bounds[0]: self.qr_bounds[1],
|
||||||
|
self.qr_bounds[2]: self.qr_bounds[3]]
|
||||||
|
|
||||||
def _trim_to_qr_area(self, source_qr, modified_qr, inverted_pattern):
|
def _trim_to_qr_area(self, source_qr, modified_qr, inverted_pattern):
|
||||||
self.qr_bounds = self._get_qr_bounds(source_qr, inverted_pattern)
|
self.qr_bounds = self._get_qr_bounds(source_qr, inverted_pattern)
|
||||||
@@ -302,20 +429,35 @@ class QRErrorMasker:
|
|||||||
|
|
||||||
def _reshape_tensor_to_modules(self, tensor):
|
def _reshape_tensor_to_modules(self, tensor):
|
||||||
if len(tensor.shape) != 2:
|
if len(tensor.shape) != 2:
|
||||||
raise RuntimeError("Module reshaping requires a 2 dimensional array.")
|
raise RuntimeError("Module reshaping requires a 2 dimensional "
|
||||||
|
"array.")
|
||||||
length = tensor.shape[0] // self.module_size
|
length = tensor.shape[0] // self.module_size
|
||||||
reshaped_tensor = tensor.view(length, self.module_size, length, self.module_size)
|
reshaped_tensor = tensor.view(length,
|
||||||
|
self.module_size,
|
||||||
|
length,
|
||||||
|
self.module_size)
|
||||||
rehaped_tensor = reshaped_tensor.permute(0, 2, 1, 3).contiguous()
|
rehaped_tensor = reshaped_tensor.permute(0, 2, 1, 3).contiguous()
|
||||||
return rehaped_tensor.view(length, length, self.module_size ** 2)
|
return rehaped_tensor.view(length, length, self.module_size ** 2)
|
||||||
|
|
||||||
def _check_bounds_and_module_size(self):
|
def _check_bounds_and_module_size(self):
|
||||||
height = self.qr_bounds[1] - self.qr_bounds[0]
|
height = self.qr_bounds[1] - self.qr_bounds[0]
|
||||||
width = self.qr_bounds[3] - self.qr_bounds[2]
|
width = self.qr_bounds[3] - self.qr_bounds[2]
|
||||||
color_warning = "Make sure that qr_fill and back colors have exact #FFFFFFF and #000000 values (and that module color values do not occur outside the QR) and invert is set correctly."
|
color_warning = "Make sure that qr_fill and back colors have exact "
|
||||||
|
"#FFFFFFF and #000000 values (and that module color values do not "
|
||||||
|
"occur outside the QR) and invert is set correctly."
|
||||||
if width != height:
|
if width != height:
|
||||||
raise RuntimeError(f"Source QR dimensions are {width} x {height}. They must be a perfect square. {color_warning}")
|
raise RuntimeError(f"Source QR dimensions are {width} x {height}. "
|
||||||
|
f"They must be a perfect square. "
|
||||||
|
f"{color_warning}")
|
||||||
if width % self.module_size:
|
if width % self.module_size:
|
||||||
raise RuntimeError(f"QR width of {width} does not fit module_size of {self.module_size}. It must be perfectly divisible. {color_warning}")
|
raise RuntimeError(f"QR width of {width} does not fit module_size "
|
||||||
|
f"of {self.module_size}. It must be perfectly "
|
||||||
|
f"divisible. {color_warning}")
|
||||||
|
|
||||||
|
def _check_equal_shape(self, source_qr, modified_qr):
|
||||||
|
if source_qr.shape != modified_qr.shape:
|
||||||
|
raise ValueError("Source and modified QR must have the same batch "
|
||||||
|
"size and dimensions.")
|
||||||
|
|
||||||
def _squeeze_by_mean(self, tensor):
|
def _squeeze_by_mean(self, tensor):
|
||||||
return torch.mean(tensor, dim=-1)
|
return torch.mean(tensor, dim=-1)
|
||||||
@@ -324,14 +466,18 @@ class QRErrorMasker:
|
|||||||
if gamma == 1:
|
if gamma == 1:
|
||||||
return tensor
|
return tensor
|
||||||
if gamma == 2.2:
|
if gamma == 2.2:
|
||||||
return torch.where(tensor <= 0.04045, tensor / 12.92, ((tensor + 0.055) / 1.055) ** 2.4)
|
return torch.where(tensor <= 0.04045,
|
||||||
|
tensor / 12.92,
|
||||||
|
(tensor + 0.055) / 1.055) ** 2.4
|
||||||
return tensor ** gamma
|
return tensor ** gamma
|
||||||
|
|
||||||
def _gamma_compression(self, tensor, gamma):
|
def _gamma_compression(self, tensor, gamma):
|
||||||
if gamma == 1:
|
if gamma == 1:
|
||||||
return tensor
|
return tensor
|
||||||
if gamma == 2.2:
|
if gamma == 2.2:
|
||||||
return torch.where(tensor <= .0031308, tensor * 12.92, 1.055 * tensor ** (1/2.4) - 0.055)
|
return torch.where(tensor <= .0031308,
|
||||||
|
tensor * 12.92,
|
||||||
|
1.055 * tensor ** (1/2.4) - 0.055)
|
||||||
return tensor ** (1/gamma)
|
return tensor ** (1/gamma)
|
||||||
|
|
||||||
def _grayscale_by_luminance(self, tensor, gamma):
|
def _grayscale_by_luminance(self, tensor, gamma):
|
||||||
@@ -346,7 +492,8 @@ class QRErrorMasker:
|
|||||||
tensor = self._reshape_tensor_to_modules(tensor)
|
tensor = self._reshape_tensor_to_modules(tensor)
|
||||||
if method == "mean":
|
if method == "mean":
|
||||||
return self._squeeze_by_mean(tensor)
|
return self._squeeze_by_mean(tensor)
|
||||||
raise RuntimeError("Module aggregation currently only supports the mean.")
|
raise RuntimeError("Module aggregation currently only supports the "
|
||||||
|
"mean.")
|
||||||
|
|
||||||
def _reduce_to_modules(
|
def _reduce_to_modules(
|
||||||
self,
|
self,
|
||||||
@@ -358,12 +505,8 @@ class QRErrorMasker:
|
|||||||
inverted_pattern,
|
inverted_pattern,
|
||||||
gamma
|
gamma
|
||||||
):
|
):
|
||||||
if source_qr.shape != modified_qr.shape:
|
|
||||||
raise ValueError("Source and modified QR must have the same dimensions.")
|
|
||||||
self.module_size = module_size
|
self.module_size = module_size
|
||||||
self.canvas_shape = (source_qr.shape[1], source_qr.shape[2])
|
self.canvas_shape = (source_qr.shape[0], source_qr.shape[1])
|
||||||
# Ignore batch dimension
|
|
||||||
source_qr, modified_qr = source_qr[0], modified_qr[0]
|
|
||||||
# Processed first for simplified indexing of QR bounds.
|
# Processed first for simplified indexing of QR bounds.
|
||||||
source_qr = self._squeeze_by_mean(source_qr)
|
source_qr = self._squeeze_by_mean(source_qr)
|
||||||
source_qr, modified_qr = self._trim_to_qr_area(source_qr,
|
source_qr, modified_qr = self._trim_to_qr_area(source_qr,
|
||||||
@@ -375,13 +518,14 @@ class QRErrorMasker:
|
|||||||
elif grayscale_method == "luminance":
|
elif grayscale_method == "luminance":
|
||||||
modified_qr = self._grayscale_by_luminance(modified_qr, gamma)
|
modified_qr = self._grayscale_by_luminance(modified_qr, gamma)
|
||||||
else:
|
else:
|
||||||
raise ValueError("Currently only mean is supported for rgb to grayscale conversion.")
|
raise ValueError("Currently only mean is supported for rgb to "
|
||||||
source_qr = self._squeeze_to_modules(source_qr, "mean")
|
"grayscale conversion.")
|
||||||
|
source_qr = torch.round(self._squeeze_to_modules(source_qr, "mean"))
|
||||||
modified_qr = self._squeeze_to_modules(modified_qr, aggregate_method)
|
modified_qr = self._squeeze_to_modules(modified_qr, aggregate_method)
|
||||||
return source_qr, modified_qr
|
return source_qr, modified_qr
|
||||||
|
|
||||||
def _create_finder_pattern_mask(self, width, inverted):
|
def _create_finder_pattern_mask(self, width, inverted):
|
||||||
mask = np.zeros((width, width), dtype=bool)
|
mask = torch.zeros((width, width), dtype=torch.bool)
|
||||||
# When borders are trimmed and QR code has module size of 1, results
|
# When borders are trimmed and QR code has module size of 1, results
|
||||||
# are consistent.
|
# are consistent.
|
||||||
finder_coords = [[0, 7, 0, 7], [0, 7, -7, None], [-7, None, 0, 7]]
|
finder_coords = [[0, 7, 0, 7], [0, 7, -7, None], [-7, None, 0, 7]]
|
||||||
@@ -411,7 +555,9 @@ class QRErrorMasker:
|
|||||||
def _replace_qr_to_canvas(self, tensor):
|
def _replace_qr_to_canvas(self, tensor):
|
||||||
length = tensor.shape[0] * self.module_size
|
length = tensor.shape[0] * self.module_size
|
||||||
bounds = self.qr_bounds
|
bounds = self.qr_bounds
|
||||||
tensor = F.interpolate(tensor.unsqueeze(0).unsqueeze(0), size=(length, length), mode='nearest')
|
tensor = F.interpolate(tensor.unsqueeze(0).unsqueeze(0),
|
||||||
|
size=(length, length),
|
||||||
|
mode='nearest')
|
||||||
canvas = torch.zeros(self.canvas_shape, dtype=torch.float32)
|
canvas = torch.zeros(self.canvas_shape, dtype=torch.float32)
|
||||||
canvas[bounds[0]:bounds[1], bounds[2]:bounds[3]] = tensor.squeeze()
|
canvas[bounds[0]:bounds[1], bounds[2]:bounds[3]] = tensor.squeeze()
|
||||||
return canvas
|
return canvas
|
||||||
@@ -423,12 +569,14 @@ class QRErrorMasker:
|
|||||||
mask,
|
mask,
|
||||||
error_difficulty
|
error_difficulty
|
||||||
):
|
):
|
||||||
modified_qr = self._bin_tensor_to_threshold(modified_qr, error_difficulty)
|
modified_qr = self._bin_tensor_to_threshold(modified_qr,
|
||||||
|
error_difficulty)
|
||||||
error = source_qr != modified_qr
|
error = source_qr != modified_qr
|
||||||
percent_error = error[mask].sum().item() / error[mask].numel()
|
percent_error = error[mask].sum().item() / error[mask].numel()
|
||||||
if mask is not None:
|
if mask is not None:
|
||||||
error[~mask] = False
|
error[~mask] = False
|
||||||
return self._replace_qr_to_canvas((error).to(torch.float32)), percent_error
|
return (self._replace_qr_to_canvas((error).to(torch.float32)),
|
||||||
|
percent_error)
|
||||||
|
|
||||||
def _qr_correlation(self, source_qr, modified_qr, mask):
|
def _qr_correlation(self, source_qr, modified_qr, mask):
|
||||||
source_qr = source_qr[mask].numpy().reshape((-1))
|
source_qr = source_qr[mask].numpy().reshape((-1))
|
||||||
@@ -451,36 +599,47 @@ class QRErrorMasker:
|
|||||||
inverted_pattern,
|
inverted_pattern,
|
||||||
gamma,
|
gamma,
|
||||||
):
|
):
|
||||||
source_qr, modified_qr = self._reduce_to_modules(source_qr,
|
self._check_equal_shape(source_qr, modified_qr)
|
||||||
modified_qr,
|
error_masks, error_percents, correlations, rmses = [], [], [], []
|
||||||
module_size,
|
for i in range(source_qr.shape[0]):
|
||||||
grayscale_method,
|
qr_s, qr_m = source_qr[i], modified_qr[i]
|
||||||
aggregate_method,
|
qr_s, qr_m = self._reduce_to_modules(qr_s,
|
||||||
inverted_pattern,
|
qr_m,
|
||||||
gamma
|
module_size,
|
||||||
)
|
grayscale_method,
|
||||||
mask = self._create_qr_mask(source_qr.shape[0], evaluate)
|
aggregate_method,
|
||||||
error_mask, percent_error = self._compare_modules(source_qr,
|
inverted_pattern,
|
||||||
modified_qr,
|
gamma
|
||||||
mask,
|
)
|
||||||
error_difficulty
|
mask = self._create_qr_mask(qr_s.shape[0], evaluate)
|
||||||
)
|
error_mask, percent_error = self._compare_modules(qr_s,
|
||||||
correlation = self._qr_correlation(source_qr, modified_qr, mask)
|
qr_m,
|
||||||
rmse = self._qr_rmse(source_qr, modified_qr, mask)
|
mask,
|
||||||
return (error_mask, percent_error, correlation, rmse)
|
error_difficulty
|
||||||
|
)
|
||||||
|
correlation = self._qr_correlation(qr_s, qr_m, mask)
|
||||||
|
rmse = self._qr_rmse(qr_s, qr_m, mask)
|
||||||
|
error_masks.append(error_mask)
|
||||||
|
error_percents.append(percent_error)
|
||||||
|
correlations.append(correlation)
|
||||||
|
rmses.append(rmse)
|
||||||
|
error_masks = torch.stack(error_masks, dim=0)
|
||||||
|
return (error_masks, error_percents, correlations, rmses)
|
||||||
|
|
||||||
|
|
||||||
NODE_CLASS_MAPPINGS = {
|
NODE_CLASS_MAPPINGS = {
|
||||||
"comfy-qr-by-module-size": QRByModuleSize,
|
"comfy-qr-by-module-size": QRByModuleSize,
|
||||||
"comfy-qr-by-image-size": QRByImageSize,
|
"comfy-qr-by-image-size": QRByImageSize,
|
||||||
"comfy-qr-by-module-split": QRByModuleSizeSplitFunctionPatterns,
|
"comfy-qr-by-module-split":
|
||||||
|
QRByModuleSizeSplitFunctionPatterns,
|
||||||
"comfy-qr-mask_errors": QRErrorMasker,
|
"comfy-qr-mask_errors": QRErrorMasker,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||||
"comfy-qr-by-module-size": "QR Code",
|
"comfy-qr-by-module-size": "QR Code",
|
||||||
"comfy-qr-by-image-size": "QR Code (Conformed to Image Size)",
|
"comfy-qr-by-image-size": "QR Code (Conformed "
|
||||||
|
"to Image Size)",
|
||||||
"comfy-qr-by-module-split": "QR Code (Split)",
|
"comfy-qr-by-module-split": "QR Code (Split)",
|
||||||
"comfy-qr-mask_errors": "Mask QR Errors",
|
"comfy-qr-mask_errors": "Mask QR Errors",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
qrcode >= 7.1
|
qrcode >= 7.1
|
||||||
|
pillow >= 9.0
|
||||||
|
|||||||