Set in memory image in PDF with Flask - python

I am just trying to draw an image to a pdf. This image is loaded from my mongodb database through an API.
I tried this solution but it raises the following error:
2022-09-14T21:05:56.561767+00:00 app[web.1]: remote_file = ImageReader(urlopen(img_url)).read()
2022-09-14T21:05:56.561767+00:00 app[web.1]: AttributeError: 'ImageReader' object has no attribute 'read'
Also, if you know a better way to set this image in the pdf let me know please.
This is the code I am using:
def get(self, usermail, dog_name):
client = pymongo.MongoClient('mongodb://uri')
filter={'UserMail':usermail,'title':dog_name}
result = client['db']['Todo'].find(
filter=filter
)
json_response = json.dumps(list(result), default=json_util.default)
dog = json.loads(json_response)
df = pd.DataFrame(dog).to_dict()
dog_img = df['DogImg'][0]
img_url = 'https://url' + dog_img
dog_age = df['Age'][0]
dog_desc = df['DogDescription'][0]
dog_name = df['title'][0]
dog_breed = df['Breed'][0]
buf = io.BytesIO()
c = canvas.Canvas(buf, pagesize=letter)
#c.drawImage(logo, 30, 700, width=50, height=50)
c.setFont("Helvetica", 20)
c.drawString(100, 720, dog_name)
buf.seek(0)
remote_file = ImageReader(urlopen(img_url)).read()
memory_file = io.BytesIO(remote_file)
buf.seek(0)
new_pdf = PdfFileReader(buf)
existing_pdf = PdfFileReader(memory_file)
pdf = PdfFileWriter()
page = existing_pdf.getPage(0)
page.mergePage(new_pdf.getPage(0))
pdf.addPage(page)
outputStream = open("destination.pdf", "wb")
pdf.write(outputStream)
outfile = io.BytesIO()
pdf.write(outfile)
outfile.seek(0)
return send_file(outfile, mimetype='application/pdf')

Try using the following
from reportlab.platypus import Image, SimpleDocTemplate
from flask import send_file
pdf_filename = 'original.pdf'
new_filename = "new_filename.pdf"
pdf_template = SimpleDocTemplate(pdf_filename, pagesize=letter,topMargin=0, bottomMargin=0, leftMargin=0, rightMargin=0)
story1 = []
img_url = 'https://url' + dog_img
# or from locally in project
# img_url = os.path.join(cwd, "dog_img")
img1 = Image(img_url, width=600, height=780)
story1.append(img1)
pdf_template.build(story1)
return send_file(pdf_filename, attachment_filename=new_filename, as_attachment=True)

Related

How to extracting long views code block in a smaller method?

