Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/preview-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ Audio thumbnails will default to embedded cover art (if any) and fallback to gen
Preview support for office documents or well-known project file formats varies by the format and whether or not embedded thumbnails are available to be read from. OpenDocument-based files are typically supported.

| Filetype | Extensions | Preview Type |
| ------------------------------------ | --------------------- | -------------------------------------------------------------------------- |
|------------------------------------- |-----------------------|----------------------------------------------------------------------------|
| Blender | `.blend`, `.blend<#>` | Embedded thumbnail :material-alert-circle:{ title="If available in file" } |
| Clip Studio Paint | `.clip` | Embedded thumbnail |
| Keynote (Apple iWork) | `.key` | Embedded thumbnail |
Expand All @@ -98,6 +98,7 @@ Preview support for office documents or well-known project file formats varies b
| Paint.NET | `.pdn` | Embedded thumbnail |
| PDF | `.pdf` | First page render |
| Photoshop | `.psd` | Flattened image render |
| Pixelmator Pro (Apple iWork) | `.pxd` | Embedded thumbnail |
| PowerPoint (Microsoft Office) | `.pptx`, `.ppt` | Embedded thumbnail :material-alert-circle:{ title="If available in file" } |

### :material-archive: Archives
Expand Down
21 changes: 11 additions & 10 deletions src/tagstudio/core/media_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
logger = structlog.get_logger(__name__)

FILETYPE_EQUIVALENTS = [
set(["aif", "aiff", "aifc"]),
set(["html", "htm", "xhtml", "shtml", "dhtml"]),
set(["jfif", "jpeg_large", "jpeg", "jpg_large", "jpg"]),
set(["json", "jsonc", "json5"]),
set(["md", "markdown", "mkd", "rmd"]),
set(["tar.gz", "tgz"]),
set(["xml", "xul"]),
set(["yaml", "yml"]),
{"aif", "aiff", "aifc"},
{"html", "htm", "xhtml", "shtml", "dhtml"},
{"jfif", "jpeg_large", "jpeg", "jpg_large", "jpg"},
{"json", "jsonc", "json5"},
{"md", "markdown", "mkd", "rmd"},
{"tar.gz", "tgz"},
{"xml", "xul"},
{"yaml", "yml"},
]


Expand Down Expand Up @@ -75,7 +75,7 @@ class MediaCategory:
extensions (set[str]): The set of file extensions associated with this category.
Includes leading ".", all lowercase, and does not need to be unique to this category.

is_iana (bool): Represents whether or not this is an IANA registered category.
is_iana (bool): Represents whether this is an IANA registered category.
"""

media_type: MediaType
Expand Down Expand Up @@ -257,6 +257,7 @@ class MediaCategories:
".odt",
".pages",
".pdf",
".pxd",
".rtf",
".tex",
".wpd",
Expand Down Expand Up @@ -336,7 +337,7 @@ class MediaCategories:
".webp",
}
_INSTALLER_SET: set[str] = {".appx", ".msi", ".msix"}
_IWORK_SET: set[str] = {".key", ".pages", ".numbers"}
_IWORK_SET: set[str] = {".key", ".numbers", ".pages"}
_MATERIAL_SET: set[str] = {".mtl"}
_MDIPACK_SET: set[str] = {".mdp"}
_MODEL_SET: set[str] = {".3ds", ".fbx", ".obj", ".stl"}
Expand Down
33 changes: 20 additions & 13 deletions src/tagstudio/qt/previews/renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,7 @@ def _apply_edge(
image (Image.Image): The image to apply the edge to.
edge (tuple[Image.Image, Image.Image]): The edge images to apply.
Item 0 is the inner highlight, and item 1 is the outer shadow.
faded (bool): Whether or not to apply a faded version of the edge.
faded (bool): Whether to apply a faded version of the edge.
Used for light themes.
"""
opacity: float = 1.0 if not faded else 0.8
Expand Down Expand Up @@ -847,7 +847,7 @@ def _open_doc_thumb(filepath: Path) -> Image.Image | None:

@staticmethod
def _krita_thumb(filepath: Path) -> Image.Image | None:
"""Extract and render a thumbnail for an Krita file.
"""Extract and render a thumbnail for a Krita file.

Args:
filepath (Path): The path of the file.
Expand Down Expand Up @@ -1218,14 +1218,18 @@ def _image_vector_thumb(filepath: Path, size: int) -> Image.Image:
return im

@staticmethod
def _iwork_thumb(filepath: Path) -> Image.Image | None:
"""Extract and render a thumbnail for an Apple iWork (Pages, Numbers, Keynote) file.
Comment thread
Sola-ris marked this conversation as resolved.
def _apple_embedded_thumb(filepath: Path) -> Image.Image | None:
"""Extract and render an apple embedded thumbnail (iWork, Apple Creative Studio).

Args:
filepath (Path): The path of the file.
"""
preview_thumb_dir = "preview.jpg"
quicklook_thumb_dir = "QuickLook/Thumbnail.jpg"
thumb_files: list[str] = [
"preview.jpg",
"QuickLook/Preview.heic",
"QuickLook/Thumbnail.jpg",
"QuickLook/Thumbnail.heic",
]
im: Image.Image | None = None

def get_image(path: str) -> Image.Image | None:
Expand All @@ -1240,10 +1244,10 @@ def get_image(path: str) -> Image.Image | None:
thumb: Image.Image | None = None

# Check if the file exists in the zip
if preview_thumb_dir in zip_file.namelist():
thumb = get_image(preview_thumb_dir)
elif quicklook_thumb_dir in zip_file.namelist():
thumb = get_image(quicklook_thumb_dir)
for thumb_file in thumb_files:
if thumb_file in zip_file.namelist():
thumb = get_image(thumb_file)
break
else:
logger.error("Couldn't render thumbnail", filepath=filepath)

Expand Down Expand Up @@ -1314,7 +1318,7 @@ def _pdf_thumb(filepath: Path, size: int) -> Image.Image | None:
page_size *= size / page_size.height()
else:
page_size *= size / page_size.width()
# Enlarge image for antialiasing
# Enlarge image for anti-aliasing
scale_factor = 2.5
page_size *= scale_factor
# Render image with no anti-aliasing for speed
Expand Down Expand Up @@ -1865,8 +1869,11 @@ def _render(
):
image = self._open_doc_thumb(_filepath)
# Apple iWork Suite ============================================
elif MediaCategories.is_ext_in_category(ext, MediaCategories.IWORK_TYPES):
image = self._iwork_thumb(_filepath)
elif (
MediaCategories.is_ext_in_category(ext, MediaCategories.IWORK_TYPES)
or ext == ".pxd"
):
image = self._apple_embedded_thumb(_filepath)
# Plain Text ===================================================
elif MediaCategories.is_ext_in_category(
ext, MediaCategories.PLAINTEXT_TYPES, mime_fallback=True
Expand Down
Loading