How to get Pdf Orientation using PyPDF2 - python

I'm using Python/Django.
PyPDF2 to read my current pdf.
I want to read a pdf that I have saved and get the orientation of a single page within the pdf.
I'm expecting to be able to determine if the page is either landscape or portrait.
tempoutpdffilelocation = settings.TEMPLATES_ROOT + nameOfFinalPdf
pageOrientation = pageToEdit.mediaBox
pdfOrientation = PdfFileReader(file(temppdffilelocation, "rb"))
# tempPdfOrientationPage = pdfOrientation.getPage(numberOfPageToEdit).mediaBox
print("existing pdf width: ")
# print(existing_pdf.getPage(numberOfPageToEdit).getWidth)
# print("get page size with rotation")
# print(tempPdfOrientationPage.getPageSizeWithRotation)
existing_pdf = pdfOrientation.getPage(numberOfPageToEdit).mediaBox
# print(pageOrientation)
if pageOrientation.getUpperRight_x() - pageOrientation.getUpperLeft_x() > pageOrientation.getUpperRight_y() - pageOrientation.getLowerRight_y():
print('Landscape')
print(pageOrientation)
# print(pdfOrientation.getWidth())
else:
print('Portrait')
print(pageOrientation)
# print(pdfOrientation.getWidth())
# create a new PDF with Reportlab
can = canvas.Canvas(packet, pagesize=letter)
The last line setting the pagesize=letter what I want to determine based on my current pdf.
And here's my imports:
from PyPDF2 import PdfFileWriter, PdfFileReader
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter, landscape
import urllib
I've tried pyPdf .mediaBox but that always returns the same value of the expected file size, not the actual size. And pyPdf is outdated.
As you can see I've also tried getWidth and withRotation.
I would think there's be an easy way for PyPDF2 PdfFileReader to determine the orientation of a selected object.
Any help is appreciated. Thanks.

I used simply "/Rotate" attribute of the page:
OrientationDegrees = pdf.getPage(numberOfPageToEdit).get('/Rotate')
it can be 0, 90, 180, 270 or None

The rotate attribute will override the mediaBox settings. To account for this, check the page rotation before making final judgement. Note the text too can be rotated.
from PyPDF2 import PdfFileReader
pdf_path = 'yourPDFname.pdf'
pdf_reader = PdfFileReader(pdf_path)
deg = pdf_reader.getPage(0).get('/Rotate')
page = pdf_reader.getPage(0).mediaBox
if page.getUpperRight_x() - page.getUpperLeft_x() > page.getUpperRight_y() -page.getLowerRight_y():
if deg in [0,180,None]:
print('Landscape')
else:
print('Portrait')
else:
if deg in [0,180,None]:
print('Portrait')
else:
print('Landscape')

You can detect it by using this code snippet:
from PyPDF2 import PdfFileReader
pdf = PdfFileReader(file('example.pdf'))
page = pdf.getPage(0).mediaBox
if page.getUpperRight_x() - page.getUpperLeft_x() > page.getUpperRight_y() -
page.getLowerRight_y():
print('Landscape')
else:
print('Portrait')

This one works, fully tested:
import PyPDF2
from PyPDF2 import PdfFileReader
pdf = PdfFileReader(open('YourPDFname.pdf', 'rb'))
page = pdf.getPage(0).mediaBox
if page.getUpperRight_x() - page.getUpperLeft_x() > page.getUpperRight_y() -
page.getLowerRight_y():
print('Landscape')
else:
print('Portrait')

Related

Draw lines using PyPDF

I am currently merging two pages into a single page in PyPDF3 but I need to draw a line in the middle of the two pages. Is this possible? Below is the sample code for reference. Thanks in advance!
from PyPDF3 import PdfFileWriter, PdfFileReader
from PyPDF3.pdf import PageObject
pdf_file = "Plan.pdf"
inputPDF = PdfFileReader(open(pdf_file, "rb"), strict=False)
outputPDF = PdfFileWriter()
for x in range(0, inputPDF.numPages, 2):
page1 = inputPDF.getPage(x).rotateClockwise(90)
page2 = inputPDF.getPage(x + 1).rotateClockwise(90)
total_width = max([page1.mediaBox.upperRight[0],page2.mediaBox.upperRight[0]])
total_height = page1.mediaBox.upperRight[1] + page2.mediaBox.upperRight[1]
new_page = PageObject.createBlankPage(None, total_width, total_height)
new_page.mergeTranslatedPage(page1, 0, page1.mediaBox.upperRight[1])
new_page.mergeTranslatedPage(page2, 0, 0)
outputPDF.addPage(new_page.rotateCounterClockwise(90))
outputFile = "Merged_Plan.pdf"
outputPDF.write(open(outputFile, "wb"))
You can use the Line annotation: https://pypdf.readthedocs.io/en/latest/user/adding-pdf-annotations.html#line
It was recently added to pypdf. You might need to update your installed version.
I recommend to switch away from PyPDF2 / PyPDF3 / PyPDF4 towards pypdf.

