Can I access ImageMagick API with Python? - python

I need to use ImageMagick as PIL does not have the amount of image functionality available that I am looking for. However, I am wanting to use Python.
The python bindings (PythonMagick) have not been updated since 2009. The only thing I have been able to find is os.system calls to use the command line interface but this seems clunky.
Is there any way to access the API directly using ctypes and conversions of some sort?
As a last resort is there any other library out there that has the extensive amount of image editing tools like ImageMagick that I have looked over?

I would recommend using Wand (explanations follows).
I was looking for proper binding to ImageMagick library, that would:
work error/problem free
be regularly maintained and up to date
allow nice objective Python
But indeed python API (binding) has too many different (mostly discontinued) versions. After reading a nice historical overview by Benjamin Schweizer it has all become clear:
GraphicsMagick
PythonMagick - first implementation
PythonMagickWand/Achim Domma - first Wand - a CDLL implementation
PythonMagickWand/Ian Stevens
MagickFoo - included in python-magickwand
Wand/Hong Minhee - not the latest project
[UPD 2023] Eric McConville https://github.com/emcconville/wand
Now Wand is just a (reduced) C API to the ImageMagick ".. API is the recommended interface between the C programming language and the ImageMagick image processing libraries. Unlike the MagickCore C API, MagickWand uses only a few opaque types. Accessors are available to set or get important wand properties." (See project homepage)
So it is already a simplified interface that is easer to maintain.
[UPD 2023] PS as any API software py-wand inherits any transient errors from the parent

This has worked for me for the following command to create an image from text for the letter "P":
import subprocess
cmd = '/usr/local/bin/convert -size 30x40 xc:white -fill white -fill black -font Arial -pointsize 40 -gravity South -draw "text 0,0 \'P\'" /Users/fred/desktop/draw_text2.gif'
subprocess.call(cmd, shell=True)

I found no good Python binding for ImageMagick, so in order to use ImageMagick in Python program I had to use subprocess module to redirect input/output.
For example, let's assume we need to convert PDF file into TIF:
path = "/path/to/some.pdf"
cmd = ["convert", "-monochrome", "-compress", "lzw", path, "tif:-"]
fconvert = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = fconvert.communicate()
assert fconvert.returncode == 0, stderr
# now stdout is TIF image. let's load it with OpenCV
filebytes = numpy.asarray(bytearray(stdout), dtype=numpy.uint8)
image = cv2.imdecode(filebytes, cv2.IMREAD_GRAYSCALE)
Here I used tif:- to tell ImageMagick's command-line utility that I want to get TIF image as stdout stream. In the similar way you may tell it to use stdin stream as input by specifying - as input filename.

Related

Convert PNG to ZPL and print

