Skip to content

Commit

Permalink
Merge branch 'unstable' into stable for 0.9.9 release
Browse files Browse the repository at this point in the history
  • Loading branch information
JacobDev1 committed Apr 15, 2024
2 parents 71b6969 + b48c4f8 commit b70cd4f
Show file tree
Hide file tree
Showing 42 changed files with 1,932 additions and 430 deletions.
21 changes: 13 additions & 8 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
private_files
build
dist
/private_files/
/build/
/dist/
.vscode
__pycache__
.pytest_cache
tmp.py
env
sample_img
unit_tests_tmp
misc/appimagetool
misc/VC_redist.x64.exe
/env/
/env_test/
/sample_img/
/unit_tests_tmp/
/misc/appimagetool
/misc/VC_redist.x64.exe
/bin/
/.coverage
/htmlcov/
97 changes: 72 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ You can submit a bug report in 2 ways
- \[public\] Submit a new [GitHub Issue](https://github.com/JacobDev1/xl-converter/issues)
- \[private\] Email me at [email protected]

## Contributions

Pull requests are ignored to avoid licensing issues when reusing the code.

Feel free to make bug reports as contributions.

## Building from Source

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

[Provide tool binaries](#providing-tool-binaries).

Setup `venv`.

```cmd
Expand Down Expand Up @@ -115,6 +123,8 @@ chmod -R +x xl-converter
cd xl-converter
```

[Provide tool binaries](#providing-tool-binaries).

Create and activate a virtual environment.

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

### Troubleshooting Build Issues
### Providing Tool Binaries

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

The build may not be generated successfully, because `PyInstaller` sometimes clashes with virtual environments on Linux.
Binaries needed:
- [libjxl](https://github.com/libjxl/libjxl) 0.10.2
- cjxl
- djxl
- jxlinfo
- cjpegli
- [libavif](https://github.com/AOMediaCodec/libavif) 1.0.3 (**AVIF_CODEC_AOM**)
- avifenc
- avifdec
- [imagemagick](https://imagemagick.org/) 7.1.1-15 Q16-HDRI
- magick - AppImage for Linux
- magick.exe - Windows
- [exiftool](https://exiftool.org/) 12.77
- exiftool.exe - Windows
- exiftool - standalone Perl build
- [oxipng](https://github.com/shssoichiro/oxipng) 0.8.0

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

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

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

Install packages globally.
```bash
pip install -r requirements.txt
```
## Info

### Python Version

The project runs on Python `3.11.6`. It should also work on a slightly older version. `3.12` and newer are not supported.

### Large Files

Don't forget `--depth 1` when running `git clone`. This repo contains large files.

### Development Branch

Try again.
The dev branch can be accessed with

```bash
make build
git clone -b unstable --depth 1 https://github.com/JacobDev1/xl-converter.git
```

#### Python Version on Linux
## Unit Testing

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.
Unit tests are currently being reworked.

#### Large Files
### Running

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

## Development Build
Create a test environment.

To access the development build, clone this branch
```bash
python3 -m venv env_test
source env/bin/activate
pip install -r requirements.txt
pip install -r requirements_test.txt
```

Run tests (Linux)

```bash
git clone --depth 1 -b unstable https://github.com/JacobDev1/xl-converter.git
make test
```

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

## Contributions
```cmd
python test.py
```

Pull requests are ignored to avoid potential legal complications when reusing the code.
### Deprecated

Forward your code and feature suggestions to my email at [email protected]
`tests_old.py` is a deprecated, but still accessible test suite.

To run them, put any image with a varying aspect ratio inside a `sample_img` folder in the project's directory.

```bash
python tests_old.py
```
40 changes: 38 additions & 2 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def download(self, url, dst, checksum = None):
return

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

# Windows
self.redist_path = "misc/VC_redist.x64.exe" # Needed for ImageMagick to work

# Binary tools
self.tools_win = [
"cjxl.exe",
"djxl.exe",
"jxlinfo.exe",
"cjpegli.exe",
"avifenc.exe",
"avifdec.exe",
"exiftool.exe",
"magick.exe",
]
self.tools_linux = [
"cjxl",
"djxl",
"jxlinfo",
"cjpegli",
"avifenc",
"avifdec",
"exiftool",
"magick",
]

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

def build(self):
self._verifyTools()
self._prepare()
self._buildBinaries()
self._copyDependencies()
Expand Down Expand Up @@ -225,7 +248,7 @@ def _prepare(self):
print("[Building] Using previously compiled cache")
else:
print("[Building] Platform mismatch - deleting the cache")
rmTree("build")
rmTree("build")
rmTree("__pycache__")
else:
print("[Building] \"last_built_on\" not found - deleting the cache")
Expand Down Expand Up @@ -334,6 +357,19 @@ def _build7z(self):
move(f"{self.dst_dir}/{os.path.basename(self.installer_path['Linux'])}", dst)
move(f"{self.dst_dir}/{os.path.basename(self.desktop_entry_path)}", dst)
subprocess.run(("7z", "a", f"{dst_direct}.7z", dst_direct), cwd=self.dst_dir)

def _verifyTools(self):
match platform.system():
case "Windows":
for i in self.tools_win:
if not os.path.exists(os.path.join(PROGRAM_FOLDER, "bin", "win", i)):
print(f"[Error] /bin/win/{i} is missing")
case "Linux":
for i in self.tools_linux:
if not os.path.exists(os.path.join(PROGRAM_FOLDER, "bin", "linux", i)):
print(f"[Error] /bin/linux/{i} is missing")
case _:
raise Exception("Unrecognized platform (_verifyTools)")

if __name__ == '__main__':
try:
Expand Down
19 changes: 13 additions & 6 deletions core/conflicts.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,33 @@
from core.exceptions import GenericException

def checkForConflicts(ext: str, _format: str, downscaling: dict) -> bool:
"""Raises exceptions and returns True If any conflicts occur."""
def checkForConflicts(ext: str, file_format: str, downscaling=False) -> bool:
"""
Raises exceptions and returns True If any conflicts occur.
Args:
- ext - extension (without a dot in the beginning and lowercase)
- file_format - target format (uppercase)
- downscaling - is downscaling on
"""
if ext in ("gif", "apng"):
conflict = True

# Animation
match ext:
case "gif":
if _format in ("JPEG XL", "WEBP", "PNG"):
if file_format in ("JPEG XL", "WEBP", "PNG"):
conflict = False
case "apng":
if _format in ("JPEG XL"):
if file_format in ("JPEG XL"):
conflict = False

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

# Downscaling
if downscaling:
conflict = True
raise GenericException("cf.", f"Downscaling is not supported for animation - stopped the process")
raise GenericException("CF1", f"Downscaling is not supported for animation")
else:
conflict = False

Expand Down
3 changes: 2 additions & 1 deletion core/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def getExtensionJxl(src_path):
return "png"

def parseArgs(args):
"""Splits arguments by spaces and flattens them into a list."""
tmp = []
for arg in args:
tmp.extend(arg.split())
Expand Down Expand Up @@ -68,7 +69,7 @@ def getDecoderArgs(decoder_path: str, threads: int) -> list:
else:
return []

def log(msg, n = None):
def log(msg, n=None):
if n == None:
logging.info(f"[Convert] {msg}")
else:
Expand Down
30 changes: 15 additions & 15 deletions core/downscale.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,6 @@
from core.convert import convert, getDecoder
from core.exceptions import CancellationException, GenericException, FileException

# ------------------------------------------------------------
# Helper
# ------------------------------------------------------------

def _downscaleToPercent(src, dst, amount=90, resample="Default", n=None):
amount = clip(amount, 1, 100)

args = []
if resample != "Default" and resample in ALLOWED_RESAMPLING:
args.append(f"-filter {resample}") # Needs to come first
args.extend([f"-resize {amount}%"])

convert(IMAGE_MAGICK_PATH, src, dst, args, n)

# ------------------------------------------------------------
# Math
# ------------------------------------------------------------
Expand Down Expand Up @@ -59,6 +45,20 @@ def _extrapolateScale(sample_points, desired_size) -> int:

return int(y_new)

# ------------------------------------------------------------
# Helper
# ------------------------------------------------------------

def _downscaleToPercent(src, dst, amount=90, resample="Default", n=None):
amount = clip(amount, 1, 100)

args = []
if resample != "Default" and resample in ALLOWED_RESAMPLING:
args.append(f"-filter {resample}") # Needs to come first
args.extend([f"-resize {amount}%"])

convert(IMAGE_MAGICK_PATH, src, dst, args, n)

def cancelCheck(*tmp_files):
"""Checks if the task was canceled and removes temporary files."""
if task_status.wasCanceled():
Expand Down Expand Up @@ -203,7 +203,7 @@ def _downscaleManualModes(params):
case "Percent":
args.append(f"-resize {params['percent']}%")
case "Resolution":
args.append(f"-resize {params['width']}x{params['height']}")
args.append(f"-resize {params['width']}x{params['height']}>")
case "Shortest Side":
args.append(f"-resize {params['shortest_side']}x{params['shortest_side']}^>")
case "Longest Side":
Expand Down
4 changes: 2 additions & 2 deletions core/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
class GenericException(Exception):
def __init__(self, id, msg):
def __init__(self, id: str, msg: str):
self.id = id
self.msg = msg

class FileException(Exception):
def __init__(self, id, msg):
def __init__(self, id: str, msg: str):
self.id = id
self.msg = msg

Expand Down
Loading

0 comments on commit b70cd4f

Please sign in to comment.