# Inner/Outer Stroke Offset Possible?

**URL:** <https://discourse.processing.org/t/inner-outer-stroke-offset-possible/38075>\
**Category:** Coding Questions\
**Created:** [July 24, 2022, 1:56pm UTC](https://discourse.processing.org/t/inner-outer-stroke-offset-possible/38075 "2022-07-24T13:56:39Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![arbo](https://avatars.discourse-cdn.com/v4/letter/a/ed8c4c/32.png) [@arbo](https://discourse.processing.org/u/arbo)\
**Post date:** [July 24, 2022, 1:56pm UTC](https://discourse.processing.org/t/inner-outer-stroke-offset-possible/38075/1 "2022-07-24T13:56:39Z")

</div>

Using P5js, is it possible to create either an inner or outer equidistant stroke line which follows the contour of the shape?

Take for example the image below. if I had the capitol letter ‘E’ and wanted to draw the inner blue line. How can I code something like this in P5js?  
 ![e_outline](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/5/2/5245939b8bcf00e680fe6959f0aec9a3082e6f8e.jpeg)

The ‘beginContour’ function seems to be the right idea, but don’t know how to apply this to advanced shapes.

The solution may be simple, I just can’t seem to wrap my brain around an implementation.

---

<div class="post-metadata">

**Author:** ![TimeLex](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/timelex/32/12869_2.png) [@TimeLex](https://discourse.processing.org/u/TimeLex)\
**Post date:** [July 24, 2022, 4:26pm UTC](https://discourse.processing.org/t/inner-outer-stroke-offset-possible/38075/2 "2022-07-24T16:26:44Z")

</div>

You could draw the shape with a specific stroke weight and extract the outlines by using a convolution. if you only want to get the inner or outer line, you can draw it only if it is inside or outside of your shape.

---

<div class="post-metadata">

**Author:** ![TimeLex](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/timelex/32/12869_2.png) [@TimeLex](https://discourse.processing.org/u/TimeLex)\
**Post date:** [July 24, 2022, 5:00pm UTC](https://discourse.processing.org/t/inner-outer-stroke-offset-possible/38075/3 "2022-07-24T17:00:09Z")

</div>

I wrote this code. It’s very messy but i hope you get the Idea:

```auto
void setup() {
  size(500, 500);
  
  PVector[] shape = new PVector[]{new PVector(100, 100), new PVector(400, 100), new PVector(400, 200), new PVector(300, 200), new PVector(300, 300), new PVector(400, 300), new PVector(400, 400), new PVector(100, 400)};
  
  background(255);
  
  PGraphics shapeGraphics = createGraphics(width, height);
  shapeGraphics.beginDraw();
  shapeGraphics.strokeCap(ROUND);
  shapeGraphics.stroke(0);
  shapeGraphics.strokeWeight(30);
  for(int i = 0; i < shape.length; i++) {
    PVector v1 = shape[i];
    PVector v2 = shape[(i+1)%shape.length];
    shapeGraphics.line(v1.x, v1.y, v2.x, v2.y);
  }
  shapeGraphics.endDraw();
  
  PGraphics innerArea = createGraphics(width, height);
  innerArea.beginDraw();
  innerArea.noStroke();
  innerArea.fill(0);
  innerArea.beginShape();
  for(PVector vert : shape)
    innerArea.vertex(vert.x, vert.y);
  innerArea.endShape(CLOSE);
  innerArea.endDraw();
  
  loadPixels();
  for(int x = 0; x < width; x++)
    for(int y = 0; y < height; y++) {
      color current = shapeGraphics.pixels[x + y*width];
      boolean sameColor = true;
      for(int dx = -1; dx <= 1; dx++)
        for(int dy = -1; dy <= 1; dy++)
          if(x+dx >= 0 && x+dx < width && y+dy >= 0 && y+dy < height && shapeGraphics.pixels[x+dx + (y+dy)*width] != current) {
            sameColor = false;
            dx = 1;
            dy = 1;
          }
      if(!sameColor && alpha(innerArea.pixels[x + y*width]) > 256/2)
        pixels[x + y*width] = #000000;
    }
  updatePixels();
  
  stroke(#FF0000);
  strokeWeight(2);
  noFill();
  beginShape();
  for(PVector vert : shape)
    vertex(vert.x, vert.y);
  endShape(CLOSE);
}

```

 ![Frame](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/8/0/80476c02f754ff5729cda4b8e2921f1979c8ded0.png)

---

<div class="post-metadata">

**Author:** ![arbo](https://avatars.discourse-cdn.com/v4/letter/a/ed8c4c/32.png) [@arbo](https://discourse.processing.org/u/arbo)\
**Post date:** [July 24, 2022, 6:22pm UTC](https://discourse.processing.org/t/inner-outer-stroke-offset-possible/38075/4 "2022-07-24T18:22:57Z")

</div>

TimeLex,

Thank you for the fast response! Exactly what I was looking for.

This is a clever implementation. You obviously have a lot of experience with Processing.  
I’ve been playing with the different parameters in your code to better understand what’s going on.

How about for a PFont character? If I read in an OTF font of the letter ‘D’ for example. How would you implement a solution to put an outline border on the inside or outside of that letter?

Thanks.

---

<div class="post-metadata">

**Author:** ![svan](https://avatars.discourse-cdn.com/v4/letter/s/82dd89/32.png) [@svan](https://discourse.processing.org/u/svan)\
**Post date:** [July 24, 2022, 7:04pm UTC](https://discourse.processing.org/t/inner-outer-stroke-offset-possible/38075/5 "2022-07-24T19:04:34Z")

</div>

There are open source embossed fonts available online.

---

<div class="post-metadata">

**Author:** ![TimeLex](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/timelex/32/12869_2.png) [@TimeLex](https://discourse.processing.org/u/TimeLex)\
**Post date:** [July 24, 2022, 8:09pm UTC](https://discourse.processing.org/t/inner-outer-stroke-offset-possible/38075/6 "2022-07-24T20:09:01Z")

</div>

One way would be to represent the arc as many small segments. However, it’s not perfect and can be very power hungry. It is also possible to paint a circle for each pixel of one color in an image. then you have the same effect and you just have to find out which pixels of it are in the figure. One possibility could be to group the contiguous pixels and the group with fewer pixels is the inner one. This technique could be used for any closed figure image. However, I recommend doing this step only once and saving the resulting image, as this process is very performance consuming.

---

<div class="post-metadata">

**Author:** ![TimeLex](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/timelex/32/12869_2.png) [@TimeLex](https://discourse.processing.org/u/TimeLex)\
**Post date:** [July 24, 2022, 9:27pm UTC](https://discourse.processing.org/t/inner-outer-stroke-offset-possible/38075/7 "2022-07-24T21:27:18Z")

</div>

Here the version for images:

```auto
PImage originImg;

void setup() {
  size(500, 500);
  
  noSmooth();
  
  originImg = imageFromText(" D ", width, height);
}

void draw() {
  background(0);
  
  blendMode(LIGHTEST);
  tint(#00FF00);
  image(originImg, 0, 0);
  tint(#00FFFF);
  image(outlines(wideImage(originImg, 150*max(mouseX, 1f)/width)), 0, 0);
}

void keyPressed() {
  originImg = imageFromText(" "+str(char(keyCode)).toUpperCase()+" ", width, height);
}

PImage wideImage(PImage in, float weight) {
  PGraphics out = createGraphics(in.width, in.height);
  out.beginDraw();
  out.background(#000000);
  out.noStroke();
  out.fill(#FFFFFF);
  for(int x = 0; x < in.width; x++)
    for(int y = 0; y < in.height; y++) {
      if(brightness(in.pixels[x + y*in.width]) > 256/2)
        out.circle(x, y, weight);
    }
  out.endDraw();
  return out;
}

PImage imageFromText(String text, int w, int h) {
  PGraphics out = createGraphics(w, h);
  out.beginDraw();
  out.background(#000000);
  out.fill(#FFFFFF);
  out.textAlign(CENTER, CENTER);
  out.textSize(h);
  float textWidth = out.textWidth(text);
  if(textWidth / w > 1f)
    out.textSize(h * w / textWidth);
  out.text(text, w/2f, h/2f);
  out.endDraw();
  return out;
}

PImage outlines(PImage in) {
  PImage out = createImage(in.width, in.height, ARGB);
  out.loadPixels();
  for(int x = 0; x < in.width; x++)
    for(int y = 0; y < in.height; y++) {
      color current = in.pixels[x + y*in.width];
      boolean sameColor = true;
      for(int dx = -1; dx <= 1; dx++)
        for(int dy = -1; dy <= 1; dy++)
          if(x+dx >= 0 && x+dx < in.width && y+dy >= 0 && y+dy < in.height && in.pixels[x+dx + (y+dy)*in.width] != current) {
            sameColor = false;
            dx = 1;
            dy = 1;
          }
      out.pixels[x + y*in.width] = sameColor ? #000000 : #FFFFFF;
    }
  out.updatePixels();
  return out;
}

```

 ![Frame](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/f/9/f9fb388b564f4766eacc2f05651eec52dfc1b99a.png)

I’ve not implemented the method for filtering the inner or outer line so you currently get both.

---

<div class="post-metadata">

**Author:** ![arbo](https://avatars.discourse-cdn.com/v4/letter/a/ed8c4c/32.png) [@arbo](https://discourse.processing.org/u/arbo)\
**Post date:** [July 24, 2022, 11:06pm UTC](https://discourse.processing.org/t/inner-outer-stroke-offset-possible/38075/8 "2022-07-24T23:06:11Z")

</div>

TimeLex,

Thanks so much. This is totally amazing!  
I’m amazed at the pool of skilled talent this forum has to offer.

arbo.
