The Big Bad G'MIC Thread of Silly Questions

'Godt brølt' og 17 andre ting vi skal holde op med at sige i 2018 : r ...

Ok, i think i’ll stick to black… good night!

2 Likes

I have not read the code, but by any chance, have you considered tiling the patterns? That may be more efficient and solve the last pixel row and column missing issue.

Ok, I’ll explain map again.

Try this code:

foo: 
 (5,4,1,7,8) 
 +resize. 100%,100%,100%,2,1 
 pal spec 
 +map[0,1] [2]

Ok, let’s break it down.

The first image is a single image of 5x1x1x1. It has only one channel.
The second image has 2 channels as it’s dimension is 5x1x1x2. But, every pixels has equal channel value. As the +resize denotes, this second image is a derivation of the first.
pal is a custom command for creating palette. In this case, we generated a palette of 12x1x1x3.
Let’s see what map does for the target images [0,1]

It appears that map assigns a color to each corresponding value. 5 will return the 6th color of pal image which is [168,45,45].

[5] => [168,45,45].
[5,5] => [168,45,45,168,45,45].

That’s why you see 12 channels.

Assuming the R value of your first color is $6 (so B value of your 8th color is $31).
Something like:

(${6-31}) r. 3,8,1,1,-1 permute. yzcx

should work.

Well my guess is that i got the radius wrong. And that maybe the outilne is drawn outside the circle, so the radius is 1px larger?

When i tiled the pattern at the beginning of this adventure, that’s how i found out it was missing a pixel, there was holes (2 whole crossing lines of them) in between the middle circles.
Also, i don’t want to use mirroring. But maybe it would work for that particular pattern.
Anyway the missing pixels are sort of fixed for now… color is another issue.

Actually i understand what’s happening with the channels, it’s just that’s it’s a bit annoying. I have a RGBA image, when i do split c i get 3 black images and the circles are all on the alpha channel…
That tells me that mapping will never work on this image. I tried mapping to a duplicated of the alpha channel: does nothing :open_mouth:

I also quickly tried match_rgb and it sort of work, it’s a bit too smooth though and only one color ( probably expected though).

(${14--1}) r. 3,8,1,1,-1 permute. yzcx
yes, this works just as good as @reptorian’s solution yesterday.
THe thing is i always end up with 12 channels. Looks like an impossible mission here. For some reason the circles are only drawn on the alpha channel, probably because I filled the image with black and 0 alpha.maybe i have to fix that first.

But i’d be perfectly fine with grayscale images, i never was good with color anyway.

You should use display, shortcut d, for debugging breakpoints (some, I understand, also use display to look at images. Interesting). See Post 7, Documentation and examples for writing scripts .

At the outset, interleave this command between those that make up your experimental pipeline. You will effectively single-step through your experimental pipeline. That way, when your pipeline diverges from how you think it should work to what it’s actually doing, then the next d , command stops the pipeline right at the genesis of that divergence, so that you can notice what is going awry, exactly at the point you are leaving the rails. Witnessing such departures is vitally important to furthering your understanding of G’MIC.

Strangely, the deepest insights to be garnered about G’MIC emerge not from my tutorials (splendid though they may be), but from seeing pipelines break. That is because bugs actually reside in our heads. Malformed code is but an outward manifestation of inward — and unsuspected — misunderstandings of G’MIC workings. When a pipeline breaks — and an aptly placed display command catches the calamity in the making — we feel a momentary frisson of bewilderment, as some hitherto cherished idea of how G’MIC works shatters. What we held to be so does not cover the facts in front of us. Fortunately, because of a breakpoint, we are still well-situated to work out the nature of the bugs in our heads, because the event in question has yet to be obscured by the running of subsequent commands. Absent such a breakpoint, and — if we are lucky — then some aspect of the calamity leads to G’MIC throwing an exception, a sort of automatic breakpoint, and we are not yet too far removed from the genesis of the mistake. However, it could be our lot that the defective pipeline runs to completion and we are confronted with a black image or a twelve channel image or an image with weird colors and have little idea of how we obtained the mess.

Now, instead of all of this seeming bother, it may be tempting to test little G’MIC snippet pipelines in the Custom Code filters of gmic-qt. Alas, that handy facility has its limits; it is not built for pipelines running more than a modest length, nor is it really possible to use display as a debugging breakpoint. Whatever is going awry, for example, may produce an image in excess of four channels, or pels with negative values. gmic, operating in a shell, easily takes in stride pels that are less than zero or deep channel images, but such sows no end of confusion within paint programs, where layers cannot exceed four channels and get hysterical with blacker-than-black pels. You need to debug in a shell, debug without the overhead and excess machinery of paint programs getting in the way and — possibly — sowing additional confusion.