PDF range split

I am trying to split a PDF file by finding a key word of text and then grabbing that page the key word is on and the following 4 pages after, so total of 5 pages, and splitting them from that original PDF and putting them into their own PDF so the new PDF will have those 5 pages only, then loop through again find that key text again because its repeated further down the original PDF X amount of times, grabbing that page plus the 4 after and putting into its own PDF.
Example: key word is found on page 7 the first loop so need page 7 and also pages 8-11 and put those 5 pages 7-11 into a pdf file,
the next loop they key word is found on page 12 so need page 12 and pages 13-16 so pages 12-16 split onto their own pdf at this point it has created 2 separate pdfs
the below code finds the key word and puts it into its own pdf file but only got it for that one page not sure how to include the range
import os
from PyPDF2 import PdfFileReader, PdfFileWriter
path = "example.pdf"
fname = os.path.basename(path)
reader = PdfFileReader(path)
for page_number in range(reader.getNumPages()):
writer = PdfFileWriter()
writer.addPage(reader.getPage(page_number))
text = reader.getPage(page_number).extractText()
text_stripped = text.replace("\n", "")
print(text_stripped)
if text_stripped.find("Disregarded Branch") != (-1):
output_filename = f"{fname}_page_{page_number + 1}.pdf"
with open(output_filename, "wb") as out:
writer.write(out)
print(f"Created: {output_filename}")
disclaimer: I am the author of borb, the library used in this answer.
I think your question comes down to 2 common functionalities:
find the location of a given piece of text
merge/split/extract pages from a PDF
For the first part, there is a good tutorial in the examples repo.
You can find it here. I'll repeat one of the examples here for completeness.
import typing
from borb.pdf.document.document import Document
from borb.pdf.pdf import PDF
from borb.toolkit.text.simple_text_extraction import SimpleTextExtraction
def main():
# read the Document
doc: typing.Optional[Document] = None
l: SimpleTextExtraction = SimpleTextExtraction()
with open("output.pdf", "rb") as in_file_handle:
doc = PDF.loads(in_file_handle, [l])
# check whether we have read a Document
assert doc is not None
# print the text on the first Page
print(l.get_text_for_page(0))
if __name__ == "__main__":
main()
This example extracts all the text from page 0 of the PDF. of course you could simply iterate over all pages, and check whether a given page contains the keyword you're looking for.
For the second part, you can find a good example in the examples repository. This is the link. This example (and subsequent example) takes you through the basics of frankensteining a PDF from various sources.
The example I copy/paste here will show you how to build a PDF by alternatively picking a page from input document 1, and input document 2.
import typing
from borb.pdf.document.document import Document
from borb.pdf.pdf import PDF
import typing
from decimal import Decimal
from borb.pdf.document.document import Document
from borb.pdf.page.page import Page
from borb.pdf.pdf import PDF
def main():
# open doc_001
doc_001: typing.Optional[Document] = Document()
with open("output_001.pdf", "rb") as pdf_file_handle:
doc_001 = PDF.loads(pdf_file_handle)
# open doc_002
doc_002: typing.Optional[Document] = Document()
with open("output_002.pdf", "rb") as pdf_file_handle:
doc_002 = PDF.loads(pdf_file_handle)
# create new document
d: Document = Document()
for i in range(0, 10):
p: typing.Optional[Page] = None
if i % 2 == 0:
p = doc_001.get_page(i)
else:
p = doc_002.get_page(i)
d.append_page(p)
# write
with open("output_003.pdf", "wb") as pdf_file_handle:
PDF.dumps(pdf_file_handle, d)
if __name__ == "__main__":
main()
You've almost got it!
import os
from PyPDF2 import PdfFileReader, PdfFileWriter
def create_4page_pdf(base_pdf_path, start):
reader = PdfFileReader(base_pdf_path)
writer = PdfFileWriter()
for i in range(4):
index = start + i
if index < len(reader.pages):
page = reader.pages[index]
writer.addPage(page)
fname = os.path.basename(base_pdf_path)
output_filename = f"{fname}_page_{start + 1}.pdf"
with open(output_filename, "wb") as out:
writer.write(out)
print(f"Created: {output_filename}")
def main(base_pdf_path="example.pdf"):
base_pdf_path = "example.pdf"
reader = PdfFileReader(base_pdf_path)
for page_number, page in enumerate(reader.pages):
text = page.extractText()
text_stripped = text.replace("\n", "")
print(text_stripped)
if text_stripped.find("Disregarded Branch") != (-1):
create_4page_pdf(base_pdf_path, page_number)

