lsfp 1.0.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.
lsfp-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,47 @@
1
+ Metadata-Version: 2.4
2
+ Name: lsfp
3
+ Version: 1.0.0
4
+ Summary: A hybrid image compression format by LelelelingStudio
5
+ Author-email: LelelelingStudio <hello@leleleling.site>
6
+ License: Apache-2.0
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: Apache Software License
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.8
11
+ Description-Content-Type: text/markdown
12
+ Requires-Dist: Pillow>=9.0.0
13
+
14
+ # LSFP for Python (LelelelingStudio's Format Picture)
15
+
16
+ An ultra-fast, hybrid image compression library for Python.
17
+
18
+ LSFP is designed to reduce file sizes drastically for images with large solid-color areas, UI screenshots, and icons by combining **Color Quantization**, **Run-Length Encoding (RLE)**, and **Gzip compression**.
19
+
20
+ ## 📦 Installation
21
+
22
+ *Note: This package is currently under development and will be available on PyPI soon.*
23
+
24
+ ```bash
25
+ pip install lsfp
26
+ 🚀 Quick Start
27
+ The library automatically installs its only dependency (Pillow) for reading and writing standard image formats.
28
+
29
+ python
30
+ import lsfp
31
+
32
+ # 1. Encode a standard image to LSFP
33
+ lsfp.LSFP.encode("input.png", "output.lsfp")
34
+
35
+ # 2. Decode an LSFP file back to a standard image
36
+ lsfp.LSFP.decode("output.lsfp", "restored.png")
37
+ ✨ Features
38
+ Extreme Compression: Up to 80% smaller than PNG for UI screenshots.
39
+
40
+ Cross-Platform: Fully compatible with the LSFP Web implementation (JS).
41
+
42
+ Zero-Config: Built-in intelligent color quantization prevents image darkening.
43
+
44
+ 📄 License
45
+ This project is licensed under the Apache License 2.0. See the LICENSE file for details.
46
+
47
+ Made with ❤️ by LelelelingStudio.
lsfp-1.0.0/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # LSFP for Python (LelelelingStudio's Format Picture)
2
+
3
+ An ultra-fast, hybrid image compression library for Python.
4
+
5
+ LSFP is designed to reduce file sizes drastically for images with large solid-color areas, UI screenshots, and icons by combining **Color Quantization**, **Run-Length Encoding (RLE)**, and **Gzip compression**.
6
+
7
+ ## 📦 Installation
8
+
9
+ *Note: This package is currently under development and will be available on PyPI soon.*
10
+
11
+ ```bash
12
+ pip install lsfp
13
+ 🚀 Quick Start
14
+ The library automatically installs its only dependency (Pillow) for reading and writing standard image formats.
15
+
16
+ python
17
+ import lsfp
18
+
19
+ # 1. Encode a standard image to LSFP
20
+ lsfp.LSFP.encode("input.png", "output.lsfp")
21
+
22
+ # 2. Decode an LSFP file back to a standard image
23
+ lsfp.LSFP.decode("output.lsfp", "restored.png")
24
+ ✨ Features
25
+ Extreme Compression: Up to 80% smaller than PNG for UI screenshots.
26
+
27
+ Cross-Platform: Fully compatible with the LSFP Web implementation (JS).
28
+
29
+ Zero-Config: Built-in intelligent color quantization prevents image darkening.
30
+
31
+ 📄 License
32
+ This project is licensed under the Apache License 2.0. See the LICENSE file for details.
33
+
34
+ Made with ❤️ by LelelelingStudio.
@@ -0,0 +1,168 @@
1
+ import struct
2
+ import gzip
3
+ from PIL import Image
4
+
5
+ class LSFP:
6
+ @staticmethod
7
+ def encode(image_path, output_path, quality=4):
8
+ """
9
+ 将普通图片编码为 LSFP
10
+ :param quality: 颜色量化精度 (4 表示分桶保留高 4 位,对应网页版)
11
+ """
12
+ img = Image.open(image_path).convert('RGB')
13
+ width, height = img.size
14
+ pixels = list(img.getdata())
15
+
16
+ # 1. 颜色统计与量化
17
+ color_counts = {}
18
+ for r, g, b in pixels:
19
+ hex_color = (r << 16) | (g << 8) | b
20
+ color_counts[hex_color] = color_counts.get(hex_color, 0) + 1
21
+
22
+ sorted_colors = sorted(color_counts.items(), key=lambda x: x[1], reverse=True)
23
+ palette = []
24
+ color_map = {}
25
+
26
+ if len(sorted_colors) <= 256:
27
+ # 颜色少于 256 种,全量保留
28
+ for hex_color, _ in sorted_colors:
29
+ r, g, b = (hex_color >> 16) & 0xFF, (hex_color >> 8) & 0xFF, hex_color & 0xFF
30
+ color_map[hex_color] = len(palette)
31
+ palette.append((r, g, b))
32
+ else:
33
+ # 颜色过多,采用 4x4x4 分桶量化 (防变暗)
34
+ buckets = {}
35
+ for hex_color, count in sorted_colors:
36
+ r, g, b = (hex_color >> 16) & 0xFF, (hex_color >> 8) & 0xFF, hex_color & 0xFF
37
+ bucket_key = ((r >> 4) << 8) | ((g >> 4) << 4) | (b >> 4)
38
+ if bucket_key not in buckets:
39
+ buckets[bucket_key] = {'r': 0, 'g': 0, 'b': 0, 'count': 0}
40
+ bucket = buckets[bucket_key]
41
+ bucket['r'] += r * count
42
+ bucket['g'] += g * count
43
+ bucket['b'] += b * count
44
+ bucket['count'] += count
45
+
46
+ # 取最大的 256 个桶求平均
47
+ sorted_buckets = sorted(buckets.values(), key=lambda x: x['count'], reverse=True)[:256]
48
+ for bucket in sorted_buckets:
49
+ avg_r = round(bucket['r'] / bucket['count'])
50
+ avg_g = round(bucket['g'] / bucket['count'])
51
+ avg_b = round(bucket['b'] / bucket['count'])
52
+ palette.append((avg_r, avg_g, avg_b))
53
+
54
+ # 映射每个像素到最近的调色板颜色
55
+ for hex_color, _ in sorted_colors:
56
+ r, g, b = (hex_color >> 16) & 0xFF, (hex_color >> 8) & 0xFF, hex_color & 0xFF
57
+ min_dist = float('inf')
58
+ best_idx = 0
59
+ for i, (pr, pg, pb) in enumerate(palette):
60
+ dist = (r - pr) ** 2 + (g - pg) ** 2 + (b - pb) ** 2
61
+ if dist < min_dist:
62
+ min_dist = dist
63
+ best_idx = i
64
+ color_map[hex_color] = best_idx
65
+
66
+ # 2. 生成像素索引
67
+ pixel_indices = []
68
+ for r, g, b in pixels:
69
+ hex_color = (r << 16) | (g << 8) | b
70
+ pixel_indices.append(color_map.get(hex_color, 0))
71
+
72
+ # 3. 生成 RLE 数据
73
+ rle_data = bytearray()
74
+ i = 0
75
+ total_pixels = width * height
76
+ while i < total_pixels:
77
+ current_id = pixel_indices[i]
78
+ run_length = 1
79
+ while i + run_length < total_pixels and pixel_indices[i + run_length] == current_id and run_length < 65535:
80
+ run_length += 1
81
+ rle_data.extend(struct.pack('<HH', current_id, run_length))
82
+ i += run_length
83
+
84
+ # 4. 组装二进制流
85
+ buffer = bytearray()
86
+ # Header (LSFP + v4 + flags + width + height)
87
+ buffer.extend(b'LSFP')
88
+ buffer.extend(struct.pack('<BBII', 4, 0, width, height))
89
+
90
+ # Palette
91
+ buffer.extend(struct.pack('<H', len(palette)))
92
+ for r, g, b in palette:
93
+ buffer.extend(struct.pack('<BBB', r, g, b))
94
+
95
+ # RLE Chunk (0x01)
96
+ buffer.extend(struct.pack('<B', 0x01))
97
+ buffer.extend(struct.pack('<I', len(rle_data)))
98
+ buffer.extend(rle_data)
99
+
100
+ # End Chunk (0xFF)
101
+ buffer.extend(struct.pack('<B', 0xFF))
102
+ buffer.extend(struct.pack('<I', 0))
103
+
104
+ # 5. Gzip 压缩
105
+ with gzip.open(output_path, 'wb') as f:
106
+ f.write(buffer)
107
+
108
+ print(f"✅ 压缩成功: {output_path}")
109
+
110
+ @staticmethod
111
+ def decode(lsfp_path, output_path):
112
+ """将 LSFP 解码为普通图片"""
113
+ with open(lsfp_path, 'rb') as f:
114
+ data = f.read()
115
+
116
+ # 自动检测是否 Gzip 压缩 (1F 8B)
117
+ if data[:2] == b'\x1f\x8b':
118
+ data = gzip.decompress(data)
119
+
120
+ offset = 0
121
+ magic = data[offset:offset+4]
122
+ if magic != b'LSFP':
123
+ raise ValueError("❌ 这不是一个有效的 LSFP 文件")
124
+
125
+ offset += 6 # 跳过 magic + version + flags
126
+ width, height = struct.unpack('<II', data[offset:offset+8])
127
+ offset += 8
128
+
129
+ # 读取调色板
130
+ color_count = struct.unpack('<H', data[offset:offset+2])[0]
131
+ offset += 2
132
+ palette = []
133
+ for _ in range(color_count):
134
+ r, g, b = struct.unpack('<BBB', data[offset:offset+3])
135
+ palette.append((r, g, b))
136
+ offset += 3
137
+
138
+ # 创建空白画布
139
+ img = Image.new('RGB', (width, height))
140
+ pixels = []
141
+
142
+ # 解析 Chunk
143
+ while offset < len(data):
144
+ block_type = data[offset]
145
+ offset += 1
146
+ if block_type == 0xFF:
147
+ break
148
+
149
+ block_length = struct.unpack('<I', data[offset:offset+4])[0]
150
+ offset += 4
151
+
152
+ if block_type == 0x01:
153
+ end_of_block = offset + block_length
154
+ while offset < end_of_block:
155
+ color_id, run_length = struct.unpack('<HH', data[offset:offset+4])
156
+ offset += 4
157
+ pixels.extend([palette[color_id]] * run_length)
158
+ else:
159
+ # 遇到不认识的块(比如 v4.0 的高级块),直接跳过
160
+ offset += block_length
161
+
162
+ # 将像素填入画布
163
+ if len(pixels) == width * height:
164
+ img.putdata(pixels)
165
+ img.save(output_path)
166
+ print(f"✅ 解压成功: {output_path}")
167
+ else:
168
+ print(f"❌ 错误: 像素数量不匹配 (预期 {width*height},实际 {len(pixels)})")
@@ -0,0 +1,47 @@
1
+ Metadata-Version: 2.4
2
+ Name: lsfp
3
+ Version: 1.0.0
4
+ Summary: A hybrid image compression format by LelelelingStudio
5
+ Author-email: LelelelingStudio <hello@leleleling.site>
6
+ License: Apache-2.0
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: Apache Software License
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.8
11
+ Description-Content-Type: text/markdown
12
+ Requires-Dist: Pillow>=9.0.0
13
+
14
+ # LSFP for Python (LelelelingStudio's Format Picture)
15
+
16
+ An ultra-fast, hybrid image compression library for Python.
17
+
18
+ LSFP is designed to reduce file sizes drastically for images with large solid-color areas, UI screenshots, and icons by combining **Color Quantization**, **Run-Length Encoding (RLE)**, and **Gzip compression**.
19
+
20
+ ## 📦 Installation
21
+
22
+ *Note: This package is currently under development and will be available on PyPI soon.*
23
+
24
+ ```bash
25
+ pip install lsfp
26
+ 🚀 Quick Start
27
+ The library automatically installs its only dependency (Pillow) for reading and writing standard image formats.
28
+
29
+ python
30
+ import lsfp
31
+
32
+ # 1. Encode a standard image to LSFP
33
+ lsfp.LSFP.encode("input.png", "output.lsfp")
34
+
35
+ # 2. Decode an LSFP file back to a standard image
36
+ lsfp.LSFP.decode("output.lsfp", "restored.png")
37
+ ✨ Features
38
+ Extreme Compression: Up to 80% smaller than PNG for UI screenshots.
39
+
40
+ Cross-Platform: Fully compatible with the LSFP Web implementation (JS).
41
+
42
+ Zero-Config: Built-in intelligent color quantization prevents image darkening.
43
+
44
+ 📄 License
45
+ This project is licensed under the Apache License 2.0. See the LICENSE file for details.
46
+
47
+ Made with ❤️ by LelelelingStudio.
@@ -0,0 +1,8 @@
1
+ README.md
2
+ pyproject.toml
3
+ lsfp/__init__.py
4
+ lsfp.egg-info/PKG-INFO
5
+ lsfp.egg-info/SOURCES.txt
6
+ lsfp.egg-info/dependency_links.txt
7
+ lsfp.egg-info/requires.txt
8
+ lsfp.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ Pillow>=9.0.0
@@ -0,0 +1 @@
1
+ lsfp
@@ -0,0 +1,25 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "lsfp" # 别人 pip install 的名字
7
+ version = "1.0.0"
8
+ description = "A hybrid image compression format by LelelelingStudio"
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = { text = "Apache-2.0" }
12
+ authors = [
13
+ { name = "LelelelingStudio", email = "hello@leleleling.site" }
14
+ ]
15
+ classifiers = [
16
+ "Programming Language :: Python :: 3",
17
+ "License :: OSI Approved :: Apache Software License",
18
+ "Operating System :: OS Independent",
19
+ ]
20
+ dependencies = [
21
+ "Pillow>=9.0.0" # 自动安装的依赖
22
+ ]
23
+
24
+ [tool.setuptools]
25
+ packages = ["lsfp"]
lsfp-1.0.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+