Загрузка данных


import sys
import subprocess
import threading
import os
import glob
import shutil
from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout,
                             QLineEdit, QPushButton, QLabel, QFileDialog, QMessageBox,
                             QProgressBar, QRadioButton, QButtonGroup, QGroupBox)
from PyQt5.QtCore import Qt


class ScannerApp(QWidget):
    def __init__(self):
        super().__init__()
        self.scanning = False
        self.save_dir = os.path.expanduser("~/Изображения/Сканы")
        self.initUI()

    def initUI(self):
        self.setWindowTitle('Сканер Canon DR-G1100')
        self.resize(520, 400)

        vbox = QVBoxLayout()

        # --- Выбор папки ---
        self.label_path = QLabel('Папка для сохранения:')
        self.entry_path = QLineEdit(self.save_dir)
        self.btn_browse = QPushButton('Выбрать папку...')
        self.btn_browse.clicked.connect(self.choose_path)

        hbox_path = QHBoxLayout()
        hbox_path.addWidget(self.entry_path)
        hbox_path.addWidget(self.btn_browse)

        vbox.addWidget(self.label_path)
        vbox.addLayout(hbox_path)

        # --- Выбор разрешения ---
        res_group = QGroupBox('Разрешение (dpi):')
        res_layout = QHBoxLayout()
        self.res_group_btn = QButtonGroup(self)
        self.res_200 = QRadioButton('200 (быстро)')
        self.res_300 = QRadioButton('300 (стандарт)')
        self.res_400 = QRadioButton('400 (хорошо)')
        self.res_600 = QRadioButton('600 (отлично)')
        self.res_300.setChecked(True)
        self.res_group_btn.addButton(self.res_200, 200)
        self.res_group_btn.addButton(self.res_300, 300)
        self.res_group_btn.addButton(self.res_400, 400)
        self.res_group_btn.addButton(self.res_600, 600)
        res_layout.addWidget(self.res_200)
        res_layout.addWidget(self.res_300)
        res_layout.addWidget(self.res_400)
        res_layout.addWidget(self.res_600)
        res_group.setLayout(res_layout)
        vbox.addWidget(res_group)

        # --- Кнопка сканирования ---
        self.btn_scan = QPushButton('Начать сканирование')
        self.btn_scan.setStyleSheet("font-weight: bold; height: 40px; background-color: #4CAF50; color: white;")
        self.btn_scan.clicked.connect(self.start_scan)
        vbox.addWidget(self.btn_scan)

        # --- Прогресс-бар ---
        self.progress = QProgressBar()
        self.progress.setRange(0, 0)
        self.progress.setVisible(False)
        vbox.addWidget(self.progress)

        # --- Статус ---
        self.label_status = QLabel('Готов к работе')
        self.label_status.setAlignment(Qt.AlignCenter)
        self.label_status.setStyleSheet("color: blue; font-size: 12px;")
        vbox.addWidget(self.label_status)

        # --- Кнопка открыть папку ---
        self.btn_open = QPushButton('Открыть папку со сканами')
        self.btn_open.clicked.connect(self.open_folder)
        vbox.addWidget(self.btn_open)

        self.setLayout(vbox)

    def choose_path(self):
        folder = QFileDialog.getExistingDirectory(
            self,
            "Выберите папку для сохранения",
            self.save_dir
        )
        if folder:
            self.save_dir = folder
            self.entry_path.setText(folder)

    def find_device(self):
        try:
            result = subprocess.run(["scanimage", "-L"],
                                    capture_output=True, text=True, timeout=10)
            for line in result.stdout.splitlines():
                if "canondr" in line.lower() or "drg1100" in line.lower():
                    start = line.find("`") + 1
                    end = line.find("'")
                    if start > 0 and end > start:
                        return line[start:end]
        except Exception:
            pass
        return "canondr:libusb:001:005"

    def start_scan(self):
        if self.scanning:
            return
        os.makedirs(self.save_dir, exist_ok=True)
        self.scanning = True
        self.btn_scan.setEnabled(False)
        self.btn_scan.setText('Сканирование...')
        self.btn_browse.setEnabled(False)
        self.progress.setVisible(True)
        self.label_status.setText('Идёт сканирование... Не закрывайте окно!')
        self.label_status.setStyleSheet("color: red; font-size: 12px;")
        thread = threading.Thread(target=self._do_scan)
        thread.daemon = True
        thread.start()

    def _do_scan(self):
        device = self.find_device()
        resolution = self.res_group_btn.checkedId()
        batch_pattern = os.path.join(self.save_dir, "scan_%04d.tiff")
        command = (f'scanimage -d "{device}" --ScanMode Duplex --batchMode 0 '
                   f'--resolution {resolution} --mode Color --format=tiff '
                   f'--batch="{batch_pattern}"')
        try:
            subprocess.run(command, shell=True, check=True,
                           stderr=subprocess.PIPE, text=True, timeout=600)
            tiff_files = sorted(glob.glob(os.path.join(self.save_dir, "scan_*.tiff")))
            if tiff_files:
                self.label_status.setText("Создаю PDF...")
                self.label_status.setStyleSheet("color: blue; font-size: 12px;")
                QApplication.processEvents()
                pdf_path = os.path.join(self.save_dir, "Документ.pdf")
                tiff2pdf = shutil.which("tiff2pdf") or "/usr/bin/tiff2pdf"
                subprocess.run([tiff2pdf, "-o", pdf_path] + tiff_files,
                               capture_output=True)
                for f in tiff_files:
                    try:
                        os.remove(f)
                    except Exception:
                        pass
                self.finish_scan(True, f"Файл сохранён:\n{pdf_path}")
            else:
                self.finish_scan(False, "Не создано ни одного файла")
        except subprocess.TimeoutExpired:
            self.finish_scan(False, "Превышено время ожидания")
        except subprocess.CalledProcessError as e:
            err = e.stderr if e.stderr else "Проверьте подключение сканера"
            self.finish_scan(False, f"Ошибка сканирования:\n{err}")
        except Exception as e:
            self.finish_scan(False, f"Ошибка:\n{str(e)}")

    def finish_scan(self, success, message):
        self.scanning = False
        self.btn_scan.setEnabled(True)
        self.btn_scan.setText('Начать сканирование')
        self.btn_browse.setEnabled(True)
        self.progress.setVisible(False)
        if success:
            self.label_status.setText('Готово!')
            self.label_status.setStyleSheet("color: green; font-size: 12px;")
            QMessageBox.information(self, 'Успех', message)
        else:
            self.label_status.setText('Ошибка')
            self.label_status.setStyleSheet("color: red; font-size: 12px;")
            QMessageBox.critical(self, 'Ошибка', message)

    def open_folder(self):
        os.makedirs(self.save_dir, exist_ok=True)
        subprocess.Popen(["xdg-open", self.save_dir])


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = ScannerApp()
    ex.show()
    sys.exit(app.exec_())