{"id":20204800,"url":"https://github.com/drengskapur/colab2pdf","last_synced_at":"2025-08-20T04:32:35.206Z","repository":{"id":205140624,"uuid":"713374289","full_name":"drengskapur/colab2pdf","owner":"drengskapur","description":"Convert your Colab notebook to a PDF. One-minute install. Zero configuration.","archived":false,"fork":false,"pushed_at":"2024-06-30T22:18:22.000Z","size":150,"stargazers_count":27,"open_issues_count":0,"forks_count":4,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-12-16T00:09:15.711Z","etag":null,"topics":["ai","artificial-intelligence","colab","colab-notebook","colab-notebooks","colaboratory","data-science","deep-learning","google","google-colab","google-colaboratory","gpu","huggingface","machine-learning","ml","pdf","python","pytorch","tensorflow","torch"],"latest_commit_sha":null,"homepage":"https://github.com/drengskapur/colab2pdf","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/drengskapur.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-11-02T11:48:30.000Z","updated_at":"2024-10-07T05:05:10.000Z","dependencies_parsed_at":"2023-11-26T05:25:27.546Z","dependency_job_id":"ea5f6eb5-0597-4c30-b6b4-7b97a2bb1a9c","html_url":"https://github.com/drengskapur/colab2pdf","commit_stats":null,"previous_names":["drengskapur/colab2pdf"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drengskapur%2Fcolab2pdf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drengskapur%2Fcolab2pdf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drengskapur%2Fcolab2pdf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drengskapur%2Fcolab2pdf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/drengskapur","download_url":"https://codeload.github.com/drengskapur/colab2pdf/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230394228,"owners_count":18218707,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","artificial-intelligence","colab","colab-notebook","colab-notebooks","colaboratory","data-science","deep-learning","google","google-colab","google-colaboratory","gpu","huggingface","machine-learning","ml","pdf","python","pytorch","tensorflow","torch"],"created_at":"2024-11-14T05:15:11.105Z","updated_at":"2025-08-20T04:32:35.193Z","avatar_url":"https://github.com/drengskapur.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Directions: Copy→Paste→Run\n\n```python\ndef colab2pdf():\n  # @title Download Notebook in PDF Format{display-mode:'form'}\n  !apt-get install -yqq --no-install-recommends librsvg2-bin\u003e/dev/null;\n  import contextlib,datetime,google,io,IPython,ipywidgets,json,locale,nbformat,os,pathlib,requests,urllib,warnings,werkzeug,yaml,re;locale.setlocale(locale.LC_ALL,'en_US.UTF-8');warnings.filterwarnings('ignore',category=nbformat.validator.MissingIDFieldWarning);\n  %matplotlib inline\n  def convert(b):\n    try:\n      s.value='🔄 Converting';b.disabled=True\n      n=pathlib.Path(werkzeug.utils.secure_filename(urllib.parse.unquote(requests.get(f'http://{os.environ[\"COLAB_JUPYTER_IP\"]}:{os.environ[\"KMP_TARGET_PORT\"]}/api/sessions').json()[0]['name'])))\n      p=pathlib.Path('/content/pdfs')/f'{datetime.datetime.utcnow().strftime(\"%Y%m%d_%H%M%S\")}_{n.stem}';p.mkdir(parents=True,exist_ok=True);nb=nbformat.reads(json.dumps(google.colab._message.blocking_request('get_ipynb',timeout_sec=600)['ipynb']),as_version=4)\n      u=[u for c in nb.cells if c.get('cell_type')=='markdown' for u in re.findall(r'!\\[.*?\\]\\((https?://.*?)\\)',c['source']) if requests.head(u,timeout=5).status_code!=200]\n      if u:raise Exception(f\"Bad Image URLs: {','.join(u)}\")\n      nb.cells=[cell for cell in nb.cells if '--Colab2PDF' not in cell.source]\n      nb=nbformat.v4.new_notebook(cells=nb.cells or [nbformat.v4.new_code_cell('#')]);nbformat.validator.normalize(nb)\n      nbformat.write(nb,(p/f'{n.stem}.ipynb').open('w',encoding='utf-8'))\n      with (p/'config.yml').open('w', encoding='utf-8') as f: yaml.dump({'include-in-header':[{'text':r'\\usepackage{fvextra}\\DefineVerbatimEnvironment{Highlighting}{Verbatim}{breaksymbolleft={},showspaces=false,showtabs=false,breaklines,breakanywhere,commandchars=\\\\\\{\\}}'}],'include-before-body':[{'text':r'\\DefineVerbatimEnvironment{verbatim}{Verbatim}{breaksymbolleft={},showspaces=false,showtabs=false,breaklines}'}]},f)\n      !quarto render {p}/{n.stem}.ipynb --metadata-file={p}/config.yml --to pdf -M latex-auto-install -M margin-top=1in -M margin-bottom=1in -M margin-left=1in -M margin-right=1in --quiet\n      google.colab.files.download(str(p/f'{n.stem}.pdf'));s.value=f'✅ Downloaded: {n.stem}.pdf'\n    except Exception as e:s.value=f'❌ {str(e)}'\n    finally:b.disabled=False\n  if not pathlib.Path('/usr/local/bin/quarto').exists():\n    !wget -q 'https://quarto.org/download/latest/quarto-linux-amd64.deb' \u0026\u0026 dpkg -i quarto-linux-amd64.deb\u003e/dev/null \u0026\u0026 quarto install tinytex --update-path --quiet \u0026\u0026 rm quarto-linux-amd64.deb\n  b=ipywidgets.widgets.Button(description='⬇️ Download');s=ipywidgets.widgets.Label();b.on_click(lambda b:convert(b));IPython.display.display(ipywidgets.widgets.HBox([b,s]))\ncolab2pdf() # | Colab2PDF v1.6 | https://github.com/drengskapur/colab2pdf | GPL-3.0-or-later |\n```\n\n## Code Breakdown\n\n### Importing Libraries and Setting Up Environment\n\n```python\ndef colab2pdf():\n    \"\"\"Download Google Colab notebook as a PDF.\n    colab2pdf installs dependencies, converts notebook to PDF, and provides a download link.\n    \"\"\"\n    # Install necessary system package for PDF conversion\n    !apt-get install -yqq --no-install-recommends librsvg2-bin \u003e /dev/null  # Install librsvg2-bin for SVG conversion\n\n    # Import necessary libraries\n    import contextlib  # Provides utilities for working with context managers\n    import datetime   # Supplies classes for manipulating dates and times\n    import google     # Google Colab specific utilities\n    import io         # Core tools for working with streams\n    import IPython    # Interactive computing tools\n    import ipywidgets # Interactive widgets for Jupyter notebooks\n    import json       # JSON encoder and decoder\n    import locale     # Internationalization services\n    import nbformat   # Jupyter notebook format\n    import os         # Miscellaneous operating system interfaces\n    import pathlib    # Object-oriented filesystem paths\n    import requests   # HTTP library for Python\n    import urllib     # URL handling modules\n    import warnings   # Warning control\n    import werkzeug   # Comprehensive WSGI web application library\n    import yaml       # YAML parser and emitter\n    import re         # Regular expression operations\n\n    # Set locale to US English\n    locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')  # Ensure consistent formatting\n\n    # Ignore specific warnings\n    warnings.filterwarnings('ignore', category=nbformat.validator.MissingIDFieldWarning)  # Ignore nbformat warnings\n\n    # Enable inline plotting for matplotlib\n    %matplotlib inline  # Enable inline plotting\n```\n\n1. **System Package Installation:**\n   - The `librsvg2-bin` package is installed using `apt-get`. This package is necessary for converting SVG images to PDF. Without this package, SVG images in the notebook will cause errors during the PDF conversion process.\n\n1. **Importing Libraries:**\n   - Various Python libraries are imported:\n     - `contextlib`: Provides utilities for working with context managers.\n     - `datetime`: Supplies classes for manipulating dates and times.\n     - `google`: Google Colab specific utilities.\n     - `io`: Core tools for working with streams.\n     - `IPython`: Interactive computing tools.\n     - `ipywidgets`: Interactive widgets for Jupyter notebooks.\n     - `json`: JSON encoder and decoder.\n     - `locale`: Internationalization services.\n     - `nbformat`: Jupyter notebook format.\n     - `os`: Miscellaneous operating system interfaces.\n     - `pathlib`: Object-oriented filesystem paths.\n     - `requests`: HTTP library for Python.\n     - `urllib`: URL handling modules.\n     - `warnings`: Warning control.\n     - `werkzeug`: Comprehensive WSGI web application library.\n     - `yaml`: YAML parser and emitter.\n     - `re`: Regular expression operations.\n\n1. **Locale Setting:**\n   - The locale is set to US English to ensure consistent formatting.\n\n1. **Warning Filtering:**\n   - Specific warnings related to `nbformat` are ignored.\n\n1. **Matplotlib Inline:**\n   - Inline plotting is enabled for `matplotlib`.\n\n### Convert Function Definition\n\n```python\n    def convert(button):\n        \"\"\"Convert the current notebook to PDF and provide a download link.\"\"\"\n        try:\n            # Update button status to indicate conversion is in progress\n            status_label.value = '🔄 Converting'  # Update status label\n            button.disabled = True  # Disable button to prevent multiple clicks\n\n            # Get the notebook name from the Colab session\n            session_url = f'http://{os.environ[\"COLAB_JUPYTER_IP\"]}:{os.environ[\"KMP_TARGET_PORT\"]}/api/sessions'\n            session_response = requests.get(session_url)  # Get session data\n            session_data = session_response.json()  # Parse JSON response\n            notebook_name = session_data[0]['name']  # Extract notebook name\n\n            # Create a secure filename for the notebook\n            secure_notebook_name = werkzeug.utils.secure_filename(urllib.parse.unquote(notebook_name))  # Secure filename\n            notebook_path = pathlib.Path(secure_notebook_name)  # Create Path object\n\n            # Create a directory for the PDF with a timestamp\n            timestamp = datetime.datetime.utcnow().strftime(\"%Y%m%d_%H%M%S\")  # Current timestamp\n            pdf_dir = pathlib.Path('/content/pdfs') / f'{timestamp}_{notebook_path.stem}'  # PDF directory path\n            pdf_dir.mkdir(parents=True, exist_ok=True)  # Create directory\n\n            # Read the current notebook content\n            notebook_data = google.colab._message.blocking_request('get_ipynb', timeout_sec=600)['ipynb']  # Get notebook data\n            notebook_json = json.dumps(notebook_data)  # Convert to JSON string\n            notebook = nbformat.reads(notebook_json, as_version=4)  # Read notebook\n\n            # Check for broken image URLs in markdown cells\n            broken_urls = []\n            for cell in notebook.cells:\n                if cell.get('cell_type') == 'markdown':  # Check markdown cells\n                    urls = re.findall(r'!\\[.*?\\]\\((https?://.*?)\\)', cell['source'])  # Find image URLs\n                    for url in urls:\n                        if requests.head(url, timeout=5).status_code != 200:  # Check URL status\n                            broken_urls.append(url)  # Add broken URL to list\n            if broken_urls:\n                raise Exception(f\"Bad Image URLs: {', '.join(broken_urls)}\")  # Raise exception for broken URLs\n\n            # Remove cells containing '--Colab2PDF' in their source\n            notebook.cells = [cell for cell in notebook.cells if '--Colab2PDF' not in cell.source]  # Filter cells\n            # Removing cells containing '--Colab2PDF' in their source. This is done to ensure that the code for the colab2pdf function itself is not included in the final PDF. The string '--Colab2PDF' acts as a marker to identify and remove these cells.\n\n            # Create a new notebook with the filtered cells\n            new_notebook = nbformat.v4.new_notebook(cells=notebook.cells or [nbformat.v4.new_code_cell('#')])  # New notebook\n            nbformat.validator.normalize(new_notebook)  # Normalize notebook\n\n            # Write the new notebook to a file\n            notebook_file_path = pdf_dir / f'{notebook_path.stem}.ipynb'  # Notebook file path\n            with notebook_file_path.open('w', encoding='utf-8') as notebook_file:\n                nbformat.write(new_notebook, notebook_file)  # Write notebook to file\n\n            # Create a configuration file for Quarto\n            config_content = {\n                'include-in-header': [{\n                    'text': r'\\usepackage{fvextra}\\DefineVerbatimEnvironment{Highlighting}{Verbatim}{breaksymbolleft={},showspaces=false,showtabs=false,breaklines,breakanywhere,commandchars=\\\\\\{\\}}'\n                }],\n                'include-before-body': [{\n                    'text': r'\\DefineVerbatimEnvironment{verbatim}{Verbatim}{breaksymbolleft={},showspaces=false,showtabs=false,breaklines}'\n                }]\n            }\n            config_file_path = pdf_dir / 'config.yml'  # Config file path\n            with config_file_path.open('w', encoding='utf-8') as config_file:\n                yaml.dump(config_content, config_file)  # Write config to file\n\n            # Convert the notebook to PDF using Quarto\n            !quarto render {notebook_file_path} --metadata-file={config_file_path} --to pdf -M latex-auto-install -M margin-top=1in -M margin-bottom=1in -M margin-left=1in -M margin-right=1in --quiet\n            # Converting the notebook to PDF using Quarto with the specified configuration.\n\n            # Provide a download link for the PDF\n            pdf_file_path = pdf_dir / f'{notebook_path.stem}.pdf'  # PDF file path\n            google.colab.files.download(str(pdf_file_path))  # Provide download link\n            status_label.value = f'✅ Downloaded: {notebook_path.stem}.pdf'  # Update status label\n\n        except Exception as e:\n            # Handle any exceptions that occur during the conversion process\n            status_label.value = f'❌ {str(e)}'  # Display error message\n\n        finally:\n            # Re-enable the button after the process is complete\n            button.disabled = False  # Re-enable button\n```\n\n1. **Button Status Update:**\n   - The status label is updated to indicate that the conversion is in progress.\n   - The button is disabled to prevent multiple clicks during the conversion process.\n\n1. **Get Notebook Name:**\n   - The notebook name is retrieved from the Colab session using the Colab API.\n\n1. **Create Secure Filename:**\n   - A secure filename is created for the notebook using `werkzeug.utils.secure_filename` and `urllib.parse.unquote`.\n\n1. **Create Directory for PDF:**\n   - A directory is created to store the PDF, with a timestamp to ensure uniqueness.\n\n1. **Read Notebook Content:**\n   - The current notebook content is retrieved using the Colab API and read into a `nbformat` notebook object.\n\n1. **Check for Broken Image URLs:**\n   - The function checks for broken image URLs in markdown cells. If any broken URLs are found, an exception is raised. This check is necessary because broken image URLs can cause a silent error and cut off the PDF at the point of the broken image link.\n\n1. **Remove Colab2PDF Code from PDF:**\n   - Cells containing `--Colab2PDF` in their source are removed from the notebook. This is done to ensure that the `colab2pdf` code itself is not included in the final PDF. The string `--Colab2PDF` acts as a marker to identify it.\n\n1. **Create New Notebook:**\n   - A new notebook is created with the filtered cells, and it is normalized using `nbformat.validator.normalize`.\n\n1. **Write Notebook to File:**\n    - The new notebook is written to a file in the created directory.\n\n1. **Create Configuration File for Quarto:**\n    - A configuration file for Quarto is created with specific settings for the PDF conversion.\n\n1. **Convert Notebook to PDF:**\n    - The notebook is converted to PDF using Quarto with the specified configuration.\n\n1. **Provide Download Link:**\n    - A download link for the PDF is provided using `google.colab.files.download`.\n\n1. **Exception Handling:**\n    - Any exceptions that occur during the conversion process are caught and displayed in the status label.\n\n1. **Re-enable Button:**\n    - The button is re-enabled after the process is complete.\n\n### Check and Install Quarto\n\n```python\n    # Check if Quarto is installed, if not, install it\n    if not pathlib.Path('/usr/local/bin/quarto').exists():\n        !wget -q 'https://quarto.org/download/latest/quarto-linux-amd64.deb'  # Download Quarto\n        !dpkg -i quarto-linux-amd64.deb \u003e /dev/null  # Install Quarto\n        !quarto install tinytex --update-path --quiet  # Install TinyTeX\n        !rm quarto-linux-amd64.deb  # Remove Quarto package\n```\n\n1. **Check if Quarto is Installed:**\n   - The function checks if Quarto is installed by verifying the existence of the Quarto binary.\n\n1. **Download and Install Quarto:**\n   - If Quarto is not installed, it is downloaded using `wget` and installed using `dpkg`.\n\n1. **Install TinyTeX:**\n   - TinyTeX is installed using Quarto to ensure LaTeX dependencies are met.\n\n1. **Remove Quarto Package:**\n   - The downloaded Quarto package is removed after installation.\n\n### Create and Display UI Elements\n\n```python\n    # Create a button and status label for the user interface\n    download_button = ipywidgets.widgets.Button(description='⬇️ Download')  # Create download button\n    status_label = ipywidgets.widgets.Label()  # Create status label\n\n    # Set the button click event to trigger the convert function\n    download_button.on_click(lambda b: convert(b))  # Set button click event\n\n    # Display the button and status label\n    IPython.display.display(ipywidgets.widgets.HBox([download_button, status_label]))  # Display UI elements\n\n# Call the function to display the download button\ncolab2pdf()\n```\n\n1. **Create UI Elements:**\n   - A download button and a status label are created using `ipywidgets`.\n\n1. **Set Button Click Event:**\n   - The button click event is set to trigger the `convert` function.\n\n1. **Display UI Elements:**\n   - The button and status label are displayed using `IPython.display.display`.\n\n1. **Call the Function:**\n   - The `colab2pdf` function is called to display the download button and initialize the process.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrengskapur%2Fcolab2pdf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdrengskapur%2Fcolab2pdf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrengskapur%2Fcolab2pdf/lists"}