I need to write a script that does the following:
# open a tiff
# get it's dpi, width, height and colorspace
# set the dpi, width, height and colorspace
# and then save the tiff out with no compression and no layers.
So far I've gotten:
from win32com.client.dynamic import Dispatch
ps = Dispatch( "Photoshop.Application" )
file_path = "C:\\Users\\me\\myImg.tif"
doc = ps.Open( file_path )
dpi = doc.Resolution
width = doc.Width # in cm
height = doc.Height # in cm
# up to here the code works, but then I try
doc.Resolution = 72
ps.ResizeImage( 120 , 120 )
ps.PsColorSpaceType( 3 ) # psSRGB
ps.TiffSaveOptions.ImageCompression = 1 # psNoTIFFCompression
ps.TiffSaveOptions.Layers = False
ps.Save()
# and this last section fails
Please help, any ideas, tips, soultions would be greatly appreciated :D
After a lot of googeling and some trial and error and then even more trial and error I've managed to come up with the code below.
Hope this can help someone else.
Code
file_path = "C:\\Users\\me\\myImg.tif"
color_settings = "North America General Purpose 2"
from win32com.client.dynamic import Dispatch
ps_app = Dispatch( "Photoshop.Application" )
# set photoshop to use pixels as dimensions
ps_app.Preferences.RulerUnits = 1 # 'for PsUnits --> 1 (psPixels)
ps_app.Preferences.TypeUnits = 1 # 'for PsTypeUnits --> 1 (psPixels)
doc = ps_app.Open( file_path ) # Open a file and store open file as doc
dpi = doc.Resolution
width = doc.Width
height = doc.Height
cor_res = 1024
ps_app.ChangeColorSettings( color_settings )
doc.ResizeImage( cor_res , cor_res , 72 )
options = Dispatch('Photoshop.TiffSaveOptions')
options.ImageCompression = 1 # ps_appNoTIFFCompression
options.Layers = False # no layers
doc.SaveAs( file_path , options ) # Save with specified options
doc.Close( 2 ) # psDoNotSaveChanges
Related
The picture I am trying to read is outputting "ones". I don't know how it's getting that. My code:
left = 980
right = 1000
top = 237
bottom = 265
CroppedImage = cropimage.crop((left,top,right,bottom))
if os.path.isfile("Price.png"):
os.remove("Price.png")
CroppedImage.save('Price.png', 'PNG')
Check_Price = pytesseract.image_to_string(Image.open('Price.png'), lang='eng')
Check_Price = Check_Price[:-2]
if len(Check_Price) == 4:
Found_Price = True
print(Check_Price)
I have pytesseract properly installed and PIL. It's all working for 2 other ones that I have, but it just won't read this text.
You need to scale the image up, using this code i can get your number you need.
import pytesseract
from PIL import Image
pytesseract.pytesseract.tesseract_cmd = r'C:\\Program Files\\Tesseract-OCR\\tesseract.exe'
def read():
i = Image.open('./JA9JF.png')
scale = 2.1
i_width = i.size[1] * scale
i_height = i.size[0] * scale
i = i.resize((int(i_width), int(i_height)), Image.BILINEAR)
xconfig = "-c page_separator=''"
Check_Price = pytesseract.image_to_string(i, lang='eng', config=xconfig)
print(Check_Price)
read()
And so your code would be.
left = 980
right = 1000
top = 237
bottom = 265
CroppedImage = cropimage.crop((left,top,right,bottom))
if os.path.isfile("Price.png"):
os.remove("Price.png")
CroppedImage.save('Price.png', 'PNG')
i = Image.open('Price.png')
scale = 2.1
i_width = i.size[1] * scale
i_height = i.size[0] * scale
i = i.resize((int(i_width), int(i_height)), Image.BILINEAR)
xconfig = "-c page_separator=''"
Check_Price = pytesseract.image_to_string(i, lang='eng', config=xconfig)
Check_Price = Check_Price[:-2]
if len(Check_Price) == 4:
Found_Price = True
print(Check_Price)
i've added xconfig = "-c page_separator=''" because for me pytesseract add \n\x0c for some reason. I also don't know if this will work with other numbers, if it doesn't I'll have to fix it using cv2.
I have a task to create water mark in images and create pptx using these images
and i should not change the aspect ratio of an image as per the rules
Image ratio = 4000x6016
Without changing the ratio, images are not fitting inside the pptx
Is there any way to fit an image in pptx without changing the aspect ratio of an image using python pptx package
Expected ouput:
current ouput
Code:
from wand.image import Image
from pptx import Presentation
from pptx.util import Inches
prs = Presentation()
blankSideLayout = prs.slide_layouts[4]
def makePPTX(path):
slide = prs.slides.add_slide(blankSideLayout)
slide.shapes.title.text = "sample title"
slide.placeholders[2].text = "Sample Sub Title"
slide.shapes.add_picture(path, Inches(1), Inches(3))
prs.save("slides.pptx")
logoImg = Image(filename='logo.jpg')
logoImg.transparentize(0.33)
img = Image(filename='img.jpg')
img.composite_channel("all_channels",logoImg,"dissolve",20,20)
img.save(filename='imgwatermark.jpg')
makePPTX('imgwatermark.jpg')
Yes. In my project (md2pptx) I do this.
Essentially you
Work out the dimensions of the graphic and the space you want to fit it in.
You figure out which dimension you need to scale by and by how much. Answers to 1. guide you in this.
You create the graphic scaling according to 2.
Here's code from the md2pptx repo:
def scalePicture(maxPicWidth, maxPicHeight, imageWidth, imageHeight):
heightIfWidthUsed = maxPicWidth * imageHeight / imageWidth
widthIfHeightUsed = maxPicHeight * imageWidth / imageHeight
if heightIfWidthUsed > maxPicHeight:
# Use the height to scale
usingHeightToScale = True
picWidth = widthIfHeightUsed
picHeight = maxPicHeight
else:
# Use the width to scale
usingHeightToScale = False
picWidth = maxPicWidth
picHeight = heightIfWidthUsed
return (picWidth, picHeight, usingHeightToScale)
The main difficulty is going to be figuring out the dimensions of the source graphic.
Here is some code I borrowed for that:
import imghdr, struct
def get_image_size(fname):
"""Determine the image type of fhandle and return its size.
from draco"""
try:
with open(fname, "rb") as fhandle:
head = fhandle.read(24)
if len(head) != 24:
return -1, -1
if imghdr.what(fname) == "png":
check = struct.unpack(">i", head[4:8])[0]
if check != 0x0D0A1A0A:
return
width, height = struct.unpack(">ii", head[16:24])
elif imghdr.what(fname) == "gif":
width, height = struct.unpack("<HH", head[6:10])
elif imghdr.what(fname) == "jpeg":
try:
fhandle.seek(0) # Read 0xff next
size = 2
ftype = 0
while not 0xC0 <= ftype <= 0xCF:
fhandle.seek(size, 1)
byte = fhandle.read(1)
while ord(byte) == 0xFF:
byte = fhandle.read(1)
ftype = ord(byte)
size = struct.unpack(">H", fhandle.read(2))[0] - 2
# We are at a SOFn block
fhandle.seek(1, 1) # Skip 'precision' byte.
height, width = struct.unpack(">HH", fhandle.read(4))
except Exception: # IGNORE:W0703
return
else:
return
return width, height
except EnvironmentError:
return -1, -1
How can you correctly set the Author, Title and Subject attributes for a PDF File using Reportlab?
I have found the methods in the Reportlab User Guide on page 56, but I am not sure how to implement them correctly.
Below in my PDF cropping and scaling script, I have added the annotations method, but I don't know where to call them from, or if a whole new Canvas object is needed. Please excuse the lengthy code, but only after line 113 is the doc being created, above are mostly auxiliary methods, including the annotations method on line 30.
# All the necessary parameters are accessible after line 92,
# but can of course be changed manually in the Code
# imports for the crop, rename to avoid conflict with reportlab Image import
from PIL import Image as imgPIL
from PIL import ImageChops, ImageOps, ImageFilter
import os.path, sys
# import for the PDF creation
import glob
from reportlab.lib.pagesizes import A4
from reportlab.lib import utils
from reportlab.platypus import Image, SimpleDocTemplate, Spacer
from reportlab.pdfgen import canvas
# get os path for Cropping
path = (os.path.dirname(os.path.abspath("cropPDF.py")))
dirs = os.listdir(path)
def trim(im, border="white"):
bg = imgPIL.new(im.mode, im.size, border)
diff = ImageChops.difference(im, bg)
bbox = diff.getbbox()
if bbox:
return im.crop(bbox)
def annotations(canvas):
canvas.setAuthor("the ReportLab Team")
canvas.setTitle("ReportLab PDF Generation User Guide")
canvas.setSubject("How to Generate PDF files using the ReportLab modules")
def findMaxWidth():
maxWidth = 0
for item in dirs:
try:
fullpath = os.path.join(path, item)
if os.path.isfile(fullpath):
im = imgPIL.open(fullpath)
maxWidth = max(maxWidth, im.size[0])
except:
pass
return maxWidth
def padImages(docHeight):
maxWidth = findMaxWidth()
for item in dirs:
try:
fullpath = os.path.join(path, item)
if os.path.isfile(fullpath):
im = imgPIL.open(fullpath)
f, e = os.path.splitext(fullpath)
width, height = im.size # get the image dimensions, the height is needed for the blank image
if not docHeight <= height: # to prevent oversized images from bein padded, such that they remain centered
image = imgPIL.new('RGB', (maxWidth, height),
(255, 255, 255)) # create a white image with the max width
image.paste(im, (0, 0)) # paste the original image overtop the blank one, flush on the left side
image.save(f + ".png", "PNG", quality=100)
except:
pass
def crop():
for item in dirs:
try:
fullpath = os.path.join(path, item)
if os.path.isfile(fullpath):
im = imgPIL.open(fullpath)
f, e = os.path.splitext(fullpath)
imCrop = trim(im, "white")
imCrop.save(f + ".png", "PNG", quality=100)
except:
pass
def add_page_number(canvas, doc):
canvas.saveState()
canvas.setFont('Times-Roman', numberFontSize)
page_number_text = "%d" % (doc.page)
canvas.drawCentredString(
pageNumberSpacing * mm,
pageNumberSpacing * mm,
page_number_text
)
canvas.restoreState()
#############################
executeCrop = True
executePad = True
outputName = "output.pdf" #The name of the file that will be created
fileAuthor = "Roman Stadler" #these 3 attributes are visible in the file info menu
fileTitle = ""
fileSubject = ""
margin = 0.5
imageWidthDefault = 550
spacerHeight = 7
scalingIfImageTooTall = 0.95 # larger than 95 can result in an empty page after the image
includePagenumbers = True
numberFontSize = 10
pageNumberSpacing = 5
############################
doc = SimpleDocTemplate(
outputName,
topMargin=margin * mm,
leftMargin=margin * mm,
rightMargin=margin * mm,
bottomMargin=margin * mm,
pagesize=A4
)
if executeCrop:
crop()
if executePad:
padImages(doc.height)
filelist = glob.glob("*.png") # Get a list of files in the current directory
filelist.sort()
story = [] # create the list of images for the PDF
for fn in filelist:
img = utils.ImageReader(fn)
img_width, img_height = img.getSize() # necessary for the aspect ratio
aspect = img_height / float(img_width)
documentHeight = doc.height
imageWidth = imageWidthDefault
imageHeight = imageWidth * aspect
if imageHeight > documentHeight:
imageHeight = documentHeight * scalingIfImageTooTall
imageWidth = imageHeight / aspect
img = Image(
fn,
width=imageWidth,
height=imageHeight
)
story.append(img)
space = Spacer(width=0, height=spacerHeight)
story.append(space)
if includePagenumbers and not len(filelist) == 0: # if pagenumbers are desired, or not
doc.build(
story,
onFirstPage=add_page_number,
onLaterPages=add_page_number,
)
elif not len(filelist) == 0:
doc.build(story)
else: # to prevent an empty PDF that can't be opened
print("no files found")
In the meantime, I have found another way, that does not use reportlab, but instead relies on PyPDF2:
The following import is needed:
# PyPDF2 for the metadata modification
from PyPDF2 import PdfFileReader, PdfFileWriter
Then the metadata can be edited like this:
author = "Roman Stadler"
title = "CropPDF"
subject = "Stackoverflow"
#rest of the script
#attemp the metadate edit
try:
file = open('output.pdf', 'rb+')
reader = PdfFileReader(file)
writer = PdfFileWriter()
writer.appendPagesFromReader(reader)
metadata = reader.getDocumentInfo()
writer.addMetadata(metadata)
writer.addMetadata({
'/Author': author,
'/Title': title,
'/Subject' : subject,
'/Producer' : "CropPDF",
'/Creator' : "CropPDF",
})
writer.write(file)
file.close()
except:
print("Error while editing metadata")
You can define attributes like the author when defining the doc as a SimpleDocTemplate
doc = SimpleDocTemplate(
outputName,
topMargin=margin * mm,
leftMargin=margin * mm,
rightMargin=margin * mm,
bottomMargin=margin * mm,
pagesize=A4,
title="This is the title of the document", #exchange with your title
author="John Smith", #exchange with your authors name
subject"Adding metadata to pdf via reportlab" #exchange with your subject
)
I am trying to stitch about 50 images(all in the same 287x287 size) together. Specifically, there should be 25 images on the top row and 25 images on the bottom row, and there also exists a small distance between each two images.
I met two difficulties during my attempts:
First problem is that there are 25 images in a folder with their name 'prefix-70',...,'prefix-94' while other 25 images in another folder with the same name 'prefix-70',...,'prefix-94'. I do not know how to them in Python without conflicts.
Second problem is that I wrote the following code to read one folder images to form a row but it outputs a column.
#!/usr/bin/python3.0
#encoding=utf-8
import numpy as np
from PIL import Image
import glob,os
if __name__=='__main__':
#prefix=input('Input the prefix of images:')
prefix = 'prefix'
files=glob.glob(prefix+'-*')
num=len(files)
filename_lens=[len(x) for x in files] #length of the files
min_len=min(filename_lens) #minimal length of filenames
max_len=max(filename_lens) #maximal length of filenames
if min_len==max_len:#the last number of each filename has the same length
files=sorted(files) #sort the files in ascending order
else:
index=[0 for x in range(num)]
for i in range(num):
filename=files[i]
start=filename.rfind('-')+1
end=filename.rfind('.')
file_no=int(filename[start:end])
index[i]=file_no
index=sorted(index)
files=[prefix+'-'+str(x)+'.png' for x in index]
print(files[0])
baseimg=Image.open(files[0])
sz=baseimg.size
basemat=np.atleast_2d(baseimg)
for i in range(1,num):
file=files[i]
im=Image.open(file)
im=im.resize(sz,Image.ANTIALIAS)
mat=np.atleast_2d(im)
print(file)
basemat=np.append(basemat,mat,axis=0)
final_img=Image.fromarray(basemat)
final_img.save('merged.png')
I guess i have got into a wrong way...
How can i stitch them properly? Any suggestion is appreciated.
Try this (explanation in comments):
from PIL import Image
from os import listdir, path
space_between_row = 10
new_image_path = 'result.jpg'
im_dirs = ['images/1', 'images/2']
# get sorted list of images
im_path_list = [[path.join(p, f) for f in sorted(listdir(p))] for p in im_dirs]
# open images and calculate total widths and heights
im_list = []
total_width = 0
total_height = 0
for path_list in im_path_list:
images = list(map(Image.open, path_list))
widths, heights = zip(*(i.size for i in images))
total_width = max(total_width, sum(widths))
total_height += max(heights)
im_list.append(images)
# concat images
new_im = Image.new('RGB', (total_width, total_height))
y_offset = 0
for images in im_list:
x_offset = 0
max_height = 0
for im in images:
new_im.paste(im, (x_offset, y_offset))
x_offset += im.size[0]
max_height = max(im.size[1], max_height)
y_offset = y_offset + max_height + space_between_row
# show and save
new_im.show()
new_im.save(new_image_path)
Install ImageMagick, then tell it where your two directories are.
#!/usr/bin/python3
##=========================================================
## required ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
##
## imagemagick.org/script/download.php
##
##=========================================================
## libs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import subprocess as sp
##=========================================================
## vars ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
offset = 2 ## pixel gap between images
color = '#000000' ## background color to fill gaps
dir1 = '/home/me/Pictures/topRow/'
dir2 = '/home/me/Pictures/bottomRow/'
## note: windows dirs use double backslashes
## 'C:\\Users\\me\\Pictures\\topRow\\'
##=========================================================
## script ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
row1args = ['convert', '+smush', offset, '-background', color, dir1 + '*.png', 'row1.png']
row2args = ['convert', '+smush', offset, '-background', color, dir2 + '*.png', 'row2.png']
merge = ['convert', '-smush', offset, '-background', color, 'row*.png', 'merged.png']
##=========================================================
## main ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sp .call(row1args)
sp .call(row2args)
sp .call(merge)
##=========================================================
## eof ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I am currently trying to save a mayavi animation generated by my simulation, so I don't have to rerun the code each time to see it.
plt = points3d(x_coord, y_coord, z_coord)
msplt = plt.mlab_source
#mlab.animate(delay=100)
def anim():
f = mlab.gcf()
while True:
#animation updates here
msplt.set(x = x_coord, y = y_coord, z = z_coord)
yield
anim()
mlab.savefig(filename = 'ani.mp4')
mlab.show()
I have tried saving it through the pipleline editor and just get a still of the frame it is on, and mlab.savefig doesn't generate a file. Any help appreciated.
The following will will work for both viewing the animation, saving each frame as a 'png', and then converting them to a movie, BUT it is perhaps fastest in this case to forgo playing the animation, and just cycle through the data saving figures, and then using this method to make a video.
from mayavi import mlab
import numpy as np
import os
# Output path for you animation images
out_path = './'
out_path = os.path.abspath(out_path)
fps = 20
prefix = 'ani'
ext = '.png'
# Produce some nice data.
n_mer, n_long = 6, 11
pi = np.pi
dphi = pi/1000.0
phi = np.arange(0.0, 2*pi + 0.5*dphi, dphi, 'd')
mu = phi*n_mer
x = np.cos(mu)*(1+np.cos(n_long*mu/n_mer)*0.5)
y = np.sin(mu)*(1+np.cos(n_long*mu/n_mer)*0.5)
z = np.sin(n_long*mu/n_mer)*0.5
# Init plot
plt = mlab.points3d(x[0], y[0], z[0])
padding = len(str(len(x)))
# Define data source and update routine
msplt = plt.mlab_source
#mlab.animate(delay=10)
def anim():
f = mlab.gcf()
for i in range(len(x)):
#animation updates here
msplt.set(x=x[i], y=y[i], z=z[i])
# create zeros for padding index positions for organization
zeros = '0'*(padding - len(str(i)))
# concate filename with zero padded index number as suffix
filename = os.path.join(out_path, '{}_{}{}{}'.format(prefix, zeros, i, ext))
mlab.savefig(filename=filename)
yield
anim()
mlab.view(distance=15)
mlab.show()
import subprocess
ffmpeg_fname = os.path.join(out_path, '{}_%0{}d{}'.format(prefix, padding, ext))
cmd = 'ffmpeg -f image2 -r {} -i {} -vcodec mpeg4 -y {}.mp4'.format(fps,
ffmpeg_fname,
prefix)
print cmd
subprocess.check_output(['bash','-c', cmd])
# Remove temp image files with extension
[os.remove(f) for f in os.listdir(out_path) if f.endswith(ext)]
Instead of saving the images to disk and then stitching them together it's also possible to pipe them directly to ffmpeg using the python-ffmpeg package.
import ffmpeg
# Set up the figure
width = 200
height = 200
mlab.options.offscreen = True # Stops the view window popping up and makes sure you get the correct size screenshots.
fig = mlab.figure(size=(width, height))
# ... set up the scene ...
# Define update function
def update_scene(idx):
# -- update the scene
return
# Initialise ffmpeg process
output_args = {
'pix_fmt': 'yuv444p',
'vcodec': 'libx264',
'r': 25,
}
process = (
ffmpeg
.input('pipe:', format='rawvideo', pix_fmt='rgb24', s=f'{width}x{height}')
.output('animation.mp4', **output_args)
.overwrite_output()
.run_async(pipe_stdin=True)
)
fig.scene._lift() # Throws an error without this.
for i in range(100):
update_scene(i)
screenshot = mlab.screenshot(mode='rgb', antialiased=True)
frame = Image.fromarray(screenshot, 'RGB')
process.stdin.write(frame.tobytes())
# Flush video
process.stdin.close()
process.wait()