Deskewing PDF pages
Pages that come off a scanner or a phone camera are rarely square to the page. A few degrees of rotation is enough to hurt OCR accuracy, throw off barcode and table detection, and make an otherwise clean archive look sloppy. Deskewing straightens the page before any of that downstream work runs.
Deskewing at the page level keeps the operation narrow. You correct the pages you know came from a scanner and leave the rest of the document untouched, which matters in mixed documents where born-digital pages are already square.
This sample shows how to straighten a single page of a document using Nutrient Python SDK and save the result. The input can be any document format the SDK supports. If the input isn’t already a PDF, the SDK converts it to PDF automatically when you create the editor.
Download sampleHow Nutrient helps
Nutrient Python SDK detects and corrects skew behind a single method call. The SDK:
- Implicitly converts non-PDF inputs (images, multi-page TIFFs, Office documents) to PDF when the editor is created
- Rasterizes the target page and measures its dominant text baseline angle
- Rotates the page content by the detected angle to bring it back to square
- Applies the correction to the page content stream, so text and vector art stay vector — the page isn’t flattened to an image
- Leaves the page alone when no skew is detected
Other pages in the document aren’t touched.
Preparing the project
Import the classes used in the sample:
from nutrient_sdk import Documentfrom nutrient_sdk import PdfEditorfrom nutrient_sdk import NutrientExceptionOpening the document
Open the source document and attach a PDF editor to it:
def main(): try: with Document.open("input_skewed_scan.pdf") as document: editor = PdfEditor.edit(document)PdfEditor.edit(document) attaches an editor to the open document. If the input isn’t already a PDF, the SDK converts it to PDF at this step. The context manager(opens in a new tab) closes the document when the block exits, even if deskewing raises.
Tuning detection
Three document settings control the detector, and they must be set before you deskew.
skew_tolerance is the search window in degrees — skew larger than this isn’t corrected. Narrow it when you know your scans are only slightly off and you want to avoid over-correcting a page whose layout merely looks slanted.
optimistic_skew_detection relaxes the confidence checks that suppress a borderline result. Enable it when you already know a batch is skewed and the conservative pass is reporting nothing. Leave it off for mixed input, where it raises the chance of rotating a page that was actually straight.
skew_binarization_method chooses how the page is reduced to black and white before the skew is measured. Set it to "sauvola" for faint, grayish, or unevenly lit scans, where a global threshold loses too much text for the detector to lock onto. "default" and "otsu" both use Modified Otsu.
document.settings.deskew_settings.skew_tolerance = 10.0 document.settings.deskew_settings.optimistic_skew_detection = False document.settings.deskew_settings.skew_binarization_method = "default"All three have sensible defaults (a 15-degree window, conservative detection, Modified Otsu), so you can skip this step entirely and call auto_deskew() directly.
These settings are shared with the recognition pipelines, so the same values apply if you later run OCR or data extraction over the document. The other properties on DeskewSettings cover model-based cardinal orientation correction, which runs only in those pipelines and doesn’t affect a page-level deskew.
Straightening a single page
Get the target page from the editor and deskew it:
pages = editor.get_page_collection()
page = pages.get_first() applied_angle = page.auto_deskew()
if applied_angle != 0: print(f"Corrected a skew of {applied_angle:.2f} degrees.") else: print("No skew detected, page left unchanged.")editor.get_page_collection().get_first() returns the first page of the document, and auto_deskew() measures that page’s skew and rotates its content to correct it. A page the detector reads as already square is left unchanged, so the call is safe to run over pages you aren’t sure about.
The return value is the rotation that was applied, in degrees, and is 0 when nothing was corrected. Use it to log what happened or to flag pages that came in badly skewed.
To target a different page, use the page collection accessor (for example pages.get(2) for the third page) and call auto_deskew() on that page instead.
Saving the result
Save the modified document to a new file and close the editor:
editor.save_as("output.pdf") editor.close() except NutrientException as e: print(f"Error: {e}")
if __name__ == "__main__": main()The except clause surfaces any licensing or I/O issue raised by the SDK. Deskewing requires an unencrypted document — an encrypted source raises an error rather than silently skipping the page.
Conclusion
The workflow for deskewing a single PDF page is:
- Open the source document.
- Create a
PdfEditorfor the document. - Optionally tune
skew_toleranceandoptimistic_skew_detectionon the document settings. - Get the target page from
editor.get_page_collection(). - Call
auto_deskew()on that page. - Save the result and close the editor.
Only the targeted page is straightened. The rest of the document is left as it was.
For related workflows, refer to the Python SDK guides.