I have a Django application. And I have a long method where a user can upload a file and the content of the file will be shown in textarea.
Because of the S.O.L.I.D principle. The code that is responsible for extracting the data from the file has to be in a seperate method.
So this is the views.py:
class ReadingFile(View):
def get(self, request):
form = ProfileForm()
return render(request, "main/create_profile.html", {
"form": form
})
def extractingtextfromimage():
pass
def post(self, request):
submitted_form = ProfileForm(request.POST, request.FILES)
content = ''
if submitted_form.is_valid():
uploadfile = UploadFile(image=request.FILES["upload_file"])
name_of_file = str(request.FILES['upload_file'])
uploadfile.save()
print('path of the file is:::', uploadfile.image.name)
with open(os.path.join(settings.MEDIA_ROOT,
f"{uploadfile.image}"), 'r') as f:
print("Now its type is ", type(name_of_file))
print(uploadfile.image.path)
# reading PDF file
if name_of_file.endswith('.pdf'):
pdfFile = wi(filename= uploadfile.image.path , resolution=300)
text_factuur_verdi = []
image = pdfFile.convert('jpeg')
imageBlobs = []
for img in image.sequence:
imgPage = wi(image=img)
imageBlobs.append(imgPage.make_blob('jpeg'))
for imgBlob in imageBlobs:
image = Image.open(io.BytesIO(imgBlob))
text = pytesseract.image_to_string(image, lang='eng')
text_factuur_verdi.append(text)
content = text_factuur_verdi
print(text_factuur_verdi)
# ENDING Reading pdf file
else:
content = f.read()
print(content)
return render(request, "main/create_profile.html", {
'form': ProfileForm(),
"content": content
})
return render(request, "main/create_profile.html", {
"form": submitted_form,
})
And it is about the comment:
reading PDF file
till: # ENDING Reading pdf file
How to seperate that block of code in a seperate method?
I am realy stuck about that part.
Frankly, I don't understand what is your problem.
I can't test it but I would simply copy code to function and send some values as parameters, and use return to send result - so it could be something like this
class ReadingFile(View):
# ... other functions ...
def read_pdf_file(self, uploadfile):
pdfFile = wi(filename=uploadfile.image.path , resolution=300)
text_factuur_verdi = []
image = pdfFile.convert('jpeg')
imageBlobs = []
for img in image.sequence:
imgPage = wi(image=img)
imageBlobs.append(imgPage.make_blob('jpeg'))
for imgBlob in imageBlobs:
image = Image.open(io.BytesIO(imgBlob))
text = pytesseract.image_to_string(image, lang='eng')
text_factuur_verdi.append(text)
content = text_factuur_verdi
print(text_factuur_verdi)
return content
def post(self, request):
# ... code ...
# reading PDF file
if name_of_file.endswith('.pdf'):
content = self.read_pdf_file(uploadfile)
# ENDING Reading pdf file
else:
content = f.read()
# ... code ...
BTW:
I would reduce code to single for-loop, and send only filename instead of uploadfile
def read_pdf_file(self, filename):
content = []
pdf_file = wi(filename=filename, resolution=300)
all_images = pdf_file.convert('jpeg')
for image in all_images.sequence:
image = wi(image=image)
image = image.make_blob('jpeg')
image = Image.open(io.BytesIO(image))
text = pytesseract.image_to_string(image, lang='eng')
content.append(text)
#print(content)
#content = '\n'.join(content) # convert list to single string
return content
# ... later ...
content = self.read_pdf_file(uploadfile.image.path)
And I think it should be
if uploadfile.image.path.endswith('.pdf'):
content = self.read_pdf_file(uploadfile.image.path)
else:
with open(os.path.join(settings.MEDIA_ROOT, uploadfile.image.path)) as f:
content = f.read()

Trying to extract a range of PDF page numbers from a pdf page to split and save it as a separate file using Python

I am trying to create a range of page numbers from a pdf file and then split and save them as a separate file.
Below is the code written for it.
import os
from PyPDF2 import PdfFileReader, PdfFileWriter
import re
def pdf_splitter(pdf_path):
directory = "C:\\Users\\Docs\\"
fname = os.path.splitext(os.path.basename(pdf_path))[0]
print(fname)
object = PdfFileReader(pdf_path)
NumPages = object.getNumPages()
print(NumPages)
string = "Challenge 1:"
string2 = "Challenge 2:"
res=0
pageList=[]
for txt in range(0,NumPages):
pdf_writer = PdfFileWriter()
pageObject = object.getPage(txt)
Text = pageObject.extractText()
print(Text)
acc_pos = Text.find(string)
print(acc_pos)
Cur_pos = Text.find(string2)
print(Cur_pos)
loanAcctName = Text[acc_pos+12:Cur_pos]
print (loanAcctName)
# pageList.append(txt)
# print(pageList)
ReSearch = re.search(string, Text)
if ReSearch != None:
pageList.append(txt)
elif ReSearch ==None:
pageList.append(txt)
print(pageList)
res = res + 1
pdf_writer.addPage(object.getPage(page_num))
output_filename = '{}_page_{}.pdf'.format(loanAcctName,page + 1)
with open(output_filename, 'wb') as out:
pdf_writer.write(out)
print('Created: {}'.format(output_filename))
out.close()
res = res + 1
if __name__ == '__main__':
pdf_path = r"C:\Users\FY22.pdf"
pdf_splitter(pdf_path)

tkinter couldn't recognize image data

