Pārlūkot izejas kodu

Изменент основной шаблон для печати пропуска,
Исправлены некоторые баги
Перенесены некоторые функции в другие места

Alex Sidorov 1 gadu atpakaļ
vecāks
revīzija
5c190b3507

+ 36 - 41
docs/template_propusk.html

@@ -5,63 +5,58 @@
     <meta charset="UTF-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Document</title>
+    <title>{{ id_propusk }}</title>
 </head>
 
 <body style="padding: 0; margin: 0; font-size: 12pt">
     {% for _ in range(2) %}
-    <table >
+    <table>
         <tbody>
             <tr>
-                <td><b>Временный пропуск №:</b> {{ id_propusk }}</td>
-                <td rowspan="5">
-                    <img src="{{ face }}" height="200" width="300"/>
+                <td colspan="2">
+                    <b>Временный пропуск КБГУ №:</b> {{ id_propusk }}
+                    <br>
+                    <b>Дата выдачи:</b> {{ date_from }}
+                    <br>
+                    <b>Действителен до:</b> {{ date_to }}
+                    <br>
+                    <b>Выдал:</b> {{ personal }}
+                    <br><br>
+                    _______________________________________
+                    <br />Подпись сотрудника бюро пропусков
+                    <br>
+                    <b>Место выдачи:</b> {{ place }}
+                    <br>
+                    <b>Принимающий:</b> {{ receiving_man }}
+                    <br>
+                    <b>Цель визита:</b> {{ purpose_visite }}
+                    <br>
+                    <b>Время выхода: __________________</b>
+                </td>
+                <td rowspan="2">
+                    <img src="{{document}}" height="650" width="500" />
                 </td>
-            </tr>
-            <tr>
-                <td><b>Дата выдачи:</b> {{ date_from }}</td>
-                <td></td>
-            </tr>
-            <tr>
-                <td><b>Действителен до:</b> {{ date_to }}</td>
-            </tr>
-            <tr>
-                <td><b>Выдал:</b> {{ personal }}</td>
             </tr>
             <tr>
                 <td>
-                    <p style="font-size: 12pt;">__________________________________</p>
-                    <p style="font-size: 10pt !important;">&nbsp;&nbsp;Подпись сотрудника бюро пропусков</p>
-                    <p style="font-size: 10pt !important;">&nbsp;&nbsp;Печать</p>
+                    <div style="border: 1px solid #000" width="350" height="300" align="center">
+                        <b>Используйте этот <br> QR-код для прохода <br> через турникет</b>
+                        <br>
+                        <img src="{{ qrcode }}" height="300" width="250">
+                    </div>
+
                 </td>
-                <td></td>
-                
-            </tr>
-            <tr height="200" width="300">
-                <td><b>Место выдачи:</b>{{ place }}</td>
-                <td rowspan="6">
-                    <img src="{{ document }}" height="200" width="300" />
+                <td>
+                    <img src="{{ face }}"
+                        height="300" width="250">
                 </td>
             </tr>
-            <tr>
-                <td><b>Принимающий:</b></td>
-            </tr>
-            <tr>
-                <td>{{ receiving_man }}</td>
-            </tr>
-            <tr>
-                <td><b>Цель визита:</b></td>
-            </tr>
-            <tr> 
-                <td>{{ purpose_visite }}</td></tr>
-            <tr>
-                <td><b>Время выхода: __________________</b></td>
-            </tr>
         </tbody>
     </table>
     <br>
-    <hr>
-    <br>
+    <div>
+            --------------------------------------------------------------------------------------- линия разрыва ----------------------------------------------------------------------------------------
+    </div>
     {% endfor %}
 </body>
 

+ 68 - 0
docs/template_propusk_back_four.html

