Convert a PIL image to GMIC stream's string for CLI

result = run([r'gmic.exe','my_image.png','-fx_solidify_td','75,1,20,0,0','-o','png:-'], stdout=PIPE, shell=True)
#print(result.stdout)
image = Image.open(BytesIO(result.stdout))
image.save("my_image_GMIC.png", "PNG")

In Python 3.8, I’m trying to input a ‘my_image.png’ as a stream to a python subprocess command, I think I can input ‘(my_imageAsAGmicStream)’ in place of ‘my_image.png’ im the above CLI. But I cannot figure out how to write the my_imageAsAGmicStream from a PIL image.
So is there a way to convert a PIL image to a GMIC string’s stream for the CLI?
I doesn’t figure out also how to send to stdin the bytes of the image, and retrieve the stdout. Perhaps an other solution. Gmic-py is not available on my OS (win10)

Thanks in advance,

Ramel

1 Like

@Ramel welcome to the forum!

@myselfhimself @KaRo would be most familiar with this subject. Let’s wait for them to reply.

1 Like

Hello @Ramel,

Welcome aboard in this community!

PIL (Pillow / Python Imaging Library) being for Python mostly, you may use the new gmic-py G’MIC Python binding. It has helpers for GmicImage to PIL.Image bidirectional conversions, as well as for scikit Image and numpy Image.
The details for this are on the gmic-py documentation website: gmic-py.readthedocs.io, especially the PIL support page. Also, the flipbook-making tutorial has some PIL<->G’MIC magic at the beginning.

import gmic
import numpy
from PIL import Image, ImageSequence

im = Image.open("moonphases.gif")

images_list = []

for frame in ImageSequence.Iterator(im):
    images_list.append(gmic.GmicImage.from_PIL(frame))

gmic.run("display", images_list)

Right now, gmic-py is available:

  • for Linux through pip install gmic(see available versions here: https://pypi.org/project/gmic/#history ; you may get the latest unstable version through pip install gmic==2.9.4a1 )
  • for MacOS through MacPorts (port install gmic), this is very new so, not documented yet on the gmic-py documentation website
  • for Windows… not yet despite many requests… but you can use the Windows Subsystem Linux (WSL or WSL2) shell, and pip install gmic just the way you would for Linux, with possible display windows if you use vcxsrv. This is also quite new but undocumented yet.

gmic-py wraps the libgmic C++ library, so its gmic.run() entry points imitates its C++ counterpart’s method signature which is gmic::run(commands, gmic_list of gmic_image buffers, gmic_list of gmic_image strings)

In gmic-py, your piece of code would need to be written as:

  • first version, if you just care about saving to a filesystem file… without PIL:
import gmic
gmic.run("your command output yourfile.png") # note that the "display" command instead of output is your friend in gmic-py for popping up a preview window without your needing to save anything to a file
  • second version, if you want to keep the resulting image(s) buffer(s) around and pass them on to numpy/PIL/scikit-image. Note that you must have numpy installed (pip install numpy) if you want PIL/gmic-py I/O, because the gmic-py’s PIL uses a GmicImage->numpy.ndarray->PIL.Image bridging (and backwards too) as there is a missing codec in PIL (interleaved float64…):
import gmic
import PIL
images = [] # the libgmic gmic_list of images is a pure Python list in gmic-py, you need to create one and tie to a variable first if you want to explore and handle your list later on for other operations
gmic.run('my_image.png -fx_solidify_td 75,1,20,0,0', images) 
print(images) # shows a regular Python list of one GmicImage only I believe, depending on how fx_solidify_td alters your gmic images list
myPILImage = images[0].to_PIL() # your PIL Image object

If you intend to use gmic.run() a lot, it is inefficient in terms of performance because it spawns and deletes a G’MIC interpeter object each time, instead of keeping one alive, tying a gmic.Gmic() object to a variable is the way to go. This is explained in tutorial 2.

1 Like

Thanks @myselfhimself for the reply.
I’m first trying to not use gmic-py as it’s not available in Win10. So my idea is to known how to convert a RGBA image to a GMIC stream string to input it between the () in the CLI.
The stream should be some formatted string, but I don’t see any information about it on GMIC website. There is a sample but I cannot figure which format is the :

https://gmic.eu/tutorial/_input.shtml

A white cross on a black field

gmic '(0,0,0,255;0,0,0,255;0,0,0,255;255,255,255,255,255,255,255;0,0,0,255;0,0,0,255;0,0,0,255)'

As I suppose I can translate my input image to this form, but how?

Thanks

Perhaps a (r,g,b;r,g,b;r,g,b) array ?

Something like:

$ gmic input.png img2str e ${}

(you may have to quote things depending on the shell you use).

1 Like

Have you tried running python3 and pip under WSL at least?
https://www.youtube.com/watch?v=5RTSlby-l9w

I do not want to force you into this, though. I know that a native windows gmic-py availability is somewhat urgent regarding the demand…

@myselfhimself I’ll try to avoid Wsl for now, but I’ll make a try later, you’re right gmic-py seems the best option if I cannot do it in DOS CLI :slight_smile: It’s a shame it’s not available in Windows.
@David_Tschumperle yes, the missing command. Thanks, Gmic power at the rescue.

1 Like