Please can someone help a poor old artist :)

Hi All
I am a professional artist from Norfolk, UK.
I am trying to make some high definition stencils and stumbled across a chaps website that gave some info and details on processing and a script that he had made with help from others here and based on similar code. His zip file can be download here:

https://paolocirio.net/work/hd-stencils/SCRIPT_HD_STENCILS_Open_March_2015.zip

This file includes the script and instructions.
However, I am a dimbo when it comes to programming code and despite getting processing, spending hours and hours creating errors in scripts, I have got nowhere.
Please can someone help.

Its a very short script and I would think quite simple to you clever chaps and chapeses.
It basically is meant to create a pdf file that laser cutters can read, with lots of shapes on that the cutter cuts out. These are tiny holes, although Im not sure how you determine the hole sizes.
The script is designed for use by being able to create a pdf file for each colour channel, from CYMK image files, but I dont even need that, I just want to be able to create one file, not one for each channel. Im just looking to make this HD stencil from a basic greyscale or midtone.
Creating the image is easy for me, not a problem
But altering this code, even with the line tips, is impossible.

I dont know where to add my file, how to change sizes, how to attach various files etc, code changes to point to my image etc. I suspect a lot of the lines can be removed (especially since I only need one colour channel).

I will paste the script below but there are some supporting files that go with it at the link above. These appear to be the files that tell the script the hole shapes etc.

If someone could create a version of this script for me that assumes an image file called “untitled.jpg” or something, with dimensions of 800x600 then at least I can perhaps pick through it and understand it better. If there are any other lines/parameters that I need to be aware of and that I can change please highlight them, then I can try and work it out. But a basic A4 size image with fine holes from loading a single image is enough to create my stencil I think :slight_smile:
Once again thank you, I will donate or send a piece of art to my life savers!

Best Regards
Phil Daniels

Oh heres the script:

/*******************************************************************************
High Definition Stencils
http://paolocirio.net/work/hd-stencils/
Stencils made with the laser cutter for spray paint.
Created and invented by Paolo Cirio between 2011-2015

The script in Processing as well as the technique invented for this project are released in Open Source 
with Attribution-NonCommercial-ShareAlike CC BY-NC-SA This license lets others remix, tweak, and build upon
your work non-commercially as long as they credit you and license their new creations under the identical terms.
http://creativecommons.org/licenses/by-nc-sa/4.0/deed.en_US

Script adapted from: Daniel Shiffman -Example 16-8: Brightness mirror
/********************************************************************************/