@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Document</title>
+</head>
+
+<body style="padding: 0; margin: 0; font-size: 12pt">
+    {% for _ in range(2) %}
+    <table >
+        <tbody>
+            <tr>
+                <td><b>Временный пропуск №:</b> {{ id_propusk }}</td>
+                <td rowspan="5">
+                    <img src="{{ face }}" height="200" width="300"/>
+                </td>
+            </tr>
+            <tr>
+                <td><b>Дата выдачи:</b> {{ date_from }}</td>
+                <td></td>
+            </tr>
+            <tr>
+                <td><b>Действителен до:</b> {{ date_to }}</td>
+            </tr>
+            <tr>
+                <td><b>Выдал:</b> {{ personal }}</td>
+            </tr>
+            <tr>
+                <td>
+                    <p style="font-size: 12pt;">__________________________________</p>
+                    <p style="font-size: 10pt !important;">&nbsp;&nbsp;Подпись сотрудника бюро пропусков</p>
+                    <p style="font-size: 10pt !important;">&nbsp;&nbsp;Печать</p>
+                </td>
+                <td></td>
+                
+            </tr>
+            <tr height="200" width="300">
+                <td><b>Место выдачи:</b>{{ place }}</td>
+                <td rowspan="6">
+                    <img src="{{ document }}" height="200" width="300" />
+                </td>
+            </tr>
+            <tr>
+                <td><b>Принимающий:</b></td>
+            </tr>
+            <tr>
+                <td>{{ receiving_man }}</td>
+            </tr>
+            <tr>
+                <td><b>Цель визита:</b></td>
+            </tr>
+            <tr> 
+                <td>{{ purpose_visite }}</td></tr>
+            <tr>
+                <td><b>Время выхода: __________________</b></td>
+            </tr>
+        </tbody>
+    </table>
+    <br>
+    <hr>
+    <br>
+    {% endfor %}
+</body>
+
+</html>

+ 35 - 35
docs/template_propusk_back_two.html

@@ -5,7 +5,7 @@
     <meta charset="UTF-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Document</title>
+    <title>{{ id_propusk }}</title>
 </head>
 
 <body style="padding: 0; margin: 0; font-size: 12pt">
@@ -13,48 +13,48 @@
     <table>
         <tbody>
             <tr>
-                <td><b>Временный пропуск №:</b> {{ id_propusk }}</td>
-                <td rowspan="12">
-                    <img src="{{ face_photo }}" width="300" height="400"/>
+                <td colspan="2">
+                    <b>Временный пропуск КБГУ №:</b> {{ id_propusk }}
+                    <br>
+                    <b>Дата выдачи:</b> {{ date_from }}
+                    <br>
+                    <b>Действителен до:</b> {{ date_to }}
+                    <br><br>
+                    _______________________________________
+                    <br />Подпись сотрудника бюро пропусков
+                    <br>
+                    <b>Выдал:</b> {{ personal }}
+                    <br>
+                    <b>Принимающий:</b> {{ receiving_man }}
+                    <br>
+                    <b>Цель визита:</b> {{ purpose_visite }}
+                    <br>
+                    <b>Время выхода: __________________</b>
+                </td>
+                <td rowspan="2">
+                    <img src="file:/home/asidorov/project/propusk/test2.jpg" height="650" width="400" />
                 </td>
-            </tr>
-            <tr>
-                <td><b>Дата выдачи:</b> {{ date_from }}</td>
-                
-            </tr>
-            <tr>
-                <td><b>Действителен до:</b> {{ date_to }}</td>
-            </tr>
-            <tr>
-                <td><b>Выдал:</b> {{ personal }}</td>
             </tr>
             <tr>
                 <td>
-                    <p style="font-size: 12pt;">__________________________________</p>
-                    <p style="font-size: 10pt !important;">&nbsp;&nbsp;Подпись сотрудника бюро пропусков</p>
-                    <p style="font-size: 10pt !important;">&nbsp;&nbsp;Печать</p>
+                    <div style="border: 1px solid #000" width="350" height="300" align="center">
+                        <b>Используйте этот <br> QR-код для прохода <br> через турникет</b>
+                        <br>
+                        <img src="file:/{{qrcode}}" height="300" width="300">
+                    </div>
+
+                </td>
+                <td>
+                    <img src="file:/home/asidorov/project/propusk/test2.jpg"
+                        height="400" width="300">
                 </td>
-            </tr>
-            <tr>
-                <td><b>Место выдачи:</b> {{ place }}</td>
-            </tr>
-            <tr>
-                
-            </tr>
-            <tr>
-                <td></td>
-            </tr>
-            <tr>
-                
-            </tr>
-            <tr> 
-                <td></td></tr>
-            <tr>
-                <td><b>Время выхода: __________________</b></td>
             </tr>
         </tbody>
     </table>
-    <hr>
+    <br>
+    <div>
+            --------------------------------------------------------------------------------------- линия разрыва ----------------------------------------------------------------------------------------
+    </div>
     {% endfor %}
 </body>
 

+ 11 - 14
module/ImageTool.py

@@ -28,17 +28,14 @@ def rotate_image(path_file: str, gradus: int = -90) -> str:
 
 
 def cupture_face(path_photo: str, new_path: str) -> None:
