Splitting PDF to make multiple PDFs less than 20Mb

Viewed 885

I am new to Python programming but have over 5 years of coding experience.

I have to split large PDFs into smaller ones less than 20Mb. I have currently written code with the following logic.

  1. Find the file size. Divide the file size by 20 and round the number, lets call this number partitions. Ex: File Size 45 then I divide 45 by 20 and round the value from 2.25 to 3.
  2. Find the number of pages. Let's say there are around 500 pages.
  3. Divide the number of pages by the partitions (3). So there will be 3 sets, from Pages 1 to 171, 172 to 343 and 344 to 515.
  4. I split the PDF into number of partitions as mentioned above.

The challenge I am facing is that all the pages are not of the same size so some PDFs become really small and some might exceed the 20Mb limit.

Can someone suggest any solution to this? Even a better approach is welcome.

3 Answers

I don't know which library you are working with, but maybe it could work like this:

Open a PDF file. Then create a new one and add pages until you have reached the 20mb or stop a little bit earlier. The only problem here is that you don't know the size of the page before you have added it and saved the file to check the file size again.

But I am not confident with python and PDF's so maybe someone else have a better approach for you.

Here is an algorithm that would work. The implementation is just a matter of reading the documentation of that library (which I don't know) and are noted as ....

input_pdf = ...
size_of_input_pdf = ...
target_size = 20*1024*1024 # 20 MB
pages = ... # a list of all the pages contained in the input_pdf

# Check the weight of each individual page.
list_of_weights = []

for n, page in enumerate(pages):
    file_name = f"whatever_temporary_name_{n}"
    create_new_pdf(file_name, page)
    size_of_that_single_page = ...
    list_of_weights.append(size_of_that_single_page)
    os.remove(file_name)

# Take note of which page to put in which partition.
partition_weight = 0
list_of_pages_to_merge = [[]]

for m, weigh in enumerate(list_of_weights):
    if partition_weight + weight < target_size:
        partition_weight += weight # add current weight.
        list_of_pages_to_merge[-1].append(m) # add current page to partition.
    else:
        partition_weight = weight # reset weight.
        list_of_pages_to_merge.append([m]) # prepare next pages list for next partition.

# Now create the actual documents.
for partition, pages in enumerate(list_of_pages_to_merge):
    file_name = f"original_fine_name_partition_{partition}"
    sum_all_pages = ... # no clue how you'll do that.
    create_new_pdf(file_name, sum_all_pages)

Is performance critical?

If not, you could write to disk after each page is added, to track progress.

Something like.

let source be original PDF
let y and z be target output PDF files.
let n = 0
let c = page count of source

load source
create a new empty PDF, let this be y

while(n < c):
  import page n from source to y
  save y to disk
  if(y > 20MB):
    delete y
    backup z (this is one of your output files...)
    start new y and re-import page n
  else:
    copy y to z
  ++n

One obvious bug with the above is if any one page itself is over 20MB, not sure how you would handle that in your particular case.

Related