import os import shutil import sys import logging from datetime import datetime # Set up logging logging.basicConfig( filename=f"conversion_log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log", level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s" ) # For .docx conversion try: from docx2pdf import convert as docx_convert except ImportError: logging.error("docx2pdf not installed. Run 'pip install docx2pdf'.") sys.exit(1) # For .pptx conversion try: import win32com.client except ImportError: logging.error("pywin32 not installed. Run 'pip install pywin32'.") sys.exit(1) try: import comtypes.client except ImportError: logging.warning("comtypes not installed. Run 'pip install comtypes' for fallback.") def check_irm_status(filepath): """Check if IRM is enabled on a PPTX file.""" try: ppt_app = win32com.client.Dispatch("PowerPoint.Application") pres = ppt_app.Presentations.Open(os.path.abspath(filepath), ReadOnly=True, WithWindow=False) irm_enabled = pres.Permission.Enabled pres.Close() ppt_app.Quit() return irm_enabled except Exception as e: logging.error(f"Failed to check IRM for {filepath}: {e}") return None def convert_pptx_print(filepath, output_pdf): """Attempt PPTX to PDF conversion using print-to-PDF.""" try: ppt_app = win32com.client.Dispatch("PowerPoint.Application") pres = ppt_app.Presentations.Open(os.path.abspath(filepath), ReadOnly=True, WithWindow=False) pres.PrintOut(PrintToFile=output_pdf) pres.Close() ppt_app.Quit() logging.info(f"Converted {filepath} to {output_pdf} using print-to-PDF.") return True except Exception as e: logging.error(f"Print-to-PDF failed for {filepath}: {e}") return False def convert_pptx_win32(filepath, output_pdf): """Attempt PPTX to PDF conversion using win32com SaveAs.""" try: ppt_app = win32com.client.Dispatch("PowerPoint.Application") pres = ppt_app.Presentations.Open(os.path.abspath(filepath), ReadOnly=True, WithWindow=False) pres.SaveAs(output_pdf, 32) # 32 = ppSaveAsPDF pres.Close() ppt_app.Quit() logging.info(f"Converted {filepath} to {output_pdf} using win32com SaveAs.") return True except Exception as e: logging.error(f"win32com SaveAs failed for {filepath}: {e}") return False def convert_pptx_comtypes(filepath, output_pdf): """Attempt PPTX to PDF conversion using comtypes SaveAs.""" try: ppt_app = comtypes.client.CreateObject("PowerPoint.Application") pres = ppt_app.Presentations.Open(os.path.abspath(filepath), ReadOnly=True, WithWindow=False) pres.SaveAs(output_pdf, 32) # 32 = ppSaveAsPDF pres.Close() ppt_app.Quit() logging.info(f"Converted {filepath} to {output_pdf} using comtypes SaveAs.") return True except Exception as e: logging.error(f"comtypes SaveAs failed for {filepath}: {e}") return False def main(input_dir, output_dir): if not os.path.isdir(input_dir): logging.error(f"{input_dir} is not a directory.") sys.exit(1) os.makedirs(output_dir, exist_ok=True) for root, _, files in os.walk(input_dir): rel_dir = os.path.relpath(root, input_dir) target_subdir = os.path.join(output_dir, rel_dir) os.makedirs(target_subdir, exist_ok=True) for file in files: filepath = os.path.join(root, file) base, ext = os.path.splitext(file) output_pdf = os.path.join(target_subdir, base + '.pdf') try: if ext.lower() == '.docx': docx_convert(filepath, output_pdf) logging.info(f"Converted {filepath} to {output_pdf}") elif ext.lower() == '.pptx': # Check IRM status irm_status = check_irm_status(filepath) if irm_status is not None: logging.info(f"IRM enabled for {filepath}: {irm_status}") # Try print-to-PDF first (bypasses edit restrictions) if not convert_pptx_print(filepath, output_pdf): # Fallback to SaveAs methods if not convert_pptx_win32(filepath, output_pdf): if 'comtypes' in sys.modules and not convert_pptx_comtypes(filepath, output_pdf): logging.warning(f"Failed to convert {filepath}. Likely IRM or strict restrictions.") elif not 'comtypes' in sys.modules: logging.warning(f"Failed to convert {filepath}. Install comtypes for additional fallback.") elif ext.lower() == '.pdf': shutil.copy(filepath, output_pdf) logging.info(f"Copied {filepath} to {output_pdf}") except Exception as e: logging.error(f"Error processing {filepath}: {e}") if __name__ == "__main__": main("OrigFolder", "ConvertedFiles") # Use OrigFolder directly