-    img = cv2.imread(path_photo)
-    face_recog = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
-    face_result = face_recog.detectMultiScale(img, scaleFactor=2, minNeighbors=3)
-    print(face_result)
-    if len(face_result) != 0:
-        
-        x,y,w,h = face_result[-1]
-        
-        img = img[y-50:y+h+80,x-50:x+50+w]
-        cv2.imwrite(new_path, img)
-            
-        # cv2.imshow("Result", img)
-        #Этот метод выводит результат на экран. Первый аргумент - что то по типу комментария к картинке, второй - сама картинка
-        # cv2.waitKey(0)
+    try:
+        img = cv2.imread(path_photo)
+        face_recog = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_alt_tree.xml')
+        face_result = face_recog.detectMultiScale(img, scaleFactor=2, minNeighbors=3)
+        if len(face_result) != 0:
+            logger.info(F"Find face: {face_result}")
+            x,y,w,h = face_result[-1]        
+            img = img[y-50:y+h+80,x-50:x+50+w]
+            cv2.imwrite(new_path, img)
+    except cv2.error as err:
+        logger.error(err)

+ 42 - 8
module/Printer.py

@@ -1,14 +1,48 @@
-from PySide6.QtWidgets import QTextEdit, QDialog
+from PySide6.QtWidgets import QDialog
 from PySide6.QtPrintSupport import QPrintDialog, QPrinter
+from PySide6.QtGui import QPainter, QPixmap, QPageSize
+from PySide6.QtCore import Qt
+import pdfkit
+from module import create_filename
+from pdf2image import convert_from_path
 
 
-class Printer:
+class Print:
     def __init__(self, text: str) -> None:
+        
         self.printer = QPrinter()
-        self.editor = QTextEdit()
-        self.editor.setHtml(text)
-
-    def print(self) -> None:
+        self.printer.setFullPage(True)
+        self.printer.setPageSize(QPageSize.A4)
+        
+        pdf  = CreatorPDF(text)
+        image = convert_from_path(pdf.get_path_to_pdf())[0].toqimage()
+        image = QPixmap.fromImage(image)
+        # print(self.printer.pageRect())
+        image = image.scaledToWidth(self.printer.width(), Qt.SmoothTransformation)
+        
         dialog = QPrintDialog(self.printer)
-        if dialog.exec_() == QDialog.Accepted:
-            self.editor.document().print_(dialog.printer())
+        if dialog.exec() == QDialog.Accepted:
+            self.handle_paint_request(image)
+
+        
+    def handle_paint_request(self, im):
+        painter = QPainter(self.printer)
+        
+        painter.drawPixmap(0, 0, im)
+        painter.end()
+       
+
+
+class CreatorPDF():
+    def __init__(self, text_html):
+        self.__file_name = create_filename('pdf')
+        # self.__file_name = 'pdf.pdf'
+        configuration = pdfkit.configuration(
+            wkhtmltopdf="/usr/bin/wkhtmltopdf")
+        pdfkit.from_string(text_html, self.__file_name, configuration=configuration, css=None, options={
+            "enable-local-file-access": ""
+        })
+        
+    def get_path_to_pdf(self) -> str:
+        return self.__file_name
+ 

+ 20 - 4
module/__init__.py

@@ -1,10 +1,26 @@
 from datetime import datetime
 import os
+import platform
+import subprocess
 
 
 
-def create_filename() -> str:
-    return os.path.join(os.environ.get('PHOTO_DIR'), F"propusk_{datetime.now().timestamp()}.jpg")
+def create_filename(prefix: str = "propusk") -> str:
+    return os.path.join(os.environ.get('PHOTO_DIR'), F"{prefix}_{datetime.now().timestamp()}.jpg")
 
-def create_path_qr() -> str:
-    return os.path.join(os.environ.get('PHOTO_DIR'), F"qr_{datetime.now().timestamp()}.png")
+def get_path_wkhtmltopdf() -> str:
+    match platform.system():
+        case 'Linux':
+            result = subprocess.Popen(['whereis wkhtmltopdf'], shell=True, stdout=subprocess.PIPE).stdout.read()
+            return str(result).split(' ')[1]
+        case 'Windows':
+            pass
+        case _: ...
+    
+    
+def main():
+    print(get_path_wkhtmltopdf())
+
+
+if __name__ == "__main__":
+    main()

+ 8 - 13
module/cam/IPCam.py

@@ -27,32 +27,26 @@ class IPCam(Thread):
             if 'rtsp' in self.lnk_connect:
                 self.cap.open(self.lnk_connect)
 
