quantum-pixel 2.2.0__tar.gz → 2.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/Cargo.lock +1 -1
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/Cargo.toml +1 -1
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/PKG-INFO +7 -2
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/README.md +6 -1
- {quantum_pixel-2.2.0/quantum_pixel → quantum_pixel-2.2.2}/README_PYPI.md +6 -1
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2/quantum_pixel}/README_PYPI.md +6 -1
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/quantum_pixel/templates/index.html +1 -1
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/quantum_pixel/web.py +5 -5
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/tests/test_generator.py +7 -6
- quantum_pixel-2.2.2/tests/test_steganography.py +95 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/uv.lock +6 -6
- quantum_pixel-2.2.0/tests/test_steganography.py +0 -93
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/.github/FUNDING.yml +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/.github/workflows/CI.yml +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/.github/workflows/render-md-mermaid.yml +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/.gitignore +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/.python-version +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/LICENSE +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/assets/encoded.png +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/assets/grok.png +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/assets/intro.png +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/assets/material.png +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/assets/mermaid.png +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/assets/preview.png +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/pyproject.toml +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/quantum_pixel/__init__.py +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/quantum_pixel/generator.py +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/quantum_pixel/main.py +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/quantum_pixel/static/decode.js +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/quantum_pixel/static/encode.js +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/quantum_pixel/static/favicon.svg +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/quantum_pixel/static/robots.txt +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/quantum_pixel/static/styles.css +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/quantum_pixel/static/upload.js +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/quantum_pixel/steganography.py +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/quantum_pixel/templates/decode.html +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/quantum_pixel/templates/encode.html +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/quantum_pixel/templates/error.html +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/quantum_pixel/templates/result.html +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/render.yaml +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/requirements.txt +0 -0
- {quantum_pixel-2.2.0 → quantum_pixel-2.2.2}/src/lib.rs +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
edition = "2024"
|
|
3
3
|
name = "quantum-pixel"
|
|
4
|
-
version = "2.2.
|
|
4
|
+
version = "2.2.2"
|
|
5
5
|
description = "When both YES and NO are existed. Only human with emotions can comprehend."
|
|
6
6
|
readme = "README_PYPI.md"
|
|
7
7
|
license = "GNU General Public License v3 (GPLv3)"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quantum-pixel
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.2
|
|
4
4
|
Classifier: Development Status :: 5 - Production/Stable
|
|
5
5
|
Classifier: Natural Language :: English
|
|
6
6
|
Classifier: Programming Language :: Rust
|
|
@@ -53,6 +53,12 @@ Project-URL: repository, https://github.com/Linos1391/quantum-pixel.git
|
|
|
53
53
|
|
|
54
54
|
<br>
|
|
55
55
|
|
|
56
|
+
<a href="https://www.youtube.com/watch?v=BAnnDlOJboA">
|
|
57
|
+
<img src="https://img.youtube.com/vi/BAnnDlOJboA/maxresdefault.jpg" alt="YouTube video" width="100%">
|
|
58
|
+
</a>
|
|
59
|
+
|
|
60
|
+
<br>
|
|
61
|
+
|
|
56
62
|
- [1. Introduction](#1-introduction)
|
|
57
63
|
- [1.1. Local system (RECOMMEND)](#11-local-system-recommend)
|
|
58
64
|
- [1.2. Web service (NOT RECOMMEND)](#12-web-service-not-recommend)
|
|
@@ -60,7 +66,6 @@ Project-URL: repository, https://github.com/Linos1391/quantum-pixel.git
|
|
|
60
66
|
- [3. License](#3-license)
|
|
61
67
|
- [4. Disclaimer](#4-disclaimer)
|
|
62
68
|
|
|
63
|
-
|
|
64
69
|
<br>
|
|
65
70
|
|
|
66
71
|
# 1. Introduction
|
|
@@ -30,6 +30,12 @@
|
|
|
30
30
|
|
|
31
31
|
<br>
|
|
32
32
|
|
|
33
|
+
<a href="https://www.youtube.com/watch?v=BAnnDlOJboA">
|
|
34
|
+
<img src="https://img.youtube.com/vi/BAnnDlOJboA/maxresdefault.jpg" alt="YouTube video" width="100%">
|
|
35
|
+
</a>
|
|
36
|
+
|
|
37
|
+
<br>
|
|
38
|
+
|
|
33
39
|
- [1. Introduction](#1-introduction)
|
|
34
40
|
- [1.1. Local system (RECOMMEND)](#11-local-system-recommend)
|
|
35
41
|
- [1.2. Web service (NOT RECOMMEND)](#12-web-service-not-recommend)
|
|
@@ -37,7 +43,6 @@
|
|
|
37
43
|
- [3. License](#3-license)
|
|
38
44
|
- [4. Disclaimer](#4-disclaimer)
|
|
39
45
|
|
|
40
|
-
|
|
41
46
|
<br>
|
|
42
47
|
|
|
43
48
|
# 1. Introduction
|
|
@@ -30,6 +30,12 @@
|
|
|
30
30
|
|
|
31
31
|
<br>
|
|
32
32
|
|
|
33
|
+
<a href="https://www.youtube.com/watch?v=BAnnDlOJboA">
|
|
34
|
+
<img src="https://img.youtube.com/vi/BAnnDlOJboA/maxresdefault.jpg" alt="YouTube video" width="100%">
|
|
35
|
+
</a>
|
|
36
|
+
|
|
37
|
+
<br>
|
|
38
|
+
|
|
33
39
|
- [1. Introduction](#1-introduction)
|
|
34
40
|
- [1.1. Local system (RECOMMEND)](#11-local-system-recommend)
|
|
35
41
|
- [1.2. Web service (NOT RECOMMEND)](#12-web-service-not-recommend)
|
|
@@ -37,7 +43,6 @@
|
|
|
37
43
|
- [3. License](#3-license)
|
|
38
44
|
- [4. Disclaimer](#4-disclaimer)
|
|
39
45
|
|
|
40
|
-
|
|
41
46
|
<br>
|
|
42
47
|
|
|
43
48
|
# 1. Introduction
|
|
@@ -30,6 +30,12 @@
|
|
|
30
30
|
|
|
31
31
|
<br>
|
|
32
32
|
|
|
33
|
+
<a href="https://www.youtube.com/watch?v=BAnnDlOJboA">
|
|
34
|
+
<img src="https://img.youtube.com/vi/BAnnDlOJboA/maxresdefault.jpg" alt="YouTube video" width="100%">
|
|
35
|
+
</a>
|
|
36
|
+
|
|
37
|
+
<br>
|
|
38
|
+
|
|
33
39
|
- [1. Introduction](#1-introduction)
|
|
34
40
|
- [1.1. Local system (RECOMMEND)](#11-local-system-recommend)
|
|
35
41
|
- [1.2. Web service (NOT RECOMMEND)](#12-web-service-not-recommend)
|
|
@@ -37,7 +43,6 @@
|
|
|
37
43
|
- [3. License](#3-license)
|
|
38
44
|
- [4. Disclaimer](#4-disclaimer)
|
|
39
45
|
|
|
40
|
-
|
|
41
46
|
<br>
|
|
42
47
|
|
|
43
48
|
# 1. Introduction
|
|
@@ -85,7 +85,7 @@ def _join_uid(uid: str, filename: str) -> str:
|
|
|
85
85
|
@app.get("/", response_class=HTMLResponse)
|
|
86
86
|
async def start(request: Request):
|
|
87
87
|
"""A default start on app."""
|
|
88
|
-
return templates.TemplateResponse("index.html"
|
|
88
|
+
return templates.TemplateResponse(request, "index.html")
|
|
89
89
|
|
|
90
90
|
@app.post("/", response_class=JSONResponse)
|
|
91
91
|
async def upload(request: Request):
|
|
@@ -126,10 +126,10 @@ async def upload(request: Request):
|
|
|
126
126
|
async def start_encode(request: Request, uid: str):
|
|
127
127
|
"""Start the encode html."""
|
|
128
128
|
if not os.path.exists(_join_uid(uid, "encode_input.png")):
|
|
129
|
-
return templates.TemplateResponse("encode.html", {
|
|
129
|
+
return templates.TemplateResponse(request, "encode.html", {
|
|
130
130
|
"error": ("The image file cannot be found, you might just exit and got auto cleanup! "
|
|
131
131
|
"Otherwise, there might be an attack/error, please issue me if that's so.")})
|
|
132
|
-
return templates.TemplateResponse("encode.html", {"
|
|
132
|
+
return templates.TemplateResponse(request, "encode.html", {"uid": uid})
|
|
133
133
|
|
|
134
134
|
@app.post("/encode/{uid}")
|
|
135
135
|
async def end_encode(request: Request, uid: str):
|
|
@@ -240,10 +240,10 @@ async def end_encode(request: Request, uid: str):
|
|
|
240
240
|
async def start_decode(request: Request, uid: str):
|
|
241
241
|
"""Start the decode html."""
|
|
242
242
|
if not os.path.exists(_join_uid(uid, "decode_input.png")):
|
|
243
|
-
return templates.TemplateResponse("decode.html", {
|
|
243
|
+
return templates.TemplateResponse(request, "decode.html", {
|
|
244
244
|
"error": ("The image file cannot be found, you might just exit and got auto cleanup! "
|
|
245
245
|
"Otherwise, there might be an attack/error, please issue me if that's so.")})
|
|
246
|
-
return templates.TemplateResponse("decode.html"
|
|
246
|
+
return templates.TemplateResponse(request, "decode.html")
|
|
247
247
|
|
|
248
248
|
@app.post("/decode/{uid}", response_class=JSONResponse)
|
|
249
249
|
async def end_decode(request: Request, uid: str):
|
|
@@ -10,6 +10,8 @@ from PIL import Image
|
|
|
10
10
|
from quantum_pixel import Generator
|
|
11
11
|
|
|
12
12
|
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
13
|
+
ASSET_PATH = os.path.join(PROJECT_ROOT, "assets")
|
|
14
|
+
TEST_ASSET_PATH = os.path.join(PROJECT_ROOT, "tests", "assets")
|
|
13
15
|
|
|
14
16
|
def test_unreadable_file():
|
|
15
17
|
"""Test raising error when passing an unreadable file."""
|
|
@@ -18,7 +20,7 @@ def test_unreadable_file():
|
|
|
18
20
|
|
|
19
21
|
def test_init():
|
|
20
22
|
"""Test the __init__ function"""
|
|
21
|
-
generator = Generator(os.path.join(
|
|
23
|
+
generator = Generator(os.path.join(ASSET_PATH, "material.png"))
|
|
22
24
|
|
|
23
25
|
assert isinstance(generator.img_data, np.ndarray)
|
|
24
26
|
|
|
@@ -28,9 +30,8 @@ def test_init():
|
|
|
28
30
|
|
|
29
31
|
def test_preview():
|
|
30
32
|
"""Test the `preview` function"""
|
|
31
|
-
generator = Generator(os.path.join(
|
|
33
|
+
generator = Generator(os.path.join(ASSET_PATH, "material.png"))
|
|
34
|
+
generator.preview(0.2, os.path.join(TEST_ASSET_PATH, "preview.png"))
|
|
32
35
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
assert Image.open(os.path.join(PROJECT_ROOT, "tests", "assets", "preview.png"))
|
|
36
|
-
shutil.rmtree(os.path.join(PROJECT_ROOT, "tests", "assets"))
|
|
36
|
+
assert Image.open(os.path.join(TEST_ASSET_PATH, "preview.png"))
|
|
37
|
+
shutil.rmtree(TEST_ASSET_PATH)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#Cspell:ignore getbbox
|
|
2
|
+
"""Pytest for the `steganography.py`"""
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
import shutil
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
from PIL import Image, ImageChops
|
|
9
|
+
|
|
10
|
+
from quantum_pixel import Steganography
|
|
11
|
+
|
|
12
|
+
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
13
|
+
ASSET_PATH = os.path.join(PROJECT_ROOT, "assets")
|
|
14
|
+
TEST_ASSET_PATH = os.path.join(PROJECT_ROOT, "tests", "assets")
|
|
15
|
+
|
|
16
|
+
def _same_image(img1: Image.Image, img2: Image.Image):
|
|
17
|
+
return ImageChops.difference(img1, img2).getbbox() is None
|
|
18
|
+
|
|
19
|
+
def test_encode_overload():
|
|
20
|
+
"""Test encoding with unfit disguised image. (too small)"""
|
|
21
|
+
assert Steganography.encode(
|
|
22
|
+
password="",
|
|
23
|
+
input_file_path=os.path.join(ASSET_PATH, "material.png"),
|
|
24
|
+
output_file_path=os.path.join(TEST_ASSET_PATH, "overload.png"),
|
|
25
|
+
disguised_file_path=os.path.join(ASSET_PATH, "intro.png"),
|
|
26
|
+
).startswith("Capacity Error")
|
|
27
|
+
|
|
28
|
+
def test_decode_wrong_path():
|
|
29
|
+
"""Test decoding wrong path."""
|
|
30
|
+
assert Steganography.decode(
|
|
31
|
+
password="",
|
|
32
|
+
disguise_image=os.path.join("Not", "a", "path.png"),
|
|
33
|
+
output_folder=os.path.join(TEST_ASSET_PATH, "output")
|
|
34
|
+
) == "Image media is invalid"
|
|
35
|
+
|
|
36
|
+
def test_decode_normal_file():
|
|
37
|
+
"""Test decoding normal file which has no file embedded within."""
|
|
38
|
+
with pytest.raises(BaseException): # Rust Panic.
|
|
39
|
+
Steganography.decode(
|
|
40
|
+
password="",
|
|
41
|
+
disguise_image=os.path.join(ASSET_PATH, "intro.png"),
|
|
42
|
+
output_folder=os.path.join(TEST_ASSET_PATH, "output")
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
def test_encode_no_password():
|
|
46
|
+
"""Test encoding without password."""
|
|
47
|
+
assert Steganography.encode(
|
|
48
|
+
password="",
|
|
49
|
+
input_file_path=os.path.join(ASSET_PATH, "intro.png"),
|
|
50
|
+
output_file_path=os.path.join(TEST_ASSET_PATH, "no_password.png"),
|
|
51
|
+
disguised_file_path=os.path.join(ASSET_PATH, "material.png"),
|
|
52
|
+
) == ""
|
|
53
|
+
|
|
54
|
+
def test_decode_no_password():
|
|
55
|
+
"""Test decoding without password."""
|
|
56
|
+
assert Steganography.decode(
|
|
57
|
+
password="",
|
|
58
|
+
disguise_image=os.path.join(TEST_ASSET_PATH, "no_password.png"),
|
|
59
|
+
output_folder=os.path.join(TEST_ASSET_PATH, "output")
|
|
60
|
+
) == ""
|
|
61
|
+
assert _same_image(
|
|
62
|
+
img1=Image.open(os.path.join(ASSET_PATH, "intro.png")),
|
|
63
|
+
img2=Image.open(os.path.join(TEST_ASSET_PATH, "output", "intro.png"))
|
|
64
|
+
)
|
|
65
|
+
shutil.rmtree("tests/assets")
|
|
66
|
+
|
|
67
|
+
def test_encode_with_password():
|
|
68
|
+
"""Test encoding with password."""
|
|
69
|
+
assert Steganography.encode(
|
|
70
|
+
password="supercalifragilisticexpialidocious",
|
|
71
|
+
input_file_path=os.path.join(ASSET_PATH, "intro.png"),
|
|
72
|
+
output_file_path=os.path.join(TEST_ASSET_PATH, "with_password.png"),
|
|
73
|
+
disguised_file_path=os.path.join(ASSET_PATH, "material.png"),
|
|
74
|
+
) == ""
|
|
75
|
+
|
|
76
|
+
def test_decode_wrong_password():
|
|
77
|
+
"""Test decoding with wrong password."""
|
|
78
|
+
assert Steganography.decode(
|
|
79
|
+
password="serendipitous",
|
|
80
|
+
disguise_image=os.path.join(TEST_ASSET_PATH, "with_password.png"),
|
|
81
|
+
output_folder=os.path.join(TEST_ASSET_PATH, "output")
|
|
82
|
+
) == "Decryption error"
|
|
83
|
+
|
|
84
|
+
def test_decode_with_password():
|
|
85
|
+
"""Test decoding with password."""
|
|
86
|
+
assert Steganography.decode(
|
|
87
|
+
password="supercalifragilisticexpialidocious",
|
|
88
|
+
disguise_image=os.path.join(TEST_ASSET_PATH, "with_password.png"),
|
|
89
|
+
output_folder=os.path.join(TEST_ASSET_PATH, "output")
|
|
90
|
+
) == ""
|
|
91
|
+
assert _same_image(
|
|
92
|
+
img1=Image.open(os.path.join(ASSET_PATH, "intro.png")),
|
|
93
|
+
img2=Image.open(os.path.join(TEST_ASSET_PATH, "output", "intro.png"))
|
|
94
|
+
)
|
|
95
|
+
shutil.rmtree(TEST_ASSET_PATH)
|
|
@@ -125,7 +125,7 @@ wheels = [
|
|
|
125
125
|
|
|
126
126
|
[[package]]
|
|
127
127
|
name = "fastapi"
|
|
128
|
-
version = "0.
|
|
128
|
+
version = "0.135.1"
|
|
129
129
|
source = { registry = "https://pypi.org/simple" }
|
|
130
130
|
dependencies = [
|
|
131
131
|
{ name = "annotated-doc" },
|
|
@@ -134,9 +134,9 @@ dependencies = [
|
|
|
134
134
|
{ name = "typing-extensions" },
|
|
135
135
|
{ name = "typing-inspection" },
|
|
136
136
|
]
|
|
137
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
137
|
+
sdist = { url = "https://files.pythonhosted.org/packages/e7/7b/f8e0211e9380f7195ba3f3d40c292594fd81ba8ec4629e3854c353aaca45/fastapi-0.135.1.tar.gz", hash = "sha256:d04115b508d936d254cea545b7312ecaa58a7b3a0f84952535b4c9afae7668cd", size = 394962, upload-time = "2026-03-01T18:18:29.369Z" }
|
|
138
138
|
wheels = [
|
|
139
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
139
|
+
{ url = "https://files.pythonhosted.org/packages/e4/72/42e900510195b23a56bde950d26a51f8b723846bfcaa0286e90287f0422b/fastapi-0.135.1-py3-none-any.whl", hash = "sha256:46e2fc5745924b7c840f71ddd277382af29ce1cdb7d5eab5bf697e3fb9999c9e", size = 116999, upload-time = "2026-03-01T18:18:30.831Z" },
|
|
140
140
|
]
|
|
141
141
|
|
|
142
142
|
[package.optional-dependencies]
|
|
@@ -568,11 +568,11 @@ wheels = [
|
|
|
568
568
|
|
|
569
569
|
[[package]]
|
|
570
570
|
name = "python-dotenv"
|
|
571
|
-
version = "1.2.
|
|
571
|
+
version = "1.2.2"
|
|
572
572
|
source = { registry = "https://pypi.org/simple" }
|
|
573
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
573
|
+
sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" }
|
|
574
574
|
wheels = [
|
|
575
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
575
|
+
{ url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" },
|
|
576
576
|
]
|
|
577
577
|
|
|
578
578
|
[[package]]
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
#Cspell:ignore getbbox
|
|
2
|
-
"""Pytest for the `steganography.py`"""
|
|
3
|
-
|
|
4
|
-
import os
|
|
5
|
-
import shutil
|
|
6
|
-
|
|
7
|
-
import pytest
|
|
8
|
-
from PIL import Image, ImageChops
|
|
9
|
-
|
|
10
|
-
from quantum_pixel import Steganography
|
|
11
|
-
|
|
12
|
-
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
13
|
-
|
|
14
|
-
def _same_image(img1: Image.Image, img2: Image.Image):
|
|
15
|
-
return ImageChops.difference(img1, img2).getbbox() is None
|
|
16
|
-
|
|
17
|
-
def test_encode_overload():
|
|
18
|
-
"""Test encoding with unfit disguised image. (too small)"""
|
|
19
|
-
assert Steganography.encode(
|
|
20
|
-
password="",
|
|
21
|
-
input_file_path=os.path.join(PROJECT_ROOT, "assets", "material.png"),
|
|
22
|
-
output_file_path=os.path.join(PROJECT_ROOT, "tests", "assets", "overload.png"),
|
|
23
|
-
disguised_file_path=os.path.join(PROJECT_ROOT, "assets", "intro.png"),
|
|
24
|
-
).startswith("Capacity Error")
|
|
25
|
-
|
|
26
|
-
def test_decode_wrong_path():
|
|
27
|
-
"""Test decoding wrong path."""
|
|
28
|
-
assert Steganography.decode(
|
|
29
|
-
password="",
|
|
30
|
-
disguise_image=os.path.join("Not", "a", "path.png"),
|
|
31
|
-
output_folder=os.path.join(PROJECT_ROOT, "tests", "assets", "output")
|
|
32
|
-
) == "Image media is invalid"
|
|
33
|
-
|
|
34
|
-
def test_decode_normal_file():
|
|
35
|
-
"""Test decoding normal file which has no file embedded within."""
|
|
36
|
-
with pytest.raises(BaseException): # Rust Panic.
|
|
37
|
-
Steganography.decode(
|
|
38
|
-
password="",
|
|
39
|
-
disguise_image=os.path.join(PROJECT_ROOT, "assets", "intro.png"),
|
|
40
|
-
output_folder=os.path.join(PROJECT_ROOT, "tests", "assets", "output")
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
def test_encode_no_password():
|
|
44
|
-
"""Test encoding without password."""
|
|
45
|
-
assert Steganography.encode(
|
|
46
|
-
password="",
|
|
47
|
-
input_file_path=os.path.join(PROJECT_ROOT, "assets", "intro.png"),
|
|
48
|
-
output_file_path=os.path.join(PROJECT_ROOT, "tests", "assets", "no_password.png"),
|
|
49
|
-
disguised_file_path=os.path.join(PROJECT_ROOT, "assets", "material.png"),
|
|
50
|
-
) == ""
|
|
51
|
-
|
|
52
|
-
def test_decode_no_password():
|
|
53
|
-
"""Test decoding without password."""
|
|
54
|
-
assert Steganography.decode(
|
|
55
|
-
password="",
|
|
56
|
-
disguise_image=os.path.join(PROJECT_ROOT, "tests", "assets", "no_password.png"),
|
|
57
|
-
output_folder=os.path.join(PROJECT_ROOT, "tests", "assets", "output")
|
|
58
|
-
) == ""
|
|
59
|
-
assert _same_image(
|
|
60
|
-
img1=Image.open(os.path.join(PROJECT_ROOT, "assets", "intro.png")),
|
|
61
|
-
img2=Image.open(os.path.join(PROJECT_ROOT, "tests", "assets", "output", "intro.png"))
|
|
62
|
-
)
|
|
63
|
-
shutil.rmtree("tests/assets")
|
|
64
|
-
|
|
65
|
-
def test_encode_with_password():
|
|
66
|
-
"""Test encoding with password."""
|
|
67
|
-
assert Steganography.encode(
|
|
68
|
-
password="supercalifragilisticexpialidocious",
|
|
69
|
-
input_file_path=os.path.join(PROJECT_ROOT, "assets", "intro.png"),
|
|
70
|
-
output_file_path=os.path.join(PROJECT_ROOT, "tests", "assets", "with_password.png"),
|
|
71
|
-
disguised_file_path=os.path.join(PROJECT_ROOT, "assets", "material.png"),
|
|
72
|
-
) == ""
|
|
73
|
-
|
|
74
|
-
def test_decode_wrong_password():
|
|
75
|
-
"""Test decoding with wrong password."""
|
|
76
|
-
assert Steganography.decode(
|
|
77
|
-
password="serendipitous",
|
|
78
|
-
disguise_image=os.path.join(PROJECT_ROOT, "tests", "assets", "with_password.png"),
|
|
79
|
-
output_folder=os.path.join(PROJECT_ROOT, "tests", "assets", "output")
|
|
80
|
-
) == "Decryption error"
|
|
81
|
-
|
|
82
|
-
def test_decode_with_password():
|
|
83
|
-
"""Test decoding with password."""
|
|
84
|
-
assert Steganography.decode(
|
|
85
|
-
password="supercalifragilisticexpialidocious",
|
|
86
|
-
disguise_image=os.path.join(PROJECT_ROOT, "tests", "assets", "with_password.png"),
|
|
87
|
-
output_folder=os.path.join(PROJECT_ROOT, "tests", "assets", "output")
|
|
88
|
-
) == ""
|
|
89
|
-
assert _same_image(
|
|
90
|
-
img1=Image.open(os.path.join(PROJECT_ROOT, "assets", "intro.png")),
|
|
91
|
-
img2=Image.open(os.path.join(PROJECT_ROOT, "tests", "assets", "output", "intro.png"))
|
|
92
|
-
)
|
|
93
|
-
shutil.rmtree(os.path.join(PROJECT_ROOT, "tests", "assets"))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|