I'm trying to convert an image to ZPl and then print the label to a 6.5*4cm label on a TLP 2844 zebra printer on Python.
My main problems are:
1.Converting the image
2.Printing from python to the zebra queue (I've honestly tried all the obvious printing packages like zebra0.5/ win32 print/ ZPL...)
Any help would be appreciated.
I had the same issue some weeks ago. I made a python script specifically for this printer, with some fields available. I commented (#) what does not involve your need, but left it in as you may find it helpful.
I also recommend that you set your printer to the EPL2 driver, and 5cm/s print speed. With this script you'll get the PNG previews with an EAN13 formatted barcode. (If you need other formats, you might need to hit the ZPL module docs.)
Please bear in mind that if you print with ZLP 2844, you will either need to use their paid software, or you will need to manually configure the whole printer.
import os
import zpl
#import pandas
#df= pandas.read_excel("Datos.xlsx")
#a=pandas.Series(df.GTIN.values,index=df.FINAL).to_dict()
for elem in a:
l = zpl.Label(15,25.5)
height = 0
l.origin(3,1)
l.write_text("CUIT: 30-11111111-7", char_height=2, char_width=2, line_width=40)
l.endorigin()
l.origin(2,5)
l.write_text("Art:", char_height=2, char_width=2, line_width=40)
l.endorigin()
l.origin(5.5,4)
l.write_text(elem, char_height=3, char_width=2.5, line_width=40)
l.endorigin()
l.origin(2, 7)
l.write_barcode(height=40, barcode_type='2', check_digit='N')
l.write_text(a[elem])
l.endorigin()
height += 8
l.origin(8.5, 13)
l.write_text('WILL S.A.', char_height=2, char_width=2, line_width=40)
l.endorigin()
print(l.dumpZPL())
lista.append(l.dumpZPL())
l.preview()
To print the previews without having to watch and confirm each preview, I ended up modifying the ZPL preview method, to return an IO variable so I can save it to a file.
fake_file = io.BytesIO(l.preview())
img = Image.open(fake_file)
img = img.save('tags/'+'name'+'.png')
On the Label.py from ZPL module (preview method):
#Image.open(io.BytesIO(res)).show(). <---- comment out the show, but add the return of the BytesIO
return res
I had similar issues and created a .net core application which takes an image and converts it to ZPL, either to a file or to the console so it's pipeable in bash scripts. You could package it with your python app call it as a subprocess like so:
output = subprocess.Popen(["zplify", "path/to/file.png"], stdout=subprocess.PIPE).communicate()[0]
Or feel free to use my code as a reference point and implement it in python.
Once you have a zpl file or stream you can send it directly to a printer using lpr if you're on linux. If on windows you can connect to a printer using it's IP address as shown in this stack overflow question
For what is worth and for anyone else reference, was facing a similar situation and came up with a solution. To whom it may help:
Converting the image?
After trying many libraries i came across ZPLGRF although it seems the demo is focused on PDF only, i found in the source that there is a from_image() class property that could convert from image to zpl combining it part of the demo/exaples. Full code description below
Printing from python to the zebra queue?
Many libraries again but i settled with ZEBRA seem to be the most straight forward one to send raw zpl to a zebra printer
CODE
from zplgrf import GRF
from zebra import Zebra
#Open the image file and generate ZPL from it
with open(path_to_your_image, 'rb') as img:
grf = GRF.from_image(img.read(), 'LABEL')
grf.optimise_barcodes()
zpl_code = grf.to_zpl
#Setup and print to Zebra Printer
z = Zebra()
#This will return a list of all the printers on a given machine as a list
#['printer1', 'printer2', ...]
z.getqueues()
#If or once u know the printer queue name then u can set it up with
z.setqueue('printer1')
#And now is ready to send the raw ZPL text
z.output(zpl_code )
The above i have tested successfully with a Zebra GX430t printer connected via USB in a Windows 11 machine.
Hope it helps

Appending images using python and imagemagick

Most people recommend "wand" when it comes to imagemagick for python but how can I append images using it in python ? I want to add lables to bottom of images using imagemagick in python : http://www.imagemagick.org/Usage/annotating/ but wand api seems to be very basic and doesn't have lots of imgemagick commands including labels and appending.
Is there any other way to use imagemagick in python ? my images are png type and are BytesIO streams inside the python code not files so I can not pass them to imagemagick using command line and can't save them on any temporary file either.
I'm not really sure what your asking for, but I'm guessing you want to write a label "below" an image. Here's an example with the wand library.
from wand.image import Image
from wand.compat import nested
from wand.color import Color
from wand.font import Font
with nested(Image(filename='logo:'),
Image(filename='null:')) as (source, text):
text.font = Font('Impact', 64)
text.read(filename='label:Hello world!')
largest_width = max(source.width, text.width)
offset = (largest_width - min(source.width, text.width)) / 2
with Image(width=largest_width,
height=source.height + text.height,
background=Color('WHITE')) as dst:
dst.composite(source, 0, 0)
dst.composite(text, int(offset), source.height)
dst.save(filename="output.png")
Overview
with nested(Image(filename='logo:'),
Image(filename='null:')) as (source, text):
Create two images. You would be responsible for replacing logo: image with your ByteIO buffer. The null: image is a placeholder for allocating a wand instance.
text.font = Font('Impact', 64)
text.read(filename='label:Hello world!')
This defines the typeface & text to draw. The label: protocol can be replaced with caption: for additional behavior(s?).
with Image(width=largest_width,
height=source.height + text.height,
background=Color('WHITE')) as dst:
Create a third "blank" image that is large enough to include both images.
dst.composite(source, 0, 0)
dst.composite(text, int(offset), source.height)
Copy the image data from the source & text to the new image.
Imagemagick is great but has steep learning curve. You need to have 3rd party ImageMagick installed (Would have to be 32 or 64 bit depending on your version of python). Installation alone is a pain considering you need to add it to path and the executable is necessary to run your script.
Consider something more portable and contained like Pillow which has number of features for achieving your goal.
pip install pillow
In pillow you can read images from BytesIO. And also draw or print on them. There is number of options available.
from PIL import Image, ImageDraw
import io
# Reading bytes from file but you can skip that and simply open your bytes like below.
with open('picture.jpg', 'rb') as f:
im = Image.open(io.BytesIO(f.read()))
draw = ImageDraw.Draw(im)
draw.text((10,10), "Hello World", fill=(255))
im.show() # do whatever you like with the image
Check the docs for more examples. https://pillow.readthedocs.io/en/latest/

Specify "Extra Light" font style in MATLAB figure `text` command

I want to use Gotham Cond SSm XLight in MATLAB's text command to draw several digits, letters and symbols in the font above. However, it seems, according to the official documentation, FontWeight in text only allows normal|bold, but not XLight for Extra Light style.
Here is the fonts I have installed in my system.
$ ls GothamCondensed/OpenType/
GothamCondSSm-Black.otf GothamCondSSm-Book.otf GothamCondSSm-Medium.otf
GothamCondSSm-BlackItalic.otf GothamCondSSm-BookItalic.otf GothamCondSSm-MediumItalic.otf
GothamCondSSm-Bold.otf GothamCondSSm-Light.otf GothamCondSSm-XLight.otf
GothamCondSSm-BoldItalic.otf GothamCondSSm-LightItalic.otf GothamCondSSm-XLightItalic.otf
Here is what I used for MATLAB R2015b:
% draw symbol `$' in Gotham Cond SSm XLight
text(0,0,'$','FontName','Gotham Cond SSm','FontWeight', 'XLight');
% also try this, just in case
text(0,0,'$','FontName','Gotham Cond SSm XLight');
text(0,0,'$','FontName','Gotham Cond SSm XLight','FontWeight', 'XLight');
If it is not supported in MATLAB, even by some undocumented java hack, then it would still be great to be able to produce these symbols (e.g. `$') in any language (preferably Python or R) in high resolution by specifying size in pixels, then saving them as grayscale image files. I could then read those image files into my MATLAB struct.

Convert EMF/WMF files to PNG/JPG

I am receiving an form upload with a Word docx document. I got all the parsing done successfully. I have to then display that Word document on the web.
The problem I am running into at this moment is that I have embedded EMF files (that the PIL library recognizes as WMF format), and I cannot figure how to convert them to something that can be displayed on the web (arbitrarily chosen PNG).
The code is somewhat simple:
im = PIL.Image.open(StringIO.StringIO(data))
fmt = im.format
if (fmt == 'WMF'):
fmt = 'PNG'
output = StringIO.StringIO()
im.save(output, format=fmt)
data = output.getvalue()
output.close()
return '''<img src="data:image/{0};base64,{1}" />'''.format(fmt, base64.encodestring(data))
The error i get is:
IOError: cannot find loader for this WMF file
These Word documents come from average user that may just have cut-and-paste images from the web or insert from file.
Is there a solution for me on a linux system?
Thanks.
EDIT:
To my defense, I tried to upload that document to google drive and the image is not displayed either. Maybe there are no simple solutions?
pip install Pillow
from PIL import Image
Image.open("xxx.wmf").save("xxx.png")
I found it easier to use the Wand package for such conversion. I tried the previous suggestions without success. So here is what I did:
(BTW, I wanted to convert all '.wmf' files into pdf)
import os
from wand.image import Image as wima
folder='C:/Users/PythonLover/Pictures/pics'
for oldfilename in os.listdir(folder):
if oldfilename.endswith(".wmf"):
with wima(filename=folder+'/'+oldfilename) as img:
newfilename = oldfilename.split('.')[0]+'.pdf'
newfilename = folder+'/'+newfilename
img.format = 'pdf'
img.save(filename=newfilename)
You need to understand what you are dealing with in order to see why what you are attempting to do is problematic. WMF files (or the more recent EMF and EMF+ formats) require Windows GDI to render the image it describes. So there is no simple solution when you are converting this format outside of Windows, since you need to replicate the GDI API.
One solution is to use the unoconv tool which relies on the UNO bindings for OpenOffice/LibreOffice. A second solution would use the pyemf module to decode the input, and then a second tool (to be done by you) would render it.
You may use libwmf to convert image to SVG and then pyrsvg to convert to PNG (described in another question).
I haven't found libwmf project website, but Debian (and Ubuntu) has package libwmf-bin that contains wmf2svg utility.
WMF stands for Windows Metafile; EMF stands for Enhanced Metafile. These files drive Windows to display an image. Within Microsoft Office applications it is a standard format for vector images. The Metafile is managed by Microsoft and is not an open format.
Since libreoffice is an alternative to Microsoft Office in Linux environment, it would be better to have a small service where we can use libreoffice and imagemagick(install them if you cannot).
Then a language independent solution would be this:
build a libreoffice container using this Dockerfile(or install libreoffice)
FROM linuxserver/libreoffice:7.2.2
start a RESTful API(or RPC API) in the container receiving an emf file and sending back a png file
in the service we implement the following function:
a. save the emf file in a path, say /mnt/b.emf
b. convert the file by the command libreoffice --headless --convert-to png /mnt/b.emf in any language; for example, in Python we can use the snippet at the end of this answer.
c. read the png file /mnt/b.png and send it back via the API
use imagemagick to trim the white space of the resultant image
Here is the Python implementation:
from os
from flask import Flask, jsonify, request
def emf_to_png(im):
temp_emf_path = '/tmp/temp.emf'
temp_png_path = '/tmp/temp.png'
with open(temp_emf_path, 'wb') as f:
f.write(im)
command = f"libreoffice --headless --convert-to png {temp_emf_path} --outdir /tmp"
os.system(command)
command = f'convert {temp_png_path} -fuzz 1% -trim +repage {temp_png_path}'
os.system(command)
f = open(temp_png_path, 'rb')
png_b = f.read()
f.close()
os.remove(temp_emf_path)
os.remove(temp_png_path)
return png_b
app = Flask(__name__)
#app.route("/convert/emf2png", methods=["POST"])
def start_training():
try:
emf = request.data
png_b = emf_to_png(emf)
return jsonify(code=200, message="succeed", data=png_b)
except Exception as e:
return jsonify(code=100, message=f"error {e}")
if __name__ == '__main__':
app.run("0.0.0.0", port=1111)
References:
https://stackoverflow.com/a/28749719/3552975
https://ask.libreoffice.org/t/convert-to-jpg-wmf-on-linux-resolution-issue/44578
I have a similar problem, but I used bash and inkscape to convert the images to png format, I attach the small script that performs this task for me:
#!/usr/bin/bash
for file in *.emf; do
export_name=$(echo $file | sed 's/\.emf$/.png/');
echo inkscape $file -e $export_name
inkscape $file -e $export_name
done
For more information, check the inkscape option:
inkscape --help
# -e, --export-png=FILE NAME
On linux you can use inkscape to do the conversion from .emf to .png with the help of command (pip install Command)
I also tried pillow and wand before, they both only works on windows.
import command
path_emf = 'path_to_your_emf_file'
path_png = 'path_to_save_png_file'
command.run(['inkscape', '-e', path_png, path_emf])

Use ImageMagick with python. (on a linux system) [duplicate]

This question already has answers here:
Can I access ImageMagick API with Python?
(3 answers)
Closed 9 years ago.
I want to define a function that "call" imagemagick to convert an image.
def convert(filein,fileout):
#imagemagick>convert filein fileout
How can I call and use imagemagick with Python?
I'm running on a linux system, imagemagick is installed, and I'm not using PIL.module because it doesn't handle PPM[p3].
Disclaimer: I am the author of Wand.
You can easily do that using Wand, a simple binding of ImageMagick for Python. For example, the following code converts a PNG image to a JPEG image:
from wand.image import Image
with Image(filename='in.png') as img:
img.format = 'jpeg'
img.save(filename='out.jpg')
See this tutorial as well.
Either use one of the shell interfaces of Python (os.system, subprocess.Popen) to call the imagemagick binary, or try out PythonMagick.
I would suggest u use subprocess it is safer
import subprocess
params = ['convert', 'src_file', 'result_file']
subprocess.check_call(params)
I have not used image magic but you could use os.system to call a shell command:
import os
os.system('imagemagick-converting-command filein fileout')
I suggest you go with PythonMagic as Creshal said. It is provided by ImageMagic and thus must be one of the best port available for python.

Categories