Good day.
I am trying to create a for loop to read the lines of a file until a condition is met so it can write these lines in a image and i plan to do this with every line of the file, like the example below:
Number: 123456789
Connecting to Database
no rows selected
Disconnecting from Database
Number: 9876543211
Connecting to Database
1111;48446511911986;Helen;Thursday
2222;48498489489489;Helen;Friday
3333;84545221185986;Helen;Monday
Disconnecting from Database
Number: 963852741
Connecting to Database
1234;123456789456123;Clyde;Friday
4321;123456789456123;Clyde;Thuesday
1423;123456789456123;Clyde;Sunday
2341;123456789456123;Clyde;Friday
Disconnecting from Database
Number: 456987321
Connecting to Database
no rows selected
Disconnecting from Database
As you can see every time the word Database shows up for the second time the next line is about a new number information, so i tried using the word database as a parameter for the loop below.
import os
import PIL
import PIL.Image as Image
import PIL.ImageDraw as ImageDraw
import PIL.ImageFont as ImageFont
img = Image.open("C:/Users/dir/image/black_background.png")
draw = ImageDraw.Draw(img)
fonts_dir = os.path.join(os.environ['WINDIR'], 'Fonts')
font_name = 'consolab.ttf'
font = ImageFont.truetype(os.path.join(fonts_dir, font_name), 15)
x = 2
y = 0
next_print_count = 0
filename = "info.txt"
Number = ""
for line in open(filename):
if 'Number:' in line:
Number= line.split(" ",1)[1].strip()
if 'Testing ' in line:
line = ""
draw.text((x, y),line,(200,200,200),font=font)
y += 15
img.save(Number + ".png")
Problem is that every time it starts a new file it also prints the information from the previous lines as well. How do i avoid that?
I also tried to use NUMBER as a parameter as well but it didn't work.
you need to delete the current img and draw object every time line is "Disconnecting from Database" and make new objects after deleting them. In your original code, you were also saving the image every line, which is not good either. See the code below.
import os
import PIL
import PIL.Image as Image
import PIL.ImageDraw as ImageDraw
import PIL.ImageFont as ImageFont
fonts_dir = os.path.join(os.environ['WINDIR'], 'Fonts')
font_name = 'consolab.ttf'
font = ImageFont.truetype(os.path.join(fonts_dir, font_name), 15)
x = 2
y = 0
next_print_count = 0
filename = r'info.txt'
Number = ""
with open(filename) as f:
img = Image.open("C:\Users\Public\Pictures\Sample Pictures/Chrysanthemum.jpg")
draw = ImageDraw.Draw(img)
for line in f:
if 'Number:' in line:
Number= line.split(" ",1)[1].strip()
if 'Testing ' in line:
line = ""
draw.text((x, y),line,(200,200,200),font=font)
y += 15
if 'Disconnecting from Database' in line:
img.save(Number + ".png")
del draw, img
img = Image.open("C:\Users\Public\Pictures\Sample Pictures/Chrysanthemum.jpg")
draw = ImageDraw.Draw(img)
y=0
results in (only showing two samples images here, but 4 are created)
Related
I am taking a screenshot, and then I need to reference the shot I just took so I can translate what's inside it.
When I directly pass a file location, e.g "filex.png", to readtext, it works, but I just need it to pass the written file into it.
import easyocr
import pyautogui
import time
import cv2
import numpy as np
reader = easyocr.Reader(['en'])
tag = 1
for i in range(2):
time.sleep(4)
image = pyautogui.screenshot(region=(630,400,650,130))
image = cv2.cvtColor(np.array(image),
cv2.COLOR_RGB2BGR)
tag+=1
img = cv2.imwrite(f"image{tag}.png", image)
results = reader.readtext(img)
text=""
for result in results:
text += result[1] + " "
print(text)
In answer to your specific question, I think you're looking for something like:
import easyocr
import pyautogui
import time
import cv2
import numpy as np
reader = easyocr.Reader(['en'])
tag = 1
for i in range(2):
time.sleep(4)
image = pyautogui.screenshot(region=(630, 400, 650, 130))
image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
tag += 1
f_name = f"image{tag}.png"
cv2.imwrite(f_name, image)
results = reader.readtext(f_name)
text = ""
for result in results:
text += result[1] + " "
print(text)
You can just store your file name in a variable in pass it to both imwrite and readtext
There are other options as well, depending on what information you need access to within the program, and how quickly you need to process your data.
Option: Pass the np.array directly to readtext
image = pyautogui.screenshot(region=(630, 400, 650, 130))
image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
results = reader.readtext(image)
Option: Pass the data from the written file to the readtext function.
f_name = f"image{tag}.png"
cv2.imwrite(f_name, image)
with open(f_name, 'rb') as f:
results = reader.readtext(f.read())
import pyautogui
import easyocr
import numpy as np
reader = easyocr.Reader(['en'],gpu=False)
im = pyautogui.screenshot(region=(630,400,650,130)
result = reader.readtext(np.array(im),detail = 0)
just pass the pyautogui image as np.array
I have a list of pdf files and I need to highlight specific text on each page of these files and save a snapshot for each of the text instances.
So far I am able to highlight the text and save the entire page of a pdf file as a snapshot. But, I want to find the position of highlighted text and take a zoomed in the snapshot which will be more detailed compared to the full page snapshot.
I'm pretty sure there must be a solution to this problem. I am new to Python and hence I am not able to find it. I would be really grateful if someone can help me out with this.
I have tried using PyPDF2, Pymupdf libraries but I couldn't figure out the solution. I also tried highlighting by providing coordinates which works but couldn't find a way to get these coordinates as output.
[![Sample snapshot from the code[![\]\[1\]][1]][1]][1]
#import PyPDF2
import os
import fitz
from wand.image import Image
import csv
#import re
#from pdf2image import convert_from_path
check = r'C:\Users\Pradyumna.M\Desktop\Pradyumna\Automation\Intel Bytes\Create Source Docs\Sample Check 8 Apr 2019'
dir1 = check + '\\Source Docs\\'
dir2 = check + '\\Output\\'
dir = [dir1, dir2]
for x in dir:
try:
os.mkdir(x)
except FileExistsError:
print("Directory ", x, " already exists")
### READ PDF FILE
with open('upload1.csv', newline='') as myfile:
reader = csv.reader(myfile)
for row in reader:
rowarray = '; '.join(row)
src = rowarray.split("; ")
file = check + '\\' + src[4] + '.pdf'
print(file)
#pdfFileObj = open(file,'rb')
#pdfReader = PyPDF2.PdfFileReader(pdfFileObj)
#print("Total number of pages: " + str(pdfReader.numPages))
doc = fitz.open(file)
print(src[5])
for i in range(int(src[5])-1, int(src[5])):
i = int(i)
page = doc[i]
print("Processing page: " + str(i))
text = src[3]
#SEARCH TEXT
print("Searching: " + text)
text_instances = page.searchFor(text)
for inst in text_instances:
highlight = page.addHighlightAnnot(inst)
file1 = check + '\\Output\\' + src[4] + '_output.pdf'
print(file1)
doc.save(file1, garbage=4, deflate=True, clean=True)
### Screenshot
with(Image(filename=file1, resolution=150)) as source:
images = source.sequence
newfilename = check + "\\Source Docs\\" + src[0] + '.jpeg'
Image(images[i]).save(filename=newfilename)
print("Screenshot of " + src[0] + " saved")
"couldn't find a way to get these coordinates as output"
- you can get the coordinates out by doing this:
for inst in text_instances:
print(inst)
inst are fitz.Rect objects which contain the top left and bottom right coordinates of the piece of text that was found. All the information is available in the docs.
I managed to highlight points and also save a cropped region using the following snippet of code. I am using python 3.7.1 and my output for fitz.version is ('1.14.13', '1.14.0', '20190407064320').
import fitz
doc = fitz.open("foo.pdf")
inst_counter = 0
for pi in range(doc.pageCount):
page = doc[pi]
text = "hello"
text_instances = page.searchFor(text)
five_percent_height = (page.rect.br.y - page.rect.tl.y)*0.05
for inst in text_instances:
inst_counter += 1
highlight = page.addHighlightAnnot(inst)
# define a suitable cropping box which spans the whole page
# and adds padding around the highlighted text
tl_pt = fitz.Point(page.rect.tl.x, max(page.rect.tl.y, inst.tl.y - five_percent_height))
br_pt = fitz.Point(page.rect.br.x, min(page.rect.br.y, inst.br.y + five_percent_height))
hl_clip = fitz.Rect(tl_pt, br_pt)
zoom_mat = fitz.Matrix(2, 2)
pix = page.getPixmap(matrix=zoom_mat, clip = hl_clip)
pix.writePNG(f"pg{pi}-hl{inst_counter}.png")
doc.close()
I tested this on a sample pdf that i peppered with "hello":
Some of the outputs from the script:
I composed the solution out of the following pages of the documentation:
Tutorial page to get introduced into the library
page.searchFor to figure out the return type of the searchFor method
fitz.Rect to understand what the returned objects from page.searchFor are
Collection of Recipes page (called faq in the URL) to figure out how to crop and save part of a pdf page
I am trying to copy elements of a doc from one doc file to other. The text part is easy, the images is where it gets tricky.
Attaching an image to explain the structure of the doc: Just some text and 1 image.
from docx import Document
import io
doc = Document('/Users/neha/Desktop/testing.docx')
new_doc = Document()
for elem in doc.element.body:
new_doc.element.body.append(elem)
new_doc.save('/Users/neha/Desktop/out.docx')
This gets me the whole structure of the doc in the new_doc but the image is still blank. Image below:
Good thing is I have the blank image in the right place so I thought of getting the byte level data from the previous image and insert it in the new doc. Here is how I extended the above code:
from docx import Document
import io
doc = Document('/Users/neha/Desktop/testing.docx')
new_doc = Document()
for elem in doc.element.body:
new_doc.element.body.append(elem)
im = doc.inline_shapes[0]
blip = im._inline.graphic.graphicData.pic.blipFill.blip
rId = blip.embed
doc_part = doc.part
image_part = doc_part.related_parts[rId]
bytes = image_part._blob #Here I get the byte level data for the image
im2 = new_doc.inline_shapes[0]
blip2 = im2._inline.graphic.graphicData.pic.blipFill.blip
rId2 = blip2.embed
document_part2 = new_doc.part
document_part2.related_parts[rId2]._blob = bytes
new_doc.save('/Users/neha/Desktop/out.docx')
But the image still shows empty in the new_doc. What should I do from here?
I figured out a solution a couple of days back. However the text loses formatting using this way, but the images are correctly placed.
So the idea is, for para in paras for the source doc, if there is text, I write it to dest doc. And if there is an inline image present, I add a unique identifier at that place in the dest doc (refer here to see how these identifiers work, and contexts in docxtpl). These identifiers and docxtpl proved to be particularly useful here. And then using those unique identifiers I create a 'context' (as shown below) which is basically a map mapping the unique identifier to its particular InlineImage, and finally I render this context..
Below is my code (Apologies for the unnecessary indentation, I copied it directly from my text editor, and shift+tab doesn't work here :P)
from docxtpl import DocxTemplate, InlineImage
import Document
import io
import xml.etree.ElementTree as ET
dest = DocxTemplate()
source = Document(source_path)
context = {}
ims = [im for im in source.inline_shapes]
im_addresses = []
im_streams = []
count = 0
for im in ims:
blip = im._inline.graphic.graphicData.pic.blipFill.blip
rId = blip.embed
doc_part = source.part
image_part = doc_part.related_parts[rId]
byte_data = image_part._blob
image_stream = io.BytesIO(byte_data)
im_streams.append(image_stream)
image_name = self.img_path+"img_"+"_"+str(count)+".jpeg"
with open(image_name, "wb") as fh:
fh.write(byte_data)
fh.close()
im_addresses.append(image_name)
count += 1
paras = source.paragraphs
im_idx = 0
for para in paras:
p = dest.add_paragraph()
r = p.add_run()
if(para.text):
r.add_text(para.text)
root = ET.fromstring(para._p.xml)
namespace = {'wp':"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"}
inlines = root.findall('.//wp:inline',namespace)
if(len(inlines) > 0):
uid = "img_"+str(im_idx)
r.add_text("{{ " + uid + " }}")
context[uid] = InlineImage(dest,im_addresses[im_idx])
im_idx += 1
try:
dest.render(context)
except Exception as e:
print(e)
dest.save(dest_path)
PS: If a paragraph has two images, this code will prove to be sub-optimal.. One will have to make some change in the following:
if(len(inlines) > 0):
uid = "img_"+str(im_idx)
r.add_text("{{ " + uid + " }}")
context[uid] = InlineImage(dest,im_addresses[im_idx])
im_idx += 1
Will have to add a for loop inside the if statement as well. Since I didn't need as usually my images were big enough, so they always came in different paragraphs. Just a side note for anyone who may need it..
Cheers!
You could try:
Extracting the images from the first document by unzipping the .docx file (per How can I search a word in a Word 2007 .docx file?)
Save those images to the file system (as foo.png, for instance)
Generate the new .docx file with Python and add the .png file using document.add_picture('foo.png').
This problem is solved by this package https://docxtpl.readthedocs.io/en/latest/
I am working on an art project and am converting text to binary to images.
So far, I have what I think is the hard part done and am almost there ...
except i'm not quite sure how to approach this last bit of the problem:
I have a series of images displayed one after another but I need to wrap the images so that they are formatted to all fit on a page of A4 (printer paper) in landscape orientation.
How should I approach this?
I have the basic script to convert text to binary to images.
One additional issue I'm seeing is that when I run the script on the entire passage, too many files are opened and I receive an error(shown below):
Traceback (most recent call last):
File "ascii_to_binary.py", line 73, in <module>
imgs = [Image.open(i) for i in list_im]
File "/home/odroid/.virtualenvs/cv/local/lib/python2.7/site-packages/PIL/Image.py", line 2410, in open
fp = builtins.open(filename, "rb")
IOError: [Errno 24] Too many open files: 'open_circle.png'
Here's the script in its entirety for reference:
import numpy as np
import cv2
import imutils
import sys
from PIL import Image
open_circle = 'open_circle.png'
closed_circle = 'closed_circle.png'
diamond = 'diamond.png'
text1 = open("filename.text", "r")
letters = text1.read()
a = len(letters)
binary_text = [None]*a #pre-allocating a list
encoded_bin = ' '.join([bin(ord(letter))[2:].zfill(8) for letter in letters])
b = len(encoded_bin[0:18])
list_im = [0]*b
for val in range(b):
if encoded_bin[val] == '0':
list_im[val] = closed_circle
if encoded_bin[val] == '1':
list_im[val] = open_circle
if encoded_bin[val] == ' ':
list_im[val] = diamond
imgs = [Image.open(i) for i in list_im]
min_shape = sorted( [(np.sum(i.size), i.size) for i in imgs] )[0][1]
imgs_comb = np.hstack( (np.asarray(i.resize(min_shape)) for i in imgs) )
imgs_comb = Image.fromarray(imgs_comb)
imgs_comb.show()
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().