//////////////////////////////////////////////////////////////////////////////////
// Load system variables and libraries
import processing.pdf.*;
PImage img;
PShape pointShape;
int cols, rows, imgScale, minDot, offSet, offsetX, offsetY;
int marginY, marginX, centX, centY, holderSize, holderPos, numbDots;
String filename, channel, pinhole;
//////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////
// Configure values to crate the vector files of the stencils
void setup() { 
  
// SET INPUT FILE NAME 
// It must be a JPG, filename will be composed by name color channel + .jpg
filename = "Untitled-1_";

// SET COLOR CHANNEL for OFFSET and OUTPUT FILE 
// Case Sensitive, from Photoshop name files splitting channels
// Cyan, Magenta, Yellow, Black.
channel = "Yellow";

// Set shapte PINHOLES
// Triangle, Circle, Square, Star
pinhole = "Triangle";

// SET RESOLUTION
imgScale = 25;    
// Size of each cell in the grid - smaller numb increases resolution
// 15 quite too high res. very slow
// 20 with all the ones tested _GOOD_
// 30 very big and fast
// 5 - 4 makes better resolution
// 11 good for text and logos

// SET MIN. SIZE Shapes
minDot = 0; 
// originally 0.5 the minum size it draws / smaller numb increases resolution
// for TXT can be 1 / for Pictures can be 0.8 
// 0.2mm minimum cut shape size 

// Set frame for stencil holders
marginX= 137; // 2,5 cm
marginY= 548; // 10 cm
holderSize= 7;
holderPos = 40;

// SET Offset between color channel
// Automatic setting are fine, no panic.
offSet = imgScale/2;
offsetX=offsetY=0;
     if(channel=="Cyan") offsetX =+ offSet;
else if(channel=="Magenta") offsetX =- offSet;
else if(channel=="Yellow") offsetY =+ offSet;
else if(channel=="Black") offsetY =- offSet;

//////////////////////////////////////////////////////////////////////////////////
// RUN MAN RUN !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//////////////////////////////////////////////////////////////////////////////////
// Creates laser cut templates from CMYK channels for spray painting. 
// Uses imported shape or of built-in options.

  pointShape = loadShape("shape" + pinhole + ".svg");
  // pointShape = loadShape("shapeSquare.svg");
 
  // Set INPUT and OUTPUT FILES
  img = loadImage( filename + channel + ".jpg");
  
  size(img.width+marginX,img.height+marginY);
  centX=(marginX/2);
  centY=(marginY/2);


  cols = (width-marginX)/imgScale;
  rows = (height-marginY)/imgScale;
  // smooth();
  beginRecord(PDF, filename + channel + ".pdf");
  
      
        ////////////////////////////////////////////////////
        // Create the hole holder for the stencil at the edge of them
        ellipseMode(RADIUS);
        stroke(255, 0, 0);
        strokeWeight(0.13333); //1pt = 1.3333px => 0.1pt = 0.13333px
        noFill();
        ellipse( holderPos, holderPos, holderSize, holderSize);
        ellipse( ((img.width+marginX)-(holderPos+holderSize)), holderPos, holderSize, holderSize);
        ellipse( holderPos, ((img.height+marginY)-holderPos-holderSize), holderSize, holderSize);
        ellipse( ((img.width+marginX)-(holderPos+holderSize)), ((img.height+marginY)-holderPos-holderSize), holderSize, holderSize);
        
        
  
 // image(img,0,0);
 // background(255);

  img.loadPixels();
  //img.filter(GRAY);
  //img.filter(POSTERIZE, 12);

  for (int i = 0; i < cols; i++) {
    for (int j = 0; j < rows; j++) {

      // pixel-wise
      int x = i*imgScale;
      int y = j*imgScale; 

      // Reversing x to mirror the image
      // In order to mirror the image, the column is reversed with the following formula:
      // mirrored column = width - column - 1
      // int loc = (img.width - i - 1) + j*img.width;
      int loc = x + y*img.width;
      
      // Each rect is colored with a size determined by brightness
      color c = img.pixels[loc];

      // A rectangle size is calculated as a function of the pixel's brightness. 
      // A bright pixel is a large rectangle, and a dark pixel is a small one.
      float sz = (((brightness(c))/255.0)*imgScale*1.1);  //this equation may be adjusted for different shapes
      
      // place something in any case to avoid null spots?
      //if(sz < 1) sz = sz * 0.5;
      // print(sz);
      
      if(sz > minDot){
    
        
        ////////////////////////////////////////////////////
        // Option with drawing the rectacle
        //rectMode(CENTER);
        //fill(c);
        //fill(0);
        //noStroke();
        //noFill();
        //stroke(255, 0, 0);
        //strokeWeight(0.13333); //1pt = 1.3333px => 0.1pt = 0.13333px
  
        //rect(centX + x + offsetX + imgScale/2, centY + y + offsetY + imgScale/2, sz, sz);
        
        ////////////////////////////////////////////////////
        // Option with placing the shape pinhole
        shapeMode(CENTER);
        shape(pointShape, centX + x + offsetX + imgScale/2, centY + y + offsetY + imgScale/2, sz, sz);
        
        // Counting for log data
        numbDots++;
        
       } 
        
    }
  }
  
  // Print logs
  print(numbDots);
        
  endRecord();  //MUST be present when beginRecord() is used
}

void draw() {
  
}
1 Like

I probably should add that during my rough attempts to run this it errors with a box saying:

Could not find sketch size
The size of this sketch could not be determined from your code.
Use only numbers (not variables) for the size() command.
Read the size() reference for more details.

