Skip to content

Commit b70cd4f

Browse files
committed
Merge branch 'unstable' into stable for 0.9.9 release
2 parents 71b6969 + b48c4f8 commit b70cd4f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1932
-430
lines changed

.gitignore

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
private_files
2-
build
3-
dist
1+
/private_files/
2+
/build/
3+
/dist/
44
.vscode
55
__pycache__
6+
.pytest_cache
67
tmp.py
7-
env
8-
sample_img
9-
unit_tests_tmp
10-
misc/appimagetool
11-
misc/VC_redist.x64.exe
8+
/env/
9+
/env_test/
10+
/sample_img/
11+
/unit_tests_tmp/
12+
/misc/appimagetool
13+
/misc/VC_redist.x64.exe
14+
/bin/
15+
/.coverage
16+
/htmlcov/

README.md

Lines changed: 72 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ You can submit a bug report in 2 ways
6060
- \[public\] Submit a new [GitHub Issue](https://github.com/JacobDev1/xl-converter/issues)
6161
- \[private\] Email me at contact@codepoems.eu
6262

63+
## Contributions
64+
65+
Pull requests are ignored to avoid licensing issues when reusing the code.
66+
67+
Feel free to make bug reports as contributions.
68+
6369
## Building from Source
6470

6571
### Windows 10
@@ -75,6 +81,8 @@ git clone -b stable --depth 1 https://github.com/JacobDev1/xl-converter.git
7581
cd xl-converter
7682
```
7783

84+
[Provide tool binaries](#providing-tool-binaries).
85+
7886
Setup `venv`.
7987

8088
```cmd
@@ -115,6 +123,8 @@ chmod -R +x xl-converter
115123
cd xl-converter
116124
```
117125

126+
[Provide tool binaries](#providing-tool-binaries).
127+
118128
Create and activate a virtual environment.
119129

120130
```bash
@@ -144,51 +154,88 @@ Extra building modes:
144154
- `make build-7z` - package to a 7z file (with an installer) (requires `p7zip-full`)
145155
- `make build-appimage` - package as an AppImage (requires `fuse`)
146156

147-
### Troubleshooting Build Issues
157+
### Providing Tool Binaries
148158

149-
#### Building on Linux
159+
To build XL Converter, you need to provide various binaries. This can be quite challenging.
150160

151-
The build may not be generated successfully, because `PyInstaller` sometimes clashes with virtual environments on Linux.
161+
Binaries needed:
162+
- [libjxl](https://github.com/libjxl/libjxl) 0.10.2
163+
- cjxl
164+
- djxl
165+
- jxlinfo
166+
- cjpegli
167+
- [libavif](https://github.com/AOMediaCodec/libavif) 1.0.3 (**AVIF_CODEC_AOM**)
168+
- avifenc
169+
- avifdec
170+
- [imagemagick](https://imagemagick.org/) 7.1.1-15 Q16-HDRI
171+
- magick - AppImage for Linux
172+
- magick.exe - Windows
173+
- [exiftool](https://exiftool.org/) 12.77
174+
- exiftool.exe - Windows
175+
- exiftool - standalone Perl build
176+
- [oxipng](https://github.com/shssoichiro/oxipng) 0.8.0
152177

153-
If the executable doesn't launch do the following.
178+
Place them in the following directories:
179+
- `xl-converter\bin\win` for Windows (x86_64)
180+
- `xl-converter/bin/linux` for Linux (x86_64)
154181

155-
Deactivate the virtual environment.
182+
All binaries are built statically. The version numbers should match. Binaries on Windows have an `.exe` extension.
156183

157-
```bash
158-
deactivate
159-
```
184+
See the official [XL Converter builds](https://github.com/JacobDev1/xl-converter/releases) for examples.
160185

161-
Install packages globally.
162-
```bash
163-
pip install -r requirements.txt
164-
```
186+
## Info
187+
188+
### Python Version
189+
190+
The project runs on Python `3.11.6`. It should also work on a slightly older version. `3.12` and newer are not supported.
191+
192+
### Large Files
193+
194+
Don't forget `--depth 1` when running `git clone`. This repo contains large files.
195+
196+
### Development Branch
165197

166-
Try again.
198+
The dev branch can be accessed with
167199

168200
```bash
169-
make build
201+
git clone -b unstable --depth 1 https://github.com/JacobDev1/xl-converter.git
170202
```
171203

172-
#### Python Version on Linux
204+
## Unit Testing
173205

174-
The project runs on Python `3.11.6`. The one in your repo should work, but If it doesn't use `pyenv` to get this one specifically.
206+
Unit tests are currently being reworked.
175207

176-
#### Large Files
208+
### Running
177209

178-
Don't forget `--depth 1` when running `git clone`. This repo contains large files.
210+
[Setup repo](#building-from-source).
179211

180-
## Development Build
212+
Create a test environment.
181213

182-
To access the development build, clone this branch
214+
```bash
215+
python3 -m venv env_test
216+
source env/bin/activate
217+
pip install -r requirements.txt
218+
pip install -r requirements_test.txt
219+
```
220+
221+
Run tests (Linux)
183222

184223
```bash
185-
git clone --depth 1 -b unstable https://github.com/JacobDev1/xl-converter.git
224+
make test
186225
```
187226

188-
Then follow the [building section](#building-from-source)
227+
Run tests (Windows)
189228

190-
## Contributions
229+
```cmd
230+
python test.py
231+
```
191232

192-
Pull requests are ignored to avoid potential legal complications when reusing the code.
233+
### Deprecated
193234

194-
Forward your code and feature suggestions to my email at contact@codepoems.eu
235+
`tests_old.py` is a deprecated, but still accessible test suite.
236+
237+
To run them, put any image with a varying aspect ratio inside a `sample_img` folder in the project's directory.
238+
239+
```bash
240+
python tests_old.py
241+
```

build.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ def download(self, url, dst, checksum = None):
106106
return
107107

108108
# Download the file
109-
print(f"[Downloading] Downloading \"{dst.name}\"")
109+
print(f"[Downloading] Downloading {dst.name}")
110110
response = requests.get(url)
111111
if response.status_code == 200:
112112
with open(Path(dst), 'wb') as f:
@@ -189,13 +189,36 @@ def __init__(self):
189189

190190
# Windows
191191
self.redist_path = "misc/VC_redist.x64.exe" # Needed for ImageMagick to work
192+
193+
# Binary tools
194+
self.tools_win = [
195+
"cjxl.exe",
196+
"djxl.exe",
197+
"jxlinfo.exe",
198+
"cjpegli.exe",
199+
"avifenc.exe",
200+
"avifdec.exe",
201+
"exiftool.exe",
202+
"magick.exe",
203+
]
204+
self.tools_linux = [
205+
"cjxl",
206+
"djxl",
207+
"jxlinfo",
208+
"cjpegli",
209+
"avifenc",
210+
"avifdec",
211+
"exiftool",
212+
"magick",
213+
]
192214

193215
# Build Names
194216
self.build_inno_name = f"xl-converter-win-{VERSION}-x86_64"
195217
self.build_7z_name = f"xl-converter-linux-{VERSION}-x86_64"
196218
self.build_appimage_name = f"xl-converter-linux-{VERSION}-x86_64.AppImage"
197219

198220
def build(self):
221+
self._verifyTools()
199222
self._prepare()
200223
self._buildBinaries()
201224
self._copyDependencies()
@@ -225,7 +248,7 @@ def _prepare(self):
225248
print("[Building] Using previously compiled cache")
226249
else:
227250
print("[Building] Platform mismatch - deleting the cache")
228-
rmTree("build")
251+
rmTree("build")
229252
rmTree("__pycache__")
230253
else:
231254
print("[Building] \"last_built_on\" not found - deleting the cache")
@@ -334,6 +357,19 @@ def _build7z(self):
334357
move(f"{self.dst_dir}/{os.path.basename(self.installer_path['Linux'])}", dst)
335358
move(f"{self.dst_dir}/{os.path.basename(self.desktop_entry_path)}", dst)
336359
subprocess.run(("7z", "a", f"{dst_direct}.7z", dst_direct), cwd=self.dst_dir)
360+
361+
def _verifyTools(self):
362+
match platform.system():
363+
case "Windows":
364+
for i in self.tools_win:
365+
if not os.path.exists(os.path.join(PROGRAM_FOLDER, "bin", "win", i)):
366+
print(f"[Error] /bin/win/{i} is missing")
367+
case "Linux":
368+
for i in self.tools_linux:
369+
if not os.path.exists(os.path.join(PROGRAM_FOLDER, "bin", "linux", i)):
370+
print(f"[Error] /bin/linux/{i} is missing")
371+
case _:
372+
raise Exception("Unrecognized platform (_verifyTools)")
337373

338374
if __name__ == '__main__':
339375
try:

core/conflicts.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,33 @@
11
from core.exceptions import GenericException
22

3-
def checkForConflicts(ext: str, _format: str, downscaling: dict) -> bool:
4-
"""Raises exceptions and returns True If any conflicts occur."""
3+
def checkForConflicts(ext: str, file_format: str, downscaling=False) -> bool:
4+
"""
5+
Raises exceptions and returns True If any conflicts occur.
6+
7+
Args:
8+
- ext - extension (without a dot in the beginning and lowercase)
9+
- file_format - target format (uppercase)
10+
- downscaling - is downscaling on
11+
"""
512
if ext in ("gif", "apng"):
613
conflict = True
714

815
# Animation
916
match ext:
1017
case "gif":
11-
if _format in ("JPEG XL", "WEBP", "PNG"):
18+
if file_format in ("JPEG XL", "WEBP", "PNG"):
1219
conflict = False
1320
case "apng":
14-
if _format in ("JPEG XL"):
21+
if file_format in ("JPEG XL"):
1522
conflict = False
1623

1724
if conflict:
18-
raise GenericException("cf.", f"Animation is not supported for {_format} - stopped the process")
25+
raise GenericException("CF0", f"Animation is not supported for {ext.upper()} -> {file_format}")
1926

2027
# Downscaling
2128
if downscaling:
2229
conflict = True
23-
raise GenericException("cf.", f"Downscaling is not supported for animation - stopped the process")
30+
raise GenericException("CF1", f"Downscaling is not supported for animation")
2431
else:
2532
conflict = False
2633

core/convert.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def getExtensionJxl(src_path):
3838
return "png"
3939

4040
def parseArgs(args):
41+
"""Splits arguments by spaces and flattens them into a list."""
4142
tmp = []
4243
for arg in args:
4344
tmp.extend(arg.split())
@@ -68,7 +69,7 @@ def getDecoderArgs(decoder_path: str, threads: int) -> list:
6869
else:
6970
return []
7071

71-
def log(msg, n = None):
72+
def log(msg, n=None):
7273
if n == None:
7374
logging.info(f"[Convert] {msg}")
7475
else:

core/downscale.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,6 @@
1111
from core.convert import convert, getDecoder
1212
from core.exceptions import CancellationException, GenericException, FileException
1313

14-
# ------------------------------------------------------------
15-
# Helper
16-
# ------------------------------------------------------------
17-
18-
def _downscaleToPercent(src, dst, amount=90, resample="Default", n=None):
19-
amount = clip(amount, 1, 100)
20-
21-
args = []
22-
if resample != "Default" and resample in ALLOWED_RESAMPLING:
23-
args.append(f"-filter {resample}") # Needs to come first
24-
args.extend([f"-resize {amount}%"])
25-
26-
convert(IMAGE_MAGICK_PATH, src, dst, args, n)
27-
2814
# ------------------------------------------------------------
2915
# Math
3016
# ------------------------------------------------------------
@@ -59,6 +45,20 @@ def _extrapolateScale(sample_points, desired_size) -> int:
5945

6046
return int(y_new)
6147

48+
# ------------------------------------------------------------
49+
# Helper
50+
# ------------------------------------------------------------
51+
52+
def _downscaleToPercent(src, dst, amount=90, resample="Default", n=None):
53+
amount = clip(amount, 1, 100)
54+
55+
args = []
56+
if resample != "Default" and resample in ALLOWED_RESAMPLING:
57+
args.append(f"-filter {resample}") # Needs to come first
58+
args.extend([f"-resize {amount}%"])
59+
60+
convert(IMAGE_MAGICK_PATH, src, dst, args, n)
61+
6262
def cancelCheck(*tmp_files):
6363
"""Checks if the task was canceled and removes temporary files."""
6464
if task_status.wasCanceled():
@@ -203,7 +203,7 @@ def _downscaleManualModes(params):
203203
case "Percent":
204204
args.append(f"-resize {params['percent']}%")
205205
case "Resolution":
206-
args.append(f"-resize {params['width']}x{params['height']}")
206+
args.append(f"-resize {params['width']}x{params['height']}>")
207207
case "Shortest Side":
208208
args.append(f"-resize {params['shortest_side']}x{params['shortest_side']}^>")
209209
case "Longest Side":

core/exceptions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
class GenericException(Exception):
2-
def __init__(self, id, msg):
2+
def __init__(self, id: str, msg: str):
33
self.id = id
44
self.msg = msg
55

66
class FileException(Exception):
7-
def __init__(self, id, msg):
7+
def __init__(self, id: str, msg: str):
88
self.id = id
99
self.msg = msg
1010

0 commit comments

Comments
 (0)