So. Before becoming the lead actor in your own personal snuff film, you wrote this pipeline:

`gmic run 'sp tiger s. c . a c  map cool'`

It produced a 12 channel image. How did that happen?

Single stepping through the pipeline given as the run argument, then a debug exercise provides this narrative:

  1. sp tiger d , The image stack acquires from the sample command one w×h×d×s sample with dimensions 750x500x1x3. It appears to be a tiger image.
  2. s. c d , The single image on the stack, so selected with a pip (.) splits, channel-wise, into three scalar images. Put a pin through “scalar”. I’ll revisit the word in the sweet by-and-by. We might interpret this threesome of images, now splayed along the image stack, as the “red”, “green” and “blue” channels of the once-composited tiger, but that is just our suppositions at work. G’MIC’s split command couldn’t care less about our self-imposed interpretations.
  3. . d , The single pip is shorthand for input [-1]. This re-inputs what we interpret to be the blue channel of the tiger image and leaves an image stack with four scalar images, each dimensioned 750x500x1x1.
  4. a c d , An append command, unrestrained by any selection, consoldates the four scalar images into one 750x500x1x4 item. Because display commands have been interleaved, this gives us a readout of image geometry and a pause to consider: do we really want a four channel RGBB image (imposing, still, our color channel interpretations)? Possibly we stop to wonder if what is happening on the image stack has anything to do with our aims are. An RGBB image? we might ask ourselves. Of course, we may not pause to consider, because it is such a pain to interleave d , commands throughout our pipelines. So we let the pipeline flow on.
  5. map cool We’re off the rails now. A twelve channel image. Not our expectations. What happened?

First, a tip of the hat to @David_Tschumperle . His language is terse and efficient. When he wrote the #@cli header for map, the help text runs just so: “Map specified vector-valued palette to selected indexed scalar images” (emphasis mine). A scalar image in G’MIC-speak is a precise idea. It represents a single channel image — always. Should an image be made up of more than one channel, then it is a vector-valued image — always. That is because a pixel of a multi-channel image is multi-part, just like a vector. Though not written out anywhere in any appendix, @David_Tschumperle uses consistent expressions for each of the common image types in G’MIC. A scalar image is a one-channel image.

Second, The help text of map imposes one further quality on its selected images. Not only are selected images composed of single-channel scalars, those scalars are to be taken as indices. What do they index? The vector-valued palette given as map's first argument, either explicitly, as a selection of some palette image on the stack, or symbolically, one of the palettes known to the G’MIC palette command.

Now, I wrote earlier that, generally, G’MIC imposes no general interpretations on image channels. However, that does not preclude certain G’MIC commands from placing specific interpretations on the channels of “selected images.” In this case, map expects selected images to be composed of scalar look-up values that correspond to pixel positions of the given palette.

As I whimsically noted in its tutorial, map is G’MIC’s paint-by-numbers command. It’s modus operandi is to scan each selected image, left-to-right, top-to-bottom, and with each picture element, (pel), i(x,y) , (1) take it to be a scalar value, and (2) use it to retrieve a vector-value from the palette, found by counting from the beginning of the palette until it reaches the position equal to the given i(x,y) index value. map then replaces (‘maps’) the scalar with the retrieved vector value. Here’s a knock-on effect: the selected image goes from being a single channel image of scalars to a vector valued image, one with a channel count equal to that of the of the palette.

Finally, It should be clear, now, how the map cool portion of the pipeline left the rails. map, lacking a selection decorator, defaults to selecting all images on the stack. There is only one image on the stack, the 750x500x1x4 vector4-valued RGBB tiger image. That’s not built like an indexed, scalar image. map is not getting the kind of image that it expects. So it punts.

As with many G’MIC commands, map is designed to behave as reasonably as possible when handed unreasonable selections. When its selection is vector-valued instead of the expected indexed scalar value, map internally (1) performs split c; in the case of the tiger image, it now has four indexed scalar images, inputs more to its liking. (2) map then performs its left-to-right top-to-bottom scan on each of the four split-out channels. Recall the knock-on effect: tiger's channels go from being scalar images to vector-valued ones, composed of vectors retrieved from the palette. As you may surmise, the cool palette is a three-channel vector-valued image. That means each of the four channels of the tiger image become three-channel, vector-valued images in their own right. So, finally, (3) map appends these four, three channel, vector valued images together along the spectral axis, making one output image that has 4×3=12 channels.

