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 17651 days, 5 hours, 16 minutes ago.