Passing image PIL object from view to other view django - python

How do I pass a PIL Image object from one view def to another view def? It is possible to use a reverse() function. I would like to display the changed image on the imageSizeConverter view without saving. My code is
def imageSizeConverter(request):
if request.method == 'POST':
item = request.FILES.get('imgInp')
width = int(request.POST.get('width'))
height = int(request.POST.get('height'))
proportion = request.POST.get('proportion')
root = tk.Tk()
root.withdraw()
file_path = filedialog.askdirectory()
name = request.POST.get('fname')
print(file_path)
img = Image.open(item)
if(proportion == 'on'):
img.thumbnail((width, height))
else:
img.resize((width, height))
resultFileName, file_extension = os.path.splitext(name)
if not file_extension:
filename, file_extension = os.path.splitext(item.name)
nazwa = file_path + "/" + resultFileName + file_extension
img.save(nazwa)
return render(request, "app/imageSizeConverter.html",
{
'title':'Zmiana rozmiaru',
'year':datetime.now().year,
'image': reverse('show_image')
})
def show_image(request):
response = HttpResponse(content_type="image/png")
img.save(response, "PNG")
return response
Edit
This is the solution to my problem:
output = BytesIO()
img.save(output, format='JPEG')
im_data = output.getvalue()
data_url = 'data:image/jpg;base64,' + base64.b64encode(im_data).decode()
return render(request, "app/imageSizeConverter.html",
{
'title':'Zmiana rozmiaru',
'year':datetime.now().year,
'image': data_url
})
And use on the template:
<img src="{{ image }}" alt=""/>

Related

When creating a GIF of two images using Pillow in python it is messing up Image orientation

When I try to create a GIF using Pillow one of the two images is being rotated in random direction resulting in a gif where one image is like the original but the other one is rotated anticlockwise.
I am using it in a lambda fuction to make a GIF of two image showing the original and edited image so I need them both in the original orientation.
My Code ->
import json
import boto3
from PIL import Image
from io import BytesIO
import uuid
s3_client = boto3.client("s3")
dynamodb = boto3.client("dynamodb")
def makeGIF(orig_string, after_string):
frames = [Image.open(BytesIO(orig_string)), Image.open(BytesIO(after_string))]
frame_one = frames[0]
frame_one.save('/tmp/new_gif.gif', format="GIF", append_images=[frames[1]],
save_all=True, duration=600, loop=0, optimize=False)
def lambda_handler(event, context):
try:
s3 = event["Records"][0]['s3']
print("S3 object reveived::",s3)
if s3['object']['key'][-1] == '/': return
splitted = s3['object']['key'].split("/")
if len(splitted) != 3:
print("ERROR:: Folder hierarchy is not valid!")
return {}
afterFilename = splitted[-1].replace("+", " ")
print('Filename::', afterFilename)
if afterFilename[0:6] not in ['after_', 'AFTER_', 'After_']:
print('Error::', 'Filename does not starts with after_, After_ or AFTER_')
return {}
EXT = ['.jpg', '.jpeg', '.png']
origFilename = afterFilename[6:]
origKey = f"original/{splitted[1]}/{origFilename}"
fileWithoutExt = origFilename.split(".")[0]
BUCKET = s3['bucket']['name']
file_content_orig = None
try:
file_content_orig = s3_client.get_object(Bucket=BUCKET, Key=origKey)["Body"].read()
except:
for ext in EXT:
try:
print("LOOKING::", f"original/{splitted[1]}/{fileWithoutExt}{ext}")
file_content_orig = s3_client.get_object(Bucket=BUCKET, Key=f"original/{splitted[1]}/{fileWithoutExt}{ext}")["Body"].read()
print("FOUND::", f"original/{splitted[1]}/{fileWithoutExt}{ext}")
break
except: pass
if file_content_orig is None:
print('Error::', 'No original image found looked (jpg, jpeg, png)')
return {}
print("LOOKING::", f"after/{splitted[1]}/{afterFilename}")
file_content_after = s3_client.get_object(Bucket=BUCKET, Key=f"after/{splitted[1]}/{afterFilename}")["Body"].read()
makeGIF(file_content_orig, file_content_after)
gifKey = f"gif/{splitted[1]}/gif_{fileWithoutExt}.gif"
with open('/tmp/new_gif.gif', 'rb') as f:
s3_client.upload_fileobj(f, BUCKET, gifKey)
itemId = uuid.uuid4().hex
bucketLink = f"https://{BUCKET}.s3.us-east-2.amazonaws.com"
print("bucketLink", bucketLink)
item = {
"id": {'S': itemId},
"folder_name": {'S': splitted[1]},
"image_name": {'S': origFilename},
"original_link": {'S': f"{bucketLink}/{origKey}"},
"download_link": {'S': f"{bucketLink}/{s3['object']['key']}"},
"gif_link": {'S': f"{bucketLink}/{gifKey}"}
}
dynamodb.put_item(TableName='fototone-db-table', Item = item)
return {
'statusCode': 200,
'body': json.dumps({"message": "Successfully proceessed", "filename": origFilename })
}
except Exception as ex:
print("ERROR:: Some error occured", ex)
return {}

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()

Django, Do I have to use is_valid() when I get request.FILES?

I wanted to save the images, so I wrote the code like this.
def test_form(request):
if request.method == "POST":
for key in request.FILES.keys():
for img in request.FILES.getlist(key):
f = Image()
f.image = img
f.save
Can't I save it after validating it like this?
def extension_filter(filename):
filter = ['png','jpeg','jpg',...]
extenstion = filename.split('.')[-1]
if extenstion in filter:
return True
else :
return False
...
for key in request.FILES.keys():
for img in request.FILES.getlist(key):
if extenstion_filter(img):
f = Image()
f.image = img
f.save
else:
continue
...

Django HEIC to PNG conversion

I'm trying to convert heic to png, which I successfully achieved in Python with the help of Wand library. I also saved the file locally to see, if the convertion worked, and it did. The problem is that Django's serializer cant take in Wand image, and I have to convert it to InMemoryUploadedFile. Whatever I do, I still can't make the serializator to take in the converted image.
views.py update_post()
#api_view(['PUT'])
#permission_classes([IsAuthenticated])
def update_post(request, id):
image = request.FILES['image']
print(image.size, image.name, image.file,
image.content_type, image.field_name)
if image.content_type == 'image/heif':
img = Image(file=image)
img.format = 'png'
img_io = io.BytesIO()
img.save(file=img_io)
filename = image.name.replace('.heic', '.png')
img.save(filename=filename)
img_file = InMemoryUploadedFile(
img_io,
'image',
filename,
'image/png',
sys.getsizeof(img_io),
None)
print(img_file.size, img_file.name, img_file.file,
img_file.content_type, img_file.field_name)
image = img_file
#request.data['image'] = img_file
#request.FILES['image'] = img_file
# data = request.data
# print(img_file, image)
loggedin_user = request.user.username
post = Post.objects.get(id=id)
post_user = post.user
if (str(post_user) == str(loggedin_user)):
serializer = PostSerializer(
instance=post, data={'caption': request.data['caption'], 'image': image})
if serializer.is_valid():
print(serializer.validated_data)
serializer.save()
else:
print('achjo')
print(serializer.data)
return Response(status=status.HTTP_200_OK)

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