mirror of
https://github.com/hacksider/Deep-Live-Cam.git
synced 2026-09-01 21:40:52 +02:00
Merge pull request #1864 from 5uck1ess/pr/webp-support
feat: WEBP source image support
This commit is contained in:
+7
-4
@@ -6,10 +6,13 @@ from typing import List, Dict, Any
|
||||
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
WORKFLOW_DIR = os.path.join(ROOT_DIR, "workflow")
|
||||
|
||||
file_types = [
|
||||
("Image", ("*.png", "*.jpg", "*.jpeg", "*.gif", "*.bmp")),
|
||||
("Video", ("*.mp4", "*.mkv")),
|
||||
]
|
||||
# Canonical media extensions, defined once so the file dialogs and
|
||||
# has_image_extension never drift. GIF is intentionally excluded: OpenCV's
|
||||
# cv2.imread/imwrite (the only image I/O this app uses) cannot decode or
|
||||
# encode GIF on 4.10 or 4.11, so offering it would silently fail. WEBP works
|
||||
# via the libwebp bundled with opencv-python.
|
||||
IMAGE_EXTENSIONS = (".png", ".jpg", ".jpeg", ".bmp", ".webp")
|
||||
VIDEO_EXTENSIONS = (".mp4", ".mkv")
|
||||
|
||||
# Face Mapping Data
|
||||
source_target_map: List[Dict[str, Any]] = [] # Stores detailed map for image/video processing
|
||||
|
||||
+18
-6
@@ -237,6 +237,18 @@ _RECENT_SOURCE_DIR: Optional[str] = None
|
||||
_RECENT_TARGET_DIR: Optional[str] = None
|
||||
_RECENT_OUTPUT_DIR: Optional[str] = None
|
||||
|
||||
# QFileDialog filter strings, built from the canonical extension sets in
|
||||
# globals so every dialog stays in sync (no hand-copied lists to drift).
|
||||
_IMAGE_FILE_FILTER = "Images (" + " ".join(
|
||||
f"*{ext}" for ext in modules.globals.IMAGE_EXTENSIONS
|
||||
) + ")"
|
||||
_MEDIA_FILE_FILTER = "Media (" + " ".join(
|
||||
f"*{ext}" for ext in (*modules.globals.IMAGE_EXTENSIONS, *modules.globals.VIDEO_EXTENSIONS)
|
||||
) + ")"
|
||||
_VIDEO_FILE_FILTER = "Videos (" + " ".join(
|
||||
f"*{ext}" for ext in modules.globals.VIDEO_EXTENSIONS
|
||||
) + ")"
|
||||
|
||||
|
||||
# ─── image utilities ─────────────────────────────────────────────────────
|
||||
|
||||
@@ -734,7 +746,7 @@ class MainWindow(QMainWindow):
|
||||
path, _filter = QFileDialog.getOpenFileName(
|
||||
self, _("select an source image"),
|
||||
_RECENT_SOURCE_DIR or "",
|
||||
"Images (*.png *.jpg *.jpeg *.gif *.bmp)",
|
||||
_IMAGE_FILE_FILTER,
|
||||
)
|
||||
if path and is_image(path):
|
||||
modules.globals.source_path = path
|
||||
@@ -755,7 +767,7 @@ class MainWindow(QMainWindow):
|
||||
path, _filter = QFileDialog.getOpenFileName(
|
||||
self, _("select an target image or video"),
|
||||
_RECENT_TARGET_DIR or "",
|
||||
"Media (*.png *.jpg *.jpeg *.gif *.bmp *.mp4 *.mkv)",
|
||||
_MEDIA_FILE_FILTER,
|
||||
)
|
||||
if not path:
|
||||
return
|
||||
@@ -886,13 +898,13 @@ class MainWindow(QMainWindow):
|
||||
path, _f = QFileDialog.getSaveFileName(
|
||||
self, _("save image output file"),
|
||||
os.path.join(_RECENT_OUTPUT_DIR or "", "output.png"),
|
||||
"Images (*.png *.jpg *.jpeg *.bmp)",
|
||||
_IMAGE_FILE_FILTER,
|
||||
)
|
||||
elif is_video(modules.globals.target_path):
|
||||
path, _f = QFileDialog.getSaveFileName(
|
||||
self, _("save video output file"),
|
||||
os.path.join(_RECENT_OUTPUT_DIR or "", "output.mp4"),
|
||||
"Videos (*.mp4 *.mkv)",
|
||||
_VIDEO_FILE_FILTER,
|
||||
)
|
||||
else:
|
||||
return
|
||||
@@ -1334,7 +1346,7 @@ class MapperDialog(QDialog):
|
||||
path, _f = QFileDialog.getOpenFileName(
|
||||
self, _("select an source image"),
|
||||
_RECENT_SOURCE_DIR or "",
|
||||
"Images (*.png *.jpg *.jpeg *.gif *.bmp)",
|
||||
_IMAGE_FILE_FILTER,
|
||||
)
|
||||
if not path:
|
||||
return
|
||||
@@ -1439,7 +1451,7 @@ class LiveMapperDialog(QDialog):
|
||||
path, _f = QFileDialog.getOpenFileName(
|
||||
self, _("select an source image"),
|
||||
_RECENT_SOURCE_DIR or "",
|
||||
"Images (*.png *.jpg *.jpeg *.gif *.bmp)",
|
||||
_IMAGE_FILE_FILTER,
|
||||
)
|
||||
if not path:
|
||||
return
|
||||
|
||||
@@ -262,11 +262,16 @@ def clean_temp(target_path: str) -> None:
|
||||
|
||||
|
||||
def has_image_extension(image_path: str) -> bool:
|
||||
return image_path.lower().endswith(("png", "jpg", "jpeg"))
|
||||
# splitext so only the real extension counts (e.g. "photo.png.bak" is not
|
||||
# an image); the set is centralized in globals to stay in sync with dialogs.
|
||||
return os.path.splitext(image_path)[1].lower() in modules.globals.IMAGE_EXTENSIONS
|
||||
|
||||
|
||||
def is_image(image_path: str) -> bool:
|
||||
if image_path and os.path.isfile(image_path):
|
||||
# Extension check first — Windows mimetypes doesn't always register webp
|
||||
if has_image_extension(image_path):
|
||||
return True
|
||||
mimetype, _ = mimetypes.guess_type(image_path)
|
||||
return bool(mimetype and mimetype.startswith("image/"))
|
||||
return False
|
||||
|
||||
Reference in New Issue
Block a user