Tutorial: Compiling G'MIC for Android Devices

Preamble

Although G’MIC has not been officially or extensively developed or tested on the Android platform, I have found ways in which to do so.
(Note: for Android version 7.0 and above)
The first way we could do it, would be to simply install the Termux terminal emulator (details below) and type:

pkg upgrade

followed by:

pkg install gmic

This will give you the latest available version of gmic as a command-line interface and you can then use it for image processing and the like to your heart’s content…

Except…

…certain users (well, just me as far as I know), have reported some filters are just not working at all, although the cause of these discrepancies hasn’t been definitively determined, it could be processor architecture or maybe application conflicts etc, having things randomly not work is a real pain…

So to attempt to resolve this issue I went about compiling G’MIC on an Android phone, as a relative novice in all things programmatic - in that I can produce very basic Python scripts, usually for image processing etc, and I have a certain level of experience with the command-line in Windows as well as Linux - I would not be classed as an expert. So I was pleasantly surprised to be able to compile it myself (and to fix the initial problem) - so here we go!

Compiling gmic cli

In order to compile the G’MIC command-line interface (cli) on an Android device, try the following method:

If you haven’t done so already install F-Droid, this is a good place to download Termux (there are other ways which I shall come to, but there are other great applications at F-Droid, so why not…).

Download the F-Droid APK file at https://f-droid.org - confirm the download and, tap on ‘Open’, choose the default ‘Open with Package installer’ or similar, or open it from your Downloads directory and take it from there if you prefer. Then tap on ‘Install’ and confirm that. Open the app, and once it has finished updating repositories, you can search using the Spy Glass icon bottom-right of the screen to search for Termux.

As I mentionad, there are other ways to get Termux i.e. the Github releases page here, as well as other methods, the thing to avoid is (sinister music plays) the Google Play Store as the Termux version there is deprecated and could therefore be problematic, so best to go with the latest from the above mentioned parties!

Okay so download the Termux app and open it, you may be prompted to give consent for privileged access and the like, do this (it’s perfectly safe) and continue to the Termux terminal, which is much like any standerd interface like Windows command prompt or the Linux terminal, there will be displayed some helpful hints and messages, and you can get going.

A good way to learn the basics of Termux is to visit the wiki here Termux - Getting started.
So, best practice, as stated before type in to Termux:

pkg upgrade

Next up is Proot Distro, from the Github page it tells us a little bit about it:
“A Bash script wrapper for utility proot for easy management of chroot-based Linux distribution installations. It does not require root or any special ROM, kernel, etc.
…PRoot Distro is not a virtual machine. This is a container environment manager based on proot utility which is able to emulate chroot and mount --bind.”

So we need this in order to get ourselves a Linux distribution within our Termux environment, in order to utilise tools not available to the native Termux distribution, for our purposes I’ll be using Ubuntu.

So, in the Termux terminal, type or paste:

pkg install proot-distro

Once that is complete, we do:

proot-distro install ubuntu

When that completes, to enter the Ubuntu instance, type or paste:

proot-distro login ubuntu

and you should see:

root@localhost:~#

From there type:

apt-get update

You are now ready for G’MIC!

Okay first off the G’MIC webpage compilation guide states “First you need to install all the required tools and libraries:”, so to do that type or paste:

apt install git build-essential libgimp2.0-dev libcurl4-openssl-dev libfftw3-dev libtiff-dev libjpeg-dev libopenexr-dev qtbase5-dev qttools5-dev-tools

We don’t need to type ‘sudo’ because proot provides a way to simulate a root filesystem without actually needing root privileges on the host system. Which is nice.

Once completed get the G’MIC source, type/paste:

wget https://gmic.eu/files/source/gmic_3.4.0.tar.gz && tar zxvf gmic_3.4.0.tar.gz && cd gmic-3.4.0/src