-                if not self.cap.isOpened():
-                    raise ConnectionError
-
             while self.status:
 
                 if 'http' in self.lnk_connect:
                     self.cap.open(self.lnk_connect)
 
-                    if not self.cap.isOpened():
-                        raise ConnectionError
-
+                if not self.cap.isOpened():
+                    raise ConnectionError
+                
                 ret, frame = self.cap.read()
-                if not ret:
-                    continue
+                if not ret: continue
 
                 color_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
 
-                _, _, ch = color_frame.shape
-                
-                
+                h, w, ch = color_frame.shape
                 img = QImage(color_frame.data, w, h,
                              ch * w, QImage.Format_RGB888)
                 
                 
                 label_geometry = self.qLabel.geometry()
-                h, w = label_geometry.height(), label_geometry.width()
+                h, w = label_geometry.height()-20, label_geometry.width()-20
                 
                 self.__scaled_img = QPixmap.fromImage(
                     img.scaled(h, w, Qt.KeepAspectRatio))
@@ -83,5 +77,6 @@ class IPCam(Thread):
         qLabel.setPixmap(self.__scaled_img)
         self.__scaled_img.save(name_file, 'jpg')
         self.stop_cam()
-        cupture_face(name_file, F"face_{create_filename()}")
+        face_file_name = create_filename('face')
+        cupture_face(name_file, face_file_name)
         return name_file

+ 1 - 1
module/cam/USBCam.py

@@ -94,7 +94,7 @@ class USBCam:
     def image_saved(self, id, fileName):
         load_image(self._label, fileName)
         self.stop_cam()
-        cupture_face(fileName, F"face_{create_filename()}")
+        return fileName
 
 
 def load_image(qlabel: QLabel, path_file: str) -> None:

+ 14 - 17
widgets/PStackedWidget.py

@@ -1,5 +1,5 @@
 from PySide6.QtWidgets import QStackedWidget, QWidget, QLabel, QGridLayout
-from PySide6.QtGui import QResizeEvent, QPixmap
+from PySide6.QtGui import QResizeEvent, QPixmap, QImage
 from PySide6.QtCore import QSize
 from PySide6.QtMultimediaWidgets import QVideoWidget
 from module.cam.USBCam import load_image
@@ -20,18 +20,15 @@ class PStackedWidget(QStackedWidget):
     def __resize(self, event: QResizeEvent) -> None:
         self.image.resize(event.size())
         self.video.resize(event.size())
-        img = self.image.pixmap().toImage().scaled(
-            event.size().width()-20,
-            event.size().height()-20
-        )
-        self.image.setPixmap(QPixmap.fromImage(img))
         
-        if self.video.__class__.__name__ in 'QLabel':
-            img = self.video.pixmap().toImage().scaled(
-                event.size().width()-20,
-                event.size().height()-20
-            )
-            self.video.setPixmap(QPixmap.fromImage(img))
+        self.image.setPixmap(QPixmap.fromImage(
+            self.__scaled_image(self.image, event)                                       
+        ))
+        
+        if self.__mode not in 'video':
+            self.video.setPixmap(QPixmap.fromImage(
+                self.__scaled_image(self.video, event)
+            ))
         
         # print(type(self.video))
 
@@ -74,8 +71,8 @@ class PStackedWidget(QStackedWidget):
     def to_video(self) -> None:
         self.setCurrentIndex(1)
 
-    # def cupture_image(self) -> None:
-    #     if self.__mode == 'video':
-    #         self.video = self.video.cupture_image(self.image)
-    #     else:
-    #         self.video = self.video.cupture_image(self.image)
+    def __scaled_image(self, label: QLabel, event: QResizeEvent) -> QImage:
+        return label.pixmap().toImage().scaled(
+            event.size().width()-20,
+            event.size().height()-20
+        ) 

+ 31 - 15
window/DialogHistory.py

@@ -1,13 +1,21 @@
-from PySide6.QtWidgets import QDialog
+import os
+
+# from module.ImageTool import rotate_image
+from pdf2image import convert_from_path
 from PySide6.QtCore import Slot
-from .ui_py.ui_DialogHistory import Ui_DialogHistory
-from module.WorkWithDB import connect, list_propusk, list_personal, list_place
-from sqlalchemy import select, func
+from PySide6.QtGui import QPixmap
+from PySide6.QtWidgets import QDialog
+from sqlalchemy import func, select
+
+from logger import logger
+from module import create_filename
 from module.ModelPropusk import PropuskDataMethods