But this is only one of the errors received during my bungled attempts to attach an image to the script and run it. I still think that it could be stripped down (since I only need one colour channel) and perhaps the instruction lines made clearer so I understand what lines to alter if needed :slight_smile:

Hello,

this assumes “untitled.jpg” in sketch folder of size 800x600

you need to copy this into sketch folder

it resizes image to 800,600 on loading

this line size(937, 837);
must be size (image width plus marginX, image height plus marginY) ;
At the moment is correct, but whan you change marginX, marginY, change size too please.

Warm regards to Norfolk,

Chrisir




// assumes "untitled.jpg" in sketch folder and size of it 800x600

// https://discourse.processing.org/t/please-can-someone-help-a-poor-old-artist/11094

/*******************************************************************************
 High Definition Stencils
 http://paolocirio.net/work/hd-stencils/
 Stencils made with the laser cutter for spray paint.
 Created and invented by Paolo Cirio between 2011-2015
 
 The script in Processing as well as the technique invented for this project are released in Open Source 
 with Attribution-NonCommercial-ShareAlike CC BY-NC-SA This license lets others remix, tweak, and build upon
 your work non-commercially as long as they credit you and license their new creations under the identical terms.
 http://creativecommons.org/licenses/by-nc-sa/4.0/deed.en_US
 
 Script adapted from: Daniel Shiffman -Example 16-8: Brightness mirror
/********************************************************************************/

