commit 316102bbc46d754d79cb93111840ffdbf1f330e3 Author: alex Date: Fri Sep 5 21:44:38 2025 +0200 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f55ce59 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +# Python-generated files +__pycache__/ +*.py[oc] +build/ +dist/ +wheels/ +*.egg-info + +# Virtual environments +.venv +wifi_qr_ext.png +wifi_qr.png diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..24ee5b1 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..b7d7111 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,11 @@ +[project] +name = "create-qrcode" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.13" +dependencies = [ + "argparse>=1.4.0", + "pillow>=11.3.0", + "qrcode[pil]>=8.2", +] diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..9f1e361 --- /dev/null +++ b/uv.lock @@ -0,0 +1,110 @@ +version = 1 +revision = 3 +requires-python = ">=3.13" + +[[package]] +name = "argparse" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/dd/e617cfc3f6210ae183374cd9f6a26b20514bbb5a792af97949c5aacddf0f/argparse-1.4.0.tar.gz", hash = "sha256:62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4", size = 70508, upload-time = "2015-09-12T20:22:16.217Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/94/3af39d34be01a24a6e65433d19e107099374224905f1e0cc6bbe1fd22a2f/argparse-1.4.0-py2.py3-none-any.whl", hash = "sha256:c31647edb69fd3d465a847ea3157d37bed1f95f19760b11a47aa91c04b666314", size = 23000, upload-time = "2015-09-14T16:03:16.137Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "create-qrcode" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "argparse" }, + { name = "pillow" }, + { name = "qrcode", extra = ["pil"] }, +] + +[package.metadata] +requires-dist = [ + { name = "argparse", specifier = ">=1.4.0" }, + { name = "pillow", specifier = ">=11.3.0" }, + { name = "qrcode", extras = ["pil"], specifier = ">=8.2" }, +] + +[[package]] +name = "pillow" +version = "11.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/d0d6dea55cd152ce3d6767bb38a8fc10e33796ba4ba210cbab9354b6d238/pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523", size = 47113069, upload-time = "2025-07-01T09:16:30.666Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/93/0952f2ed8db3a5a4c7a11f91965d6184ebc8cd7cbb7941a260d5f018cd2d/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd", size = 2128328, upload-time = "2025-07-01T09:14:35.276Z" }, + { url = "https://files.pythonhosted.org/packages/4b/e8/100c3d114b1a0bf4042f27e0f87d2f25e857e838034e98ca98fe7b8c0a9c/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8", size = 2170652, upload-time = "2025-07-01T09:14:37.203Z" }, + { url = "https://files.pythonhosted.org/packages/aa/86/3f758a28a6e381758545f7cdb4942e1cb79abd271bea932998fc0db93cb6/pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f", size = 2227443, upload-time = "2025-07-01T09:14:39.344Z" }, + { url = "https://files.pythonhosted.org/packages/01/f4/91d5b3ffa718df2f53b0dc109877993e511f4fd055d7e9508682e8aba092/pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c", size = 5278474, upload-time = "2025-07-01T09:14:41.843Z" }, + { url = "https://files.pythonhosted.org/packages/f9/0e/37d7d3eca6c879fbd9dba21268427dffda1ab00d4eb05b32923d4fbe3b12/pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd", size = 4686038, upload-time = "2025-07-01T09:14:44.008Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b0/3426e5c7f6565e752d81221af9d3676fdbb4f352317ceafd42899aaf5d8a/pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e", size = 5864407, upload-time = "2025-07-03T13:10:15.628Z" }, + { url = "https://files.pythonhosted.org/packages/fc/c1/c6c423134229f2a221ee53f838d4be9d82bab86f7e2f8e75e47b6bf6cd77/pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1", size = 7639094, upload-time = "2025-07-03T13:10:21.857Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c9/09e6746630fe6372c67c648ff9deae52a2bc20897d51fa293571977ceb5d/pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805", size = 5973503, upload-time = "2025-07-01T09:14:45.698Z" }, + { url = "https://files.pythonhosted.org/packages/d5/1c/a2a29649c0b1983d3ef57ee87a66487fdeb45132df66ab30dd37f7dbe162/pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8", size = 6642574, upload-time = "2025-07-01T09:14:47.415Z" }, + { url = "https://files.pythonhosted.org/packages/36/de/d5cc31cc4b055b6c6fd990e3e7f0f8aaf36229a2698501bcb0cdf67c7146/pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2", size = 6084060, upload-time = "2025-07-01T09:14:49.636Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ea/502d938cbaeec836ac28a9b730193716f0114c41325db428e6b280513f09/pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b", size = 6721407, upload-time = "2025-07-01T09:14:51.962Z" }, + { url = "https://files.pythonhosted.org/packages/45/9c/9c5e2a73f125f6cbc59cc7087c8f2d649a7ae453f83bd0362ff7c9e2aee2/pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3", size = 6273841, upload-time = "2025-07-01T09:14:54.142Z" }, + { url = "https://files.pythonhosted.org/packages/23/85/397c73524e0cd212067e0c969aa245b01d50183439550d24d9f55781b776/pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51", size = 6978450, upload-time = "2025-07-01T09:14:56.436Z" }, + { url = "https://files.pythonhosted.org/packages/17/d2/622f4547f69cd173955194b78e4d19ca4935a1b0f03a302d655c9f6aae65/pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580", size = 2423055, upload-time = "2025-07-01T09:14:58.072Z" }, + { url = "https://files.pythonhosted.org/packages/dd/80/a8a2ac21dda2e82480852978416cfacd439a4b490a501a288ecf4fe2532d/pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e", size = 5281110, upload-time = "2025-07-01T09:14:59.79Z" }, + { url = "https://files.pythonhosted.org/packages/44/d6/b79754ca790f315918732e18f82a8146d33bcd7f4494380457ea89eb883d/pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d", size = 4689547, upload-time = "2025-07-01T09:15:01.648Z" }, + { url = "https://files.pythonhosted.org/packages/49/20/716b8717d331150cb00f7fdd78169c01e8e0c219732a78b0e59b6bdb2fd6/pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced", size = 5901554, upload-time = "2025-07-03T13:10:27.018Z" }, + { url = "https://files.pythonhosted.org/packages/74/cf/a9f3a2514a65bb071075063a96f0a5cf949c2f2fce683c15ccc83b1c1cab/pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c", size = 7669132, upload-time = "2025-07-03T13:10:33.01Z" }, + { url = "https://files.pythonhosted.org/packages/98/3c/da78805cbdbee9cb43efe8261dd7cc0b4b93f2ac79b676c03159e9db2187/pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8", size = 6005001, upload-time = "2025-07-01T09:15:03.365Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fa/ce044b91faecf30e635321351bba32bab5a7e034c60187fe9698191aef4f/pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59", size = 6668814, upload-time = "2025-07-01T09:15:05.655Z" }, + { url = "https://files.pythonhosted.org/packages/7b/51/90f9291406d09bf93686434f9183aba27b831c10c87746ff49f127ee80cb/pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe", size = 6113124, upload-time = "2025-07-01T09:15:07.358Z" }, + { url = "https://files.pythonhosted.org/packages/cd/5a/6fec59b1dfb619234f7636d4157d11fb4e196caeee220232a8d2ec48488d/pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c", size = 6747186, upload-time = "2025-07-01T09:15:09.317Z" }, + { url = "https://files.pythonhosted.org/packages/49/6b/00187a044f98255225f172de653941e61da37104a9ea60e4f6887717e2b5/pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788", size = 6277546, upload-time = "2025-07-01T09:15:11.311Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5c/6caaba7e261c0d75bab23be79f1d06b5ad2a2ae49f028ccec801b0e853d6/pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31", size = 6985102, upload-time = "2025-07-01T09:15:13.164Z" }, + { url = "https://files.pythonhosted.org/packages/f3/7e/b623008460c09a0cb38263c93b828c666493caee2eb34ff67f778b87e58c/pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e", size = 2424803, upload-time = "2025-07-01T09:15:15.695Z" }, + { url = "https://files.pythonhosted.org/packages/73/f4/04905af42837292ed86cb1b1dabe03dce1edc008ef14c473c5c7e1443c5d/pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12", size = 5278520, upload-time = "2025-07-01T09:15:17.429Z" }, + { url = "https://files.pythonhosted.org/packages/41/b0/33d79e377a336247df6348a54e6d2a2b85d644ca202555e3faa0cf811ecc/pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a", size = 4686116, upload-time = "2025-07-01T09:15:19.423Z" }, + { url = "https://files.pythonhosted.org/packages/49/2d/ed8bc0ab219ae8768f529597d9509d184fe8a6c4741a6864fea334d25f3f/pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632", size = 5864597, upload-time = "2025-07-03T13:10:38.404Z" }, + { url = "https://files.pythonhosted.org/packages/b5/3d/b932bb4225c80b58dfadaca9d42d08d0b7064d2d1791b6a237f87f661834/pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673", size = 7638246, upload-time = "2025-07-03T13:10:44.987Z" }, + { url = "https://files.pythonhosted.org/packages/09/b5/0487044b7c096f1b48f0d7ad416472c02e0e4bf6919541b111efd3cae690/pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027", size = 5973336, upload-time = "2025-07-01T09:15:21.237Z" }, + { url = "https://files.pythonhosted.org/packages/a8/2d/524f9318f6cbfcc79fbc004801ea6b607ec3f843977652fdee4857a7568b/pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77", size = 6642699, upload-time = "2025-07-01T09:15:23.186Z" }, + { url = "https://files.pythonhosted.org/packages/6f/d2/a9a4f280c6aefedce1e8f615baaa5474e0701d86dd6f1dede66726462bbd/pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874", size = 6083789, upload-time = "2025-07-01T09:15:25.1Z" }, + { url = "https://files.pythonhosted.org/packages/fe/54/86b0cd9dbb683a9d5e960b66c7379e821a19be4ac5810e2e5a715c09a0c0/pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a", size = 6720386, upload-time = "2025-07-01T09:15:27.378Z" }, + { url = "https://files.pythonhosted.org/packages/e7/95/88efcaf384c3588e24259c4203b909cbe3e3c2d887af9e938c2022c9dd48/pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214", size = 6370911, upload-time = "2025-07-01T09:15:29.294Z" }, + { url = "https://files.pythonhosted.org/packages/2e/cc/934e5820850ec5eb107e7b1a72dd278140731c669f396110ebc326f2a503/pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635", size = 7117383, upload-time = "2025-07-01T09:15:31.128Z" }, + { url = "https://files.pythonhosted.org/packages/d6/e9/9c0a616a71da2a5d163aa37405e8aced9a906d574b4a214bede134e731bc/pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6", size = 2511385, upload-time = "2025-07-01T09:15:33.328Z" }, + { url = "https://files.pythonhosted.org/packages/1a/33/c88376898aff369658b225262cd4f2659b13e8178e7534df9e6e1fa289f6/pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae", size = 5281129, upload-time = "2025-07-01T09:15:35.194Z" }, + { url = "https://files.pythonhosted.org/packages/1f/70/d376247fb36f1844b42910911c83a02d5544ebd2a8bad9efcc0f707ea774/pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653", size = 4689580, upload-time = "2025-07-01T09:15:37.114Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1c/537e930496149fbac69efd2fc4329035bbe2e5475b4165439e3be9cb183b/pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6", size = 5902860, upload-time = "2025-07-03T13:10:50.248Z" }, + { url = "https://files.pythonhosted.org/packages/bd/57/80f53264954dcefeebcf9dae6e3eb1daea1b488f0be8b8fef12f79a3eb10/pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36", size = 7670694, upload-time = "2025-07-03T13:10:56.432Z" }, + { url = "https://files.pythonhosted.org/packages/70/ff/4727d3b71a8578b4587d9c276e90efad2d6fe0335fd76742a6da08132e8c/pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b", size = 6005888, upload-time = "2025-07-01T09:15:39.436Z" }, + { url = "https://files.pythonhosted.org/packages/05/ae/716592277934f85d3be51d7256f3636672d7b1abfafdc42cf3f8cbd4b4c8/pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477", size = 6670330, upload-time = "2025-07-01T09:15:41.269Z" }, + { url = "https://files.pythonhosted.org/packages/e7/bb/7fe6cddcc8827b01b1a9766f5fdeb7418680744f9082035bdbabecf1d57f/pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50", size = 6114089, upload-time = "2025-07-01T09:15:43.13Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f5/06bfaa444c8e80f1a8e4bff98da9c83b37b5be3b1deaa43d27a0db37ef84/pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b", size = 6748206, upload-time = "2025-07-01T09:15:44.937Z" }, + { url = "https://files.pythonhosted.org/packages/f0/77/bc6f92a3e8e6e46c0ca78abfffec0037845800ea38c73483760362804c41/pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12", size = 6377370, upload-time = "2025-07-01T09:15:46.673Z" }, + { url = "https://files.pythonhosted.org/packages/4a/82/3a721f7d69dca802befb8af08b7c79ebcab461007ce1c18bd91a5d5896f9/pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db", size = 7121500, upload-time = "2025-07-01T09:15:48.512Z" }, + { url = "https://files.pythonhosted.org/packages/89/c7/5572fa4a3f45740eaab6ae86fcdf7195b55beac1371ac8c619d880cfe948/pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa", size = 2512835, upload-time = "2025-07-01T09:15:50.399Z" }, +] + +[[package]] +name = "qrcode" +version = "8.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8f/b2/7fc2931bfae0af02d5f53b174e9cf701adbb35f39d69c2af63d4a39f81a9/qrcode-8.2.tar.gz", hash = "sha256:35c3f2a4172b33136ab9f6b3ef1c00260dd2f66f858f24d88418a015f446506c", size = 43317, upload-time = "2025-05-01T15:44:24.726Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dd/b8/d2d6d731733f51684bbf76bf34dab3b70a9148e8f2cef2bb544fccec681a/qrcode-8.2-py3-none-any.whl", hash = "sha256:16e64e0716c14960108e85d853062c9e8bba5ca8252c0b4d0231b9df4060ff4f", size = 45986, upload-time = "2025-05-01T15:44:22.781Z" }, +] + +[package.optional-dependencies] +pil = [ + { name = "pillow" }, +] diff --git a/wifi_qr.py b/wifi_qr.py new file mode 100644 index 0000000..b45ff6c --- /dev/null +++ b/wifi_qr.py @@ -0,0 +1,456 @@ +#!/usr/bin/env python3 +""" +Generatore di QR Code Universale +Supporta WiFi, URL, testo, email, SMS, contatti vCard, eventi calendario e altro +""" + +import qrcode +from PIL import Image +import argparse +import sys +import os +import re +from datetime import datetime +from urllib.parse import quote + +class UniversalQRGenerator: + def __init__(self): + self.qr_types = { + 'wifi': 'Connessione WiFi', + 'url': 'URL/Link web', + 'text': 'Testo semplice', + 'email': 'Email', + 'sms': 'SMS', + 'phone': 'Numero telefono', + 'vcard': 'Biglietto da visita (vCard)', + 'event': 'Evento calendario', + 'geo': 'Posizione geografica', + 'whatsapp': 'Messaggio WhatsApp', + 'raw': 'Contenuto personalizzato' + } + + # === GENERATORI DI CONTENUTO === + + def generate_wifi_qr(self, ssid, password=None, security='WPA', hidden=False): + """Genera QR code per WiFi""" + if security not in ['WPA', 'WEP', 'nopass']: + raise ValueError("Sicurezza deve essere: WPA, WEP o nopass") + + ssid_escaped = self._escape_wifi_chars(ssid) + password_escaped = self._escape_wifi_chars(password) if password else "" + + wifi_string = f"WIFI:T:{security};" + wifi_string += f"S:{ssid_escaped};" + if password and security != 'nopass': + wifi_string += f"P:{password_escaped};" + if hidden: + wifi_string += "H:true;" + wifi_string += ";" + + return wifi_string + + def generate_url_qr(self, url): + """Genera QR code per URL""" + if not url.startswith(('http://', 'https://')): + url = 'https://' + url + return url + + def generate_email_qr(self, email, subject=None, body=None): + """Genera QR code per email""" + if not self._is_valid_email(email): + raise ValueError("Email non valida") + + mailto_string = f"mailto:{email}" + params = [] + if subject: + params.append(f"subject={quote(subject)}") + if body: + params.append(f"body={quote(body)}") + + if params: + mailto_string += "?" + "&".join(params) + + return mailto_string + + def generate_sms_qr(self, number, message=None): + """Genera QR code per SMS""" + sms_string = f"sms:{number}" + if message: + sms_string += f"?body={quote(message)}" + return sms_string + + def generate_phone_qr(self, number): + """Genera QR code per chiamata telefonica""" + return f"tel:{number}" + + def generate_vcard_qr(self, first_name, last_name, phone=None, email=None, + organization=None, url=None): + """Genera QR code per biglietto da visita (vCard)""" + vcard = "BEGIN:VCARD\nVERSION:3.0\n" + vcard += f"FN:{first_name} {last_name}\n" + vcard += f"N:{last_name};{first_name};;;\n" + + if phone: + vcard += f"TEL:{phone}\n" + if email: + vcard += f"EMAIL:{email}\n" + if organization: + vcard += f"ORG:{organization}\n" + if url: + vcard += f"URL:{url}\n" + + vcard += "END:VCARD" + return vcard + + def generate_event_qr(self, title, start_date, end_date=None, location=None, description=None): + """Genera QR code per evento calendario""" + # Formato: YYYYMMDDTHHMMSS + start_formatted = start_date.strftime("%Y%m%dT%H%M%S") + end_formatted = end_date.strftime("%Y%m%dT%H%M%S") if end_date else start_formatted + + vevent = "BEGIN:VEVENT\n" + vevent += f"SUMMARY:{title}\n" + vevent += f"DTSTART:{start_formatted}\n" + vevent += f"DTEND:{end_formatted}\n" + + if location: + vevent += f"LOCATION:{location}\n" + if description: + vevent += f"DESCRIPTION:{description}\n" + + vevent += "END:VEVENT" + return vevent + + def generate_geo_qr(self, latitude, longitude, altitude=None): + """Genera QR code per posizione geografica""" + if altitude: + return f"geo:{latitude},{longitude},{altitude}" + else: + return f"geo:{latitude},{longitude}" + + def generate_whatsapp_qr(self, number, message=None): + """Genera QR code per messaggio WhatsApp""" + # Rimuovi caratteri non numerici dal numero + clean_number = re.sub(r'[^\d+]', '', number) + + wa_string = f"https://wa.me/{clean_number}" + if message: + wa_string += f"?text={quote(message)}" + return wa_string + + def generate_text_qr(self, text): + """Genera QR code per testo semplice""" + return text + + def generate_raw_qr(self, content): + """Genera QR code per contenuto personalizzato""" + return content + + # === UTILITΓ€ === + + def _escape_wifi_chars(self, text): + """Escape caratteri speciali per WiFi""" + if not text: + return "" + special_chars = ['\\', ';', ',', '"', ':'] + escaped_text = text + for char in special_chars: + escaped_text = escaped_text.replace(char, f'\\{char}') + return escaped_text + + def _is_valid_email(self, email): + """Validazione email semplice""" + pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' + return re.match(pattern, email) is not None + + # === GENERATORE QR CODE === + + def create_qr_code(self, content, filename='qrcode.png', + error_correction=qrcode.constants.ERROR_CORRECT_M, + border=4, box_size=10, fill_color="black", back_color="white"): + """Genera il QR code dal contenuto""" + try: + qr = qrcode.QRCode( + version=1, + error_correction=error_correction, + box_size=box_size, + border=border, + ) + + qr.add_data(content) + qr.make(fit=True) + + img = qr.make_image(fill_color=fill_color, back_color=back_color) + img.save(filename) + + return img, content + + except Exception as e: + print(f"❌ Errore nella generazione del QR code: {e}") + return None, None + + # === INTERFACCIA PRINCIPALE === + + def generate_qr(self, qr_type, filename='qrcode.png', show_details=True, **kwargs): + """Metodo principale per generare QR code di qualsiasi tipo""" + try: + # Genera il contenuto in base al tipo + if qr_type == 'wifi': + content = self.generate_wifi_qr(**kwargs) + elif qr_type == 'url': + content = self.generate_url_qr(**kwargs) + elif qr_type == 'email': + content = self.generate_email_qr(**kwargs) + elif qr_type == 'sms': + content = self.generate_sms_qr(**kwargs) + elif qr_type == 'phone': + content = self.generate_phone_qr(**kwargs) + elif qr_type == 'vcard': + content = self.generate_vcard_qr(**kwargs) + elif qr_type == 'event': + content = self.generate_event_qr(**kwargs) + elif qr_type == 'geo': + content = self.generate_geo_qr(**kwargs) + elif qr_type == 'whatsapp': + content = self.generate_whatsapp_qr(**kwargs) + elif qr_type == 'text': + content = self.generate_text_qr(**kwargs) + elif qr_type == 'raw': + content = self.generate_raw_qr(**kwargs) + else: + raise ValueError(f"Tipo QR non supportato: {qr_type}") + + # Genera il QR code + img, final_content = self.create_qr_code(content, filename) + + if img and show_details: + print("βœ… QR Code generato con successo!") + print(f"πŸ“ File salvato: {filename}") + print(f"🏷️ Tipo: {self.qr_types.get(qr_type, qr_type)}") + print(f"πŸ“„ Contenuto: {final_content[:100]}{'...' if len(final_content) > 100 else ''}") + + return img + + except Exception as e: + print(f"❌ Errore: {e}") + return None + +def main(): + """Interfaccia da riga di comando""" + parser = argparse.ArgumentParser( + description='Generatore QR Code Universale', + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Tipi di QR Code supportati: + wifi - Connessione WiFi + url - URL/Link web + text - Testo semplice + email - Email + sms - SMS + phone - Numero telefono + vcard - Biglietto da visita + event - Evento calendario + geo - Posizione geografica + whatsapp - Messaggio WhatsApp + raw - Contenuto personalizzato + +Esempi di utilizzo: + python qr_generator.py wifi -s "MiaRete" -p "password123" + python qr_generator.py url --url "https://google.com" + python qr_generator.py email --email "test@example.com" --subject "Ciao" + python qr_generator.py sms --number "+39123456789" --message "Ciao!" + python qr_generator.py vcard --first-name "Mario" --last-name "Rossi" --phone "+39123456789" + python qr_generator.py geo --latitude 45.4642 --longitude 9.1900 + """ + ) + + parser.add_argument('type', choices=list(UniversalQRGenerator().qr_types.keys()), + help='Tipo di QR code da generare') + parser.add_argument('-o', '--output', default='qrcode.png', + help='Nome del file di output') + parser.add_argument('-q', '--quiet', action='store_true', + help='Non mostrare i dettagli') + + # Argomenti per WiFi + wifi_group = parser.add_argument_group('WiFi') + wifi_group.add_argument('-s', '--ssid', help='Nome rete WiFi') + wifi_group.add_argument('-p', '--password', help='Password WiFi') + wifi_group.add_argument('--security', choices=['WPA', 'WEP', 'nopass'], + default='WPA', help='Tipo sicurezza WiFi') + wifi_group.add_argument('--hidden', action='store_true', help='Rete nascosta') + + # Argomenti per URL + url_group = parser.add_argument_group('URL') + url_group.add_argument('--url', help='URL del sito web') + + # Argomenti per email + email_group = parser.add_argument_group('Email') + email_group.add_argument('--email', help='Indirizzo email') + email_group.add_argument('--subject', help='Oggetto email') + email_group.add_argument('--body', help='Corpo email') + + # Argomenti per SMS/Phone + comm_group = parser.add_argument_group('SMS/Telefono') + comm_group.add_argument('--number', help='Numero di telefono') + comm_group.add_argument('--message', help='Messaggio SMS/WhatsApp') + + # Argomenti per vCard + vcard_group = parser.add_argument_group('vCard') + vcard_group.add_argument('--first-name', help='Nome') + vcard_group.add_argument('--last-name', help='Cognome') + vcard_group.add_argument('--organization', help='Organizzazione') + + # Argomenti per geolocalizzazione + geo_group = parser.add_argument_group('Geolocalizzazione') + geo_group.add_argument('--latitude', type=float, help='Latitudine') + geo_group.add_argument('--longitude', type=float, help='Longitudine') + geo_group.add_argument('--altitude', type=float, help='Altitudine') + + # Argomenti per testo/raw + text_group = parser.add_argument_group('Testo/Raw') + text_group.add_argument('--text', help='Testo da codificare') + text_group.add_argument('--content', help='Contenuto raw personalizzato') + + args = parser.parse_args() + + # Preparazione parametri per il generatore + generator = UniversalQRGenerator() + kwargs = {} + + if args.type == 'wifi': + if not args.ssid: + print("❌ SSID obbligatorio per WiFi") + sys.exit(1) + kwargs = { + 'ssid': args.ssid, + 'password': args.password, + 'security': args.security, + 'hidden': args.hidden + } + elif args.type == 'url': + if not args.url: + print("❌ URL obbligatorio") + sys.exit(1) + kwargs = {'url': args.url} + elif args.type == 'email': + if not args.email: + print("❌ Email obbligatoria") + sys.exit(1) + kwargs = { + 'email': args.email, + 'subject': args.subject, + 'body': args.body + } + elif args.type in ['sms', 'phone']: + if not args.number: + print("❌ Numero obbligatorio") + sys.exit(1) + kwargs = {'number': args.number} + if args.type == 'sms' and args.message: + kwargs['message'] = args.message + elif args.type == 'vcard': + if not (args.first_name and args.last_name): + print("❌ Nome e cognome obbligatori per vCard") + sys.exit(1) + kwargs = { + 'first_name': args.first_name, + 'last_name': args.last_name, + 'phone': args.number, + 'email': args.email, + 'organization': args.organization + } + elif args.type == 'geo': + if args.latitude is None or args.longitude is None: + print("❌ Latitudine e longitudine obbligatorie") + sys.exit(1) + kwargs = { + 'latitude': args.latitude, + 'longitude': args.longitude, + 'altitude': args.altitude + } + elif args.type == 'whatsapp': + if not args.number: + print("❌ Numero obbligatorio per WhatsApp") + sys.exit(1) + kwargs = { + 'number': args.number, + 'message': args.message + } + elif args.type == 'text': + if not args.text: + print("❌ Testo obbligatorio") + sys.exit(1) + kwargs = {'text': args.text} + elif args.type == 'raw': + if not args.content: + print("❌ Contenuto obbligatorio") + sys.exit(1) + kwargs = {'content': args.content} + + # Genera il QR code + result = generator.generate_qr( + args.type, + filename=args.output, + show_details=not args.quiet, + **kwargs + ) + + sys.exit(0 if result else 1) + +def interactive_mode(): + """ModalitΓ  interattiva""" + generator = UniversalQRGenerator() + + print("πŸ”§ Generatore QR Code Universale - ModalitΓ  Interattiva") + print("=" * 60) + + # Selezione tipo + print("\nπŸ“‹ Tipi di QR Code disponibili:") + types_list = list(generator.qr_types.items()) + for i, (key, desc) in enumerate(types_list, 1): + print(f" {i:2d}. {desc}") + + try: + choice = int(input(f"\nScegli (1-{len(types_list)}): ")) + qr_type = types_list[choice - 1][0] + except (ValueError, IndexError): + print("❌ Scelta non valida") + return + + print(f"\n🎯 Tipo selezionato: {generator.qr_types[qr_type]}") + + # Input specifici per tipo + kwargs = {} + + if qr_type == 'wifi': + kwargs['ssid'] = input("πŸ“Ά SSID (nome rete): ") + kwargs['security'] = input("πŸ”’ Sicurezza (WPA/WEP/nopass) [WPA]: ") or 'WPA' + if kwargs['security'] != 'nopass': + kwargs['password'] = input("πŸ”‘ Password: ") + kwargs['hidden'] = input("πŸ‘οΈ Rete nascosta? (s/N): ").lower().startswith('s') + + elif qr_type == 'url': + kwargs['url'] = input("🌐 URL: ") + + elif qr_type == 'email': + kwargs['email'] = input("πŸ“§ Email: ") + kwargs['subject'] = input("πŸ“ Oggetto (opzionale): ") or None + kwargs['body'] = input("πŸ’¬ Messaggio (opzionale): ") or None + + elif qr_type == 'text': + kwargs['text'] = input("πŸ“„ Testo: ") + + # Altri tipi... + + # Nome file + filename = input("πŸ“ Nome file [qrcode.png]: ") or "qrcode.png" + + # Genera + print("\n⏳ Generazione in corso...") + generator.generate_qr(qr_type, filename=filename, **kwargs) + +if __name__ == "__main__": + if len(sys.argv) == 1: + interactive_mode() + else: + main() \ No newline at end of file