crossstitch.frink

View or download crossstitch.frink in plain text format


// Program to simulate cross-stitch.

// Draws a single "x" in a cross-stitch.
drawX[gr is graphics, left, top, right, bottom, r, g, b, sdColor, threadWidth, subThreads, jitter] :=
{
   width = right-left
   height = bottom-top
   halfWidth = width / 2
   halfHeight = height / 2

   perSide = sqrt[subThreads]

   // Width of each sub-thread
   subWidth = threadWidth / perSide * 1.1   // TODO:  Make this changeable
   halfThreadWidth = threadWidth / 2
   quarterThreadWidth = threadWidth / 4

   xc1 = left  + halfThreadWidth
   yc1 = top  + halfThreadWidth
   
   xc2 = right - halfThreadWidth
   yc2 = bottom  - halfThreadWidth

   halfThreadWidth = threadWidth / 2
   
   gr.stroke[subWidth]
   gr.color[.5,.5,.5]
   gr.fillEllipseCenter[right,bottom,threadWidth,threadWidth]
   for n = 0 to subThreads-1
   {
      xx = (n mod perSide) / perSide
      yy = (n div perSide) / perSide

      xo = threadWidth * xx - halfThreadWidth
      yo = threadWidth * yy - halfThreadWidth

      jitterWidth = subWidth * jitter
      
      gr.color[randColor[r, sdColor],
               randColor[g, sdColor],
               randColor[b, sdColor],
               .5]

      gr.line[randomGaussian[xc1 + xo, jitterWidth],
              randomGaussian[yc1 + yo, jitterWidth],
              randomGaussian[xc2 + xo, jitterWidth],
              randomGaussian[yc2 + yo, jitterWidth]]

      gr.color[randColor[r, sdColor],
               randColor[g, sdColor],
               randColor[b, sdColor],
               .5]
      
      gr.line[randomGaussian[xc1 + xo, jitterWidth],
              randomGaussian[yc2 + yo, jitterWidth],
              randomGaussian[xc2 + xo, jitterWidth],
              randomGaussian[yc1 + yo, jitterWidth]]
   }
}

// Picks a normally-distributed color component around the color component x
// with specified standard deviation.
randColor[x, sd] := constrain[randomGaussian[x, sd], 0, 1]

// Constrains the value of x to be between min and max.
constrain[x, min, max] := (x < min ? min : (x > max ? max : x))

// Draw a cross-stitch of the image.
crossStitchImage[gr is graphics, i, left, top, right, bottom, steps] :=
{
   w = i.getWidth[]
   h = i.getHeight[]

   aspect = w/h
   if (aspect > 1)              // Wider than tall?
   {
      xstep = w/round[steps*aspect]
      ystep = h/steps
   } else
   {
      xstep = w / steps
      ystep = h / round[steps/aspect]
   }

   threadWidth = .3 xstep
   
   for x=0 to w-xstep step xstep
      for y = 0 to h-ystep step ystep
      {
         [r,g,b,a] = i.averagePixels[x,y,x+xstep, y+ystep]
         drawX[gr,x,y,x+xstep,y+ystep,r,g,b,.15,threadWidth,36,.7]
      }
}

g = new graphics
g.backgroundColor[0.7,0.7,0.7]
//i = new image["http://futureboy.us/images/futureboydomethumb4.gif"]
//i = new image["file:maui.jpg"]
//i = new image["file:kittyface.jpg"]
i = new image["file:jeffreycrop.jpg"]
crossStitchImage[g, i, 0, 0, 1, 1, 40]
g.show[]
g.write["jeffreycrop.html",1000,800]
browse["jeffreycrop.html"]
g.write["jeffreycrop.svg",1000,800]


View or download crossstitch.frink in plain text format


This is a program written in the programming language Frink.
For more information, view the Frink Documentation or see More Sample Frink Programs.

Alan Eliasen was born 17592 days, 15 hours, 28 minutes ago.