Module solute.solute_gui

Expand source code
# Imports -----------------------------------------------------

import tkinter as tk
from tkinter import Menu, messagebox
from tkinter import filedialog
from tkinter import ttk
from tkinter import font

try:
    import core
except ImportError:
    from solute import core
# -------------------------------------------------------------

# Options 
TEXT_BOX_HEIGHT = 8
PADDINGS = {'padx':10, 'pady':10}

class SoluteApp(tk.Tk):
    """ Root Window of application """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Root page configuration -----------------------------
        self.geometry('800x600')
        self.minsize(width=650, height=550)
        
        self.style = ttk.Style(self)
        self.style.theme_use('winnative')

        self.title("Solute")
        self.protocol("WM_DELETE_WINDOW", self.exit)


        # Layout Configuration --------------------------------
        DIMENSIONS = {"Rows":16, "Columns":6}
        for r in range(DIMENSIONS['Rows']):
            if r==2 or r==3:
                self.grid_rowconfigure(r, weight=1, pad=30)
            self.grid_rowconfigure(r, weight=1, minsize=2)
        for c in range(DIMENSIONS['Columns']):
            self.grid_columnconfigure(c, weight=1, minsize=2)

            
        # Icon section ----------------------------------------
        self.iconbitmap('assets/favicon_solute.ico')


        # Menubar Section -------------------------------------
        menubar = Menu(self)
        file = Menu(menubar, tearoff=0)
        menubar.add_cascade(label="Help", menu=file)
        file.add_command(label="About", command=self.developer_info)
        self.config(menu=menubar)


        # Header Section --------------------------------------
        HEADER = "SOLUTE"
        header = tk.Label(self)
        header.config(text=HEADER)
        header.config(font=('Verdana',16))
        header.config(pady=1)
        header.grid(row=0, column=0, columnspan=6, sticky='nsew')


        # Tagline section -------------------------------------
        TAG_LINE = "--- Simplified steganography tool for your data privacy ---"
        tagline = tk.Label(self)
        tagline.config(text=TAG_LINE)
        # tagline.config(font=('Verdana',12))
        tagline.grid(row=1, column=0, columnspan=6, sticky='n')
         
        
        # Workspace Area --------------------------------------
        # Configure container inside root window 
        # Container frame serves pages
        container = tk.Frame(self)
        container.grid(row=2, column=0, rowspan=13, columnspan=6)

        self.frames = {}
        self.pages = [Workspace]
        for F in self.pages:    
            # IF_CASE: F=Workspace() ==> page_name=F.__class__.__name__
            # THIS_CASE: F = Workspace
            page_name = F.__name__ 
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame

        # Display Starting page in container
        self.show_frame("Workspace")


        # Footer section --------------------------------------
        FOOTER = "Developed by [ SathvikPN ]"
        footer = tk.Label(self)
        footer.config(text=FOOTER)
        footer.grid(row=15, column=0, columnspan=6, sticky='s')


    def show_frame(self, page_name):
        """ Display passed page 
        
        Multiple pages are stacked at same container
        raises passed page to top of stack which is displayed
        """
        frame = self.frames[page_name]
        frame.tkraise()

    def developer_info(self):
        messagebox.showinfo(
            "Developer Info",
            "[Name] SathvikPN\n[GitHub] https://github.com/SathvikPN/Solute"
        )


    def exit(self):
        # Exit Confirmation Message box
        TITLE = "Exit"
        MESSAGE = "Are you sure want to exit?"

        sure = messagebox.askyesno(TITLE, MESSAGE )
        if sure is True:
            self.destroy()


    def run(self):
        self.mainloop()



# Workspace Area ----------------------------------------------