Why is PyPDF2 and reportlab removing spaces when inserting text?

I am trying to insert formatted text into the last page of my PDF. I am using the PyPDF2 and reportlab libraries to do this. I am using Python 2.7.
For some reason the text gets inserted without spaces and on a new line for every character (not for every CRLF). Where did I go wrong or is there a better way to do this?
Thanks.
PYTHON CODE:
# Libs
from PyPDF2 import PdfFileWriter, PdfFileReader, PdfFileMerger;
from reportlab.pdfgen import canvas; # PDF Editor 1
from reportlab.lib.pagesizes import letter; # PDF Editor 2
from reportlab.lib.units import inch; # PDF Editor 3
uniOCRText = 'This is a test string.';
# Create a new PDF with Reportlab
packet = io.BytesIO();
can = canvas.Canvas(packet, pagesize=letter);
textobject = can.beginText();
textobject.setTextOrigin(inch, 2.5*inch);
textobject.setFont("Times-Roman", 10);
i = 0;
for line in uniOCRText:
i = i + 1;
print("i = " + str(i) + " - line = " + str(line));
textobject.textLine(line); # Error here deletes spaces!!!
textobject.setFillGray(0.4);
can.drawText(textobject);
can.save();
# Move to the beginning of the StringIO buffer
packet.seek(0);
new_pdf = PdfFileReader(packet);
# Add watermark
output = PdfFileWriter();
page = new_pdf.getPage(0);
output.addPage(page);
tempFolder = "Temp/TempPDF.pdf";
outputStream = open(tempFolder, "wb");
output.write(outputStream);
outputStream.close();
# Create a Merger PDF
merger = PdfFileMerger();
merger.append(PdfFileReader(open(pdfFileFromLoc, 'rb')));
merger.append(PdfFileReader(open(tempFolder, 'rb')));
merger.write(pdfFileDestLoc);
>>> for line in 'hello':
... print(line)
...
h
e
l
l
o
You are iterating over characters. Calling the variable line does not make the interpreter iterate over lines. You have to splitlines() and iterate over the resulting list:
>>> for line in 'hello\nbye'.splitlines():
... print(line)
...
hello
bye

Convert plain text to PDF in Python

