Print PDF document with python's win32print module? - python

I'm trying to print a PDF document with the win32print module. Apparently this module can only accept PCL or raw text. Is that correct?
If so, is there a module available to convert a PDF document into PCL?
I contemplated using ShellExecute; however, this is not an option since it only allows printing to the default printer. I need to print to a variety of printers on servers across various networks.
Thanks for your help,
Pete

I ended up using Ghostscript to accomplish this task. There is a command line tool that relies on Ghostscript called gsprint.
You don't even need Acrobat installed to print PDFs in this fashion which is quite nice.
Here is an example:
on the command line:
gsprint -printer \\server\printer "test.pdf"
from python:
win32api.ShellExecute(0, 'open', 'gsprint.exe', '-printer "\\\\' + self.server + '\\' + self.printer_name + '" ' + file, '.', 0)
Note that I've added to my PATH variable in these examples, so I don't have to include the entire path when calling the executable.
There is one downside, however. The code is licensed under the GPL, so it's no very useful in commercial software.
Hope this helps someone,
Pete

I was already using the win32api.ShellExecute approach and needed to print to a non-default printer. The best way I could work out was to temporarily change the default printer. So right before I do the print I store what the current default printer is, change it, and then set it back after printing. Something like:
tempprinter = "\\\\server01\\printer01"
currentprinter = win32print.GetDefaultPrinter()
win32print.SetDefaultPrinter(tempprinter)
win32api.ShellExecute(0, "print", filename, None, ".", 0)
win32print.SetDefaultPrinter(currentprinter)
I'm not going to claim it's pretty, but it worked and it allowed me to leave my other code untouched.

I am not sure how to specifically get win32print to work, but there might be a couple of other options. Reportlab is often mentioned when creating PDFs from Python. If you are already invested in your approach, maybe using PyX or pypsg to generate the Postscript files and then feeding that into win32print would work.

Related

open image files from window explorer using python code

