vimiv-RawPrev/__init__.py

149 lines
4.2 KiB
Python

# vim: ft=python fileencoding=utf-8 sw=4 et sts=4
from functools import lru_cache
from typing import Any, BinaryIO
from vimiv import api
from vimiv.qt.gui import QPixmap, QImageReader
from vimiv.qt.core import QProcess
from vimiv.utils import log
_logger = log.module_logger(__name__)
def test_raf(header: bytes, _f: BinaryIO) -> bool:
return header[:15] == b"FUJIFILMCCD-RAW"
def test_cr2(header: bytes, _f: BinaryIO) -> bool:
return header[:2] in (b"II", b"MM") and header[8:10] == b"CR"
def test_orf(header: bytes, _f: BinaryIO) -> bool:
return header[:4] == b"IIRO"
def test_cr3(header: bytes, _f: BinaryIO) -> bool:
return (
header[4:8] == b"ftyp"
and header[8:11] == b"crx"
and header[16:24] == b"crx isom"
and header[28:32] == b"moov"
)
@lru_cache(maxsize=40)
def load_dcraw(path) -> QPixmap:
"""Extract thumbnail using `dcraw` and initialize QPixmap."""
process = QProcess()
process.start("dcraw", ["-e", "-c", path])
if not process.waitForFinished():
_logger.error(f"Process exited with code {process.exitCode()}")
raise OSError("Error waiting for process")
if (
process.exitStatus() != QProcess.ExitStatus.NormalExit
or process.exitCode() != 0
):
_logger.error(f"Process exited with code {process.exitCode()}")
stderr = process.readAllStandardError()
raise OSError(f"Error calling dcraw: '{stderr.data().decode()}'")
handler = QImageReader(process, "jpeg".encode())
handler.setAutoTransform(True)
process.closeWriteChannel()
process.terminate()
# Extract QImage from QImageReader and convert to QPixmap
pixmap = QPixmap()
pixmap.convertFromImage(handler.read())
return pixmap
def load_exiv2(path) -> QPixmap:
process = QProcess()
@lru_cache(maxsize=40)
def load_exiftool(path) -> QPixmap:
"""Extract thumbnail using `exiftool` and initialize QPixmap."""
import datetime
# Fix race condition when load_exiftool is called on same path in parallel
timestamp = datetime.datetime.now().strftime("%S%f")
process = QProcess()
process.start(
"exiftool",
[
"-b",
"-JpgFromRaw",
"-w!",
f"/tmp/vimiv-RawPrev%d%F_{timestamp}.jpg",
"-q",
"-execute",
"-tagsfromfile",
"@",
"-srcfile",
f"/tmp/vimiv-RawPrev{path}_{timestamp}.jpg",
"-overwrite_original",
"-common_args",
path,
],
)
if not process.waitForFinished():
_logger.error(f"Process exited with code {process.exitCode()}")
raise OSError("Error waiting for process")
if (
process.exitStatus() != QProcess.ExitStatus.NormalExit
or process.exitCode() != 0
):
_logger.error(f"Process exited with code {process.exitCode()}")
stderr = process.readAllStandardError()
raise OSError(f"Error calling exiftool: '{stderr.data().decode()}'")
# TODO reuse process
process = QProcess()
process.start("cat", [f"/tmp/vimiv-RawPrev{path}_{timestamp}.jpg"])
if not process.waitForFinished():
_logger.error(f"Process exited with code {process.exitCode()}")
raise OSError("Error waiting for process")
if (
process.exitStatus() != QProcess.ExitStatus.NormalExit
or process.exitCode() != 0
):
_logger.error(f"Process exited with code {process.exitCode()}")
stderr = process.readAllStandardError()
raise OSError(f"Error calling cat: '{stderr.data().decode()}'")
handler = QImageReader(process, "jpeg".encode())
handler.setAutoTransform(True)
process.closeWriteChannel()
process.terminate()
# Extract QImage from QImageReader and convert to QPixmap
pixmap = QPixmap()
pixmap.convertFromImage(handler.read())
return pixmap
def init(info: str, *_args: Any, **_kwargs: Any) -> None:
"""Setup RawPrev plugin by adding the raw handler"""
api.add_external_format("raf", test_raf, load_dcraw)
api.add_external_format("cr2", test_cr2, load_dcraw)
api.add_external_format("cr3", test_cr3, load_exiftool)
api.add_external_format("orf", test_orf, load_dcraw)
_logger.debug("Initialized RawPrev")