For my project, I get a plain text file (report.txt) from another program. It is all formatted in plain text. If you open it in Notepad, it looks nice (as much as a plain text file can). When I open the file in Word and show the paragraphs, I see the ... for spaces and the backwards P for pararaph.
I need to convert this file to PDF and add some other PDF pages to make one final PDF. All this happens in Python.
I am having trouble converting the report.txt to pdf. I have ReportLab, and am able to read the file and make a few changes (like change the text to Courier), but the spacing gets lost. When the file gets read, it appears to strip any extra spaces.
Questions:
a) is there an easier way to convert the report.txt to pdf?
b) If not, is there a way to keep my spaces when I read the file?
c) Or is there a parameter I'm missing from my paragraph style that will keep the original look?
Here's my code:
# ------------------------------------
# Styles
# ------------------------------------
styleSheet = getSampleStyleSheet()
mystyle = ParagraphStyle(name='normal',fontName='Courier',
fontSize=10,
alignment=TA_JUSTIFY,
leading=1.2*12,
parent=styleSheet['Normal'])
#=====================================================================================
model_report = 'report.txt'
# Create document for writing to pdf
doc = SimpleDocTemplate(str(pdfPath), \
rightMargin=40, leftMargin=40, \
topMargin=40, bottomMargin=25, \
pageSize=A4)
doc.pagesize = portrait(A4)
# Container for 'Flowable' objects
elements = []
# Open the model report
infile = file(model_report).read()
report_paragraphs = infile.split("\n")
for para in report_paragraphs:
para1 = '<font face="Courier" >%s</font>' % para
elements.append(Paragraph(para1, style=mystyle))
doc.build(elements)
I've created a small helper function to convert a multi-line text to a PDF file in a "report look" by using a monospaced font. Too long lines are wrapped at spaces so that it will fit the page width:
import textwrap
from fpdf import FPDF
def text_to_pdf(text, filename):
a4_width_mm = 210
pt_to_mm = 0.35
fontsize_pt = 10
fontsize_mm = fontsize_pt * pt_to_mm
margin_bottom_mm = 10
character_width_mm = 7 * pt_to_mm
width_text = a4_width_mm / character_width_mm
pdf = FPDF(orientation='P', unit='mm', format='A4')
pdf.set_auto_page_break(True, margin=margin_bottom_mm)
pdf.add_page()
pdf.set_font(family='Courier', size=fontsize_pt)
splitted = text.split('\n')
for line in splitted:
lines = textwrap.wrap(line, width_text)
if len(lines) == 0:
pdf.ln()
for wrap in lines:
pdf.cell(0, fontsize_mm, wrap, ln=1)
pdf.output(filename, 'F')
This is how you would use this function to convert a text file to a PDF file:
input_filename = 'test.txt'
output_filename = 'output.pdf'
file = open(input_filename)
text = file.read()
file.close()
text_to_pdf(text, output_filename)
ReportLab is the usual recommendation-- as you can see from the "Related" questions on the right side of this page.
Have you tried creating text with just StyleSheet['Normal']? I.e., if you get proper-looking output with the following, the problem is somehow with your style.
Paragraph(para1, style=StyleSheet['Normal'])
For converting text or text file into pdf, module fpdf shall be installed using pip install fpdf in command-line Interface.
run the below code and you will find the pdf file in folder-
from fpdf import FPDF
pdf = FPDF()
# Add a page
pdf.add_page()
# set style and size of font
# that you want in the pdf
pdf.set_font("Arial", size = 15)
# open the text file in read mode
f = open("path where text file is stored\\File_name.txt", "r")
# insert the texts in pdf
for x in f:
pdf.cell(50,5, txt = x, ln = 1, align = 'C')
# save the pdf with name .pdf
pdf.output("path where you want to store pdf file\\File_name.pdf")
reference: https://www.geeksforgeeks.org/convert-text-and-text-file-to-pdf-using-python/
I had similar issue. I solved with this code:
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
from reportlab.lib.utils import ImageReader
from PIL import Image
# .....
# ..... some exta code unimportant for this issue....
# ....
# here it is
ptr = open("tafAlternos.txt", "r") # text file I need to convert
lineas = ptr.readlines()
ptr.close()
i = 750
numeroLinea = 0
while numeroLinea < len(lineas):
if numeroLinea - len(lineas) < 60: # I'm gonna write every 60 lines because I need it like that
i=750
for linea in lineas[numeroLinea:numeroLinea+60]:
canvas.drawString(15, i, linea.strip())
numeroLinea += 1
i -= 12
canvas.showPage()
else:
i = 750
for linea in lineas[numeroLinea:]:
canvas.drawString(15, i, linea.strip())
numeroLinea += 1
i -= 12
canvas.showPage()
Pdf looks exactly same as original text file
You can create a canvas with pdf_canvas = canvas.Canvas('output_file.pdf') and generate the PDF with pdf_canvas.save().

Place image over PDF