i recently just took up python for my research studentship (so i don't have a very strong cs background). I'm dealing with a large set of image files in many different subfolders in a big folder so I want to build a python code to search and open them.
I got introduced to os and sys libraries to play around with them. I could get the file to open but that is only when I specifically put a full dirpath for the file. I'm having trouble building a code to direct python to the right folder when I only know the folder name(i'm not sure if i'm making sense haha sorry).
My goal is to be able to type the id name of a folder containing the image in the python output so the file could be pulled out and displayed.
Any suggestions would be great! thank you so much!
You should look at the documentation for the functions we recommended you in the comments. Also, you may be interested to read some tutorials on files and directory, mainly in Python.
And look at how many questions we had to ask you to understand what you wanted to do. Provide code. Explain clearly what is your input, its type, its possible values, and what is the expected output.
Anyway, from what I understood so far, here is a proposal based on os.startfile :
import os
from pathlib import Path
# here I get the path to the desired directory from user input, but it could come from elsewhere
path_to_directory = Path(input("enter the path to the folder : "))
extension_of_interest = ".jpg"
filepaths_of_interest = []
for entry in path_to_directory.iterdir():
if entry.is_file() and entry.name.endswith(extension_of_interest):
print("match: " + str(entry))
filepaths_of_interest.append(entry)
else:
print("ignored: " + str(entry))
print("now opening ...")
for filepath_of_interest in filepaths_of_interest:
os.startfile(filepath_of_interest, "open")
when run, given the path C:/PycharmProjects/stack_oveflow/animals, it prints :
enter the path to the folder : C:/PycharmProjects/stack_oveflow/animals
ignored: C:\PycharmProjects\stack_oveflow\animals\cute fish.png
match: C:\PycharmProjects\stack_oveflow\animals\cute giraffe.jpg
match: C:\PycharmProjects\stack_oveflow\animals\cute penguin.jpg
match: C:\PycharmProjects\stack_oveflow\animals\cute_bunny.jpg
now opening ...
and the 3 jpg images have been opened with my default image viewer.
The startfile function was asked to "open" the file, but there are other possibilities described in the documentation.

How can I localize argparse generated messages in a portable way?

Context:
I am developping a small module to automatically rename photographs in a directory according to their exif timestamp (goal: easily mixing pictures from different cameras or smartphones). It works smoothly either as a Python package or directly from the command line through a tiny wrapper using argparse.
And I have just had the (rather stupid) idea to localize it in non English language. Ok, gettext is my friend for all my own code, but when I came to agparse generated messages, I found myself on a sloppy ground...
Current research:
I have already found some resources on SO:
How to make python's argparse generate Non-English text?
Translate argparse's internal strings
Both end in adding the relevant strings from argparse into a po/mo file and let the argparse module automatically use the translated strings because internally it uses the _(...) wrapper. So far, so good.
My problem:
I feel this more as a workaround than a clean and neat solution because:
I could not find a word advising it in official Python documentation
It looks like a work in progress: implemented by not documented, so some strings could change in a future Python release (or did I miss something?)
Current code:
parser = argparse.ArgumentParser(
prog = prog,
description="Rename pictures according to their exif timestamp")
parser.add_argument("-v", "--version", action="version",
version="%(prog)s " + __version__)
parser.add_argument("--folder", "-f", default = ".",
help = "folder containing files to rename")
parser.add_argument("-s", "--src_mask", default="DSCF*.jpg",
help = "pattern to select the files to rename")
parser.add_argument("-d", "--dst_mask", default="%Y%m%d_%H%M%S",
help = "format for the new file name")
parser.add_argument("-e", "--ext", default=".jpg", dest="ext_mask",
help = "extension for the new file name")
parser.add_argument("-r", "--ref_file", default="names.log",
help = "a file to remember the old names")
parser.add_argument("-D", "--debug", action="store_true",
help = "print a line per rename")
parser.add_argument("-X", "--dry_run", action="store_true", dest="dummy",
help = "process normally except no rename occurs")
# subcommands configuration (rename, back, merge)
subparser = parser.add_subparsers(dest='subcommand', help="sub-commands")
ren = subparser.add_parser("rename", help=
"rename files by using their exif timestamp")
ren.add_argument("files", nargs="*",
help = "files to process (default: src_mask)")
back = subparser.add_parser("back",
help="rename files back to their original name")
back.add_argument("files", nargs="*",
help = "files to process (default: content of ref_file)")
merge = subparser.add_parser("merge",
help="merge files from a different folder")
merge.add_argument("src_folder", metavar="folder",
help = "folder from where merge picture files")
merge.add_argument("files", nargs="*",
help = "files to process (default: src_mask)")
I know how to wrap my own strings with _(), and I could probably have acceptable translations for the usage and help messages, but there are plenty of error messages when the user gives a wrong syntax, and I would like to prevent English error messages in the middle of French speaking program...
Question:
Is there any guarantee that the implementation of strings in the argparse module will not change, or is there a more robust/portable way to provide translations for its messages?
After some more research and #hpaulj's great comments, I can confirm:
the localizable messages from argparse are upward compatible from 3.3 to current version (old messages were never changed but new messages were added for new features)
the above is not true before 3.3
there are slight differences in 2.7
That means that only 2 paths are possible here:
accept the risk and provide a translation for the current version that will accept any Python version >= 3.3 - the risk is that a future version breaks the translation or add new (untranslated) messages. Nothing more to say because this will explicitely use the implementation details of the module
do not use at all argparse module and build a custom parser based on getopt. It is probably an acceptable option for simple use cases that do not require the full power of argparse
None of them are really good, but I cannot imagine a better one...
I will try to setup a project on github or gitlab providing the pot file and the french translation for the current argparse, and make it available on PyPI. If it ever exists, I will add references for it here and shall be glad to include other languages there.
A beta version of a project giving French translations for the argparse module is currently available on GitHUB
I call it beta because at this time, it has not been extensively tested, but it can be used either directly or as an example of what could be done. The binary wheel contains a little endian mo file, but the source distribution allows the mo file to be generated automatically on the target system with no additional dependency by including a copy of the msgfmt.py file from the Tools i18n of CPython.

Python - finding TTF files

Can anyone improve on this? I'm fairly new to python and am trying to write portable code. I need to locate a font file to pass to ImageDraw.Draw.Text.
import matplotlib.font_manager as fontman
def findFontFile(searchFont):
fList = fontman.findSystemFonts(fontpaths=None, fontext='ttf')
targetFont = []
for row in fList:
try:
if searchFont in row:
targetFont.append(row)
except TypeError:
pass
return targetFont[0]
On my system this gives me:
>>> findFontFile('DejaVuSans.ttf')
'/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf'
Which is exactly what I need. Does this look like it will work on Mac / Windows systems as well as Linux (tested on Linux)? Could it be done more efficiently? In a more readable style? Will Mac / Windows have a different font file naming format? Suggestions welcome.
I would do a little rewrite like (some changes are just a matter of style, more python like):
def find_font_file(query):
matches = list(filter(lambda path: query in os.path.basename(path), fontman.findSystemFonts()))
return matches
The caller would then decide the element to use (after checking permissions etc).
As for the compatibility you can view here that the lib uses a set of common directories for the "main" operating systems to search for fonts (X window manager (linux), windows and os x). But you can always pass the directories where you want to search if you have more information on the different environments where the app is going to run.
be careful when doing if searchFont in row.
If someone has username is marial, and you're searching for the font arial, by using findFontFile('arial'), your code would be getting all of the fonts installed in the user's home directory (i.e. /home/marial/.fonts).

How to check type of files without extensions? [duplicate]

This question already has answers here:
How to find the mime type of a file in python?
(18 answers)
Closed 1 year ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
I have a folder full of files and they don't have an extension. How can I check file types? I want to check the file type and change the filename accordingly. Let's assume a function filetype(x) returns a file type like png. I want to do this:
files = os.listdir(".")
for f in files:
os.rename(f, f+filetype(f))
How do I do this?
There are Python libraries that can recognize files based on their content (usually a header / magic number) and that don't rely on the file name or extension.
If you're addressing many different file types, you can use python-magic. That's just a Python binding for the well-established magic library. This has a good reputation and (small endorsement) in the limited use I've made of it, it has been solid.
There are also libraries for more specialized file types. For example, the Python standard library has the imghdr module that does the same thing just for image file types.
If you need dependency-free (pure Python) file type checking, see filetype.
The Python Magic library provides the functionality you need.
You can install the library with pip install python-magic and use it as follows:
>>> import magic
>>> magic.from_file('iceland.jpg')
'JPEG image data, JFIF standard 1.01'
>>> magic.from_file('iceland.jpg', mime=True)
'image/jpeg'
>>> magic.from_file('greenland.png')
'PNG image data, 600 x 1000, 8-bit colormap, non-interlaced'
>>> magic.from_file('greenland.png', mime=True)
'image/png'
The Python code in this case is calling to libmagic beneath the hood, which is the same library used by the *NIX file command. Thus, this does the same thing as the subprocess/shell-based answers, but without that overhead.
On unix and linux there is the file command to guess file types. There's even a windows port.
From the man page:
File tests each argument in an attempt to classify it. There are three
sets of tests, performed in this order: filesystem tests, magic number
tests, and language tests. The first test that succeeds causes the
file type to be printed.
You would need to run the file command with the subprocess module and then parse the results to figure out an extension.
edit: Ignore my answer. Use Chris Johnson's answer instead.
In the case of images, you can use the imghdr module.
>>> import imghdr
>>> imghdr.what('8e5d7e9d873e2a9db0e31f9dfc11cf47') # You can pass a file name or a file object as first param. See doc for optional 2nd param.
'png'
Python 2 imghdr doc
Python 3 imghdr doc
import subprocess as sub
p = sub.Popen('file yourfile.txt', stdout=sub.PIPE, stderr=sub.PIPE)
output, errors = p.communicate()
print(output)
As Steven pointed out, subprocess is the way. You can get the command output by the way above as this post said
You can also install the official file binding for Python, a library called file-magic (it does not use ctypes, like python-magic).
It's available on PyPI as file-magic and on Debian as python-magic. For me this library is the best to use since it's available on PyPI and on Debian (and probably other distributions), making the process of deploying your software easier.
I've blogged about how to use it, also.
With newer subprocess library, you can now use the following code (*nix only solution):
import subprocess
import shlex
filename = 'your_file'
cmd = shlex.split('file --mime-type {0}'.format(filename))
result = subprocess.check_output(cmd)
mime_type = result.split()[-1]
print mime_type
also you can use this code (pure python by 3 byte of header file):
full_path = os.path.join(MEDIA_ROOT, pathfile)
try:
image_data = open(full_path, "rb").read()
except IOError:
return "Incorrect Request :( !!!"
header_byte = image_data[0:3].encode("hex").lower()
if header_byte == '474946':
return "image/gif"
elif header_byte == '89504e':
return "image/png"
elif header_byte == 'ffd8ff':
return "image/jpeg"
else:
return "binary file"
without any package install [and update version]
Only works for Linux but Using the "sh" python module you can simply call any shell command
https://pypi.org/project/sh/
pip install sh
import sh
sh.file("/root/file")
Output:
/root/file: ASCII text
This code list all files of a given extension in a given folder recursively
import magic
import glob
from os.path import isfile
ROOT_DIR = 'backup'
WANTED_EXTENSION = 'sqlite'
for filename in glob.iglob(ROOT_DIR + '/**', recursive=True):
if isfile(filename):
extension = magic.from_file(filename, mime = True)
if WANTED_EXTENSION in extension:
print(filename)
https://gist.github.com/izmcm/6a5d6fa8d4ec65fd9851a1c06c8946ac

converting/mapping linux reference path without altering the file?

Currently on a project that my client needs the reference file path to
remain in linux format. For example
A.ma , referencing objects from --> //linux/project/scene/B.ma
B.ma , referencing objects from --> //linux/project/scene/C.ma
Most of our Maya license here however are on Windows. I can run a
Python script that convert all the paths windows paths and save the
file. For example
Z:\project\scene\B.ma
However I'm trying to figure out a way to do this without converting
or altering the original file.... I'll try to explain what I'm trying to do.
Run the script to open the file.
The script checks for the linux formatted reference path, and all
child path down the hierarchy.
Maps all paths to their appropriate windows formatted paths.
Giving the animators the ability to "save" files normally without running a separate save script.
Is this possible to achieve this with Python script? Or will I need a
fully-compiled plug in to get this to work?
Any suggestion is greatly appreciated.
edit: Thank you for your input.
A little more clarification. The projects were set up for us by a remote company and part of the requirement is that we have to keep the path as is. They come as absolute path and we have no choice in that matter.
We match the mount //linux/ on our Fedora workstations. That same drive is mapped to Z:\ on our windows workstations. We only have 2 Maya license for Linux tho which is why I'm trying to do this.
Here is a solution. First step is to create a dict that keeps track of linux/windows references (don't forget to import the re module for regexp):
>>> def windows_path(path):
return path.replace('//linux', 'Z:').replace('/', '\\')
>>> reg = re.compile('(\w+\.ma) , referencing objects from --> (.*)')
>>> d = {}
>>> for line in open('D:\\temp\\Toto.txt'):
match = reg.match(line)
if match:
file_name = match.groups()[0]
linux_path = match.groups()[1]
d[file_name] = (linux_path, windows_path(linux_path))
>>> d
{'B.ma': ('//linux/project/scene/C.ma', 'Z:\\project\\scene\\C.ma'),
'A.ma': ('//linux/project/scene/B.ma', 'Z:\\project\\scene\\B.ma')}
Then you just need to loop on this dict to ask for file save:
>>> for file_name in d.keys():
s = raw_input('do you want to save file %s ? ' % file_name)
if s.lower() in ('y', 'yes'):
# TODO: save your file thanks to d[file][0] for linux path,
# d[file][1] for windows path
print '-> file %s was saved' % file_name
else:
print '-> file %s was not saved' % file_name
do you want to save file B.ma ? n
-> file B.ma was not saved
do you want to save file A.ma ? yes
-> file A.ma was saved
Many Windows applications will interpret paths with two leading "/"s as UNC paths. I don't know if Maya is one of those, but try it out. If Maya can understand paths like "//servername/share/foo", then all you need to do is set up a SMB server named "linux", and the paths will work as they are. I would guess that this is actually what your client does, since the path "//linux" would not make sense in a Linux-only environment.
You can use environment variables to do this. Maya will expand environment vars present in a file path, you could use Maya.env to set them up properly for each platform.
What you are looking for is the dirmap mel command. It is completely non-intrusive to your files as you just define a mapping from your linux paths to windows and/or vice versa. Maya will internally apply the mapping to resolve the paths, without changing them when saving the file.
To setup dirmap, you need to run a MEL script which issues the respective commands on maya startup. UserSetup.mel could be one place to put it.
For more details, see the official documentation - this particular link points to maya 2012, the command is available in Maya 7.0 and earlier as well though:
http://download.autodesk.com/global/docs/maya2012/en_us/Commands/dirmap.html

Categories

Resources