hufi 0.1.0__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.
hufi-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,95 @@
1
+ Metadata-Version: 2.4
2
+ Name: hufi
3
+ Version: 0.1.0
4
+ Summary: A Python library for encoding and decoding .hufi image files.
5
+ Project-URL: Homepage, https://github.com/yourusername/hufipy
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: Pillow>=9.0.0
9
+
10
+ ```markdown
11
+ # HUFI (`hufipy`)
12
+
13
+ A lightweight Python library for encoding, decoding, and inspecting **`.hufi`** (Hagan's Ultimate Format for Images) files.
14
+
15
+ `.hufi` is a custom binary image format that pairs horizontal predictive sub-filtering with zlib Deflate compression to achieve fast, efficient, lossless image storage.
16
+
17
+ ---
18
+
19
+ ## Installation
20
+
21
+ Install via `pip`:
22
+
23
+ ```bash
24
+ pip install hufi
25
+
26
+ ```
27
+
28
+ ---
29
+
30
+ ## Quickstart
31
+
32
+ ### 1. Save and Open `.hufi` Files
33
+
34
+ ```python
35
+ import hufi
36
+
37
+ # Convert standard image formats (PNG, JPG, WEBP, etc.) to .hufi
38
+ hufi.save("input.png", "output.hufi")
39
+
40
+ # Load a .hufi file directly as a Pillow (PIL) Image
41
+ img = hufi.open_hufi("output.hufi")
42
+ img.show()
43
+
44
+ ```
45
+
46
+ ### 2. Extract Metadata Fast
47
+
48
+ Inspect header details without decompressing the entire image payload:
49
+
50
+ ```python
51
+ import hufi
52
+
53
+ metadata = hufi.get_metadata("output.hufi")
54
+ print(f"Dimensions: {metadata['width']}x{metadata['height']} px")
55
+ print(f"Channels: {metadata['channels']}")
56
+ print(f"Magic: {metadata['magic']}")
57
+
58
+ ```
59
+
60
+ ### 3. In-Memory Encoding & Decoding
61
+
62
+ Work with bytes and Pillow image objects in memory without writing to disk:
63
+
64
+ ```python
65
+ import hufi
66
+ from PIL import Image
67
+
68
+ # Encode a PIL Image to raw .hufi bytes
69
+ img = Image.open("photo.jpg")
70
+ hufi_bytes = hufi.encode(img, level=6)
71
+
72
+ # Decode raw .hufi bytes back to a PIL Image
73
+ restored_img = hufi.decode(hufi_bytes)
74
+
75
+ ```
76
+
77
+ ---
78
+
79
+ ## Technical Specification
80
+
81
+ The `.hufi` format consists of a 13-byte binary header followed by a compressed payload:
82
+
83
+ | Field | Type | Size | Description |
84
+ | --- | --- | --- | --- |
85
+ | **Magic Signature** | ASCII String | 4 Bytes | Magic bytes `b"HUFI"` |
86
+ | **Width** | Uint32 (Little-Endian) | 4 Bytes | Image width in pixels |
87
+ | **Height** | Uint32 (Little-Endian) | 4 Bytes | Image height in pixels |
88
+ | **Channels** | Uint8 | 1 Byte | Color channels (default `3` for RGB) |
89
+ | **Payload** | Deflate Bytes | Variable | Horizontal sub-filtered byte deltas compressed via Zlib |
90
+
91
+ ---
92
+
93
+ ## License
94
+
95
+ Licensed under the Apache License, Version 2.0. See `LICENSE` for details.
hufi-0.1.0/README.md ADDED
@@ -0,0 +1,86 @@
1
+ ```markdown
2
+ # HUFI (`hufipy`)
3
+
4
+ A lightweight Python library for encoding, decoding, and inspecting **`.hufi`** (Hagan's Ultimate Format for Images) files.
5
+
6
+ `.hufi` is a custom binary image format that pairs horizontal predictive sub-filtering with zlib Deflate compression to achieve fast, efficient, lossless image storage.
7
+
8
+ ---
9
+
10
+ ## Installation
11
+
12
+ Install via `pip`:
13
+
14
+ ```bash
15
+ pip install hufi
16
+
17
+ ```
18
+
19
+ ---
20
+
21
+ ## Quickstart
22
+
23
+ ### 1. Save and Open `.hufi` Files
24
+
25
+ ```python
26
+ import hufi
27
+
28
+ # Convert standard image formats (PNG, JPG, WEBP, etc.) to .hufi
29
+ hufi.save("input.png", "output.hufi")
30
+
31
+ # Load a .hufi file directly as a Pillow (PIL) Image
32
+ img = hufi.open_hufi("output.hufi")
33
+ img.show()
34
+
35
+ ```
36
+
37
+ ### 2. Extract Metadata Fast
38
+
39
+ Inspect header details without decompressing the entire image payload:
40
+
41
+ ```python
42
+ import hufi
43
+
44
+ metadata = hufi.get_metadata("output.hufi")
45
+ print(f"Dimensions: {metadata['width']}x{metadata['height']} px")
46
+ print(f"Channels: {metadata['channels']}")
47
+ print(f"Magic: {metadata['magic']}")
48
+
49
+ ```
50
+
51
+ ### 3. In-Memory Encoding & Decoding
52
+
53
+ Work with bytes and Pillow image objects in memory without writing to disk:
54
+
55
+ ```python
56
+ import hufi
57
+ from PIL import Image
58
+
59
+ # Encode a PIL Image to raw .hufi bytes
60
+ img = Image.open("photo.jpg")
61
+ hufi_bytes = hufi.encode(img, level=6)
62
+
63
+ # Decode raw .hufi bytes back to a PIL Image
64
+ restored_img = hufi.decode(hufi_bytes)
65
+
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Technical Specification
71
+
72
+ The `.hufi` format consists of a 13-byte binary header followed by a compressed payload:
73
+
74
+ | Field | Type | Size | Description |
75
+ | --- | --- | --- | --- |
76
+ | **Magic Signature** | ASCII String | 4 Bytes | Magic bytes `b"HUFI"` |
77
+ | **Width** | Uint32 (Little-Endian) | 4 Bytes | Image width in pixels |
78
+ | **Height** | Uint32 (Little-Endian) | 4 Bytes | Image height in pixels |
79
+ | **Channels** | Uint8 | 1 Byte | Color channels (default `3` for RGB) |
80
+ | **Payload** | Deflate Bytes | Variable | Horizontal sub-filtered byte deltas compressed via Zlib |
81
+
82
+ ---
83
+
84
+ ## License
85
+
86
+ Licensed under the Apache License, Version 2.0. See `LICENSE` for details.
@@ -0,0 +1,3 @@
1
+ from .core import encode, decode, save, open_hufi, get_metadata
2
+
3
+ __all__ = ["encode", "decode", "save", "open_hufi", "get_metadata"]
@@ -0,0 +1,119 @@
1
+ import struct
2
+ import zlib
3
+ from typing import Union, Dict, Any
4
+ from PIL import Image
5
+
6
+ # Format Specifications
7
+ MAGIC_HEADER = b"HUFI"
8
+ HEADER_FORMAT = "<4sIIB" # Magic (4s), Width (uint32), Height (uint32), Channels (uint8)
9
+ HEADER_SIZE = struct.calcsize(HEADER_FORMAT) # 13 bytes
10
+
11
+
12
+ def apply_sub_filter(raw_bytes: bytes, width: int, height: int, channels: int = 3) -> bytes:
13
+ """Applies horizontal predictive sub-filter: delta[x] = (pixel[x] - pixel[x-1]) & 0xFF."""
14
+ filtered = bytearray(len(raw_bytes))
15
+ stride = width * channels
16
+
17
+ for y in range(height):
18
+ row_start = y * stride
19
+ # First pixel in each row remains unchanged
20
+ filtered[row_start : row_start + channels] = raw_bytes[row_start : row_start + channels]
21
+
22
+ # Calculate byte deltas for remaining pixels in row
23
+ for x in range(1, width):
24
+ curr_i = row_start + x * channels
25
+ prev_i = curr_i - channels
26
+ for c in range(channels):
27
+ filtered[curr_i + c] = (raw_bytes[curr_i + c] - raw_bytes[prev_i + c]) & 0xFF
28
+
29
+ return bytes(filtered)
30
+
31
+
32
+ def undo_sub_filter(filtered_bytes: bytes, width: int, height: int, channels: int = 3) -> bytes:
33
+ """Reconstructs raw pixel data from horizontal byte deltas."""
34
+ raw = bytearray(len(filtered_bytes))
35
+ stride = width * channels
36
+
37
+ for y in range(height):
38
+ row_start = y * stride
39
+ # First pixel in each row
40
+ raw[row_start : row_start + channels] = filtered_bytes[row_start : row_start + channels]
41
+
42
+ # Reconstruct pixel values from left neighbors
43
+ for x in range(1, width):
44
+ curr_i = row_start + x * channels
45
+ prev_i = curr_i - channels
46
+ for c in range(channels):
47
+ raw[curr_i + c] = (filtered_bytes[curr_i + c] + raw[prev_i + c]) & 0xFF
48
+
49
+ return bytes(raw)
50
+
51
+
52
+ def encode(image_input: Union[str, Image.Image], level: int = 6) -> bytes:
53
+ """Encodes a file path or PIL Image into .hufi binary bytes."""
54
+ if isinstance(image_input, str):
55
+ img = Image.open(image_input).convert("RGB")
56
+ else:
57
+ img = image_input.convert("RGB")
58
+
59
+ width, height = img.size
60
+ channels = 3
61
+ raw_rgb = img.tobytes()
62
+
63
+ filtered_data = apply_sub_filter(raw_rgb, width, height, channels)
64
+ compressed_payload = zlib.compress(filtered_data, level=level)
65
+ header = struct.pack(HEADER_FORMAT, MAGIC_HEADER, width, height, channels)
66
+
67
+ return header + compressed_payload
68
+
69
+
70
+ def decode(hufi_bytes: bytes) -> Image.Image:
71
+ """Decodes .hufi binary bytes into a PIL Image object."""
72
+ if len(hufi_bytes) < HEADER_SIZE:
73
+ raise ValueError("Data is too small to contain a valid .hufi header.")
74
+
75
+ magic, width, height, channels = struct.unpack(HEADER_FORMAT, hufi_bytes[:HEADER_SIZE])
76
+ if magic != MAGIC_HEADER:
77
+ raise ValueError(f"Invalid format signature: expected {MAGIC_HEADER}, got {magic}")
78
+
79
+ compressed_payload = hufi_bytes[HEADER_SIZE:]
80
+ filtered_data = zlib.decompress(compressed_payload)
81
+ raw_rgb = undo_sub_filter(filtered_data, width, height, channels)
82
+
83
+ return Image.frombytes("RGB", (width, height), raw_rgb)
84
+
85
+
86
+ def save(image_input: Union[str, Image.Image], output_path: str, level: int = 6) -> None:
87
+ """Encodes an image and writes it directly to disk as a .hufi file."""
88
+ binary_data = encode(image_input, level=level)
89
+ with open(output_path, "wb") as f:
90
+ f.write(binary_data)
91
+
92
+
93
+ def open_hufi(filepath: str) -> Image.Image:
94
+ """Reads a .hufi file from disk and returns a PIL Image."""
95
+ with open(filepath, "rb") as f:
96
+ return decode(f.read())
97
+
98
+
99
+ def get_metadata(filepath_or_bytes: Union[str, bytes]) -> Dict[str, Any]:
100
+ """Reads header information without decompressing the payload."""
101
+ if isinstance(filepath_or_bytes, str):
102
+ with open(filepath_or_bytes, "rb") as f:
103
+ header_bytes = f.read(HEADER_SIZE)
104
+ else:
105
+ header_bytes = filepath_or_bytes[:HEADER_SIZE]
106
+
107
+ if len(header_bytes) < HEADER_SIZE:
108
+ raise ValueError("Header is corrupted or too short.")
109
+
110
+ magic, width, height, channels = struct.unpack(HEADER_FORMAT, header_bytes)
111
+ if magic != MAGIC_HEADER:
112
+ raise ValueError(f"Invalid HUFI signature: {magic}")
113
+
114
+ return {
115
+ "magic": magic.decode("ascii"),
116
+ "width": width,
117
+ "height": height,
118
+ "channels": channels,
119
+ }
@@ -0,0 +1,95 @@
1
+ Metadata-Version: 2.4
2
+ Name: hufi
3
+ Version: 0.1.0
4
+ Summary: A Python library for encoding and decoding .hufi image files.
5
+ Project-URL: Homepage, https://github.com/yourusername/hufipy
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: Pillow>=9.0.0
9
+
10
+ ```markdown
11
+ # HUFI (`hufipy`)
12
+
13
+ A lightweight Python library for encoding, decoding, and inspecting **`.hufi`** (Hagan's Ultimate Format for Images) files.
14
+
15
+ `.hufi` is a custom binary image format that pairs horizontal predictive sub-filtering with zlib Deflate compression to achieve fast, efficient, lossless image storage.
16
+
17
+ ---
18
+
19
+ ## Installation
20
+
21
+ Install via `pip`:
22
+
23
+ ```bash
24
+ pip install hufi
25
+
26
+ ```
27
+
28
+ ---
29
+
30
+ ## Quickstart
31
+
32
+ ### 1. Save and Open `.hufi` Files
33
+
34
+ ```python
35
+ import hufi
36
+
37
+ # Convert standard image formats (PNG, JPG, WEBP, etc.) to .hufi
38
+ hufi.save("input.png", "output.hufi")
39
+
40
+ # Load a .hufi file directly as a Pillow (PIL) Image
41
+ img = hufi.open_hufi("output.hufi")
42
+ img.show()
43
+
44
+ ```
45
+
46
+ ### 2. Extract Metadata Fast
47
+
48
+ Inspect header details without decompressing the entire image payload:
49
+
50
+ ```python
51
+ import hufi
52
+
53
+ metadata = hufi.get_metadata("output.hufi")
54
+ print(f"Dimensions: {metadata['width']}x{metadata['height']} px")
55
+ print(f"Channels: {metadata['channels']}")
56
+ print(f"Magic: {metadata['magic']}")
57
+
58
+ ```
59
+
60
+ ### 3. In-Memory Encoding & Decoding
61
+
62
+ Work with bytes and Pillow image objects in memory without writing to disk:
63
+
64
+ ```python
65
+ import hufi
66
+ from PIL import Image
67
+
68
+ # Encode a PIL Image to raw .hufi bytes
69
+ img = Image.open("photo.jpg")
70
+ hufi_bytes = hufi.encode(img, level=6)
71
+
72
+ # Decode raw .hufi bytes back to a PIL Image
73
+ restored_img = hufi.decode(hufi_bytes)
74
+
75
+ ```
76
+
77
+ ---
78
+
79
+ ## Technical Specification
80
+
81
+ The `.hufi` format consists of a 13-byte binary header followed by a compressed payload:
82
+
83
+ | Field | Type | Size | Description |
84
+ | --- | --- | --- | --- |
85
+ | **Magic Signature** | ASCII String | 4 Bytes | Magic bytes `b"HUFI"` |
86
+ | **Width** | Uint32 (Little-Endian) | 4 Bytes | Image width in pixels |
87
+ | **Height** | Uint32 (Little-Endian) | 4 Bytes | Image height in pixels |
88
+ | **Channels** | Uint8 | 1 Byte | Color channels (default `3` for RGB) |
89
+ | **Payload** | Deflate Bytes | Variable | Horizontal sub-filtered byte deltas compressed via Zlib |
90
+
91
+ ---
92
+
93
+ ## License
94
+
95
+ Licensed under the Apache License, Version 2.0. See `LICENSE` for details.
@@ -0,0 +1,9 @@
1
+ README.md
2
+ pyproject.toml
3
+ hufi/__init__.py
4
+ hufi/core.py
5
+ hufi.egg-info/PKG-INFO
6
+ hufi.egg-info/SOURCES.txt
7
+ hufi.egg-info/dependency_links.txt
8
+ hufi.egg-info/requires.txt
9
+ hufi.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ Pillow>=9.0.0
@@ -0,0 +1 @@
1
+ hufi
@@ -0,0 +1,16 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "hufi"
7
+ version = "0.1.0"
8
+ description = "A Python library for encoding and decoding .hufi image files."
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ dependencies = [
12
+ "Pillow>=9.0.0"
13
+ ]
14
+
15
+ [project.urls]
16
+ "Homepage" = "https://github.com/yourusername/hufipy"
hufi-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+