How to generate a GIF without saving/importing image files? - python

Say I use the following method to create a three images. I then want to combine these three images into a GIF & display the GIF (jupyter notebook, python 3). All the methods I've seen online & stackoverflow for creating GIFs include saving the images as files & then importing them. For instance, this thread. But is there a way to just generate a gif without having to save/import image files? So, in the following code, using three versions of the im=Image.fromarray(arr.astype('uint8')) generated image to create a gif on the spot?
import numpy as np
from PIL import Image
arr = np.random.randint(low = 0, high = 255, size = (300, 300, 3))
im = Image.fromarray(arr.astype('uint8'))
im.show()

I guess you need something like this. GIF is an image file type so you have to save it to have one.
#! /usr/bin/env python3
import numpy as np
from PIL import Image
im = []
for n in range(20):
arr = np.random.randint(low = 0, high = 255, size = (300, 300, 3))
im.append(Image.fromarray(arr.astype('uint8')))
im[0].save('im.gif', save_all=True, append_images=im[1:], optimize=False, duration=200, loop=0)
#im[0].show()
Then open im.gif with a browser or some app that can show animated GIFs.
If you really don't want to save the GIF but just show it, you can do something like this
#! /usr/bin/env python3
import base64
import io
import numpy as np
from PIL import Image
from viaduc import Viaduc
im = []
for n in range(20):
arr = np.random.randint(low = 0, high = 255, size = (300, 300, 3))
im.append(Image.fromarray(arr.astype('uint8')))
buffer = io.BytesIO()
im[0].save(buffer, format='GIF', save_all=True, append_images=im[1:], optimize=False, duration=200, loop=0)
buffer.seek(0)
data_uri = base64.b64encode(buffer.read()).decode('ascii')
class Presentation(Viaduc.Presentation):
width = 300
height = 300
title = 'gif'
html = '''
<!DOCTYPE html>
<head>
{{bootstrap_meta}} {{bootstrap_css}}
<title>{{title}}</title>
</head>
<body>
<img src="data:image/gif;base64,''' + data_uri + '''">
{{bootstrap_js}}
</body>
</html>
'''
if __name__ == '__main__':
Viaduc(presentation=Presentation())

Related

convert Image to PDF in Python

