In this Post, I have Managed to Make an Awesome Images to PDF Convertor Using Python TKinter. So if you like it,
then Please Subscribe to My Channel to Never Miss an Update.
Source Code and .exe Files Downlaod Links are Given Below, Make Sure To Check them Out.
About this App :-
This is an App which is Builded and Designed By me for Windows Devices. It Can Convert Many Images to a Single PDF Without Watermark, It Supports so many functions, like Converting PDF to Image, PDF Conversion with Pagination Feature, etc. So if you like the App, the Please Comment Down Below :)
How to Use :-
▶Make Sure you have Python Installed in your PC :)
First of All, Install the Packages Listed Below. After that, Make a File Anywhere and name it as "images_pdf.py". After that,Copy the Code From Below and Open the images_pdf.py Using Notepad, Now Paste the code there. After that Run it Using Python. You can use the App.
Want to Install It without Python, Download from these links :-
Python Libararies To Install Before Copying Codes
Simply Open Your Terminal [You can Use 'Command Prompt' Or 'Windows
Powershell' also. And Run These Commands there to Install These Packages.
pip install PIL
pip install pypdf2
Souce Code Here :-
from os import path
from os import remove
from threading import Thread
from tkinter import Tk
from tkinter import filedialog
from tkinter import ttk
from tkinter import LabelFrame
from tkinter import Text
from tkinter import Scale
from tkinter import Frame
from tkinter import Radiobutton
from tkinter import Checkbutton
from tkinter import IntVar
from tkinter import BooleanVar
from tkinter import Button
from tkinter import Scrollbar
from tkinter import Menu
from tkinter import messagebox
from tkinter import END
import webbrowser
from PIL import Image
from PyPDF2 import PdfFileReader
from PyPDF2 import PdfFileWriter
class MainWindow:
def __init__(self, master):
self.FORMAT = {0: '.pdf', 1: '.jpg'}
self.SETTINGS_DPI = {0: 72, 1: 100, 2: 150}
self.SETTINGS_COLOR = {0: '1', 1: 'RGB'}
self.list_files = ''
self.filename = ''
self.lenght_list_files = ''
self.text_box = Text(master, wrap='char', width=80, height=16)
self.vscroll_text_box = Scrollbar(
master, orient='vertical', command=self.text_box.yview())
self.hscroll_text_box = Scrollbar(
master, orient='horizontal', command=self.text_box.xview())
self.text_box.config(yscrollcommand=self.vscroll_text_box.set,
xscrollcommand=self.hscroll_text_box.set)
self.text_box.grid(row=2, column=2, rowspan=4, columnspan=7)
self.vscroll_text_box.grid(
row=2, column=9, rowspan=4, sticky=('se', 'ne'))
self.hscroll_text_box.grid(
row=6, column=2, columnspan=8, sticky=('we', 'ne'))
#
#
# File format settings
self.labelframe_format = LabelFrame(
master, text="File format")
self.labelframe_format.grid(
row=7, column=1, columnspan=1, rowspan=3, sticky='wens')
self.format_output_file = IntVar()
self.format_output_file.set(0)
self.radiobutton_pdf = Radiobutton(self.labelframe_format, text='PDF format',
variable=self.format_output_file, value=0, command=self.shutdown_button, cursor="hand2")
self.radiobutton_jpg = Radiobutton(self.labelframe_format, text='JPEG format',
variable=self.format_output_file, value=1, command=self.shutdown_button, cursor="hand2")
self.radiobutton_pdf.pack(fill='x')
self.radiobutton_jpg.pack(fill='x')
#
#
# Set the frame in which we will place the split settings
self.labelframe_split = LabelFrame(master, text="Pagination")
self.labelframe_split.grid(
row=7, column=2, columnspan=2, rowspan=3, sticky='wens')
self.scale_split = Scale(self.labelframe_split, from_=0, to=100,
resolution=5, orient="horizontal")
self.scale_split.pack(fill='both')
# Set the frame in which we will place the file quality settings
self.labelframe_dpi = LabelFrame(master, text="Quality settings")
self.labelframe_dpi.grid(
row=7, column=4, columnspan=2, rowspan=3, sticky='wens')
self.dpi = IntVar()
self.dpi.set(2)
self.radiobutton_dpi_72 = Radiobutton(self.labelframe_dpi, text='The average',
variable=self.dpi, value=0, cursor="hand2")
self.radiobutton_dpi_100 = Radiobutton(self.labelframe_dpi, text='Good',
variable=self.dpi, value=1, cursor="hand2")
self.radiobutton_dpi_150 = Radiobutton(self.labelframe_dpi, text='Excellent',
variable=self.dpi, value=2, cursor="hand2")
self.radiobutton_dpi_72.pack(fill='both')
self.radiobutton_dpi_100.pack(fill='both')
self.radiobutton_dpi_150.pack(fill='both')
#
#
# Frame with color or b / w selection settings
self.labelframe_color = LabelFrame(master, text="Color settings")
self.labelframe_color.grid(
row=7, column=6, columnspan=2, rowspan=3, sticky='wens')
self.color = IntVar()
self.color.set(1)
self.radiobutton_bw = Radiobutton(self.labelframe_color, text='Black / white',
variable=self.color, value=0, cursor="hand2")
self.radiobutton_color = Radiobutton(self.labelframe_color, text='Colored',
variable=self.color, value=1, cursor="hand2")
self.radiobutton_bw.pack(fill='both')
self.radiobutton_color.pack(fill='both')
#
#
# Frame with JPEG compression quality settings
self.labelframe_quality = LabelFrame(
master, text="File compression setting")
self.labelframe_quality.grid(
row=7, column=8, columnspan=2, rowspan=3, sticky='nw ne')
self.scale_quality = Scale(self.labelframe_quality, label='Worse Better', from_=1, to=100,
resolution=1, orient="horizontal", state='active')
self.scale_quality.set(100)
self.scale_quality.pack(fill='both')
#
#
# Checkbox for quality optimization
self.optimize_image = BooleanVar()
self.optimize_image.set(False)
self.checkbutton_optimize = Checkbutton(
self.labelframe_quality, text='Automatically', variable=self.optimize_image, onvalue=True, offvalue=False)
self.checkbutton_optimize.pack()
self.checkbutton_optimize.bind(
'<Button>', lambda event: self.change_state(event))
#
#
# Set the frame in which we will place the main command buttons
def color_change(e):
self.button_open["background"] = "brown"
self.button_open["foreground"] = "white"
def color_reverse(e):
self.button_open["background"] = "lime"
self.button_open["foreground"] = "black"
def color_change2(e):
self.button_save["background"] = "darkblue"
self.button_save["foreground"] = "white"
def color_reverse2(e):
self.button_save["background"] = "cyan"
self.button_save["foreground"] = "black"
def color_change3(e):
self.button_run["background"] = "pink"
self.button_run["foreground"] = "black"
def color_reverse3(e):
self.button_run["background"] = "black"
self.button_run["foreground"] = "white"
self.button_frame = Frame(master)
self.button_frame.grid(row=2, column=1, rowspan=4)
self.button_open = Button(self.button_frame, text="Add Images",
command=self.listFiles, pady=5, padx=3, cursor="hand2", bg="lime")
self.button_open.bind("<Enter>", color_change)
self.button_open.bind("<Leave>", color_reverse)
self.button_open.pack()
self.button_save = Button(self.button_frame, text="Save PDF",
command=self.savefileName, bg="cyan", pady=5, padx=10, cursor="hand2")
self.button_save.bind("<Enter>", color_change2)
self.button_save.bind("<Leave>", color_reverse2)
self.button_save.pack()
self.button_run = Button(self.button_frame, text="Run",
command=lambda x=True: ConvertFile().process(
input_file=self.list_files, output_file=self.filename,
format_file=self.FORMAT[self.format_output_file.get(
)], dpi=self.SETTINGS_DPI[self.dpi.get()],
color=self.SETTINGS_COLOR[self.color.get()],
optimize=self.optimize_image.get(),
quality=self.scale_quality.get(), split_step=self.scale_split.get()),
pady=5, padx=23, cursor="hand2", bg="black", fg="white")
self.button_run.bind("<Enter>", color_change3)
self.button_run.bind("<Leave>", color_reverse3)
self.button_run.pack()
#
#
# Progressbar
self.pbar = ttk.Progressbar(
master, orient='horizontal', mode='determinate', length=100, maximum=100)
self.pbar.grid(row=10, column=1, columnspan=9, sticky='wens')
#
#
# Program menu
self.menu = Menu(master)
master.config(menu=self.menu)
self.sub_menu1 = Menu(self.menu)
self.menu.add_cascade(label='File', menu=self.sub_menu1)
self.sub_menu1.add_command(label='Exit', command=self.closed_window)
self.sub_menu2 = Menu(self.menu)
self.sub_menu2.add_command(label="About Us", command=self.about_us)
self.menu.add_cascade(label='Information', menu=self.sub_menu2)
def about_us(self):
about = messagebox.askokcancel("About Us", "This Program is Created and Developed By An Individual Developer Named Kunal Gupta.\n\nIf you Will Press OK, then you will be redirected to My Website and My Youtube Channel.")
if about==True:
webbrowser.open("https://macstockofficial.blogspot.com/")
webbrowser.open_new_tab("https://www.youtube.com/channel/UCIXud9Ot8pfDQizzdmQ-FyQ?sub_confirmation=1")
else:
return "None"
def frange(self, start, stop, step):
while start < stop:
yield start
start += step
def change_state(self, event):
if self.optimize_image.get() is False:
self.scale_quality.config(state='disable')
else:
self.scale_quality.config(state='active')
def shutdown_button(self):
if self.format_output_file.get() == 1:
self.button_save.config(state='disable')
else:
self.button_save.config(state='active')
def update_progressbar(self, page):
step = 100 / self.lenght_list_files
step_range = list(self.frange(0, 100, step))
self.pbar['value'] = step_range[page] + step
root.update()
def show_error(self, message):
messagebox.showerror(title='ERROR', message=message)
def closed_window(self):
exitfunction = messagebox.askyesno("Exit Kunal Images to PDF Convertor", "Are You Sure you Want to Exit?")
if exitfunction==True:
root.destroy()
else:
return "None"
def listFiles(self):
"""The function is tied to the" Add files "button. The result of the function is a list of files, which is displayed in the text_box field"""
self.list_files = filedialog.askopenfilenames()
self.lenght_list_files = len(self.list_files)
self.text_box.delete(1.0, END)
for i in self.list_files:
self.text_box.insert(END, i)
self.text_box.insert(END, '\n')
return self.list_files
def savefileName(self):
"""The function is tied to the" Save file "button. The result of the function is the full path to the output file"""
default = self.FORMAT[0]
setting_format = self.FORMAT[self.format_output_file.get()]
self.filename = filedialog.asksaveasfilename(filetypes=[(f"File format *{setting_format}",
f"*{setting_format}")],
defaultextension=default)
return self.filename
class ConvertFile:
"""
The class is responsible for converting image files to PDF, JPEG, PNG formats.
For PDF files, it is possible to split into parts with a specified number of pages.
"""
def numberSteps(self, num_page, page_start, page_step):
"""
The function creates a list of range values into which the file is split
"""
steps = list(range(page_start, num_page, page_step))
steps.append(num_page)
return steps
def splitPdf(self, input_file, step):
"""
The function divides PDF into files according to the specified range.
The range is specified in pages. The function returns multiple files,
by the number of ranges (the name is generated by default).
\ n input_file: file name, required parameter, type str.
\ n step: step of the range in pages, int type.
"""
pdf_input = PdfFileReader(open(input_file, 'rb'))
steps = self.numberSteps(num_page=pdf_input.getNumPages(),
page_start=0, page_step=step)
new_outfile_path, new_outfile_format = path.splitext(input_file)
x = 1
for i in steps:
if x < len(steps):
pdf_output = PdfFileWriter()
for z in list(range(i, steps[x])):
pdf_output.addPage(pdf_input.getPage(z))
file_part = new_outfile_path + \
f"-page-{i}-{steps[x]}" + new_outfile_format
with open(file_part, 'wb') as pdf_output_stream:
pdf_output.write(pdf_output_stream)
else:
continue
x += 1
def to_image(self, in_file, optimize, quality, dpi, color, format_file='JPEG'):
input_path, input_format = path.splitext(in_file)
out_file = input_path + '.' + format_file
im = Image.open(in_file)
size = im.size
new_size = (size[0] // 2, size[1] // 2)
img_resize = im.resize(size=new_size, resample=1, reducing_gap=3.0)
img = img_resize.convert(mode=color)
img.save(out_file, format_file, quality=quality, optimize=optimize,
dpi=(dpi, dpi), progressive=True)
return out_file
def process(self, input_file, output_file, format_file, dpi, color, optimize, quality, split_step=0):
try:
"""
The function is responsible for starting the conversion process.
\ n input_file: list of files, type str.
\ n output_file: name of the resulting file, type str.
\ n format_file: format of the resulting file (values from the series are passed to the function: PDF, JPG, PNG), str type.
\ n dpi: number of dots per inch (values from the range: 72, 100, 150 are passed to the function), int type.
\ n split_step: step for splitting the PDF file (specified in pages), int type.
\ n return: files are saved in the directory.
"""
output_path, output_format = path.splitext(output_file)
page = 0
for i in input_file:
"""Start updating the progress bar in a separate process"""
Thread(target=app.update_progressbar(page)).start()
if format_file == '.pdf':
"""first convert to JPEG format"""
output_jpg = self.to_image(
i, optimize, quality, dpi, color, 'JPEG')
"""JPEG is added to the PDF file, we select the parameters of the add function based on the page number"""
if page == 0:
im = Image.open(output_jpg)
im.save(output_file, 'PDF', save_all=True)
elif page > 0:
im = Image.open(output_jpg)
im.save(output_file, 'PDF', append=True)
remove(output_jpg)
elif format_file == '.jpg':
self.to_image(i, optimize, quality, dpi, color, 'JPEG')
else:
pass
page += 1
if format_file == '.pdf' and split_step > 0:
self.splitPdf(output_file, step=split_step)
else:
messagebox.askokcancel("Successfully Completed",
"Your PDF File Generated Succesfully, at the Location You Entered.")
except:
messagebox.askretrycancel("A Problem Has Been Occured", "Please Save the File First")
# main window
if __name__ == "__main__":
root = Tk()
root.geometry('780x410+140-140')
root.resizable(0, 0)
root.iconbitmap('./img.ico')
root.title('Kunal Images to PDF Convertor')
app = MainWindow(root)
root.config(bg="darkgrey")
root.mainloop()
Hope You Will Like It