class Workspace(tk.Frame):
    """ Workspace of the Application """
    def __init__(self, parent, controller):
        super().__init__(parent)
        self.controller = controller

        # btn_start = tk.Label(text="Center of Workspace")
        # btn_start.grid(row=2, column=0, rowspan=13, columnspan=6)

        # IMAGE SELECTOR SECTION ------------------------------
        step1 = tk.Label(text="Step 1: Input Image")
        step1.grid(row=2, column=1)

        self.step1_path = tk.Entry()
        self.step1_path.grid(row=2, column=2, columnspan=2, sticky='ew')

        self.step1_btn = tk.Button(text="Select File")
        self.step1_btn.config(command=self.image_selector)
        self.step1_btn.grid(row=2, column=4)

        # SEPARATOR 
        # ttk.Separator(orient=VERTICAL).grid(column=2, row=4, rowspan=10, sticky='ns')

        # ENCODER Section -------------------------------------
        encode_header = tk.Label(text="ENCODE")
        encode_header.config(font=('Verdana',14,'bold'))
        encode_header.grid(row=3, column=0, columnspan=3, sticky='s')


        step2_enc = tk.Label(text="Step 2")
        step2_enc.grid(row=4, column=0, sticky='w', **PADDINGS)

        step2_enc_info = tk.Label(text="Enter text to hide")
        step2_enc_info.grid(row=5, column=0, sticky='w', **PADDINGS)

        self.encode_data = tk.Text(height=TEXT_BOX_HEIGHT)
        self.encode_data.grid(row=6,column=0, rowspan=4, columnspan=3, **PADDINGS) #   

        step3 = tk.Label(text="Step 3")
        step3.grid(row=10, column=0, sticky='w', **PADDINGS)

        step3_info = tk.Label(text="Enter Password")
    
        step3_info.grid(row=11, column=0, sticky='w', **PADDINGS)

        self.pwd_enc = tk.Entry()
        self.pwd_enc.config(show='*')
        self.pwd_enc.grid(row=11, column=1, columnspan=2, sticky='w', **PADDINGS)

        # ROW:12 COLUMN:(0,1,2) --> ADD PROGRESS BAR

        encode_btn = tk.Button(text="Encode and Save")
        encode_btn.config(font=8)
        encode_btn.config(command=self.save_encode)
        encode_btn.grid(row=13, rowspan=2, column=0, columnspan=3, sticky='ns')
        


        # DECODER Section -------------------------------------
        decode_header = tk.Label(text="DECODE")
        decode_header.config(font=('Verdana',14,'bold'))
        decode_header.grid(row=3, column=3, columnspan=3, sticky='s')

        step2_dec = tk.Label(text="Step 2")
        step2_dec.grid(row=4, column=3, sticky='w', **PADDINGS)

        step2_dec_info = tk.Label(text="Enter Password")
        step2_dec_info.grid(row=5, column=3, sticky='w', **PADDINGS)

        self.pwd_dec = tk.Entry()
        self.pwd_dec.config(show='*')
        self.pwd_dec.grid(row=5, column=4, columnspan=2, sticky='ew', **PADDINGS)

        decode_btn = tk.Button(text="Decode")
        decode_btn.config(font=8)
        decode_btn.config(command=self.decode)
        decode_btn.grid(row=6, column=4, sticky='ns')

        # ROW:7 COLUMNS:(3,4,5) ---> ADD PROGRESS BAR

        dec_info = tk.Label(text="Decoded data")
        dec_info.grid(row=8, column=3, sticky='w', **PADDINGS)

        self.dec_data = tk.Text(height=TEXT_BOX_HEIGHT)
        self.dec_data.grid(row=10, column=3, rowspan=4,columnspan=3,sticky='w', **PADDINGS ) # 





    def image_selector(self):
        self.step1_path.delete('0', 'end')
        FILE_TYPES = ([('Image Files',('.png','.jpg','.jpeg'))])
        self.img_path = filedialog.askopenfilename(filetypes = FILE_TYPES)
        if not self.img_path:
            messagebox.showwarning("No Image found", "Please select an image")
        else:
            self.step1_path.insert('0',self.img_path)
            return self.step1_path

    def save_encode(self):
        # self.step1_path = tk.Entry()
        # self.encode_data = tk.Text(height=TEXT_BOX_HEIGHT)
        # self.pwd_enc = tk.Entry()
        self.enc_img = filedialog.asksaveasfilename(title='Save file') # filetypes=[("PNG", ".png")]
        self.enc_img = self.enc_img+'.png'
        try:
            core.encode_img(
                self.step1_path.get(),
                self.encode_data.get("1.0","end-1c"),
                self.enc_img,
                self.pwd_enc.get()
            )
            messagebox.showinfo(
                title="Encode SUCCESS",
                message="Encoded image generated successfully.\nYay!"
            )

            self.step1_path.delete('0', 'end')
            self.encode_data.delete("1.0", "end")
            self.pwd_enc.delete('0','end')
        
        except core.DataOverflowError:
            messagebox.showwarning(
                title="Data Overflow",
                message="Data size is too big to fit inside this image"
            )

        except core.ReadImageError:
            messagebox.showerror(
                title="No Image Selected",
                message="Please select a source image to hide data."

            )


    
    def decode(self):
        # self.pwd_dec = tk.Entry()
        self.dec_data.delete("1.0","end")
        if not self.step1_path.get().endswith('.png'):
            messagebox.showinfo(
                "Incorrect Image",
                "Please select the valid image to decode\nPNG format image."
            )
            self.step1_path.delete('0','end')
        else:
            try:
                self.dec_data.insert(
                    "1.0", 
                    core.decode_img(self.step1_path.get(), self.pwd_dec.get())
                )
                messagebox.showinfo(
                    title="Decode SUCCESS",
                    message="Data extracted successfully from the image.\nYay!"
                )

            except core.PasswordError:
                messagebox.showerror(
                    title="Incorrect Credentials",
                    message="Please ensure correct image and correct password is entered."
                )
                self.pwd_dec.delete('0', 'end')

            except core.ReadImageError:
                messagebox.showerror(
                    title="No Image Selected",
                    message="Please select an image to decode"
                )

