Skip to content

Commit

Permalink
Version 3.0.0
Browse files Browse the repository at this point in the history
* Moved GUI library to PyQt6.
* Bug fix
  • Loading branch information
Augus1999 authored Jun 3, 2024
1 parent c370afd commit dba1518
Show file tree
Hide file tree
Showing 9 changed files with 360 additions and 215 deletions.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ and [PyMuPDF](https://github.com/pymupdf/PyMuPDF), designed to work on simple PD

I tried my best to make it close to Fluent UI. Icons used can be found [🔗here](https://fluenticons.co/).

From version 3.0.0, we have moved the GUI library to PyQt6. If you upgraded from a previous version, you can consider removing PyQt5:
```bash
$ pip uninstall PyQt5 PyQt5-Qt5 PyQt5-sip
```

## Features

* Support 3 languages: English, 日本語 (Japanese), and 中文 (Traditional Chinese)
Expand Down Expand Up @@ -51,8 +56,8 @@ Python>=3.7
```

```text
PyQt5>=5.15.4
PyMuPDF>=1.19.2
PyQt6>=6.7.0
PyMuPDF>=1.24.0
```

## Install & Run
Expand Down
18 changes: 6 additions & 12 deletions pypdfeditor_core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,16 @@
import os
import sys
import platform
import fitz
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication
import pymupdf
from PyQt6.QtWidgets import QApplication
from .application import reset, remove, Main, app_home

if not os.path.exists(app_home):
os.makedirs(app_home)

__system__ = platform.system()
__author__ = "Nianze A. TAO (Omozawa SUENO)"
__version__ = "2.3.0"
__version__ = "3.0.0"
__all__ = ["main", "reset", "remove"]


Expand All @@ -31,14 +30,9 @@ def main(
:param debug: whether display mupdf errors or not
:return: None
"""
a = QApplication([])
s = a.desktop().screenGeometry()
screen_w, screen_h = s.width(), s.height() # get screen info
del s, a # delete QApplication object so that it won't affect the following codes
if screen_w > 1920 and screen_h > 1080:
QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps)
fitz.TOOLS.mupdf_display_errors(debug)
if system == "Windows":
os.environ["QT_FONT_DPI"] = "96"
pymupdf.TOOLS.mupdf_display_errors(debug)
app = QApplication(sys.argv)
main_app = Main(system, version)
main_app.show()
Expand Down
34 changes: 18 additions & 16 deletions pypdfeditor_core/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
import subprocess as sp
from pathlib import Path
from typing import Dict
import fitz
from PyQt5 import QtCore
from PyQt5.QtGui import QColor, QPixmap
from PyQt5.QtWidgets import QColorDialog
import pymupdf as fitz
from PyQt6 import QtCore
from PyQt6.QtGui import QColor, QPixmap, QCloseEvent
from PyQt6.QtWidgets import QColorDialog
from .language import set_language, lag_s, lag_p
from .windows import (
MainR,
Expand Down Expand Up @@ -120,13 +120,15 @@ def __init__(self, system: str, version: str):
)
)
self.tab3.button9.clicked.connect(
lambda: os.remove(
os.path.join(app_home, "font_dir_cache.json"),
)
if os.path.exists(
os.path.join(app_home, "font_dir_cache.json"),
lambda: (
os.remove(
os.path.join(app_home, "font_dir_cache.json"),
)
if os.path.exists(
os.path.join(app_home, "font_dir_cache.json"),
)
else None
)
else None
) # delete font dir cache
self.tab3.line3.returnPressed.connect(self.preview)
self.tab3.line4.returnPressed.connect(self.preview)
Expand Down Expand Up @@ -155,7 +157,7 @@ def __init__(self, system: str, version: str):
if not self.settings.value("windowState") == None:
self.restoreState(self.settings.value("windowState"))

def closeEvent(self, event) -> None:
def closeEvent(self, event: QCloseEvent) -> None:
"""
write settings to settings.json
"""
Expand Down Expand Up @@ -489,7 +491,7 @@ def get_colour(self) -> None:
int(255 * float(self.tab3.line4.text()) / 100),
),
options=QColorDialog.ColorDialogOption(
QColorDialog.ShowAlphaChannel,
QColorDialog.ColorDialogOption.ShowAlphaChannel,
),
parent=self,
title="Select Colour",
Expand All @@ -513,7 +515,7 @@ def get_font(self) -> None:
)
else:
font_paths = QtCore.QStandardPaths.standardLocations(
QtCore.QStandardPaths.FontsLocation,
QtCore.QStandardPaths.StandardLocation.FontsLocation,
)
name_dict, file_dict = find_font(font_paths)
store_font_path(name_dict, os.path.join(app_home, "font_dir_cache.json"))
Expand Down Expand Up @@ -617,7 +619,7 @@ def _enable_select(self):
self.line1.setReadOnly(False)
self.line2.setReadOnly(False)

def closeEvent(self, event) -> None:
def closeEvent(self, event: QCloseEvent) -> None:
"""
re-write closeEvent
"""
Expand All @@ -644,7 +646,7 @@ def set_language(self, language: str) -> None:
"""
lag_p(self, language)

def closeEvent(self, event) -> None:
def closeEvent(self, event: QCloseEvent) -> None:
"""
close event
"""
Expand Down Expand Up @@ -719,7 +721,7 @@ def change_text_font(self) -> None:
fitz.TOOLS.store_shrink(100) # delete MuPDF cache
del cover, shape, page, r1, doc

def closeEvent(self, event) -> None:
def closeEvent(self, event: QCloseEvent) -> None:
"""
close event
"""
Expand Down
63 changes: 37 additions & 26 deletions pypdfeditor_core/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
import time
from typing import Union, Optional, Tuple, List
from pathlib import Path
from fitz import Document, Page, Pixmap, Rect, Point, Font
from fitz.utils import get_pixmap, set_metadata, Shape
from fitz import TOOLS, Matrix, Identity
from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtWidgets import (
from pymupdf import Document, Page, Pixmap, Rect, Point, Font
from pymupdf.utils import get_pixmap, set_metadata, Shape
from pymupdf import TOOLS, Matrix, Identity
from PyQt6 import QtGui, QtCore, QtWidgets
from PyQt6.QtWidgets import (
QInputDialog,
QHBoxLayout,
QWidget,
Expand Down Expand Up @@ -47,13 +47,12 @@ def copy(doc: Doc) -> Doc:
:param doc: document to be copied
:return: copied document
"""
_doc = Doc(doc.name)
_doc = Doc(filename=doc.name)
if not _doc.is_pdf:
pdf_bites = _doc.convert_to_pdf()
_doc = Doc("pdf", pdf_bites)
if doc.pass_word is not None:
_doc.authenticate(doc.pass_word)
_doc.name = doc.name
_doc.rotatedPages = doc.rotatedPages
if len(_doc.rotatedPages) != 0:
for page in _doc.rotatedPages:
Expand Down Expand Up @@ -86,7 +85,12 @@ def open_pdf(file_name: str, parent: QWidget) -> Tuple[Optional[Doc], bool]:
if doc.needs_pass:
while doc.is_encrypted:
value, _ = QInputDialog.getText(
parent, " ", "Password:", QLineEdit.Password, "", QtCore.Qt.Dialog
parent,
" ",
"Password:",
QLineEdit.EchoMode.Password,
"",
QtCore.Qt.WindowType.Dialog,
)
if not _:
doc.close()
Expand All @@ -106,9 +110,9 @@ def render_pdf_page(page_data: Doc.load_page) -> QtGui.QPixmap:
"""
page_pixmap = get_pixmap(page_data, matrix=Identity, clip=True)
if page_pixmap.alpha:
image_format = QtGui.QImage.Format_RGBA8888
image_format = QtGui.QImage.Format.Format_RGBA8888
else:
image_format = QtGui.QImage.Format_RGB888
image_format = QtGui.QImage.Format.Format_RGB888
page_image = QtGui.QImage(
page_pixmap.samples,
page_pixmap.w,
Expand Down Expand Up @@ -214,11 +218,11 @@ def setting_warning(set_file_name: str, parent: QWidget) -> dict:
"Error",
f"Cannot find {os.path.basename(set_file_name)}\n\n"
f"Create an empty setting file?",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
)
if reply == QMessageBox.No:
if reply == QMessageBox.StandardButton.No:
sys.exit(0)
if reply == QMessageBox.Yes:
if reply == QMessageBox.StandardButton.Yes:
content = {
"start dir": "",
"save dir": "",
Expand Down Expand Up @@ -259,7 +263,7 @@ def page_icon(page: Page, width: int, w_col: int, _scaled: float) -> QWidget:
label = QtWidgets.QLabel(None)
layout = QHBoxLayout(None)
widget = QWidget(None)
layout.addWidget(label, alignment=QtCore.Qt.AlignCenter)
layout.addWidget(label, alignment=QtCore.Qt.AlignmentFlag.AlignCenter)
widget.setLayout(layout)
if _cover.height() / _cover.width() >= 4 / 3:
scaled_height = int(width // w_col * 4 / 3 * _scaled)
Expand All @@ -271,11 +275,11 @@ def page_icon(page: Page, width: int, w_col: int, _scaled: float) -> QWidget:
QtGui.QPixmap(_cover).scaled(
scaled_width,
scaled_height,
QtCore.Qt.IgnoreAspectRatio,
QtCore.Qt.SmoothTransformation,
QtCore.Qt.AspectRatioMode.IgnoreAspectRatio,
QtCore.Qt.TransformationMode.SmoothTransformation,
),
)
label.setAlignment(QtCore.Qt.AlignCenter)
label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
label.setFixedSize(scaled_width, scaled_height)
shadow(label, QtGui.QColor(0, 0, 0, 100), 20)
del _cover, label, layout
Expand All @@ -296,9 +300,11 @@ def set_icon(
x, y = 0, 0
for i in widget.book_list:
label = page_icon(
widget.book[i]
if isinstance(widget.book_list[0], int)
else (i[0] if doc is None else doc[0]),
(
widget.book[i]
if isinstance(widget.book_list[0], int)
else (i[0] if doc is None else doc[0])
),
widget.table.width(),
widget.w_col,
_scaled,
Expand Down Expand Up @@ -386,6 +392,7 @@ def generate_menu(pos, widget: QWidget, main: QWidget, select: int = 0) -> None:
index = row_num * widget.w_col + col_num # get position
if 0 <= index < len(widget.book_list):
menu = QtWidgets.QMenu()
menu.setStyleSheet("font-size:12pt")
item1 = menu.addAction(
QtGui.QIcon(os.path.join(icon_path, "delete.svg")), MENU_L[main.language][0]
)
Expand Down Expand Up @@ -417,7 +424,7 @@ def generate_menu(pos, widget: QWidget, main: QWidget, select: int = 0) -> None:
item8 = menu.addAction(
QtGui.QIcon(str(icon_path / "arrow_move.svg")), MENU_L[main.language][7]
)
action = menu.exec_(widget.table.mapToGlobal(pos))
action = menu.exec(widget.table.mapToGlobal(pos))
if action == item1:
delete(index=index, widget=widget)
if action == item2 and select == 1:
Expand Down Expand Up @@ -539,7 +546,7 @@ def extract_img(index: int, widget: QWidget, main: QWidget) -> None:
main,
"Saved",
MESSAGE[main.language][1].format(len(img_inf), main.s_dir),
QMessageBox.Yes,
QMessageBox.StandardButton.Yes,
)
TOOLS.store_shrink(100) # delete MuPDF cache

Expand Down Expand Up @@ -583,7 +590,7 @@ def rearrange_page(index: int, widget: QWidget, parent: QWidget) -> None:
min=1,
max=book_length,
step=1,
flags=QtCore.Qt.Dialog,
flags=QtCore.Qt.WindowType.Dialog,
)
if not _:
return None
Expand All @@ -608,7 +615,7 @@ def _set_watermark_pos(main: QWidget) -> None:
:return: None
"""
pos_str, _ = QInputDialog.getText(
main, " ", "Set watermark position: x,y", flags=QtCore.Qt.Dialog
main, " ", "Set watermark position: x,y", flags=QtCore.Qt.WindowType.Dialog
)
if _:
pos = pos_str.strip().split(",")
Expand Down Expand Up @@ -804,7 +811,9 @@ def warning(parent) -> None:
:param parent: parent
:return: None
"""
QMessageBox.warning(parent, "Oops", MESSAGE[parent.language][2], QMessageBox.Yes)
QMessageBox.warning(
parent, "Oops", MESSAGE[parent.language][2], QMessageBox.StandardButton.Yes
)


def _open_warning(parent: QWidget) -> Tuple[None, bool]:
Expand All @@ -814,5 +823,7 @@ def _open_warning(parent: QWidget) -> Tuple[None, bool]:
:param parent: parent
:return: (None, False)
"""
QMessageBox.critical(parent, "Oops", MESSAGE[parent.language][0], QMessageBox.Yes)
QMessageBox.critical(
parent, "Oops", MESSAGE[parent.language][0], QMessageBox.StandardButton.Yes
)
return None, False
Loading

0 comments on commit dba1518

Please sign in to comment.