I want to show a jpg image in tkinter.Label using a base64 string that is stored inside a JSON file, but I get the following error:
_tkinter.TclError: couldn't recognize image data
here's my block of code:
import json
import base64
import tkinter as tk
image_data = {}
def image_to_json():
with open("path/to/image.jpg","rb") as image:
data = base64.b64encode(image.read())
image_data["data"]=str(data)
with open("jsonfile.json", "w") as file:
json.dump(image_data, file)
def json_to_image():
with open("jsonfile.json", "rb") as file:
contents = json.load(file)
img_data = contents["data"]
return img_data
if __name__=="__main__":
root = tk.Tk()
image_to_json()
converted_image = tk.PhotoImage(data=json_to_image())
label = tk.Label(root, image = converted_image).pack()
root.mainloop
I've also tried this using a png file and got the same error
You probably have to decode the string properly:
EDITED Try this:
image_data = {}
with open("path/to/image.png", "rb") as image:
data = base64.encodebytes(image.read())#
data = data.decode("utf-8")
image_data["data"] = data
with open("jsonfile.json", "w") as file:
json.dump(image_data, file)
with open("jsonfile.json", "rb") as file:
contents = json.load(file)
image_data = contents["data"]
Then it works:
root = tk.Tk()
converted_image = tk.PhotoImage(data=image_data)
label = tk.Label(root, image = converted_image).pack()
root.mainloop()

How to create a Barcode code using python and store the png file in s3 without saving in local

import barcode
from barcode.writer import ImageWriter
from io import StringIO # python3; python2: BytesIO
import boto3
import pandas as pd
def generate_asst(request):
df=pd.DataFrame
list_of_images = []
for i in range(10):
number = 'xxx43256'
number = number + str(i)
print(number)
EAN = barcode.get_barcode_class('Code39')
ean = EAN(number, writer=ImageWriter())
fullname = str(i) + 'barcodhhe'
# filename = ean.save(fullname)
filename = ean.save(fo)
with open(filename, 'rb') as f:
contents = f.read()
fo.close()
s3 = boto3.resource('s3')
s3_obj = s3.Object(bucket_name='bucket-name', key=fullname).put(Body=contents)
s3_client = boto3.client('s3')
response = s3_client.generate_presigned_url('get_object',
Params={'Bucket': 'bucket-name', 'Key': fullname},ExpiresIn=300
)
list_of_images.append({"imagepath":response})
print(response)
df=pd.DataFrame(list_of_images)
df=json.loads(df.to_json(orient='records'))
print(df)
# return fullname
return JsonResponse(df,safe=False)

PIL to Django ImageField

I try to create an image from an url and save it in my django model. If the first part works fine, I do not know how to associate the generated file to my object.
This is my function to generate the image file:
def get_remote_image(image_url, merchant_product_path):
im = None
name = ''
r = requests.get(image_url, stream=True)
if r.status_code == 200:
name = urlparse(image_url).path.split('/')[-1]
full_path = os.path.join(settings.MEDIA_ROOT, merchant_product_path)
if not os.path.exists(full_path):
os.makedirs(full_path)
im = Image.open(r.raw)
if im.mode != "RGB":
im = im.convert("RGB")
im.thumbnail((500, 500), Image.ANTIALIAS)
im.save(full_path + name, 'JPEG')
return {'im': im, 'name': name}
And now, the part to associate this file to my object:
i = get_remote_image(row['pict'], m.get_products_media_path())
obj, created = ProductLine.objects.update_or_create(
...
...
...
)
if i['im'] is not None:
try:
obj.main_picture.save(
i['name'],
ContentFile(i['im']),
save=True)
except TypeError:
continue
This code works but unfortunately, mu pictures are created in the correct folder, objects are created/update but each one has no picture file :(
Can someone tell me what's wrong ?
I've finally found a solution:
def get_remote_image(image_url):
im = None
name = ''
r = requests.get(image_url, stream=True)
if r.status_code == 200:
name = urlparse(image_url).path.split('/')[-1]
i = Image.open(r.raw)
buffer = BytesIO()
if i.mode != "RGB":
i = i.convert("RGB")
i.thumbnail((500, 500), Image.ANTIALIAS)
i.save(buffer, format='JPEG')
im = InMemoryUploadedFile(
buffer,
None,
name,
'image/jpeg',
buffer.tell(),
None)
return {'im': im, 'name': name}
and then:
obj, created = ProductLine.objects.update_or_create(
...
...
...
)
i = get_remote_image(row['pict'])
obj.main_picture.save(
os.path.join(m.get_products_image_path(), i['name']),
i['im'],
save=True)
Hope this will help some other users in this situation.
With a model like :
class ProductLine(models.Model):
name = models.CharField(max_length=250, null=True)
image = models.ImageField(null=True)
You can directly link the picture on your computer using is path instead of his binary content.
obj, created = ProductLine.objects.update_or_create(...)
obj.image.name = "/path/to/the/file"
obj.save()

Categories