I want to convert image to pdf in python.
this is my code:
import docx
from docx.shared import Inches, Mm
import os
from PIL import Image
from PIL import Image, ImageDraw, ImageFont
from docx2pdf import convert
from wand.image import Image as Im
image_dir = os.listdir(os.getcwd()+'\\Images')
print(len(image_dir))
doc = docx.Document()
section = doc.sections[0]
section.page_height = Mm(1000)
section.page_width = Mm(580)
section.left_margin = Mm(25.4)
section.right_margin = Mm(25.4)
section.top_margin = Mm(25.4)
section.bottom_margin = Mm(25.4)
section.header_distance = Mm(12.7)
section.footer_distance = Mm(12.7)
p = doc.add_paragraph()
x = 0
for i in range(0, len(image_dir)):
size = (130, 160)
temp_img = Image.open(os.getcwd()+'\\Images\\'+image_dir[i])
temp_img = temp_img.resize(size)
# temp_img.thumbnail(size, Image.ANTIALIAS)
# temp_img.show()
background = Image.new('RGBA', (500, 220), (255, 255, 255, 0))
for k in range(0, 3):
background.paste(temp_img, (0,0))
background.paste(temp_img, (150,0))
background.paste(temp_img, (300,0))
font = ImageFont.truetype(r'arial.ttf', 25)
d1 = ImageDraw.Draw(background)
d1.text((5, 160), image_dir[i][:-4], fill =(0, 0, 0), font = font)
background.save("temp.png")
with Im(filename ="temp.png") as img:
# generating sharp image using sharpen() function.
img.sharpen(radius = 16, sigma = 8)
img.save(filename ="temp1.png")
r = p.add_run()
r.add_picture("temp1.png")
doc.save('demo1.docx')
convert("demo1.docx")
This code run well. But IMG quality of pdf is poor and process is very slowly.
I want to improve convert speed.
Somebody help me. Thank you.
I think PIL is enough for you to combine an image with text into a PDF.
for example, you can save the combined images with text like this
import os
from PIL import Image, ImageDraw, ImageFont
image_dir = os.listdir(os.getcwd()+'\\Images')
for i in range(0, len(image_dir)):
size = (130, 160)
temp_img = Image.open(os.getcwd()+'\\Images\\'+image_dir[i])
temp_img = temp_img.resize(size)
background = Image.new('RGB', (500, 220), (255, 255, 255))
for k in range(0, 3):
background.paste(temp_img, (0,0))
background.paste(temp_img, (150,0))
background.paste(temp_img, (300,0))
font = ImageFont.truetype('arial.ttf', 25)
d1 = ImageDraw.Draw(background)
d1.text((5, 160), image_dir[i][:-4], fill =(0, 0, 0), font = font)
background.save(f"{image_dir[i][:-4]}.pdf")
This is my try. Just give the directory path and its done; you end up with a subdirectory containing all the PDF files
from pathlib import *
from PIL import Image
# path input #
path = input("Enter The path of you Images directory: \n")
path = Path(f"{path}")
####################################################
# making a subdirectory to contain the PDF version #
(path/"PDF's").mkdir(exist_ok=True)
# iterating over every file in the given directory #
# we use try function to ignore non image files #
for pp in path.glob("*"):
try:
with Image.open(pp) as image:
im = image.convert("RGB")
pth = Path(f"{path}\PDF's\{pp.stem}.pdf")
im.save(pth, save_all=True)
except:
pass
print("Conversion Completed ...")
# if you want to merge PDF's uncomment the next segment
#import PyPDF2
# merger = PyPDF2.PdfFileMerger()
# path = Path(f"{path}\PDF's")
# # (path/"MergedPDF's").touch()
# if (path/"MergedPDF's.pdf").exists():
# (path/"MergedPDF's.pdf").unlink()
# for pdf in path.glob("*.pdf"):
# merger.append(PyPDF2.PdfReader(pdf, "rb"))
# output = open(path/"MergedPDF's.pdf", "wb")
# merger.write(output)
# merger.close()
Pillow solution is pretty good in my opinion. But if u need more control over your pdf I suggest u to use PyMuPDF. Best library for pdf manipulation, hands down.
# copy image files to PDF pages
# each page will have image dimensions
import fitz
doc = fitz.open() # new PDF
imglist = [ ... image file names ...] # e.g. a directory listing
for img in imglist:
imgdoc=fitz.open(img) # open image as a document
pdfbytes=imgdoc.convert_to_pdf() # make a 1-page PDF of it
imgpdf=fitz.open("pdf", pdfbytes)
doc.insert_pdf(imgpdf) # insert the image PDF
doc.save("allmyimages.pdf")
Is pretty handy if u want to add metadata:
import fitz
doc = fitz.open()
metadata = {'producer': 'YourName', 'format': 'PDF 1.4', 'encryption': None, 'author': 'YourName',
'modDate': 'none', 'keywords': 'none', 'title': 'YourPdf', 'creationDate': 'none',
'creator': 'none', 'subject': 'none'} # your metadata needs to be a dictionary
doc.set_metadata(metadata)
table of contents:
import fitz
doc = fitz.open()
# the toc is a basically a list of lists. Each list has 3 elements:
# - first: the layer of the toc link (basically the main category (1), subcategory (2) etc..)
# - second: title of the layer
# - third: page where the title is linked
table_of_content = [[1, 'The PyMuPDF Documentation', 1], [2, 'Introduction', 1], [3, 'Note on the Name fitz', 1], [3, 'License', 1]]
doc.set_toc(table_of_content)
etc... I think that giving a look at the documentation is pretty useful

Python Resize all images in a folder

