Sometimes we need simple and basic tools to get the job done. At work, we have people that use pdf files daily, on which they need to perform certain manual operations. One of these operations is rotating pages. Thinking of programming a pdf rotator can look quite massive at first, but is it really?
To build our tool, we need to be able to rotate the pdf in three ways, clockwise, counterclockwise and 180 degrees. For simplicity, we want to rotate all pdf files in our current working directory. The user shall also be able to use the finished script, without installing Python or any dependencies on Windows. Let us walk through the steps in creating our tool.
Rotating a pdf with PyPDF2 can be done with the PageObject class's method RotateClockwise. The method takes one Int parameter, angle
which defines the rotation degrees. Note that the angle have to be specified in incremetns of 90°. There is no possibility of rotating a PDF page for example 55°.
Ok, we know how to rotate our page, now we need to load our PDF file into memory. After that, we need to initialize our PdfFileReader and PdfFileWriter objects. We can then loop through our pages by using the readers numPages variable. We get the page, rotate it, write it to our new PDF and then save it to disc.
import PyPDF2
with open("test.pdf", "rb") as pdf_file: pdf_reader = PyPDF2.PdfFileReader(pdf_file) pdf_writer = PyPDF2.PdfFileWriter() print("Rotating", degrees) for page_num in range(pdf_reader.numPages): pdf_page = pdf_reader.getPage(page_num) pdf_page.rotateClockwise(degrees) pdf_writer.addPage(pdf_page) with open("test_rotated.pdf", "wb") as pdf_file_rotated: pdf_writer.write(pdf_file_rotated)
A command line interface might work for many users, but believe me, a Graphical USer Interface (GUI) beats a Command Line Interface (CLI) by lightyears for the average user. To easily create our interface, we use Tkinter. We need three Radiobuttons for specifying the rotations, Left, Right and 180 degrees. We also need some kind of descripte text to guide the user, as well as a Button for being able to start the rotation. See the code comments for further descriptions.
import tkinter as tk # Create our root widget, set title and size master = tk.Tk() master.title("PDF rotator") master.geometry("400x100") # Create a IntVar for getting our rotate values master.degrees = tk.IntVar() # Create a description label and a couple radiobuttons, add them to the widget tk.Label(master, text="Rotates all pdf in the current folder the selected degrees.").grid(row=0,columnspan=4) tk.Radiobutton(master, text="Right 90 degrees", variable=master.degrees, value=90).grid(row=1,column=1) tk.Radiobutton(master, text="Left 90 degrees", variable=master.degrees, value=-90).grid(row=1,column=2) tk.Radiobutton(master, text="180 degrees", variable=master.degrees, value=180).grid(row=1,column=3) # Create a button for calling our function master.ok_button = tk.Button(master, command=rotate_pdf, text="Rotate pdf files") master.ok_button.grid(row=2,column=1) # Run tk.mainloop()
We want to rotate all pdf files in the folder where our script is contained.
import os # Get all the files in current folder from where we are running the script files = [f for f in os.listdir('.') if os.path.isfile(f)] files = list(filter(lambda f: f.lower().endswith(('.pdf')), files))
Here is the complete code for rotating our pdf files. Enjoy!
#!/usr/bin/env python3 # -*- coding: <utf-8> -*- import PyPDF2 import tkinter as tk import os import sys # Get all the files in current folder from where we are running the script files = [f for f in os.listdir('.') if os.path.isfile(f)] files = list(filter(lambda f: f.lower().endswith(('.pdf')), files)) # main rotate pdf function def rotate_pdf(*args): degrees = master.degrees.get() pdf_rotator(files, degrees) # The pdf rotator def pdf_rotator(files, degrees): for filename in files: if degrees != 0 and degrees != "": with open(filename, "rb") as pdf_file: pdf_reader = PyPDF2.PdfFileReader(pdf_file) pdf_writer = PyPDF2.PdfFileWriter() print("Rotating", degrees) for page_num in range(pdf_reader.numPages): pdf_page = pdf_reader.getPage(page_num) pdf_page.rotateClockwise(degrees) pdf_writer.addPage(pdf_page) with open(filename[:-4]+"rotated_"+str(degrees)+".pdf", "wb") as pdf_file_rotated: pdf_writer.write(pdf_file_rotated) sys.exit() # Create our root widget, set title and size master = tk.Tk() master.title("PDF rotator") master.geometry("400x100") # Create a IntVar for getting our rotate values master.degrees = tk.IntVar() # Create a description label and a couple radiobuttons, add them to the widget tk.Label(master, text="Rotates all pdf in the current folder the selected degrees.").grid(row=0,columnspan=4) tk.Radiobutton(master, text="Right 90 degrees", variable=master.degrees, value=90).grid(row=1,column=1) tk.Radiobutton(master, text="Left 90 degrees", variable=master.degrees, value=-90).grid(row=1,column=2) tk.Radiobutton(master, text="180 degrees", variable=master.degrees, value=180).grid(row=1,column=3) # Create a button for calling our function master.ok_button = tk.Button(master, command=rotate_pdf, text="Rotate pdf files") master.ok_button.grid(row=2,column=1) # Run tk.mainloop()
In this example, we will see how we can create a text Entry and connect a variable to it. The text in the Entry will then dynamically update a button on the form. You can see how to create a Tkinter application and a button in this earlier post.
#! python3 # -*- coding: utf-8 -*- import tkinter as tk class entries_tester_app(tk.Tk): def __init__(self, frame_title): super().__init__() # Create a title for the frame self.title(frame_title) # Create a variable for holding the text in the Entry self.entry_text_var = tk.StringVar() self.entry_text_var.trace_add("write", self.change_button_text) # Create an Entry connected to the entry_text_var self.entry_box = tk.Entry(self, text=self.entry_text_var) # Create the button self.print_button = tk.Button(self, text = "PLACEHOLDER TEXT", command=self.print_text) # Put the button and the entry to the frame self.entry_box.pack() self.print_button.pack() def change_button_text(self, *args): # Note the args # Change the button text self.print_button.config(text=self.entry_text_var.get()) def print_text(self): # Print the text to the console print("You entered: \"{}\"".format(self.entry_box.get())) if __name__ == "__main__": root = entries_tester_app("Entry test") root.mainloop()
We need to create a variable that we can track. We create a StringVar() (self.entry_text_var) to hold our text entry. You can also create number variables and boolean variables. We trace the variable with the trace_add method. Note that trace_add replaces the trace method and that the modes are "write", "read" and "unset". We also connect the trace to the change_button_text method.
The button's text will now update as you write in the text entry. Pretty cool right!
Featured Image: "Black-and-white version of the Python logo, useful for small/high contrast icons." by Waldir is licensed under CC BY-SA 4.0
In this article, we will explore how to create a simple button in Tkinter. The button is used for a lot of user interaction and is often the most basic way to interact with a user. We will also cover some of the basics of how a Tkinter application is launched. (more…)
Creating a simple file dialog box with Tkinter - Have you come to a point when you want to avoid running your Python scriot in the same folder as your files you want to work with? Do you find it annoying to input the file paths each time? Using Tkinter, you can create a native file dialog, that easily returns multiple files as a list or any other data type of your choosing. Check out the code below! (more…)
I have always wanted to build Graphical User Interface (GUI) applications but felt that the learning barrier was too high. I read online on forums that you should not use tkinter, because it is ugly and outdated. One day, I had a project where I felt that I really needed to build a GUI so I thought I would try out tkinter, and I was amazed how simple and intuitive the coding was. If you are interested in firing up a GUI fast, below is an explanation of how to do it. (more…)