The key take-away is not a blow-by-blow of how some particular experimental pipeline left the rails. The key take-away is the technique of single-stepping through pipelines, using interleaved display commands that furnish the raw information on how G’MIC behaves. You observe pipelines unfold one step at a time, and can study each step in a leisurely way, as long as you want.

And — when confronted with unexpected outcomes — you can trace the incorrect results to the bugs (G’MIC misunderstandings) that are residing in your head, where all the really vexatious bugs reside. I daresay that all regular contributors to this forum follow this or a similar debugging pattern when spelunking pipelines. I routinely extract custom commands that I wish to better understand from gmic_stdlib.gmic, put the extracted commands in small foobar.gmic files, and then interleave display commands through out portions of the command’s pipeline that I want to better understand. I sometimes even re-transcribe such commands in what I call the tutorial style, not because I think all custom commands should be written that way, but to force myself to closely read the code as I go about transcribing it.

When you master this technique, there is no real reason to stick with hazy guesses about how G’MIC behaves. You can observe its behavior in a concrete fashion and develop practical understandings on how G’MIC commands work. Soon, you will be proceeding less by guess-work, and more by preconceived, deliberate, engineered plans.

That’s when the fun really begins.

1 Like
1 Like

Ha! Changed the documentation on me! :grinning:

Oh d, oh d, I know thee!
Oh Oh w! I know thou!

William Fakepears

Seriously, d is the comand i use the most, even more than " " (read: input), to the point it bceomes painful to remove them from the script afterwards. So many of them. I also use repeat N { [stuff happening] w } to "done" to check if a repeat goes on for too long (useful for these damned circles).

Lol really?

Yes. I wanted a 4 channel image here because it is what i have in my script. RGBB worked as RGBA here. It wasn’t important what the alpha what. Could have used to_a instead but nvm.
I followed your recommendations btw, drawing circles with color 0,0,0,255 over an image filled with 0,0,0,0. Except i forgot i was drawing black on black so in the end i have 3 black channels and an alpha filled with circles, which is to be expected. Went too fast there. So using map even on only one channel of this image doesn’t do much. My bad, fell into a pit trap there.

Thanks, this is the info i needed.

Reptorian summed it up here, so yes i understood then what map does. 3 x 4 = 12… 3 x 1 = RGB. It was pretty clear then. Except i need the alpha… since i think i’m going this way (Gimp simulation), or at least something like that :

@David_Tschumperle thanks, the map definition is more clear now.

Ok thanks guys. But in the end the thing that annoys me the most is my inability to fill an image evenly with these circles. It only works for square images. No portrait, no landscape. Sad. Gotta figure it out, but i keep failing. @Reptorian got it, but i can’t read his code lol. But don’t bother explaining it to me, you’ve wasted enough time already. I have to come up with my own.

1 Like

mmmm, my first shot at this :


Not there yet i guess. :man_shrugging:

Biggest uestion will be : OMG how am i gonna fill this!? (>_<)

1 Like

label_fg is your friend. It identifies what can serve as a background region. From there a mask, a color background image fashioned from such a mask, and a composite. Serve cold.

1 Like

Thanks. I somehow managed to do it with flood, by blending the leaf with a white background (leaf is just black lines on alpha). This will probably work (although not perfect) as long as the background is a plain color.

The leaf itself is not always generated properly anyway lol.

I’ll try label_fg to see if i can manage…
EDIT: got this far. There are still a feww holes and a bit of alpha but that’s a start…

You can always remove the gray area as a copy before label_fg. Still a great start.

EDIT: +neq 0 would do. neq is short for not equal. That will remove the greys.

1 Like

Ha! I was looking for a fill expression to do that.

The fill expression equivalent would be just +f bool(i).

Even more confusing. +f !!i

I was far from all that… I was going for fill "i>0" but didn’t know what to put next, like how to tell it to fill with this or that color. I should re- read all the tutorial.

EDIT : so in the end i have these two solutions :
Flood with alpha 0:

+blend alpha,1 to_a. 
flood. 0,100%,0,255,0,1,255,255,255,0 
blend[-1,-2] alpha,1

label_fg (I still had to flood it because fill would make the background white):

