Compare commits

..
2 Commits
6 changed files with 43 additions and 19 deletions
+4 -2
View File
@@ -391,15 +391,17 @@ package manager:
* ``winget install -e --id Python.Python.3.11`` * ``winget install -e --id Python.Python.3.11``
* ``winget install -e --id UB-Mannheim.TesseractOCR`` * ``winget install -e --id UB-Mannheim.TesseractOCR``
* ``winget install -e --id ArtifexSoftware.GhostScript``
You will need to install Ghostscript manually, `since it does not support automated
installs anymore <https://artifex.com/news/ghostscript-10.01.0-disabling-silent-install-option>`_.
* `Ghostscript download page <https://ghostscript.com/releases/gsdnld.html>`_.`
(Or alternately, using the `Chocolatey <https://chocolatey.org/>`_ package manager, install (Or alternately, using the `Chocolatey <https://chocolatey.org/>`_ package manager, install
the following when running in an Administrator command prompt): the following when running in an Administrator command prompt):
* ``choco install python3`` * ``choco install python3``
* ``choco install --pre tesseract`` * ``choco install --pre tesseract``
* ``choco install ghostscript``
* ``choco install pngquant`` (optional) * ``choco install pngquant`` (optional)
Either set of commands will install the required software. At the mmoment there is no Either set of commands will install the required software. At the mmoment there is no
+12
View File
@@ -28,6 +28,18 @@ tagged yet.
.. |OCRmyPDF PyPI| image:: https://img.shields.io/pypi/v/ocrmypdf.svg .. |OCRmyPDF PyPI| image:: https://img.shields.io/pypi/v/ocrmypdf.svg
v15.4.4
=======
- Fixed documentation for installing Ghostscript on Windows. :issue:`1198`
- Added warning message about security issue in older versions of Ghostscript.
v15.4.3
=======
- Fixed deprecation warning in pikepdf older than 8.7.1; pikepdf >= 8.7.1 is
now required.
v15.4.2 v15.4.2
======= =======
+1 -1
View File
@@ -17,7 +17,7 @@ dependencies = [
"img2pdf>=0.4.4", "img2pdf>=0.4.4",
"packaging>=20", "packaging>=20",
"pdfminer.six>=20220319", "pdfminer.six>=20220319",
"pikepdf>=8", "pikepdf>=8.7.1",
"pluggy>=0.13.0", "pluggy>=0.13.0",
"reportlab>=3.6.8", "reportlab>=3.6.8",
"rich>=13", "rich>=13",
+9 -8
View File
@@ -12,12 +12,12 @@ from pathlib import Path
from pikepdf import ( from pikepdf import (
Dictionary, Dictionary,
Matrix,
Name, Name,
Operator, Operator,
Page, Page,
Pdf, Pdf,
PdfError, PdfError,
PdfMatrix,
Stream, Stream,
parse_content_stream, parse_content_stream,
unparse_content_stream, unparse_content_stream,
@@ -268,13 +268,13 @@ class OcrGrafter:
mediabox = base_page.mediabox mediabox = base_page.mediabox
wp, hp = mediabox[2] - mediabox[0], mediabox[3] - mediabox[1] wp, hp = mediabox[2] - mediabox[0], mediabox[3] - mediabox[1]
translate = PdfMatrix().translated(-wt / 2, -ht / 2) translate = Matrix().translated(-wt / 2, -ht / 2)
untranslate = PdfMatrix().translated(wp / 2, hp / 2) untranslate = Matrix().translated(wp / 2, hp / 2)
corner = PdfMatrix().translated(mediabox[0], mediabox[1]) corner = Matrix().translated(mediabox[0], mediabox[1])
# -rotation because the input is a clockwise angle and this formula # -rotation because the input is a clockwise angle and this formula
# uses CCW # uses CCW
text_rotation = -text_rotation % 360 text_rotation = -text_rotation % 360
rotate = PdfMatrix().rotated(text_rotation) rotate = Matrix().rotated(text_rotation)
# Because of rounding of DPI, we might get a text layer that is not # Because of rounding of DPI, we might get a text layer that is not
# identically sized to the target page. Scale to adjust. Normally this # identically sized to the target page. Scale to adjust. Normally this
@@ -285,12 +285,13 @@ class OcrGrafter:
scale_y = hp / ht scale_y = hp / ht
# log.debug('%r', scale_x, scale_y) # log.debug('%r', scale_x, scale_y)
scale = PdfMatrix().scaled(scale_x, scale_y) scale = Matrix().scaled(scale_x, scale_y)
# Translate the text so it is centered at (0, 0), rotate it there, adjust # Translate the text so it is centered at (0, 0), rotate it there, adjust
# for a size different between initial and text PDF, then untranslate, and # for a size different between initial and text PDF, then untranslate, and
# finally move the lower left corner to match the mediabox # finally move the lower left corner to match the mediabox. All transforms
ctm = translate @ rotate @ scale @ untranslate @ corner # must be premultiplied so they are applied in reverse order here.
ctm = corner @ untranslate @ scale @ rotate @ translate
base_resources = _ensure_dictionary(base_page.obj, Name.Resources) base_resources = _ensure_dictionary(base_page.obj, Name.Resources)
base_xobjs = _ensure_dictionary(base_resources, Name.XObject) base_xobjs = _ensure_dictionary(base_resources, Name.XObject)
+11 -2
View File
@@ -6,6 +6,8 @@ from __future__ import annotations
import logging import logging
from packaging.version import Version
from ocrmypdf import hookimpl from ocrmypdf import hookimpl
from ocrmypdf._exec import ghostscript from ocrmypdf._exec import ghostscript
from ocrmypdf.exceptions import MissingDependencyError from ocrmypdf.exceptions import MissingDependencyError
@@ -58,8 +60,15 @@ def check_options(options):
if gs_version in BLACKLISTED_GS_VERSIONS: if gs_version in BLACKLISTED_GS_VERSIONS:
raise MissingDependencyError( raise MissingDependencyError(
f"Ghostscript {gs_version} contains serious regressions and is not " f"Ghostscript {gs_version} contains serious regressions and is not "
"supported. Please upgrade to a newer version, or downgrade to the " "supported. Please upgrade to a newer version."
"previous version." )
if gs_version < Version('10.02.0'):
log.warning(
f"The installed version of Ghostscript {gs_version}, contains a remote "
"code execution security vulnerability. Please upgrade to a newer "
"version. For details see CVE-2023-43115. The issue is not known to "
"affect OCRmyPDF or processing PDFs with Ghostscript, but upgrading "
"Ghostscript is recommended."
) )
if options.output_type == 'pdfa': if options.output_type == 'pdfa':
+6 -6
View File
@@ -25,13 +25,13 @@ from warnings import warn
from pdfminer.layout import LTPage, LTTextBox from pdfminer.layout import LTPage, LTTextBox
from pikepdf import ( from pikepdf import (
Matrix,
Name, Name,
Object, Object,
Page, Page,
Pdf, Pdf,
PdfImage, PdfImage,
PdfInlineImage, PdfInlineImage,
PdfMatrix,
Stream, Stream,
UnsupportedImageTypeError, UnsupportedImageTypeError,
parse_content_stream, parse_content_stream,
@@ -209,7 +209,7 @@ def _interpret_contents(contentstream: Object, initial_shorthand=UNIT_SQUARE):
CTM unchanged. CTM unchanged.
""" """
stack = [] stack = []
ctm = PdfMatrix(initial_shorthand) ctm = Matrix(initial_shorthand)
xobject_settings: list[XobjectSettings] = [] xobject_settings: list[XobjectSettings] = []
inline_images: list[InlineSettings] = [] inline_images: list[InlineSettings] = []
name_index = defaultdict(lambda: []) name_index = defaultdict(lambda: [])
@@ -240,7 +240,7 @@ def _interpret_contents(contentstream: Object, initial_shorthand=UNIT_SQUARE):
# to do. Just pretend nothing happened, keep calm and carry on. # to do. Just pretend nothing happened, keep calm and carry on.
warn("PDF graphics stack underflowed - PDF may be malformed") warn("PDF graphics stack underflowed - PDF may be malformed")
elif operator == 'cm': elif operator == 'cm':
ctm = PdfMatrix(operands) @ ctm ctm = Matrix(operands) @ ctm
elif operator == 'Do': elif operator == 'Do':
image_name = operands[0] image_name = operands[0]
settings = XobjectSettings( settings = XobjectSettings(
@@ -614,12 +614,12 @@ def _process_content_streams(
): ):
# Set the CTM to the state it was when the "Do" operator was # Set the CTM to the state it was when the "Do" operator was
# encountered that is drawing this instance of the Form XObject # encountered that is drawing this instance of the Form XObject
ctm = PdfMatrix(shorthand) if shorthand else PdfMatrix.identity() ctm = Matrix(shorthand) if shorthand else Matrix()
# A Form XObject may provide its own matrix to map form space into # A Form XObject may provide its own matrix to map form space into
# user space. Get this if one exists # user space. Get this if one exists
form_shorthand = container.get(Name.Matrix, PdfMatrix.identity()) form_shorthand = container.get(Name.Matrix, Matrix())
form_matrix = PdfMatrix(form_shorthand) form_matrix = Matrix(form_shorthand)
# Concatenate form matrix with CTM to ensure CTM is correct for # Concatenate form matrix with CTM to ensure CTM is correct for
# drawing this instance of the XObject # drawing this instance of the XObject