//////////////////////////////////////////////////////////////////////////////////
// Load system variables and libraries
import processing.pdf.*;
PImage img;
PShape pointShape;
int cols, rows, imgScale, minDot, offSet, offsetX, offsetY;
int marginY, marginX, centX, centY, holderSize, holderPos, numbDots;
String filename;
String channel, pinhole;
//////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////
// Configure values to crate the vector files of the stencils
void setup() { 

  // SET INPUT FILE NAME 
  // It must be a JPG, filename will be composed by name color channel + .jpg
  filename = "Untitled-11_"; // in use only for writing

  // SET COLOR CHANNEL for OFFSET and OUTPUT FILE 
  // Case Sensitive, from Photoshop name files splitting channels
  // Cyan, Magenta, Yellow, Black.
  channel = "Yellow";

  // Set shapte PINHOLES
  // Triangle, Circle, Square, Star
  pinhole = "Triangle";

  // SET RESOLUTION
  imgScale = 25;    
  // Size of each cell in the grid - smaller numb increases resolution
  // 15 quite too high res. very slow
  // 20 with all the ones tested _GOOD_
  // 30 very big and fast
  // 5 - 4 makes better resolution
  // 11 good for text and logos

  // SET MIN. SIZE Shapes
  minDot = 0; 
  // originally 0.5 the minum size it draws / smaller numb increases resolution
  // for TXT can be 1 / for Pictures can be 0.8 
  // 0.2mm minimum cut shape size 

  // Set frame for stencil holders
  marginX= 137; // 2,5 cm
  marginY= 237; // WAS: 548; // 10 cm
  holderSize= 7;
  holderPos = 40;

  // SET Offset between color channel
  // Automatic setting are fine, no panic.
  offSet = imgScale/2;
  offsetX=offsetY=0;
  if (channel=="Cyan") offsetX =+ offSet;
  else if (channel=="Magenta") offsetX =- offSet;
  else if (channel=="Yellow") offsetY =+ offSet;
  else if (channel=="Black") offsetY =- offSet;

  //////////////////////////////////////////////////////////////////////////////////
  // RUN MAN RUN !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  //////////////////////////////////////////////////////////////////////////////////
  // Creates laser cut templates from CMYK channels for spray painting. 
  // Uses imported shape or of built-in options.

  pointShape = loadShape("shape" + pinhole + ".svg");
  // pointShape = loadShape("shapeSquare.svg");

  // Set INPUT and OUTPUT FILES
  img = loadImage( "untitled.jpg"); // WAS:   filename + channel + ".jpg");
  img.resize(800, 600);

  //size(img.width+marginX, img.height+marginY);
  //size(img.width+marginX, img.height+marginY);
  size(937, 837);

  centX=(marginX/2);
  centY=(marginY/2);

  cols = (img.width)/imgScale;
  rows = (img.height)/imgScale;

  // smooth();
  beginRecord(PDF, filename + channel + ".pdf");


  ////////////////////////////////////////////////////
  // Create the hole holder for the stencil at the edge of them
  ellipseMode(RADIUS);
  stroke(255, 0, 0);
  strokeWeight(0.13333); //1pt = 1.3333px => 0.1pt = 0.13333px
  noFill();
  ellipse( holderPos, holderPos, holderSize, holderSize);
  ellipse( ((img.width+marginX)-(holderPos+holderSize)), holderPos, holderSize, holderSize);
  ellipse( holderPos, ((img.height+marginY)-holderPos-holderSize), holderSize, holderSize);
  ellipse( ((img.width+marginX)-(holderPos+holderSize)), ((img.height+marginY)-holderPos-holderSize), holderSize, holderSize);

  // image(img, 0, 0);
  // background(255);

  img.loadPixels();
  //img.filter(GRAY);
  //img.filter(POSTERIZE, 12);

  for (int i = 0; i < cols; i++) {
    for (int j = 0; j < rows; j++) {

      // pixel-wise
      int x = i*imgScale;
      int y = j*imgScale; 

      // Reversing x to mirror the image
      // In order to mirror the image, the column is reversed with the following formula:
      // mirrored column = width - column - 1
      // int loc = (img.width - i - 1) + j*img.width;
      int loc = x + y*img.width;

      // Each rect is colored with a size determined by brightness
      color c = img.pixels[loc];

      // A rectangle size is calculated as a function of the pixel's brightness. 
      // A bright pixel is a large rectangle, and a dark pixel is a small one.
      float sz = (((brightness(c))/255.0)*imgScale*1.1);  //this equation may be adjusted for different shapes

      // place something in any case to avoid null spots?
      //if(sz < 1) sz = sz * 0.5;
      // print(sz);

      if (sz > minDot) {

        ////////////////////////////////////////////////////
        // Option with drawing the rectangle
        //rectMode(CENTER);
        //fill(c);
        //fill(0);
        //noStroke();
        //noFill();
        //stroke(255, 0, 0);
        //strokeWeight(0.13333); //1pt = 1.3333px => 0.1pt = 0.13333px

        //rect(centX + x + offsetX + imgScale/2, centY + y + offsetY + imgScale/2, sz, sz);

        ////////////////////////////////////////////////////
        // Option with placing the shape pinhole
        shapeMode(CENTER);
        shape(pointShape, 
          centX + x + offsetX + imgScale/2, 
          centY + y + offsetY + imgScale/2, 
          sz, sz);

        // Counting for log data
        numbDots++;
      }
    }
  }

  // Print logs
  print(numbDots);

  endRecord();  //MUST be present when beginRecord() is used

  println("\nDONE.");
}

void draw() {
  //
}
//
4 Likes

Chrisir

Oh wow thank you.
I placed a jpg file into the folder and named it untitled.jpg and ran the script.
Out plopped a perfect pdf covered in various sized triangles which a laser cutter could load and cut.
These triangles form a shape that corresponds to the tones in the image file.

I think I will try altering the triangle to a round hole, clearly I just change the line that says triangle to be circle.
I dont think I need to play with the size of the holes.

The only thing I need to play with that I dont understand, is the image size.
So I proposed 800x600 just for ease and I realise this has some impact or other with a margin measurement. But if, for example, my image measured 674 wide x 715 high what would I change in the code above? Perhaps the line:
img.resize(800, 600);
Would I just enter my actual image size? ie my example 674x715. so it reads
img.resize(674, 715);
I’m not quite sure what the margin refers to, presumably a margin around the edge that doesnt have holes produced on it.
The current line says:
size(937, 837);
Which seems to add an amount onto the original 800x600. Although there appears to be 137 added to the width and 237 added to the height in that instance (which seems strange)? With my new size should I change it to:
size(952, 811);