+from module.Printer import CreatorPDF
+from module.QRCode import make
 from module.TemplatePropusk import TemplatePropusk
-import os
-from module.ImageTool import rotate_image
-from logger import logger
+from module.WorkWithDB import connect, list_personal, list_place, list_propusk
+
+from .ui_py.ui_DialogHistory import Ui_DialogHistory
 
 
 class DialogHistory(Ui_DialogHistory, QDialog):
@@ -44,7 +52,7 @@ class DialogHistory(Ui_DialogHistory, QDialog):
             else:
                 item.setHidden(False)
 
-    def match_text(self, text, keywords) -> None:
+    def match_text(self, text: str, keywords:str) -> bool:
         return text in keywords
 
     def load_data(self) -> None:
@@ -81,14 +89,22 @@ class DialogHistory(Ui_DialogHistory, QDialog):
             ).fetchone()
 
             pdm = PropuskDataMethods(*row)
-            face = os.path.join(os.environ.get('PHOTO_DIR'), pdm.get_value("face"))
-            documet = os.path.join(os.environ.get('PHOTO_DIR'), pdm.get_value("document"))
+            face = os.path.join(os.environ.get(
+                'PHOTO_DIR'), pdm.get_value("face"))
+            documet = os.path.join(os.environ.get(
+                'PHOTO_DIR'), pdm.get_value("document"))
             pdm.set_value("face", face)
             pdm.set_value("document", documet)
+            pdm.set_value("qrcode", make(pdm.get_value('id_propusk'), create_filename('qr')))
+
+            path_doc = os.path.join(os.path.dirname(os.path.abspath(__package__)), 'docs')
+            render_text = str(TemplatePropusk(pdm._propusk_data.__dict__, path_doc))
+            # print(render_text)
             
+            # Print(render_text)
+            pdf = CreatorPDF(render_text)
+            image  = convert_from_path(pdf.get_path_to_pdf())[0]
+            image_path = create_filename()
+            QPixmap.fromImage(image.toqimage()).save(image_path, 'jpg')
             
-            render_text = str(TemplatePropusk(pdm._propusk_data.__dict__,
-                                              os.path.join(os.path.dirname(
-                                                  os.path.abspath(__package__)), 'docs')
-                                              ))
-            self.browser.setText(render_text)
+            self.browser.setText(F"<img src='file:{image_path}'>")

+ 8 - 10
window/MainWindow.py

@@ -5,12 +5,11 @@ from sqlalchemy.exc import OperationalError
 from module.WorkWithDB import *
 from module.MyMessageBox import show_dialog
 from module.TemplatePropusk import TemplatePropusk
-from module.Printer import Printer
+from module.Printer import Print
 from module.lang.ru import *
 from module.cam import IPCam, USBCam, load_image
-import module.QRCode
-from module import create_path_qr
-# from module.ImageTool import cupture_face
+from module import create_filename
+from module.QRCode import make as make_qr
 
 from widgets import PStackedWidget, create_widget_stacked
 
@@ -21,7 +20,6 @@ from .DialogSettingCam import SettingCam
 from .DialogAbout import DialogAbout
 from .DialogHistory import DialogHistory
 
-
 from datetime import datetime
 from logger import logger
 from pathlib import Path
@@ -217,7 +215,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
             self.__file_name_face = self.__wwc.cupture_image(
                 self.stacked_face.image)
             self.stacked_face.to_image()
-            
 
         self.btn_start_cam.setText(start_cam)
 
@@ -227,9 +224,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
         if self.data_propusk is None:
             self.__save()
 
-
         propusk_data = self.data_propusk.copy()
-        
+
+
         propusk_data.update({
             "personal": self.personal_combobox.currentText(),
             "place": self.place_combobox.currentText(),
@@ -237,7 +234,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
             "date_to": self.date_to.dateTime().toString('dd.MM.yyyy hh:mm'),
             "face": self.__file_name_face,
             "document": self.__file_name_document,
-            # "qrcode": QRCode.make(propusk_data.get("id_propusk"), create_path_qr())
+            "qrcode": make_qr(propusk_data.get("id_propusk"), create_filename('qr')),
+            "count_repeat": 2
         })
 
         render_text = TemplatePropusk(
@@ -245,7 +243,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
             os.path.join(os.environ.get('ABSOLUTE_PATH'), 'docs')
         )
 
-        Printer(str(render_text)).print()
+        Print(str(render_text))
 
     def __clear(self) -> None:
         if self.data_propusk is not None: