File size: 6,021 Bytes
00ae922
9f30ee2
9d868df
 
741fe95
24c5036
 
9f30ee2
12f7318
 
 
 
 
 
 
 
 
 
 
 
 
741fe95
 
9d868df
 
 
 
ac5c3ba
741fe95
9d868df
 
 
 
 
9f30ee2
741fe95
9d868df
 
 
 
 
 
 
 
9f30ee2
24c5036
 
 
 
f2af1db
741fe95
24c5036
9d868df
741fe95
 
9f30ee2
24c5036
 
 
9d868df
 
 
741fe95
9d868df
 
 
741fe95
9d868df
 
12f7318
24c5036
 
f2af1db
24c5036
9d868df
741fe95
9d868df
741fe95
 
 
 
 
 
 
 
 
 
 
9d868df
 
 
00ae922
24c5036
 
 
 
 
 
 
 
741fe95
24c5036
 
9d868df
00ae922
9d868df
741fe95
 
 
 
 
 
 
 
 
 
 
 
 
24c5036
 
 
 
 
 
 
 
 
 
 
741fe95
 
 
 
 
 
 
 
 
 
 
24c5036
 
 
 
 
 
 
 
 
 
741fe95
 
24c5036
 
 
 
 
 
 
 
741fe95
24c5036
4345f33
24c5036
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
import os
from fpdf import FPDF
from PyPDF2 import PdfMerger
from PIL import Image
import gradio as gr
#import aspose.words as aw
import pypandoc

def docx_to_pdf(docx_file, pdf_file):
    try:
        pypandoc.convert_file(
            docx_file, 'pdf', outputfile=pdf_file, extra_args=['--pdf-engine=pdflatex']
        )
    except OSError:
        # Download pandoc programmatically if it's not found
        print("Pandoc not found. Downloading pandoc...")
        pypandoc.download_pandoc()
        pypandoc.convert_file(
            docx_file, 'pdf', outputfile=pdf_file, extra_args=['--pdf-engine=pdflatex']
        )

# Function to add a single text input as a new page in an FPDF object
def add_text_as_page(pdf, text):
    pdf.add_page()
    pdf.set_auto_page_break(auto=True, margin=15)
    pdf.set_font("Arial", size=12)
    pdf.multi_cell(0, 10, text)

# Function to convert an image to a standalone PDF
def image_to_pdf(image_file):
    img = Image.open(image_file)
    pdf_path = image_file + ".pdf"
    img.convert('RGB').save(pdf_path)
    return pdf_path

# Function to merge multiple PDFs
def merge_pdfs(pdfs):
    merger = PdfMerger()
    for pdf in pdfs:
        merger.append(pdf)
    output_path = "merged_output.pdf"
    merger.write(output_path)
    merger.close()
    return output_path

# Convert DOCX to PDF
#def docx_to_pdf(docx_file, pdf_file):
#    doc = aw.Document(docx_file)
#    doc.save(pdf_file)

# Main function to process uploaded files and manual text inputs
def process_files_and_text(files, manual_texts, file_order):
    pdfs = []
    manual_text_pdf = "manual_texts.pdf"
    pdf = FPDF()

    # Process uploaded files according to file_order
    for file_name in file_order:
        file = next(f for f in files if f.name == file_name)
        file_name, file_extension = os.path.splitext(file.name)
        
        if file_extension.lower() == ".pdf":
            pdfs.append(file.name)
        
        elif file_extension.lower() == ".txt":
            text = file.read().decode("utf-8")
            add_text_as_page(pdf, text)
        
        elif file_extension.lower() == ".docx":
            docx_to_pdf(file.name, file_name + ".pdf")
            #pdf_file = file_name + ".pdf"
            #docx_to_pdf(file.name, pdf_file)
            pdfs.append(file_name + ".pdf")

        elif file_extension.lower() in [".png", ".jpg", ".jpeg"]:
            pdf_output = image_to_pdf(file.name)
            pdfs.append(pdf_output)

    # Add manual text inputs, with each input becoming a new page
    for text in manual_texts:
        if text.strip():  # Add only non-empty text
            add_text_as_page(pdf, text)

    # Save manual text inputs to PDF if any pages were added
    if len(pdf.pages) > 0:
        pdf.output(manual_text_pdf)
        pdfs.append(manual_text_pdf)

    # Merge all PDFs into one
    merged_pdf = merge_pdfs(pdfs)
    return merged_pdf

# Function to move items up or down in the list
def reorder_files(file_list, direction, index):
    if direction == "up" and index > 0:
        file_list[index], file_list[index - 1] = file_list[index - 1], file_list[index]
    elif direction == "down" and index < len(file_list) - 1:
        file_list[index], file_list[index + 1] = file_list[index + 1], file_list[index]
    return file_list

# Gradio interface function
def file_merger(files, texts, file_order):
    merged_pdf = process_files_and_text(files, texts, file_order)
    return merged_pdf

# Define Gradio interface
with gr.Blocks() as iface:
    gr.Markdown("### File Merger: Merge PDF, TXT, DOCX, Image files, and manual text inputs into a single PDF.")
    
    with gr.Row():
        file_input = gr.File(file_count="multiple", label="Upload Files")
        manual_text_inputs = gr.Textbox(
            lines=5, 
            placeholder="Enter text here...", 
            label="Manual Text Inputs", 
            elem_id="manual_text_inputs",
            interactive=True
        )
    
    file_list_state = gr.State([])
    file_display = gr.Textbox(
        label="Uploaded Files (Reorder Below)",
        interactive=False,
        lines=10
    )
    file_index = gr.Number(label="File Index to Move (Starting from 0)", value=0, interactive=True)
    with gr.Row():
        move_up_button = gr.Button("Move Up")
        move_down_button = gr.Button("Move Down")
    
    add_more_button = gr.Button("Add More Text")
    merge_button = gr.Button("Merge Files and Text")
    output = gr.File(label="Download Merged PDF")
    
    # Maintain a dynamic list for manual inputs
    manual_texts_state = gr.State(value=[])

    def add_text_to_state(current_text, state_texts):
        state_texts.append(current_text)
        return "", state_texts  # Clear the input box and update the state

    def update_file_list(files):
        file_names = [file.name for file in files]
        return file_names, "\n".join(file_names)

    def handle_reorder(file_list, direction, index):
        if 0 <= index < len(file_list):
            reordered_list = reorder_files(file_list, direction, index)
            return reordered_list, "\n".join(reordered_list)
        return file_list, "\n".join(file_list)  # No change if index is out of range

    # Add functionality to add more text
    add_more_button.click(add_text_to_state, inputs=[manual_text_inputs, manual_texts_state], outputs=[manual_text_inputs, manual_texts_state])

    # Update file list when files are uploaded
    file_input.change(update_file_list, inputs=[file_input], outputs=[file_list_state, file_display])

    # Move files up or down
    move_up_button.click(handle_reorder, inputs=[file_list_state, gr.Text("up"), file_index], outputs=[file_list_state, file_display])
    move_down_button.click(handle_reorder, inputs=[file_list_state, gr.Text("down"), file_index], outputs=[file_list_state, file_display])

    # Merge files and text
    merge_button.click(file_merger, inputs=[file_input, manual_texts_state, file_list_state], outputs=output)

iface.launch(share=True)