How can I place an image over an existing PDF file at an specific coordinate location. The pdf represents a drawing sheet with one page. The image will be scaled. I'm checking ReportLab but can't find the answer. Thanks.
Its been 5 years, I think these answers need some TLC. Here is a complete solution.
The following is tested with Python 2.7
Install dependencies
pip install reportlab
pip install pypdf2
Do the magic
from reportlab.pdfgen import canvas
from PyPDF2 import PdfFileWriter, PdfFileReader
# Create the watermark from an image
c = canvas.Canvas('watermark.pdf')
# Draw the image at x, y. I positioned the x,y to be where i like here
c.drawImage('test.png', 15, 720)
# Add some custom text for good measure
c.drawString(15, 720,"Hello World")
c.save()
# Get the watermark file you just created
watermark = PdfFileReader(open("watermark.pdf", "rb"))
# Get our files ready
output_file = PdfFileWriter()
input_file = PdfFileReader(open("test2.pdf", "rb"))
# Number of pages in input document
page_count = input_file.getNumPages()
# Go through all the input file pages to add a watermark to them
for page_number in range(page_count):
print "Watermarking page {} of {}".format(page_number, page_count)
# merge the watermark with the page
input_page = input_file.getPage(page_number)
input_page.mergePage(watermark.getPage(0))
# add page from input file to output document
output_file.addPage(input_page)
# finally, write "output" to document-output.pdf
with open("document-output.pdf", "wb") as outputStream:
output_file.write(outputStream)
References:
pypdf project page:
https://pypi.org/project/pypdf/
Reportlab docs:
http://www.reportlab.com/apis/reportlab/2.4/pdfgen.html
Reportlab complete user guide:
https://www.reportlab.com/docs/reportlab-userguide.pdf
https://pypi.org/project/pypdf/:
from pypdf import PdfWriter, PdfReader
writer = PdfWriter()
reader = PdfReader("document1.pdf")
watermark = PdfReader("watermark.pdf")
page = reader.pages[0]
page.merge_page(watermark.pages[0])
writer.add_page(page)
# finally, write the results to disk
with open("document-output.pdf", "wb") as fp:
writer.write(fp)
I think it's like watermark, see the documentation for more information
I combined ReportLab and pypdf to insert an image directly without having to generate the PDF up front:
from pyPdf import PdfFileWriter, PdfFileReader
from reportlab.pdfgen import canvas
from StringIO import StringIO
# Using ReportLab to insert image into PDF
imgTemp = StringIO()
imgDoc = canvas.Canvas(imgTemp)
# Draw image on Canvas and save PDF in buffer
imgPath = "path/to/img.png"
imgDoc.drawImage(imgPath, 399, 760, 160, 160) ## at (399,760) with size 160x160
imgDoc.save()
# Use PyPDF to merge the image-PDF into the template
page = PdfFileReader(file("document.pdf","rb")).getPage(0)
overlay = PdfFileReader(StringIO(imgTemp.getvalue())).getPage(0)
page.mergePage(overlay)
#Save the result
output = PdfFileWriter()
output.addPage(page)
output.write(file("output.pdf","w"))
Thx to the previous answers. My way with python3.4
# -*- coding: utf-8 -*-
from io import BytesIO
from PyPDF2 import PdfFileWriter, PdfFileReader
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
def gen_pdf():
# there are 66 slides (1.jpg, 2.jpg, 3.jpg...)
path = 'slades/{0}.jpg'
pdf = PdfFileWriter()
for num in range(1, 67): # for each slide
# Using ReportLab Canvas to insert image into PDF
imgTemp = BytesIO()
imgDoc = canvas.Canvas(imgTemp, pagesize=A4)
# Draw image on Canvas and save PDF in buffer
imgDoc.drawImage(path.format(num), -25, -45)
# x, y - start position
# in my case -25, -45 needed
imgDoc.save()
# Use PyPDF to merge the image-PDF into the template
pdf.addPage(PdfFileReader(BytesIO(imgTemp.getvalue())).getPage(0))
pdf.write(open("output.pdf","wb"))
if __name__ == '__main__':
gen_pdf()
This is quite easy to do with PyMuPDF without merging two PDFs:
import fitz
src_pdf_filename = 'source.pdf'
dst_pdf_filename = 'destination.pdf'
img_filename = 'barcode.jpg'
# http://pymupdf.readthedocs.io/en/latest/rect/
# Set position and size according to your needs
img_rect = fitz.Rect(100, 100, 120, 120)
document = fitz.open(src_pdf_filename)
# We'll put image on first page only but you could put it elsewhere
page = document[0]
page.insertImage(img_rect, filename=img_filename)
# See http://pymupdf.readthedocs.io/en/latest/document/#Document.save and
# http://pymupdf.readthedocs.io/en/latest/document/#Document.saveIncr for
# additional parameters, especially if you want to overwrite existing PDF
# instead of writing new PDF
document.save(dst_pdf_filename)
document.close()
This is what worked for me
from PyPDF2 import PdfFileWriter, PdfFileReader
def watermarks(temp, watermar,new_file):
template = PdfFileReader(open(temp, 'rb'))
wpdf = PdfFileReader(open(watermar, 'rb'))
watermark = wpdf.getPage(0)
for i in xrange(template.getNumPages()):
page = template.getPage(i)
page.mergePage(watermark)
output.addPage(page)
with open(new_file, 'wb') as f:
output.write(f)

Categories