I have the following code that I thought would resize the images in the specified path But when I run it, nothing works and yet python doesn't throw any error so I don't know what to do. Please advise. Thanks
import cv2
import numpy as np
import os
from PIL import Image
def image_resize(folder):
images = []
num_images = 0
location = folder+"_"
for filename in os.listdir(folder):
img = cv2.imread(os.path.join(folder, filename))
if img is not None:
new_img = np.array(Image.fromarray(img).resize((200, 200), Image.ANTIALIAS)) # Resize the images to 50 X 50
images.append(new_img)
num_images += 1
cv2.imwrite("{}/{}".format(location, filename), new_img)
return None
image_resize("2S1")
image_resize("SLICY")
image_resize("BRDM-2")
image_resize("BTR-60")
image_resize("D7")
image_resize("T62")
image_resize("ZIL131")
image_resize("ZSU-23_4")
all image in folder: G:\sar
help me
It does not do anything because your for loop is not finding any files in the folder. You are never passing the "G:\sar" part of the file path.

Display Dicom image using PIL(PILLOW) Python Library

I am trying to read and display DICOM(.dcm) images using below code:-
import pydicom as dicom
import numpy as np
from PIL import Image, ImageEnhance, ImageOps
from PIL.ImageQt import ImageQt
def display_dicom_images(self, folder_Path):
try:
# Image parameters
image_width = 382
image_height = 382
image_depth = 3
self.total_images_in_folder = len(glob.glob1(folder_Path,"*"))
# Select the center image for display
self.current_image_number = round(self.total_images_in_folder / 2)
self.display_number = self.current_image_number
image_dtype = np.uint8
pixel_array = np.ndarray([self.total_images_in_folder, image_height, image_width, image_depth]).astype(image_dtype)
# load images here, once better MR images are acquired
for image_index in range(0, self.total_images_in_folder):
# for DICOM
image_path = folder_Path + "/" + str(image_index) + ".dcm"
scan_image = dicom.dcmread(image_path)
scan_image = scan_image.pixel_array.astype(image_dtype)
pixel_array[image_index, :scan_image.shape[0], :scan_image.shape[1], :scan_image.shape[2]] = scan_image
return pixel_array
But getting error:-
IndexError('tuple index out of range',)
i am using pillow python library for image.
How do you know scan_image.shape is of length 3? MR images should only be monochrome, which would make image_depth = 1 and the length of scan_image.shape equal to 2.
C.8.3.1.1.3 Photometric Interpretation
Enumerated Values:
MONOCHROME1
MONOCHROME2

Image drawn to reportlab pdf bigger than pdf paper size

i'm writing a program which takes all the pictures in a given folder and aggregates them into a pdf. The problem I have is that when the images are drawn, they are bigger in size and are rotated to the left oddly. I've searched everywhere, havent found anything even in the reportlab documentation.
Here's the code:
import os
from PIL import Image
from PyPDF2 import PdfFileWriter, PdfFileReader
from reportlab.pdfgen import canvas
from reportlab.lib.units import cm
from StringIO import StringIO
def main():
images = image_search()
output = PdfFileWriter()
for image in images:
Image_file = Image.open(image) # need to convert the image to the specific size first.
width, height = Image_file.size
im_width = 1 * cm
# Using ReportLab to insert image into PDF
watermark_str = "watermark" + str(images.index(image)) + '.pdf'
imgDoc = canvas.Canvas(watermark_str)
# Draw image on Canvas and save PDF in buffer
# define the aspect ratio first
aspect = height / float(width)
## Drawing the image
imgDoc.drawImage(image, 0,0, width = im_width, height = (im_width * aspect)) ## at (399,760) with size 160x160
imgDoc.showPage()
imgDoc.save()
# Get the watermark file just created
watermark = PdfFileReader(open(watermark_str, "rb"))
#Get our files ready
pdf1File = open('sample.pdf', 'rb')
page = PdfFileReader(pdf1File).getPage(0)
page.mergePage(watermark.getPage(0))
#Save the result
output.addPage(page)
output.write(file("output.pdf","wb"))
#The function which searches the current directory for image files.
def image_search():
found_images = []
for doc in os.listdir(os.curdir):
image_ext = ['.jpg', '.png', '.PNG', '.jpeg', '.JPG']
for ext in image_ext:
if doc.endswith(ext):
found_images.append(doc)
return found_images
main()
I also tried scaling and specifying the aspect ratio using the im_width variable, which gave the same output.
After a little bit of confusion about your goal I figured out that the goal is to make a PDF overview of the images in the current folder. To do so we actual don't need PyPDF2 as Reportlab offers everything we need for this.
See the code below with the comments as guidelines:
def main():
output_file_loc = "overview.pdf"
imgDoc = canvas.Canvas(output_file_loc)
imgDoc.setPageSize(A4) # This is actually the default page size
document_width, document_height = A4
images = image_search()
for image in images:
# Open the image file to get image dimensions
Image_file = Image.open(image)
image_width, image_height = Image_file.size
image_aspect = image_height / float(image_width)
# Determine the dimensions of the image in the overview
print_width = document_width
print_height = document_width * image_aspect
# Draw the image on the current page
# Note: As reportlab uses bottom left as (0,0) we need to determine the start position by subtracting the
# dimensions of the image from those of the document
imgDoc.drawImage(image, document_width - print_width, document_height - print_height, width=print_width,
height=print_height)
# Inform Reportlab that we want a new page
imgDoc.showPage()
# Save the document
imgDoc.save()

