G'MIC exercises

I have been asking @David_Tschumperle in private a series of questions, using foo_* commands to help facilitate my learning. The last one might be of interest to you all. Perhaps you already have some idea or already solved this and can help me right away.

I am trying to learn how to apply : (no arg) to my commands. It isn’t so easy. I took some cues from stdlib.gmic to create this foo.

foo_noarg_:
  l[]
    if isnum("$1")
      e[] "good"
      skip ${1=0},${2=1},${3=0}
      a=$1 b=$2 c=$3
    else
      e[] "bad"
      if ["'$1'"]!=',' noarg fi
      a=0 b=1 c=0
    fi
    onfail e[] "ugly" noarg a=0 b=1 c=0
  endl
  sp $a sp $b sp $c

Out of the commands below, only gmic foo_noarg_ q works.

gmic foo_noarg_
gmic foo_noarg_ ,
gmic foo_noarg_ ,0
gmic foo_noarg_ q    # Works (^_^)
gmic foo_noarg_ , q
gmic foo_noarg_ ,0 q

I propose this shorter version:

foo_noarg_: skip ${1=0},${2=1},${3=0}
  l[]
    if "isnum($1) && isnum($2) && isnum($3)" a,b,c=$1,$2,$3
    else a,b,c=0,1,0 noarg
    fi
  onfail a,b,c=0,1,0 noarg
  endl
  sp $a,$b,$c

Your main mistake was that you were using if isnum("$1") before the skip command, where the default values of the arguments are set. skip or check should always be defined as the first instruction of a command. I don’t see any case where it could be useful to have them put elsewhere.

I admit that it was sloppy; I was bending over backwards getting it to work. What I learnt:

1 The conditional should check every parameter, not just the first one.

2 noarg should be the last element in the statement.

The problem I have with your example is that sp $a,$b,$c isn’t the same as sp $a sp $b sp $c.

There should be no difference in practice. Command sample may take multiple arguments.

You are right, if the arguments of sample are numbers (which is the case here), then you should use sp $a sp $b sp $c as you did.
Sorry about that.

Looks like we aren’t finished with our exercise yet. I have changed the variable values to see what happens with different parameters.

foo_noarg_: skip ${1=0},${2=1},${3=2}
  l[]
    if "isnum($1) && isnum($2) && isnum($3)" a,b,c=$1,$2,$3
    else a,b,c=3,4,5 noarg
    fi
    onfail a,b,c=6,7,8 noarg
  endl
  sp $a sp $b sp $c
gmic foo_noarg_      # apples, balloons, barbara
gmic foo_noarg_ ,    # apples, balloons, barbara
gmic foo_noarg_ ,0   # apples, apples, barbara
gmic foo_noarg_ q    # boats, bottles, butterfly
gmic foo_noarg_ , q  # apples, balloons, barbara
gmic foo_noarg_ ,0 q # apples, apples, barbara

gmic foo_noarg_ q is still the odd :duck:. It is the only case where the if condition fails. We never get to see an onfail either. Is onfail even necessary?


Let me skip ahead and tell you what my aim is with this enquiry. This is I want the command to do:

1 If (no arg) or ,, let $1,$2,$3 be random values.
2 If only some are omitted, only the omitted are random values.
3 If all values are specified, then all values are set.

onfail is necessary only in very rare cases. Like if what follow foo_no_arg_ would be something that destroys the math expression, but at the same time corresponds to some weird filename.
Like:

$ gmic foo_noarg_ ").jpeg"

it’s unlikely to happen in practice, but who knows ? :slight_smile:

And you your other request, I’d propose something like this:

foo : skip ${1=?},${2=?},${3=?}
  l[]
    a,b,c=?,?,?
    if ("(isnum($1) || ['$1']=='?') &&
         (isnum($2) || ['$2']=='?') &&
         (isnum($3) || ['$3']=='?')")
       a,b,c=${1-3}
    else noarg
    fi
  onfail noarg
  endl
  sp $a sp $b sp $c
1 Like

What does meshgrid() do in Octave? E.g.,

[cx, cy] = meshgrid(2*pi*[0:cols-1]/cols, 2*pi*[0:rows-1]/rows);

I suspect warp might be involved. Brain juice is lacking ATM. :dizzy_face:


Got it It generates 2 images, one filled along the x-axis and the other along the y. In the case above, the pattern is 2*pi*x/w and 2*pi*y/h.

Actually, I have no idea what you’re trying to do here. @Joan_Rake1 knows what meshgrid is, but I don’t.

Does G’MIC have a function like this?
foo( num,2,5 ) = num^2^2^2^2^2

For fill function - I used this “nexp(a,b,c)=(for(n=0,n<c,n++,a^b));”

Look everyone, my very first macro and use of eval~!

fooip_: skip ${1=2},${2=2},${3=5}
  eval fooip(x,y,z)=x^(y*z);fooip($1,$2,$3) e[] " "${}
gmic fooip_ 2,2,5
 1024

@afre @Iain How would you go by pixel sorting every pixel from top left pixel to bottom right pixel? I would like to pixel sort luminosity of every pixel in an arbitrary width and height in that order.

The only solution I can think of is to make a iterative algorithm which use bubble sorting.

I thought there were already a few commands and functions that do pixel sorting. In addition, fill already goes from pixel to pixel in a loop starting from 0,0,0,0.

pixelsort command gives me the option to go from left to right and top to bottom, but however combining both does not order every pixels from top left to bottom left. I was thinking of something like this.

1 0 5 4
2 2 3 4
8 9 1 3

to

0 1 1 2
2 3 3 4
4 5 8 9

I just learned how to do this :grinning:
This should sort the pixels of a single channel image

Width={w}

-unroll x
-sort x
-split x,$width
-append y

LOL, I was planning to give breadcrumb hints…

Thanks, I did modified it a bit as sort x was giving me a error in Krita.

ww={w}
to_gray
unroll x
pixelsort +,x
s x,$ww
a y

This is the error. 1 layer.


Let’s say I want to extrude pixel in 3d form at a specific distance, then at the bottom, it is a point in space with the point being a color and everything inbetween is a gradient from 4 or 2 channel image to the point color, then finally render the orthographic output. How would I do this?

EDIT - I realized I could use a droste code. I’ll look at those.

EDIT - Nah, I couldn’t do it. I do picture it in my head, just can’t convert into math, and then code it in.

EDIT - This is the closest I could find to the solution, it’s still not the best one though :confused: - Shaped gradient - my first plugin - Plugin Developer's Central - paint.net Forum

There’s also Light Rays, but I don’t know how to make it go backward after looking at the source, and use it to convert it into shaped gradient.

I want to do 3x3 but cannot. There must be a space before x, otherwise x disappears. E.g.

foo_by_:
  t=3 e[^-1] "Filter with a "$t"x "$t" filter" # Filter with a  3 filter

Does \ works? @afre

No, that would introduce a special character. This works though:

foo_by_:
  t=3 e[^-1] "Filter with a "$t{`"120"`}$t" filter" # Filter with a 3x3 filter