diff --git a/src/ocrmypdf/_pipeline.py b/src/ocrmypdf/_pipeline.py index b283a988..ab11da6e 100644 --- a/src/ocrmypdf/_pipeline.py +++ b/src/ocrmypdf/_pipeline.py @@ -816,16 +816,15 @@ def convert_to_pdfa(input_files_groups, output_file, log, context): # NULs in DocumentInfo seem to be common since older Acrobats included them. # pikepdf can deal with this, but we make the world a better place by # stamping them out as soon as possible. - pdf_layers_file = pikepdf.open(layers_file) - if pdf_layers_file.docinfo: - modified = False - for k, v in pdf_layers_file.docinfo.items(): - if b'\x00' in bytes(v): - pdf_layers_file.docinfo[k] = bytes(v).replace(b'\x00', b'') - modified = True - if modified: - pdf_layers_file.save(layers_file) - del pdf_layers_file + with pikepdf.open(layers_file) as pdf_layers_file: + if pdf_layers_file.docinfo: + modified = False + for k, v in pdf_layers_file.docinfo.items(): + if b'\x00' in bytes(v): + pdf_layers_file.docinfo[k] = bytes(v).replace(b'\x00', b'') + modified = True + if modified: + pdf_layers_file.save(layers_file) ps = next((ii for ii in input_files if ii.endswith('.ps')), None) ghostscript.generate_pdfa( @@ -880,6 +879,8 @@ def metadata_fixup(input_files_groups, output_file, log, context): compress_streams=True, object_stream_mode=pikepdf.ObjectStreamMode.generate, ) + original.close() + pdf.close() def optimize_pdf(input_file, output_file, log, context): diff --git a/src/ocrmypdf/_weave.py b/src/ocrmypdf/_weave.py index 86119ef9..17e37144 100644 --- a/src/ocrmypdf/_weave.py +++ b/src/ocrmypdf/_weave.py @@ -161,6 +161,7 @@ def _weave_layers_graft( _update_page_resources( page=base_page, font=font, font_key=font_key, procset=procset ) + pdf_text.close() def _find_font(text, pdf_base): @@ -169,20 +170,23 @@ def _find_font(text, pdf_base): font, font_key = None, None possible_font_names = ('/f-0-0', '/F1') try: - pdf_text = pikepdf.open(text) - pdf_text_fonts = pdf_text.pages[0].Resources.get('/Font', {}) - except Exception: + with pikepdf.open(text) as pdf_text: + try: + pdf_text_fonts = pdf_text.pages[0].Resources.get('/Font', {}) + except (AttributeError, IndexError, KeyError): + return None, None + for f in possible_font_names: + pdf_text_font = pdf_text_fonts.get(f, None) + if pdf_text_font is not None: + font_key = f + break + if pdf_text_font: + font = pdf_base.copy_foreign(pdf_text_font) + return font, font_key + except (FileNotFoundError, pikepdf.PdfError): + # PdfError occurs if a 0-length file is written e.g. due to OCR timeout return None, None - for f in possible_font_names: - pdf_text_font = pdf_text_fonts.get(f, None) - if pdf_text_font is not None: - font_key = f - break - if pdf_text_font: - font = pdf_base.copy_foreign(pdf_text_font) - return font, font_key - def _traverse_toc(pdf_base, visitor_fn, log): """ @@ -348,10 +352,10 @@ def weave_layers(infiles, output_file, log, context): log.debug("Replace") old_objgen = pdf_base.pages[page_num - 1].objgen - pdf_image = pikepdf.open(image) - keep_open.append(pdf_image) - image_page = pdf_image.pages[0] - pdf_base.pages[page_num - 1] = image_page + with pikepdf.open(image) as pdf_image: + keep_open.append(pdf_image) + image_page = pdf_image.pages[0] + pdf_base.pages[page_num - 1] = image_page # We're adding a new page, which will get a new objgen number pair, # so we need to update any references to it. qpdf did not like diff --git a/src/ocrmypdf/pdfa.py b/src/ocrmypdf/pdfa.py index 9bc3b729..684254e7 100644 --- a/src/ocrmypdf/pdfa.py +++ b/src/ocrmypdf/pdfa.py @@ -131,19 +131,19 @@ def file_claims_pdfa(filename): do full PDF/A validation. """ - pdf = pikepdf.open(filename) - pdfmeta = pdf.open_metadata() - if not pdfmeta.pdfa_status: - return { - 'pass': False, - 'output': 'pdf', - 'conformance': 'No PDF/A metadata in XMP', - } - valid_part_conforms = {'1A', '1B', '2A', '2B', '2U', '3A', '3B', '3U'} - conformance = f'PDF/A-{pdfmeta.pdfa_status}' - pdfa_dict = {} - if pdfmeta.pdfa_status in valid_part_conforms: - pdfa_dict['pass'] = True - pdfa_dict['output'] = 'pdfa' - pdfa_dict['conformance'] = conformance + with pikepdf.open(filename) as pdf: + pdfmeta = pdf.open_metadata() + if not pdfmeta.pdfa_status: + return { + 'pass': False, + 'output': 'pdf', + 'conformance': 'No PDF/A metadata in XMP', + } + valid_part_conforms = {'1A', '1B', '2A', '2B', '2U', '3A', '3B', '3U'} + conformance = f'PDF/A-{pdfmeta.pdfa_status}' + pdfa_dict = {} + if pdfmeta.pdfa_status in valid_part_conforms: + pdfa_dict['pass'] = True + pdfa_dict['output'] = 'pdfa' + pdfa_dict['conformance'] = conformance return pdfa_dict diff --git a/src/ocrmypdf/pdfinfo/__init__.py b/src/ocrmypdf/pdfinfo/__init__.py index 1dd94e60..4f2ba168 100644 --- a/src/ocrmypdf/pdfinfo/__init__.py +++ b/src/ocrmypdf/pdfinfo/__init__.py @@ -618,8 +618,9 @@ def _pdf_get_all_pageinfo(infile, detailed_analysis=False, log=None): if not log: log = Mock() - pdf = pikepdf.open(infile) + pdf = pikepdf.open(infile) # Do not close in this function if pdf.is_encrypted: + pdf.close() raise EncryptedPdfError() # Triggered by encryption with empty passwd if detailed_analysis: pages_xml = None @@ -755,7 +756,7 @@ class PdfInfo: infile, detailed_page_analysis, log=log ) self._needs_rendering = pdf.root.get('/NeedsRendering', False) - self._has_acroform = '/AcroForm' in pdf.root + pdf.close() @property def pages(self):