Create Mock Watermarked Image Bytes in Python Without PIL
Builds a mock image-like byte stream with an embedded watermark using only stdlib modules, for testing pipelines without PIL.
Python code
27 linesfrom io import BytesIO
import zlib
import struct
def create_watermarked_bytes(width: int, height: int, watermark: bytes) -> bytes:
"""Create a mock image-like byte stream with a watermark (no PIL)."""
header = struct.pack("<2I", width, height)
payload = watermark * max(1, (width * height // max(1, len(watermark))))
payload = payload[: width * height]
compressed = zlib.compress(payload)
size = struct.pack("<I", len(compressed))
return header + size + compressed
if __name__ == "__main__":
wm = b"WM" * 16
raw = create_watermarked_bytes(16, 16, wm)
b = BytesIO(raw)
w, h = struct.unpack("<2I", b.read(8))
comp_len = struct.unpack("<I", b.read(4))[0]
data = zlib.decompress(b.read(comp_len))
assert len(data) == w * h
assert data[:32] == wm[:32]
print(f"OK: {w}x{h}, {len(data)} bytes, watermark verified")
Output
OK: 16x16, 256 bytes, watermark verified
How it works
The function creates a binary structure: an 8-byte header carrying width and height, a 4-byte payload length, and zlib-compressed payload bytes. The payload repeats the watermark pattern to fill the exact pixel area (width times height bytes). Decompression verifies the payload length and the watermark appears at the start. Using BytesIO simulates reading from a file-like object, which mirrors real streaming scenarios.
Common mistakes
- Packing arguments in the wrong endianness or order
- Forgetting to compress or decompress the payload consistently
- Not truncating the repeated watermark to the exact required length
Variations
- Use a list of pixel tuples to build a richer mock image format
- Write the result to a temp file with pathlib instead of BytesIO
Real-world use cases
- Unit testing image upload handlers without loading heavyweight imaging libraries into the test environment.
- Stubbing watermark detection logic in CI pipelines where deterministic binary fixtures speed up regression runs.
- Validating storage and retrieval of binary blobs in backend services with predictable, synthetic data.
Sponsored
More from Automation & scripting
- Aggregate Log Errors Count by Hour in Python easy
- Automate Tweeting New Blog Posts in Python easy
- Automatically Clean Temporary Files from Applications Using Python medium
- Automatically Download the Latest Software Release from GitHub with Python medium
- Automatically Generate Charts from CSV Files with One Command medium
- Automatically Generate Hardware Inventory Reports in Python easy
Keep learning
Related tutorials and quizzes for this topic.