[FAQ] Как быстро сделать постер и примеры страниц для книжной раздачи (PDF, DjVu, EPUB, FB2, MOBI)
| Ответить на тему | Главная » 📚 Литература » Помощь по разделу (Литература) |
|
|
| Автор | Сообщение |
|---|---|
|
Постер и примеры страниц для раздачи
Инструкция по использованию скрипта-Для книжной раздачи нужны обложка и несколько примеров страниц. Снимать их скриншотами долго, а качество получается хуже, чем в самой книге. Ниже — готовый скрипт и инструкция, как им пользоваться. Вы перетаскиваете файл книги на ярлык, и рядом с книгой появляется папка с обложкой и примерами страниц в JPG. Одна книга обрабатывается за пару секунд, можно закинуть сразу несколько файлов. Скрипт работает с PDF, DjVu, EPUB, FB2 и MOBI. Кроме картинок он показывает количество страниц в книге — его сразу можно вставлять в шаблон раздачи. - 1. Что нужно для работыWindows. Инструкция написана для Windows 10 и 11.Python. Скачайте установщик с python.org и установите с настройками по умолчанию. Галочку «Add python.exe to PATH» ставить необязательно: используется команда py, она работает и без этого. Библиотека PyMuPDF. Откройте командную строку (Win + R → введите cmd → Enter) и выполните: py -m pip install pymupdf DjVuLibre — только для DjVu. Если вы не выкладываете DjVu, этот пункт можно пропустить. Установщик для Windows: sourceforge.net/projects/djvu/files/DjVuLibre_Windows. Или одной командой в командной строке: winget install --id DjVuLibre.DjView -e Свободное место. Картинки весят немного: комплект из обложки и четырёх страниц занимает примерно 1,5–3 МБ. 2. УстановкаШаг 1. Создайте любую папку, например D:\Скрины.Шаг 2. Создайте в ней файл pdf_shots.py и вставьте в него код из пункта 9. Шаг 3. Создайте в той же папке файл Скрины.bat с таким содержимым: @echo off py "%~dp0pdf_shots.py" %* pause Папку можно положить куда угодно, книги рядом с ней держать не нужно. 3. Как пользоватьсяСпособ 1 — перетаскиванием. Выделите одну или несколько книг и перетащите мышкой на файл Скрины.bat.Способ 2 — через окно выбора. Запустите Скрины.bat двойным щелчком. Откроется окно выбора файлов, отметьте книги и нажмите «Открыть». Пока скрипт работает, в чёрном окне видно, что происходит: Обрабатываю: Handbook of Pediatric Neurosurgery.pdf Страниц: 556 Готово: D:\Книги\Handbook of Pediatric Neurosurgery_скрины 4. Что получитсяРядом с книгой появится папка с её именем и припиской _скрины:
Набор страниц каждый раз разный. Если картинки не понравились, просто перетащите книгу на батник ещё раз. 5. НастройкиЕсли нужно, откройте pdf_shots.py в Блокноте и поправьте первые строки:DPI = 150 # качество картинок (110 — меньше размер, 200 — чётче) SHOTS = 4 # сколько страниц сохранять DJVU_DIR = r"" # папка DjVuLibre, если скрипт не нашёл её сам SHOTS — сколько страниц сохранять, кроме обложки. Для атласов удобно 6–8. DJVU_DIR — заполняется, только если скрипт пишет, что не нашёл DjVuLibre. Укажите папку, в которой лежит ddjvu.exe: DJVU_DIR = r"C:\Program Files (x86)\DjVuLibre" 6. Что важно знать про форматыPDF и DjVu. Количество страниц, которое показывает скрипт, точное, его можно указывать в раздаче.EPUB, FB2, MOBI. В этих форматах фиксированных страниц нет, текст подстраивается под экран. Скрипт пишет число со значком «~» и пометкой, что оно условное: Страниц: ~681 (для EPUB число условное — зависит от размера экрана) PDF, сделанный из EPUB. Если в PDF страниц в 2–3 раза больше, чем в печатной книге (например, 758 вместо 258), файл почти наверняка сконвертирован из EPUB. Проверьте в SumatraPDF по Ctrl + D: у такого файла маленький размер страницы, а в поле Producer указан конвертер вроде Calibre. В раздаче это стоит указать: «PDF — конвертация из EPUB». Сканы. Со сканированными PDF и DjVu скрипт работает так же. Качество картинок будет таким же, как качество скана. 7. Что делать с картинками дальшеЗагрузите poster.jpg и страницы на хостинг изображений трекера, а ссылки вставьте в шаблон оформления раздачи. Сам шаблон и теги для обложки и примеров страниц разобраны в отдельной статье FAQ.8. Если что-то не работаетПеретащил книгу на батник — ничего не происходит.Скорее всего, файл называется Скрины.bat.txt: Блокнот дописал расширение, а Windows его прячет. Включите показ расширений (Вид → Показать → Расширения имён файлов) и уберите лишнее .txt. То же самое проверьте у pdf_shots.py. Окно мелькнуло и закрылось. В батнике последней строкой должно быть pause. Если вы запускали не батник, а сам pdf_shots.py, запускайте через батник: тогда окно останется открытым и будет видно сообщение об ошибке. «py» не является внутренней или внешней командой. Python не установлен либо установлен без лаунчера. Установите его с python.org. Если он уже стоит, запустите установщик ещё раз, выберите Modify, на экране Advanced Options отметьте «Add Python to environment variables» и нажмите Install. После этого перезапустите командную строку. ModuleNotFoundError: No module named 'pymupdf'. Библиотека не установлена или установлена в другую версию Python. Выполните в командной строке: py -m pip install pymupdf Ошибка: Не найден DjVuLibre. Установите DjVuLibre по ссылке из пункта 1. Если он уже установлен в нестандартную папку, впишите её в строку DJVU_DIR в начале скрипта. В этой папке должен лежать файл ddjvu.exe. Картинки слишком тяжёлые или слишком мелкие. Измените DPI в начале скрипта: 110 — компактнее, 200–300 — чётче. Сохраните файл и запустите скрипт заново, старую папку со скринами можно удалить. Попались неудачные страницы. Запустите скрипт на этой книге ещё раз, набор страниц будет другим. Либо увеличьте SHOTS, например до 8, и выберите лучшие картинки. Книга защищена паролем. Такой файл скрипт не откроет. Пароль он не подбирает и защиту не снимает. В пути или имени файла русские буквы. Это не мешает. Папка со скринами тоже создаётся с русским именем. 9. Код скрипта (pdf_shots.py)Скопируйте всё содержимое в файл pdf_shots.py.import sys, os, glob, shutil, random, pathlib, traceback, subprocess, zipfile, posixpath import xml.etree.ElementTree as ET from urllib.parse import unquote try: import pymupdf except ImportError: print("Не установлен pymupdf. Выполните в командной строке: py -m pip install pymupdf") input("\nНажмите Enter для выхода...") sys.exit() DPI = 150 # качество картинок (110 — меньше размер, 200 — чётче) SHOTS = 4 # сколько страниц сохранять DJVU_DIR = r"" # если DjVuLibre не находится сам, укажите папку, например r"C:\Program Files (x86)\DjVuLibre" TYPES = [("Книги", "*.pdf *.djvu *.djv *.epub *.fb2 *.mobi"), ("Все файлы", "*.*")] def save_jpg(pix, path): if pix.colorspace is None or pix.colorspace.n != 3: pix = pymupdf.Pixmap(pymupdf.csRGB, pix) if pix.alpha: pix = pymupdf.Pixmap(pix, 0) pix.save(path, jpg_quality=90) def middle_pool(n, first=0): """Номера страниц для выбора: без первых и последних 10, в случайном порядке.""" pool = list(range(first + 1, first + n)) if n < 40 else list(range(first + 10, first + n - 10)) random.shuffle(pool) return pool # ---------- PDF, EPUB, FB2, MOBI ---------- def epub_cover(path): """Оригинальная обложка из EPUB (если указана в метаданных), иначе None.""" try: with zipfile.ZipFile(path) as z: opf_path = ET.fromstring(z.read("META-INF/container.xml")).find(".//{*}rootfile").get("full-path") opf = ET.fromstring(z.read(opf_path)) items = opf.findall(".//{*}manifest/{*}item") href = next((i.get("href") for i in items if "cover-image" in (i.get("properties") or "")), None) if not href: meta = next((m for m in opf.iter() if m.tag.endswith("meta") and m.get("name") == "cover"), None) if meta is not None: href = next((i.get("href") for i in items if i.get("id") == meta.get("content") and (i.get("media-type") or "").startswith("image")), None) if not href: return None return z.read(posixpath.normpath(posixpath.join(posixpath.dirname(opf_path), unquote(href)))) except Exception: return None def page_kind(page): """2 — есть картинка, 1 — нормальный текст, 0 — пустая/почти пустая страница.""" blocks = page.get_text("dict")["blocks"] if any(b["type"] == 1 for b in blocks): return 2 chars = sum(len(s["text"]) for b in blocks if b["type"] == 0 for l in b["lines"] for s in l["spans"]) return 1 if chars > 600 else 0 def process_doc(p, out): doc = pymupdf.open(p) if doc.is_reflowable: # EPUB, FB2, MOBI — раскладываем в страницы A5 doc.layout(rect=pymupdf.paper_rect("a5"), fontsize=10) cover = epub_cover(p) if p.suffix.lower() == ".epub" else None try: save_jpg(pymupdf.Pixmap(cover), out / "poster.jpg") # настоящая обложка из EPUB except Exception: save_jpg(doc[0].get_pixmap(dpi=DPI), out / "poster.jpg") # иначе — первая страница pool = middle_pool(doc.page_count) with_img, text, rest = [], [], [] for i in pool[:80]: k = page_kind(doc[i]) (with_img if k == 2 else text if k == 1 else rest).append(i) if len(with_img) >= SHOTS: break for i in sorted((with_img + text + rest + pool[80:])[:SHOTS]): save_jpg(doc[i].get_pixmap(dpi=DPI), out / f"page_{i + 1}.jpg") if doc.is_reflowable: return f"~{doc.page_count} (для {p.suffix.upper()[1:]} число условное — зависит от размера экрана)" return str(doc.page_count) # ---------- DjVu (через DjVuLibre) ---------- def djvu_tool(name): places = [DJVU_DIR] if DJVU_DIR else [] for env in ("ProgramFiles", "ProgramFiles(x86)", "ProgramW6432"): if os.environ.get(env): places += glob.glob(os.path.join(os.environ[env], "DjVuLibre*")) if os.environ.get("LOCALAPPDATA"): places += glob.glob(os.path.join(os.environ["LOCALAPPDATA"], "Programs", "DjVuLibre*")) for folder in places: exe = os.path.join(folder, name + ".exe") if os.path.isfile(exe): return exe exe = shutil.which(name) if exe: return exe raise RuntimeError("Не найден DjVuLibre. Установите его: https://sourceforge.net/projects/djvu/files/DjVuLibre_Windows/\n" "Если уже установлен в другую папку — впишите её в DJVU_DIR в начале скрипта.") def djvu_structure(data): """Число страниц и объём фонового слоя (фото, рисунки) на каждой странице — по разметке файла.""" if data[:4] != b"AT&T": raise RuntimeError("Это не DjVu-файл") bg, pages = {}, 0 def walk(pos, end, page): nonlocal pages while pos + 8 <= end: cid, size = data[pos:pos + 4], int.from_bytes(data[pos + 4:pos + 8], "big") body = pos + 8 if cid == b"FORM" and data[body:body + 4] == b"DJVU": pages += 1 walk(body + 4, body + size, pages) elif cid == b"FORM" and data[body:body + 4] == b"DJVM": walk(body + 4, body + size, 0) elif cid == b"BG44" and page: bg[page] = bg.get(page, 0) + size pos = body + size + (size & 1) walk(4, len(data), 0) return max(pages, 1), bg def process_djvu(p, out): data = p.read_bytes() # файл передаётся через stdin — так не мешают русские буквы в пути ddjvu = djvu_tool("ddjvu") def run(args): r = subprocess.run(args, input=data, capture_output=True) if r.returncode != 0 or not r.stdout: raise RuntimeError(r.stderr.decode("utf-8", "replace").strip() or "ошибка DjVuLibre") return r.stdout def render(page, dpi): # page — с единицы return pymupdf.Pixmap(run([ddjvu, "-format=ppm", f"-page={page}", f"-scale={dpi}", "-", "-"])) pages, bg = djvu_structure(data) def has_ink(page): # отсекаем пустые страницы pix = render(page, 15) s, step = pix.samples, pix.n dark = sum(1 for k in range(0, len(s), step) if s[k] < 180) return dark > 0.02 * pix.width * pix.height save_jpg(render(1, DPI), out / "poster.jpg") pool = middle_pool(pages, first=1) pics = [x for x in pool if bg.get(x, 0) > 10000] ordered = pics + [x for x in pool if x not in set(pics)] picked = [] for x in ordered[:40]: if has_ink(x): picked.append(x) if len(picked) == SHOTS: break picked += [x for x in ordered if x not in picked][:SHOTS - len(picked)] for x in sorted(picked): save_jpg(render(x, DPI), out / f"page_{x}.jpg") return str(pages) # ---------- запуск ---------- def process(path): p = pathlib.Path(path) print(f"Обрабатываю: {p.name}") out = p.with_name(p.stem + "_скрины") out.mkdir(exist_ok=True) if p.suffix.lower() in (".djvu", ".djv"): count = process_djvu(p, out) else: count = process_doc(p, out) print(f"Страниц: {count}") print(f"Готово: {out}\n") files = sys.argv[1:] if not files: from tkinter import Tk, filedialog Tk().withdraw() files = filedialog.askopenfilenames(title="Выберите книги", filetypes=TYPES) for f in files: try: process(f) except Exception as e: if isinstance(e, RuntimeError): print(f"Ошибка: {e}") else: traceback.print_exc() print() input("Нажмите Enter для выхода...") 10. Коротко
|
| Ответить на тему | Главная » 📚 Литература » Помощь по разделу (Литература) |
В начало
Текущее время: 27-окт 09:49
Часовой пояс: UTC + 5
Вы не можете начинать темы
Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете голосовать в опросах Вы не можете прикреплять файлы к сообщениям Вы не можете скачивать файлы |