Now to compile, the advice is to type
‘make cli’, however, a note of caution, this may not be (and wasn’t in my case) sufficient, so it would be wise to do the following in order to ‘tune’ your Android processor architecture to the GCC compiler functionality.

A slightly long-winded (but necessary) way of finding out the architecture name is the following command :

gcc -mtune=native -Q --help=target

This will proceed to list a lot of stuff, but what we need to find out is what the ‘-mtune’ line tells us, you may need to do some scrolling past the ‘enabled’ and ‘disabled’ entries (they are in alphabetical order luckily) to find ‘-mtune’ and thus to find your architecture type, in my case it was ‘cortex-a55’. Yours will be different probably.

The output however can make it tricky to see exactly what we’re after due to wraparound effets, as seen here (top of image)

You’ll find out your processor architecture type this way, keep a note of it, you will need it soon - and it’s on to the next step, editing the Makefile.

As you should still be in the gmic source directory, now type:

nano Makefile

This brings up our gmic Makefile in the nano editor, use the search function by pressing ‘CTRL + w’, type:

-mtune=generic

press enter, you will see the parts (two entries) to edit, replace them with the value you obtained. In my case that was ‘cortex-a55’.

Before:

After:

Now press ‘CTRL + o’ follwed by Enter, to save the file, then ‘CTRL + x’ and Enter to exit nano.
With the Makefile edited it’s now time, finally, to compile gmic cli.

This could take a long time, make sure your battey level is high enough, you don’t want it to power off.

We will need to use certain flags that are specifically used for older gcc versions, however, this seems to work also for Android devices for whatever reason, and I’m not guessing because I’d probably be wrong let’s face it, all I know is, it works, so the command to use is:

make cli OPENMP_CFLAGS="" OPENMP_LIBS=""

This will take quite a long time, but eventually it should complete and you can now use gmic command-line interface for FREE, I know it’s crazy right! (All donations welcome!). Hours of fun… Projects completed… Making people in photos look funny etc. Seriously though - it’s a powerful tool, and full respect and regards to, most importantly, @David_Tschumperle for furnishing us with this amazing tool in the first place, and to all the devs, technicians, writers, testers, designers, artists and hobbyists who all contribute to and embrace this wonderful project! (Got a bit emotional there snif)

Before you do use it though you should update the filters with:

gmic up

If you’re using a phone/tablet and don’t have access to a G’MIC gui and so can’t copy filter parameters easily, you might be a bit stuck, so as a quick (random) guide we have:

gmic image.jpg denoise 5,5,8 -o output.jpg
gmic image.jpg fx_warp_perspective 1.4,0.67,1,8.2,70,0,52,3 o warped.jpg
gmic image.jpg fx_adjust_colors 0,-3.18,4.5,0,5.25,0,50,50 -o new_coloured.jpg
gmic image.jpg jeje_normalize_local_variance 34.1,8.14,11.3,3,0,0 -o newlv.jpg

You could even string all those filters together into one command:

gmic image.jpg denoise 5,5,8 jeje_normalize_local_variance 34.1,8.14,11.3,3,0,0 fx_adjust_colors 0,-3.18,4.5,0,5.25,0,50,50 fx_warp_perspective 1.4,0.67,1,8.2,70,0,52,3 -o combo.jpg

Why you would want to do that is anybody’s guess, but it goes to prove that the possibilities are (almost) endless!
If I want to peruse a filter’s parameters without access to a GUI, I can perhaps dig out some old scripts I put together, and modify them, or I could go to https://gmic.eu/update340.json - and look at how to construct the parameters of any filter I wish - it can be a tricky and time consuming process, but it can also prove fruitful.
List of gmic commands may help too for some easier copy/pasting.
Have fun!

“I tell you, we are here on Earth to fart around, and don’t let anybody tell you different.”
(Kurt Vonnegut, from A Man Without a Country)

4 Likes

Thanks for taking the time to write this tutorial :slight_smile:
Funny enough, on a macbook air, mtune is empty. Might be normal though?

You can also use G’mic Online to copy the filters’ params.