def graphical_user_interface():
    app = SoluteApp()
    app.run()




# APP TRIGGER -------------------------------------------------
if __name__=='__main__':
    graphical_user_interface()

Functions

def graphical_user_interface()
Expand source code
def graphical_user_interface():
    app = SoluteApp()
    app.run()

Classes

class SoluteApp (*args, **kwargs)

Root Window of application

Return a new Toplevel widget on screen SCREENNAME. A new Tcl interpreter will be created. BASENAME will be used for the identification of the profile file (see readprofile). It is constructed from sys.argv[0] without extensions if None is given. CLASSNAME is the name of the widget class.

Expand source code
class SoluteApp(tk.Tk):
    """ Root Window of application """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Root page configuration -----------------------------
        self.geometry('800x600')
        self.minsize(width=650, height=550)
        
        self.style = ttk.Style(self)
        self.style.theme_use('winnative')

        self.title("Solute")
        self.protocol("WM_DELETE_WINDOW", self.exit)


        # Layout Configuration --------------------------------
        DIMENSIONS = {"Rows":16, "Columns":6}
        for r in range(DIMENSIONS['Rows']):
            if r==2 or r==3:
                self.grid_rowconfigure(r, weight=1, pad=30)
            self.grid_rowconfigure(r, weight=1, minsize=2)
        for c in range(DIMENSIONS['Columns']):
            self.grid_columnconfigure(c, weight=1, minsize=2)

            
        # Icon section ----------------------------------------
        self.iconbitmap('assets/favicon_solute.ico')


        # Menubar Section -------------------------------------
        menubar = Menu(self)
        file = Menu(menubar, tearoff=0)
        menubar.add_cascade(label="Help", menu=file)
        file.add_command(label="About", command=self.developer_info)
        self.config(menu=menubar)


        # Header Section --------------------------------------
        HEADER = "SOLUTE"
        header = tk.Label(self)
        header.config(text=HEADER)
        header.config(font=('Verdana',16))
        header.config(pady=1)
        header.grid(row=0, column=0, columnspan=6, sticky='nsew')


        # Tagline section -------------------------------------
        TAG_LINE = "--- Simplified steganography tool for your data privacy ---"
        tagline = tk.Label(self)
        tagline.config(text=TAG_LINE)
        # tagline.config(font=('Verdana',12))
        tagline.grid(row=1, column=0, columnspan=6, sticky='n')
         
        
        # Workspace Area --------------------------------------
        # Configure container inside root window 
        # Container frame serves pages
        container = tk.Frame(self)
        container.grid(row=2, column=0, rowspan=13, columnspan=6)

        self.frames = {}
        self.pages = [Workspace]
        for F in self.pages:    
            # IF_CASE: F=Workspace() ==> page_name=F.__class__.__name__
            # THIS_CASE: F = Workspace
            page_name = F.__name__ 
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame

        # Display Starting page in container
        self.show_frame("Workspace")


        # Footer section --------------------------------------
        FOOTER = "Developed by [ SathvikPN ]"
        footer = tk.Label(self)
        footer.config(text=FOOTER)
        footer.grid(row=15, column=0, columnspan=6, sticky='s')


    def show_frame(self, page_name):
        """ Display passed page 
        
        Multiple pages are stacked at same container
        raises passed page to top of stack which is displayed
        """
        frame = self.frames[page_name]
        frame.tkraise()

    def developer_info(self):
        messagebox.showinfo(
            "Developer Info",
            "[Name] SathvikPN\n[GitHub] https://github.com/SathvikPN/Solute"
        )


    def exit(self):
        # Exit Confirmation Message box
        TITLE = "Exit"
        MESSAGE = "Are you sure want to exit?"

        sure = messagebox.askyesno(TITLE, MESSAGE )
        if sure is True:
            self.destroy()


    def run(self):
        self.mainloop()

Ancestors

  • tkinter.Tk
  • tkinter.Misc
  • tkinter.Wm

Methods

def developer_info(self)
Expand source code
def developer_info(self):
    messagebox.showinfo(
        "Developer Info",
        "[Name] SathvikPN\n[GitHub] https://github.com/SathvikPN/Solute"
    )
def exit(self)
Expand source code
def exit(self):
    # Exit Confirmation Message box
    TITLE = "Exit"
    MESSAGE = "Are you sure want to exit?"

    sure = messagebox.askyesno(TITLE, MESSAGE )
    if sure is True:
        self.destroy()
def run(self)
Expand source code
def run(self):
    self.mainloop()
def show_frame(self, page_name)

Display passed page

Multiple pages are stacked at same container raises passed page to top of stack which is displayed

Expand source code
def show_frame(self, page_name):
    """ Display passed page 
    
    Multiple pages are stacked at same container
    raises passed page to top of stack which is displayed
    """
    frame = self.frames[page_name]
    frame.tkraise()
class Workspace (parent, controller)

Workspace of the Application

Construct a frame widget with the parent MASTER.

Valid resource names: background, bd, bg, borderwidth, class, colormap, container, cursor, height, highlightbackground, highlightcolor, highlightthickness, relief, takefocus, visual, width.