[0],[0],1,3,255 mv. 1 +blend[-1,-2] alpha,1 
+label_fg. 20,0,0 fill. !!i 
flood. 0,100%,0,0,0,1,0,0,0 n. 0,255 d a[0] [-1],c keep[0,2]

There is a difference though:
Flood ( there is still some kind of color outline):

Label+fill (no color outline left yay!).


But using deform on the source image before label+fill changes the output. Some regions are not filled):

Changed the design a bit, so it’s a bit more stretched and rounder on the top:


Still have to fix the middle part, which is just a “fixed” spline.

1 Like

Seems like you have moved up your game.

Well, in the end it’s still just a bunch of splines in a repeat loop. I’m trying to put things together until i get what i’m looking for. I think i’m more lucky than anything else :slight_smile:
And i was tired of circles hahaha…

Not wasted for me. I’m a writer. I explain stuff — just for the sheer jollies. And — who knows? — I might trigger one of your famously light-hearted and insouciant animations that brings such songs to my heart.

What kind of songs — ? Um. Let’s not go there…

Ah! So, the typewriter game. Hit a key. The face of the typebar strikes the paper, impressing some glyph upon it. Then the carriage translates at a set displacement, as is the wont for monspaced fonts. At the right margin, a carriage return removes all those displacements, translating back to the start point, then translates to the next row by the same set displacement, but vertical. So goes the catalogue of translations, cyclically applied, uniform: perhaps left-left-left-left-4-times-right-and-down, then again, and again, and again `til arms are bloody stumps, perhaps.
Game pieces:

  1. An image, rectangular, with arbitrary dimensions w and h.
    a. Within its confines, we step-and-repeat, these with constant-magnitude displacements. We’d rather not go off edges. Sizing exercises for steps and margins are in the offing: See 2. of Game play.
  2. A glyph, an image bound to the head of a typebar. This typewriter has one typebar — one glyph. We got the typewriter on the cheap, but it’s not very versatile.
    a. Glyphs consist of (maybe very long) position sequences of (x,y) pairs. They mark out circles, ellipses, squares, letter forms — maybe even fancy filigrees.
    b. These plots occupy the confines of an origin-centered, ±unit square, a bounding box, two units on a side. The values of these x, y coordinates all fall within the closed interval [-1,…,1].
  3. Two-channel path images store such glyphs. These occupy G’MIC’s stacks as would any other image. x coordinates occupy channel 0; y coordinates occupy channel 1; a pixel encapsulates the coordinates of one plot.
    a. G’MIC’s curve command consumes glyphs and plays a connect-the-dots game with these plots, drawing the glyph.

Game play:

  1. Plot glyphs so many times across the image (the sx step count) and and so many times down (the sy step count). sx and sy counts are integers and may or may not be equal.
  2. Sizing: To reconcile typebar faces and sx × sy step counts with image dimensions w and h, we (1) divide the image height h by sy, (2) the image width w by sx and (3) take the smaller of ratios w/sx or h/sy.
    a. That minimum establishes the stride of carriage translations; the stride also establishes the side lengths of the bounding boxes encompassing glyphs. It ensures that cumulative measures of the larger step counts fit within corresponding image dimensions.
    b. There is a contention between these sx × sy step counts, the image dimensions w and h and the stride. The image rectangle, perhaps, can be very much wider than it is high — or vice versa. Nonetheless, there are stride specifications where sy >> sx or sx >> sy. Sigh. Oh. Woe and Sorrow. To fit big step counts in correspondingly small image dimensions, the calamaty gives rise to tiny strides and little bounding boxes and unseemingly huge margins. Not pretty, but people can be silly.

Implementation:

A custom command, stampit in steprepeat.gmic carries out the game play. For example, here is a 5 × 3 stamping of a glyph rotated at 11° on a 979 × 1104 image.

gmic -m steprepeat.gmic {979*2},{1103*2+1},1,4 stampit. 5,3,11 r2dx. 50%,5 o. stampit_5-3-11.png
Output image [0] as png file 'stampit_5-3-11.png' (1 image 979x1104x1x4).

The smallest stride arises along the horizontal dimension, so there are large top-and-bottom margins.

A custom command, steprepeat, implemented below, performs the step-and-repeat pattern. It harnesses a fixed path image — the glyph — here rendered orange and generated by a gtutor_mkspectral/gtutor_specplot command pair. These ABN Filigree extracts fabricate paths from spinner chains (aka “wheelies”). How they come about is a story full of prodigious interest and indelible charm, but it is not the story here. The story here is playing the typewriter game with glyphs: the step-wise transit of these from place to place and how one might do that without bloodying oneself at a keyboard.

steprepeat.gmic
stampit: check  isint(${1=1})"        && "\
                ${1}>0"               && "\
                isint(${2=1})"        && "\
                ${2}>0"               && "\
                isnum(${3=0})
   stpx,stpy,rot=${1-3} # stepx, stepy and rotation in degrees.
   foreach {
      -name. canvas
      
      # mkspectral + specplot: Plots the path made by the tip of the last
      #                        spinner on a chain of spinners.
      # Path is in an origin-centered, ±unit square and is 2 units
      # on a side, each straddling the x or y axes. Arguments: 250
      # plots: path computed from three linked spinners each ≈1/3 in
      # length, all with 0° orientation and each spinning at 1, 3 and -13
      # Hertz, respectively.
      -gtutor_mkspectral 250,{0.95/3},0,1,{0.95/3},0,3,{0.95/3},0,-13 # filigree
   #  -gtutor_mkspectral 120,{0.95/2},0,1,{0.95/2},0,3                # 3-petal rose
   #  -gtutor_mkspectral 60,{0.95/3},0,1,{0.95/3},0,2,{0.95/3},0,-4   # bowtie
   #  -gtutor_mkspectral 20,{0.95},0,1                                # circle
      -gtutor_specplot. # Spectral ⇒ temporal conversion. Selected now a path.
      -name. plots
      -steprepeat[canvas] [plots],$stpx,$stpy,$rot
      -remove[plots]
   }

steprepeat : check ${"is_image_arg $1"}" && "\
                   isint(${2=1})"        && "\
                   ${2}>=0"              && "\
                   isint(${3=1})"        && "\
                   ${3}>=0"              && "\
                   isint(${3=1})"        && "\
                   ${4}>=0
   sx,sy,srot=${2-4} # Horizontal, vertical step counts and rotation angle, degrees.
   e[^-1] "Step and repeat given path $1 on image$? $2 times across and $3 times down."
   pass$1
   foreach {
      nm={n}
      -name. canvas
      w,h:=w#$canvas,h#$canvas # canvas dimensions: pels
      dx:=round($w/$sx,1,-1)   # across step length in pels, nearest lower whole pel.
      dy:=round($h/$sy,1,-1)   # down step length in pels, nearest lower whole pel.
      s:=min($dx,$dy)          # minimum across or down step lengths. s: stride. s × s: bounding box.
      mx:=($w-$s*$sx)/2        # across margin: (img. width – ( step length × horiz.step count.))/2
      my:=($h-$s*$sy)/2        # down margin: (img. height – ( step length × vert. step count.))/2
      pass.                    # path plotted in the origin-centered ±unit square
      -name. plots

      # Plots for a box that is just a slight smidgen smaller than
      # the bounding box. Visualization aid. Rotate, scale, shear,
      # translate along with any other path.
      -input (-0.99,-0.99^-0.99,0.99^0.99,0.99^0.99,-0.99^-0.99,-0.99)
      -name. box
      -permute[box] cyzx # swap x,y pairs from width-wise to spectral- (channel-) wise.

      # Set up initial transform from ± unit square to bounding box
      -moveglyph[plots,box] {$s/2},{-$s/2},{$mx+$s/2},{$my+$s/2},$srot
      -repeat {$sy} {
         -repeat {$sx} {
            -curve[canvas] [plots],4,0,0,1,1,255,200,0,255
            -curve[canvas]   [box],4,0,0,1,1,0,200,255,64
            -moveglyph[plots,box] 1,1,$s,0  # Step plots, box, once, +horizonal
         }
         -moveglyph[plots,box] 1,1,{-$sx*$s},$s # Step plots, box, -horizontal by one row,
                                                # then step +vertical, once.
      }
      -keep[canvas]
      -name[canvas] $nm
   }
   remove.

# Compose an affine transformation matrix and apply same
# to a path.
moveglyph : skip ${1=1},${2=1},${3=0},${4=0},${5=0}
   sx,sy,tx,ty,r=${1-5}
   foreach {
      nm={n}
      -name. plots
      -fill[plots] ">
                   begin(
                          M=eye(3);
                          M[0]=$sx;
                          M[2]=$tx;
                          M[4]=$sy;
                          M[5]=$ty;
                          $r>0?M=mul(M,rot([0,0,1],$r°),3)
                        );
                   (M*[I(x,y),1])[0,2]
                   "
      -name[plots] $nm
   }

camtrak:
   foreach {
      name. canvas
      bbs:=min(w#$canvas,h#$canvas)
      steps=200

      # Make glyph
      -gtutor_mkspectral {$steps},0.7,0,1,0.3,0,-4
      -name. glyph
      -gtutor_specplot[glyph]

      # Make path
      -gtutor_mkspectral {0.375*$steps},0.9,0,1,0.1,0,-3
      -name. track
      -gtutor_specplot[track]

      # Scale and translate glyph and track into position
      -moveglyph[track] {0.4*$bbs},{-0.4*$bbs},{0.4375*w#$canvas},{0.4375*h#$canvas}
      -moveglyph[glyph] {0.1*$bbs},{-0.1*$bbs},{I(#$track,0,0)}

      # Make (Δx,Δy) displacements to step glyph along track
      +shift[track] -1,0,0,0,2
      -sub[-1] [-2]
      -crop. 1,100%
      -name. tangents

      # Step and repeat
      -repeat {w#$tangents} {
         -curve[canvas] [glyph],5,30,50%,0,1,255,64,200
	 dx,dy:=I(#$tangents,$>+1,0)
         -moveglyph[glyph] 1,1,$dx,$dy
      }
   } 

Here’s a key bit. Applying affine transforms to path images can translate them from place to place. Or rotate them around a center point. Or scale them outward or toward critical points. Or shear them vertically or horizontally along center lines. Or do, as an indivisible action, any combination of these affine transformations. Here, the verb “apply”, stands for the action of rewriting the x and y coordinates taken from an initial path image and altering these, in place, to reflect the desired motion. Plotting the revised path image follows, perhaps using curve or some such.

Here’s another key bit. By the agency of revising x and y coordinates, path images retain “memory” of all applied transforms, these back to the initially created tabula rasa. path image. This gives step-and-repeat tasks like the typewriter game a straight forward play:

  1. Get glyph A (made by hand, like box, or, like plots, obtained wholesale from a
    gtutor_mkspectral/gtutor_specplot or similar glyph-generating toolset).

  2. Scale and translate glyph A from the origin-centered, ±unit square to the bounding box
    interior. By virtue of their rewriting, the path image coordinates retain these
    scalings and translations.

  3. repeat for vertical_steps:
    a. repeat for horizontal_steps:
    i. plot glyph A
    ii. translate glyph A horizontally 1 × stride
    Done
    b. translate glyph A –(horizontal_steps × stride)
    c. translate glyph A vertically 1 × stride
    Done

The custom command that does the ‘Apply affine transform’ operation is moveglyph. It is a wrapper that hides the mechanics of manipulating affine matrices. Give it a scaling, translation or a rotation (or all three). moveglyph sets up the appropriate affine transform matrix and applies the encoded transforms to the selected image, which is expected to be a path. Plot the path. apply another transform, plot the revised path. Apply another transform. ⇒ ∞. In a sense, the path retains the cumulative effect of the entire sequence of applied transforms.

Affine transforms descend from the garden variety 2×2 rotational/scaling matrices which David illustrated in Post 178 and Post 179 but are “augmented” in the sense that they are denizens of three dimensions and nominally operate on 3D points: (x, y, z) . The outcome of such augmented machinery are projections of 3D points onto 2D surfaces. The extra mechanics permit the inclusion of translation to the pantheon of rotational and scaling transforms, so that affine matrices can, in a uniform way, encode sequences of all three transforms, engendering shapes or motion of a subline character. But users of moveglyph need not worry about this back story; just provide a path image and ask for some transformation flavor and build up composite transforms in their path images.

Such augmentation opens up new possibilities for ABN Filigrees. In future incantations, that filter will furnish filigreed borders of the ilk shown in Squaring the Circle, except that the border need not be square, nor the filigree element a circle, and the whole enterprise can operate in resolution-independent vector graphics, a way of working that is opening up in G’MIC. The logistics of having a shape follow another shape as a guiding path is not difficult to achieve in this scheme of stepping path images with sequences of affine transforms, as the following toy, camtrak illustrates (see steprepeat.gmic, above, for the implementation):

gmic -m steprepeat.gmic 2048,2048,1,3 camtrak. r2dx[0] 50%,5 o. filigree.jpg

Paths:


Glyph and Track

EDIT: Originally posted with wrong glyph-and-track graphic.

2 Likes