1 Like

Yes, I suggested it, but it is not best practice. Better practice is to override symbols originally defined in the Makefile itself with command line over-rides; in this regime, do not edit the Makefile.

In particular, override the symbol for cc optimization flags: OPT_CFLAGS, so your make command discards the previous definition (in the Makefile) and replaces it with that found on the command line. In accordance with this example:

make cli OPENMP_CFLAGS="" OPENMP_LIBS="" OPT_CFLAGS="-03 -mtune=cortex-a55"

Perhaps smarter than my first example in 3.4.0 filters issue… Post #9 would be:

$ gcc -c -Q -march=native -mtune=native --help=target | sed 's/[[:space:]]*//g' | grep -E 'march=|mtune='
-march=znver4
-mtune=znver4
Knownvalidargumentsfor-march=option:
Knownvalidargumentsfor-mtune=option:

(znver4 is peculiar to AMD processors, here an AMD Ryzen 9 7950X3D.)
That is, first pipe to the stream editor (sed) to remove all white space (as defined by your language locale); this minimizes the possibility of line wrapping on narrow Android phone displays. Then the output of the white-space-stripped stream is piped to the pattern matcher, which finds only those lines with either march= or mtune= patterns. This should dramatically cut down on the volume of text one has to search through.

Commonly, -march and -mtune appear together but sometimes -mtune is omitted. -march chooses an Instruction Set Architecture (ISA). Choosing an ISA does not induce the compiler to actually optimize the resulting assembly language in an ISA-specific way. that is what -mtune asks for. It is a bit unusual to specify -mtune without also explicitly choosing -march. To illustrate:

gosgood@bertha ~ $ gcc -c -Q -mtune=native --help=target | sed 's/[[:space:]]*//g' | grep -E 'march=|mtune=' 
-march=x86-64
-mtune=znver4
Knownvalidargumentsfor-march=option:
Knownvalidargumentsfor-mtune=option:

If I were to use only a -mtune=znver4 compiler option, then the ISA in play, x86-64, would only include the most common assembly language instructions of Intel / AMD processors, for which I am asking for optimizations for a Ryzen 9 7950X3D processor — but I have excluded the assembly language instructions specific to the 7950X3D processor, so my optimizations are probably not going to be very optimal. In light of that, you probably would want to amend your tutorial to include both -march and -mtune switches.

There will be those out there who couldn’t be arsed for searching through anything. For those folk, there could be this command line:

make cli OPENMP_CFLAGS="" OPENMP_LIBS="" OPT_CFLAGS="-03 -march=native -mtune=native"

which means ‘pick my ISA for me, (I don’t really want to know what it is) and optimize the assembly language instructions for it, (whatever that may be).’ They wouldn’t make use of $ gcc -c -Q -mtune=native --help=target… at all and avoid trying to make sense of its output.

That could be quicker, but if errors like this crops up:

x86_64-pc-linux-gnu-g++: error: 03: linker input file not found: No such file or directory

then a more deliberative and careful setting of -march and -mtune is called for, and the fellow looking for a fast get-a-way will have to look these up through gcc -c -Q -march=native -mtune=native --help=target output.

1 Like

Oops, didn’t mean to besmirch the sacred Makefile! I shall repent…
Seriously though, I had attempted to change the -march entr(y)(ies) to -march=armv7-a+fp
… but if I recall the output suggested something untoward… so that’s why I decided on just the -mtune entries to modify. Also I tried changing the values to ‘native’ but the compiler didn’t want to know…
Anyway, food for thought, appreciate it!

EDIT:
Oddly, the gcc query:

gcc -c -Q -mtune=native --help=target | sed 's/[[:space:]]*//g' | grep -E 'march=|mtune='

produces a truncated result for me still, i.e.:

-march=armv7-a+fp
-mtune=cortex- 
1 Like

At the end of the day, it works for you, and probably works for a bunch more. That is good. Thanks again for posting!