Expand source code
class Workspace(tk.Frame):
    """ Workspace of the Application """
    def __init__(self, parent, controller):
        super().__init__(parent)
        self.controller = controller

        # btn_start = tk.Label(text="Center of Workspace")
        # btn_start.grid(row=2, column=0, rowspan=13, columnspan=6)

        # IMAGE SELECTOR SECTION ------------------------------
        step1 = tk.Label(text="Step 1: Input Image")
        step1.grid(row=2, column=1)

        self.step1_path = tk.Entry()
        self.step1_path.grid(row=2, column=2, columnspan=2, sticky='ew')

        self.step1_btn = tk.Button(text="Select File")
        self.step1_btn.config(command=self.image_selector)
        self.step1_btn.grid(row=2, column=4)

        # SEPARATOR 
        # ttk.Separator(orient=VERTICAL).grid(column=2, row=4, rowspan=10, sticky='ns')

        # ENCODER Section -------------------------------------
        encode_header = tk.Label(text="ENCODE")
        encode_header.config(font=('Verdana',14,'bold'))
        encode_header.grid(row=3, column=0, columnspan=3, sticky='s')


        step2_enc = tk.Label(text="Step 2")
        step2_enc.grid(row=4, column=0, sticky='w', **PADDINGS)

        step2_enc_info = tk.Label(text="Enter text to hide")
        step2_enc_info.grid(row=5, column=0, sticky='w', **PADDINGS)

        self.encode_data = tk.Text(height=TEXT_BOX_HEIGHT)
        self.encode_data.grid(row=6,column=0, rowspan=4, columnspan=3, **PADDINGS) #   

        step3 = tk.Label(text="Step 3")
        step3.grid(row=10, column=0, sticky='w', **PADDINGS)

        step3_info = tk.Label(text="Enter Password")
    
        step3_info.grid(row=11, column=0, sticky='w', **PADDINGS)

        self.pwd_enc = tk.Entry()
        self.pwd_enc.config(show='*')
        self.pwd_enc.grid(row=11, column=1, columnspan=2, sticky='w', **PADDINGS)

        # ROW:12 COLUMN:(0,1,2) --> ADD PROGRESS BAR

        encode_btn = tk.Button(text="Encode and Save")
        encode_btn.config(font=8)
        encode_btn.config(command=self.save_encode)
        encode_btn.grid(row=13, rowspan=2, column=0, columnspan=3, sticky='ns')
        


        # DECODER Section -------------------------------------
        decode_header = tk.Label(text="DECODE")
        decode_header.config(font=('Verdana',14,'bold'))
        decode_header.grid(row=3, column=3, columnspan=3, sticky='s')

        step2_dec = tk.Label(text="Step 2")
        step2_dec.grid(row=4, column=3, sticky='w', **PADDINGS)

        step2_dec_info = tk.Label(text="Enter Password")
        step2_dec_info.grid(row=5, column=3, sticky='w', **PADDINGS)

        self.pwd_dec = tk.Entry()
        self.pwd_dec.config(show='*')
        self.pwd_dec.grid(row=5, column=4, columnspan=2, sticky='ew', **PADDINGS)

        decode_btn = tk.Button(text="Decode")
        decode_btn.config(font=8)
        decode_btn.config(command=self.decode)
        decode_btn.grid(row=6, column=4, sticky='ns')

        # ROW:7 COLUMNS:(3,4,5) ---> ADD PROGRESS BAR

        dec_info = tk.Label(text="Decoded data")
        dec_info.grid(row=8, column=3, sticky='w', **PADDINGS)

        self.dec_data = tk.Text(height=TEXT_BOX_HEIGHT)
        self.dec_data.grid(row=10, column=3, rowspan=4,columnspan=3,sticky='w', **PADDINGS ) # 





    def image_selector(self):
        self.step1_path.delete('0', 'end')
        FILE_TYPES = ([('Image Files',('.png','.jpg','.jpeg'))])
        self.img_path = filedialog.askopenfilename(filetypes = FILE_TYPES)
        if not self.img_path:
            messagebox.showwarning("No Image found", "Please select an image")
        else:
            self.step1_path.insert('0',self.img_path)
            return self.step1_path

    def save_encode(self):
        # self.step1_path = tk.Entry()
        # self.encode_data = tk.Text(height=TEXT_BOX_HEIGHT)
        # self.pwd_enc = tk.Entry()
        self.enc_img = filedialog.asksaveasfilename(title='Save file') # filetypes=[("PNG", ".png")]
        self.enc_img = self.enc_img+'.png'
        try:
            core.encode_img(
                self.step1_path.get(),
                self.encode_data.get("1.0","end-1c"),
                self.enc_img,
                self.pwd_enc.get()
            )
            messagebox.showinfo(
                title="Encode SUCCESS",
                message="Encoded image generated successfully.\nYay!"
            )

            self.step1_path.delete('0', 'end')
            self.encode_data.delete("1.0", "end")
            self.pwd_enc.delete('0','end')
        
        except core.DataOverflowError:
            messagebox.showwarning(
                title="Data Overflow",
                message="Data size is too big to fit inside this image"
            )

        except core.ReadImageError:
            messagebox.showerror(
                title="No Image Selected",
                message="Please select a source image to hide data."

            )


    
    def decode(self):
        # self.pwd_dec = tk.Entry()
        self.dec_data.delete("1.0","end")
        if not self.step1_path.get().endswith('.png'):
            messagebox.showinfo(
                "Incorrect Image",
                "Please select the valid image to decode\nPNG format image."
            )
            self.step1_path.delete('0','end')
        else:
            try:
                self.dec_data.insert(
                    "1.0", 
                    core.decode_img(self.step1_path.get(), self.pwd_dec.get())
                )
                messagebox.showinfo(
                    title="Decode SUCCESS",
                    message="Data extracted successfully from the image.\nYay!"
                )

            except core.PasswordError:
                messagebox.showerror(
                    title="Incorrect Credentials",
                    message="Please ensure correct image and correct password is entered."
                )
                self.pwd_dec.delete('0', 'end')

            except core.ReadImageError:
                messagebox.showerror(
                    title="No Image Selected",
                    message="Please select an image to decode"
                )