Python Wand convert PDF to PNG disable transparent (alpha_channel)

I'm trying to convert a PDF to PNG - this all works fine, however, the output image is still transparent even when I believe I have disabled it:
with Image(filename='sample.pdf', resolution=300) as img:
img.background_color = Color("white")
img.alpha_channel = False
img.save(filename='image.png')
The above produces the images but are transparent, I also tried the below:
with Image(filename='sample.pdf', resolution=300, background=Color('white')) as img:
img.alpha_channel = False
img.save(filename='image.png')
which produces this error:
Traceback (most recent call last):
File "file_convert.py", line 20, in <module>
with Image(filename='sample.pdf', resolution=300, background=Color('white')) as img:
File "/Users/Frank/.virtualenvs/wand/lib/python2.7/site-packages/wand/image.py", line 1943, in __init__
raise TypeError("blank image parameters can't be used with image "
TypeError: blank image parameters can't be used with image opening parameters
I also had some PDFs to convert to PNG. This worked for me and seems simpler than compositing images, as shown above.:
from wand.image import Image
from wand.color import Color
all_pages = Image(blob=self.pdf) # PDF will have several pages.
single_image = all_pages.sequence[0] # Just work on first page
with Image(single_image) as i:
i.format = 'png'
i.background_color = Color('white') # Set white background.
i.alpha_channel = 'remove' # Remove transparency and replace with bg.
Reference: wand.image
From a previous answer, try creating an empty image with a background color, then composite over.
from wand.image import Image
from wand.color import Color
with Image(filename="sample.pdf", resolution=300) as img:
with Image(width=img.width, height=img.height, background=Color("white")) as bg:
bg.composite(img,0,0)
bg.save(filename="image.png")
Compiling the other answers, here is the function I use to convert a PDF into pages:
import os
from wand.image import Image
from wand.color import Color
def convert_pdf(filename, output_path, resolution=150):
""" Convert a PDF into images.
All the pages will give a single png file with format:
{pdf_filename}-{page_number}.png
The function removes the alpha channel from the image and
replace it with a white background.
"""
all_pages = Image(filename=filename, resolution=resolution)
for i, page in enumerate(all_pages.sequence):
with Image(page) as img:
img.format = 'png'
img.background_color = Color('white')
img.alpha_channel = 'remove'
image_filename = os.path.splitext(os.path.basename(filename))[0]
image_filename = '{}-{}.png'.format(image_filename, i)
image_filename = os.path.join(output_path, image_filename)
img.save(filename=image_filename)
The other answer (compositing with a white image) works, but only on the last page, as does setting the alpha channel directly. The following works on wand 0.4.2:
im = wand_image(filename='/tmp/foo.pdf', resolution=200)
for i, page in enumerate(im.sequence):
with wand_image(page) as page_image:
page_image.alpha_channel = False
page_image.save(filename='/tmp/foo.pdf.images/page-%s.png' % i)
I think this is probably a bug in wand. It seems like setting the alpha channel for a PDF should affect all pages, but it doesn't.
For those who are still having problem with this, I found solution (it works in version 0.4.1 and above, I am not sure about earlier versions).
So you should just use something like this:
from wand.image import Image
from wand.color import Color
with Image(filename='sample.pdf', resolution=300) as img:
img.background_color = Color("white")
img.alpha_channel = 'remove'
img.save(filename='image.png')

Categories