If I have the above correct then Im probably good to go. I dont think there is anything else that I need to ever change :slight_smile:

glad you like it

resize

When your image has the right size already just skip the line img.resize(800, 600);
e.g. by changing it to // img.resize(800, 600);
(the // means this is a comment and not code)

size

The other thing is this line size(937, 837);.
As I attempted to explain:
It must be size (image width plus marginX, image height plus marginY) ;
At the moment is correct, but when you change marginX, marginY, change size manually too please.
And with the the new image size it’s 674 plus value of marginX , 715 plus value of marginY,
so change size manually too please.

Regards, Chrisir

2 Likes

another important variable is the resolution

  // SET RESOLUTION
  imgScale = 25;    
  // Size of each cell in the grid - smaller numb increases resolution
  // 15 quite too high res. very slow
  // 20 with all the ones tested _GOOD_
  // 30 very big and fast
  // 5 - 4 makes better resolution
  // 11 good for text and logos
2 Likes

Ah okay, so if my image is the size I want to use, and have it create a PDF to the same size, just take out that line of resizing with the double //

I still struggle with the margin thing in my old age mind, but I think I can get by without worrying to much.

I changed the resolution to 4, down from 25. Oh my god the result was staggering! The level of detail is superb. Its now going to take some testing with different options to get the right results out of a cutter but its looking very good.
Thank you SO much for all your help, so very kind

3 Likes

You are welcome!

Margin is just the white border around the image with the 4 holes in the corners

Chrisir

1 Like

I hate to bump this thread but I’m having a heck of a time finding what material to use for this type of stencil.

Mylar has been alright, probably just need to tweak laser settings but I’m wondering if there’s a particular malleable, synthetic type of sheet that would work well.

What material do you use these stencils?

1 Like

Hate to bump the necro thread again but I’m having some trouble with the mindot size portion of the code.

Example:

// SET MIN. SIZE Shapes
minDot = 0;
// originally 0.5 the minum size it draws / smaller numb increases resolution
// for TXT can be 1 / for Pictures can be 0.8
// 0.2mm minimum cut shape size

No matter what I put in, there isn’t a change in the end result shape size.
1, 0 - no change.
To put in 0.2 - 0.8 I am using:

minDot = (int)(0 - 0.8)

Or variations of (int)(0 -/+ 0.X)

I’m not sure if that is correct, I can’t seem to find if the formatting is wrong or not other than it doesn’t throw a float conversion error. However, it also makes no change to the size of the ‘dot’ on the output file.

Appreciate any tips.

Thanks

This will evaluate to 0.

When you cast this to an integer you lose the decimal part.

:)

Thanks for the reply,

I noticed no float error when using, as a format example:

MinDot= (int)(0.8)

However I am also not noticing a difference in shape size between 0.8 or another decimal like 0.6, for example.

Am I on the right track or just doing it wrong in a different way? Haha

If this is the correct format is the change so slight that perhaps my eyes just aren’t catching it on the output SVG?

Thanks again

Okay, I was finally able to notice some difference using:

minDot = (1)

and

minDot = int(0.8)

There are some dots on right hand image that are not on the left hand image, which makes sense because (1) should be raising the minimum size.

image

The issue that remains is that whether I use int(0.2) or int(0.9), the shapes remain the same size. This leads me to believe I’m casting it incorrectly still for integers but I’m not sure what else to try.

Okay, I might have figured it out, or at least made some progress.

Using:

float minDot = (0.8)
and
float minDot = (0.2)

I am seeing a difference now. Not sure if this is “correct” syntax but… something happened at least.

2 Likes

float minDot = 0.2;

Chrisir

1 Like

Hello,

Java is a strongly typed language.

I encourage you to do some research on Java datatypes.

Some Processing references:

The println() statement may prove useful to you!

:)

1 Like

@glv

Thanks for the resources. I am not well versed in Java programming so this is helpful.

I was so close… :smiley:

Thanks for the correction!