Ancestors

  • tkinter.Frame
  • tkinter.Widget
  • tkinter.BaseWidget
  • tkinter.Misc
  • tkinter.Pack
  • tkinter.Place
  • tkinter.Grid

Methods

def decode(self)
Expand source code
def decode(self):
    # self.pwd_dec = tk.Entry()
    self.dec_data.delete("1.0","end")
    if not self.step1_path.get().endswith('.png'):
        messagebox.showinfo(
            "Incorrect Image",
            "Please select the valid image to decode\nPNG format image."
        )
        self.step1_path.delete('0','end')
    else:
        try:
            self.dec_data.insert(
                "1.0", 
                core.decode_img(self.step1_path.get(), self.pwd_dec.get())
            )
            messagebox.showinfo(
                title="Decode SUCCESS",
                message="Data extracted successfully from the image.\nYay!"
            )

        except core.PasswordError:
            messagebox.showerror(
                title="Incorrect Credentials",
                message="Please ensure correct image and correct password is entered."
            )
            self.pwd_dec.delete('0', 'end')

        except core.ReadImageError:
            messagebox.showerror(
                title="No Image Selected",
                message="Please select an image to decode"
            )
def image_selector(self)
Expand source code
def image_selector(self):
    self.step1_path.delete('0', 'end')
    FILE_TYPES = ([('Image Files',('.png','.jpg','.jpeg'))])
    self.img_path = filedialog.askopenfilename(filetypes = FILE_TYPES)
    if not self.img_path:
        messagebox.showwarning("No Image found", "Please select an image")
    else:
        self.step1_path.insert('0',self.img_path)
        return self.step1_path
def save_encode(self)
Expand source code
def save_encode(self):
    # self.step1_path = tk.Entry()
    # self.encode_data = tk.Text(height=TEXT_BOX_HEIGHT)
    # self.pwd_enc = tk.Entry()
    self.enc_img = filedialog.asksaveasfilename(title='Save file') # filetypes=[("PNG", ".png")]
    self.enc_img = self.enc_img+'.png'
    try:
        core.encode_img(
            self.step1_path.get(),
            self.encode_data.get("1.0","end-1c"),
            self.enc_img,
            self.pwd_enc.get()
        )
        messagebox.showinfo(
            title="Encode SUCCESS",
            message="Encoded image generated successfully.\nYay!"
        )

        self.step1_path.delete('0', 'end')
        self.encode_data.delete("1.0", "end")
        self.pwd_enc.delete('0','end')
    
    except core.DataOverflowError:
        messagebox.showwarning(
            title="Data Overflow",
            message="Data size is too big to fit inside this image"
        )

    except core.ReadImageError:
        messagebox.showerror(
            title="No Image Selected",
            message="Please select a source image to hide data."

        )