Curve-stitch Designs

[ Previous ] [ Home ] [ Up ]

      

Make Your Own Designs
by Lionel E. Deimel

A number of people have asked me how to create curve-stitch designs using PostScript. I have invariably given fragmentary instructions with little expectation that my correspondents would actually have the patience to produce designs of their own with this arcane tool. A recent request from a teacher, however, led me to think that, given a bit more guidance, a few dedicated souls might give my procedures a try. Rather than responding at length in a personalized reply to everyone who contacts me, I thought it might be more efficient to provide some instructions on my Web site once and for all. No doubt, this, too, will generate questions, but it might also lead others to produce some innovative designs.

Background. I first learned of curve-stitch designs in junior high school. My earliest designs were done with pencil and paper. I produced serious designs by trading my pencil for drafting pens and India ink. All the designs shown on Lionel Deimel’s Farrago were generated by computer using the PostScript Language, however. (PostScript is a registered trademark of Adobe Systems Incorporated.) PostScript is a so-called page description language now widely used for desktop and commercial publishing. It first achieved prominence as the language interpreted by Apple’s LaserWriter printer in 1985. PostScript came along about 20 years after I had given up the tedium of drawing designs with pen and ink.

Although most of the PostScript code generated today is produced by computer software to drive devices such as printers, PostScript is a full-blown programming language that can be used by a human programmer. What makes PostScript attractive for producing curve-stitch designs is its extensive repertoire of operators for vector graphics.

The downside of programming in PostScript, at least for the typical programmer, is that PostScript is a highly idiosyncratic language. Programming experience is certainly an asset for the person wanting to learn how to use PostScript, but it is less helpful than one might expect. PostScript makes extensive use of stacks (FIFO queues), which results in code not likely to seem very natural to most programmers. For example, one might write the following PostScript code to set the variable y to the value 3 (x + y) + 1:

/y 1 3 x y add mul add def

One could just have easily written

/y x y add 3 mul 1 add def

or some other variant.

Tools. The standard introduction to PostScript has long been PostScript Language Tutorial and Cookbook. Reading this book and following the exercises in it is a good way to learn PostScript basics. (Order the physical book or use  an electronic version of it.) To get beyond the basics, consult the PostScript Language Reference. Happily, it should not be necessary to read all of this very large book. (Again,, order the physical book or use an electronic version.)

PostScript is written in ordinary, printable characters, so programs can be composed with an ordinary text editor, such as Microsoft Notepad. (This discussion assumes the use of a Windows platform, but the procedures I describe can be carried out in an analogous way on other platforms.) Do not use a word processor, such as Microsoft Word, which saves documents in a special format. A particularly good editor for PostScript programming is Notepad++, which understands PostScript, thereby making programming easier.

Being able to write a PostScript program is of limited usefulness if you cannot display whatever it is the program is intended to draw. A PostScript printer comes in handy here, although you can waste a lot of paper while learning the language if a printer is your only available output device. It is therefore helpful to have a viewer for PostScript files. For many years, I used the free application Ghostscript. This software lacks a user-friendly interface, but another piece of software, GSView, provided a more manageable front-end. The combination allowed me to display PostScript output and generate images in common raster formats such as JPG and PNG. Unfortunately, GSView is no longer available.

Various free viewers are available with which I have no experience. Programs that allow the viewing of PDF files—the PDF format adds capabilities to a PostScript base—can often display PostScript and encapsulated PostScript files (see below). Adobe Acrobat can do this, but the free Acrobat Reader cannot. Although I have used Adobe Acrobat in the past, I have lately been using Kofax Power PDF. This program can print a PostScript or encapsulated PostScript file, convert it to a PDF file, or generate images in several graphic formats. (Oddly, saving a PNG file from a screenshot of a Power PDF window may yield a better image than simply exporting a PNG file directly from Power PDF.) Like Acrobat, Power PDF is not free.

Curve-stitch designs can be distributed as PDF files, but if images are intended for documents or Web sites, raster graphic formats, such as PNG, JPG, or TIF are more helpful. Images in these formats may be acceptable if not too large, but they do not enlarge well. A happy alternative is the SVG (Scalable Vector Graphics) file format. SVG files display sharp images that may be enlarged without image degradation.  The free program Inkscape is a vector graphics editor that can be coerced into displaying PostScript files and exporting the images as SVG files.

Viewing PostScript files in Inkscape is simple, but it requires some configuration of your computer to make this possible. I will explain what you have to do, but I will leave details to the reader, as they will differ from one computer to another. Do the following:

  1. Download and install Ghostscript.

  2. Add the locations of the bin and lib directories of the Ghostscript installation to the Path system environment variable. (On my computer, this required adding C:\Program Files\gs\gs10.00.0\bin and C:\Program& Files\gs\gs10.00.0\lib to the Path variable.)

Although Inkscape displays PostScript files nicely and produces fine SVG files, it cannot export common raster formats such as JPG and PNG.

An Example. The image below is in a SVG format. Enlarge it in your browser, and you will see that the lines continue to be sharply defined.

Example design

The PostScript code that Inkscape used to produced the above image is the ollowing:

%! Adobe-PostScript
			
%%Copyright 2007 by Lionel Deimel. All rights reserved.

% Procedure square2

% This procedure creates a square with generalized curve-stitch
% parabolas drawn inside. The following variables are used:
%
% sidelength: length of side of square (all measurements in points)
% segments: # of equal-length segments into which each side of square is
%           to be divided
% seglength: length of each segment
% offset: distance around perimeter of square in counterclockwise
%         direction (measured in # of segments) betweeen points to be
%         connected in design
% xcoord: array of x-coordinates of (4 x segments) points on square
%         perimeter
% ycoord: array of y-coordinates of (4 x segments) points on square
%         perimeter
% index: loop index representing current point on square perimeter
%        being processed
%
% This procedure expects the following arguments on the stack when
% invoked(the top of stack is at the right):
%
% segments sidelength offset
%
% The procedure draws the design and strokes it.
%
% NOTES: When segments is a even number and offset is segments / 2,
% this procedure draws a square with four standard-construction,
% non-overlapping curve-stitch parabolas inscribed in the corners of
% the square. Other designs result from manipulating the values of
% segments and offset. The value of segments should be positive, but it
% need not be even. The value of offset should be non-negative. Values
% greater than 2 x segments repeat designs achievable with smaller
% offsets.

/square2 {

	% Save entered and computed parameters in dictionary
	/offset exch def
	/sidelength exch def
	/segments exch def
	/points segments 4 mul def
	/xcoord points array def
	/ycoord points array def
	/seglength sidelength segments div def
	
	% Save coordinates of segment endpoints in arrays xcoord and
	% ycoord. The points are numbered, beginning with 0 at the
	% origin and moving counterclockwise around the square.
	0 1 segments 1 sub {
		dup
		/index exch def
		seglength mul /dist exch def
		xcoord index dist put
		xcoord index segments add sidelength put
		xcoord index segments 2 mul add sidelength dist sub put
		xcoord index segments 3 mul add 0 put
		ycoord index 0 put
		ycoord index segments add dist put 
		ycoord index segments 2 mul add sidelength put
		ycoord index segments 3 mul add sidelength dist sub put }
		for

	% Draw square
	0 0 moveto
	sidelength 0 lineto
	sidelength sidelength lineto
	0 sidelength lineto
	0 0 lineto
	closepath

	% Draw internal lines
	0 1 points 1 sub {
		/index exch def
		xcoord index get
		ycoord index get
		moveto
		xcoord index offset add points mod get
		ycoord index offset add points mod get
		lineto }
		for

	% Paint path
	stroke }
	def % square2


% Main program starts here

% Set color for background
0.2 0.4 .8 setrgbcolor
	
% Translate origin to allow for entire picture in upper right quadrant
1 1 translate

% Define dimensions of square and area around square.
% side: width of square
% matwidth: width of background around square
% picwidth: with of entire figure, ignoring framing border
/side 300 def
/matwidth 50 def
/picwidth side matwidth matwidth add add def

% Draw and fill square for curve-stitch design background
0 0 moveto
picwidth 0 lineto
picwidth picwidth lineto
0 picwidth lineto
0 0 lineto
closepath
fill

% Draw black border around just-completed square
0 0 0 setrgbcolor
2 setlinewidth
0 0 moveto
picwidth 0 lineto
picwidth picwidth lineto
0 picwidth lineto
0 0 lineto
closepath

% Paint path
stroke

% Set color and line width for design
1 1 0 setrgbcolor
0.75 setlinewidth

% Translate origin to lower left corner of design
matwidth matwidth translate

% Draw design
24 side 18 square2

% Display page
showpage

%%EOF

I wrote the program in Notepad++, previewed it in Inkscape, and saved the image as an SVG file. The PostScript describes an image at the bottom left of a PostScript logical page. By adding the line below at the top of the PostScript file, I made the logical page the same size as the figure:

<< /PageSize [402 402] >> setpagedevice

GSView can—well, could, anyway—also generate an encapsulated PostScript (EPS) file, which is a self-contained PostScript file intended for incorporation into other documents. A PostScript file can be converted to a usable EPS file by hand. The most important information that has to be added at the top of the file is information about how big the resulting image needs to be. The EPS file generated by GSView from the program above, with a little editing, is the following:

%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 402 402
%%Title: Curve-stitch design example for Lionel Deimel's Farrago
%%Creator: GSview from file web_example.ps
%%CreationDate: Thu Nov 08 13:30:09 2007
%%Copyright 2007 by Lionel Deimel. All rights reserved.
%%Pages: 1
%%EndComments
%%Page: 1 1
%%BeginDocument: Curve-stitch design example for Lionel Deimel's Farrago

% Procedure square2

% This procedure creates a square with generalized curve-stitch
% parabolas drawn inside. The following variables are used:
%
% sidelength: length of side of square (all measurements in points)
% segments: # of equal-length segments into which each side of square is
%           to be divided
% seglength: length of each segment
% offset: distance around perimeter of square in counterclockwise
%         direction (measured in # of segments) betweeen points to be
%         connected in design
% xcoord: array of x-coordinates of (4 x segments) points on square
%         perimeter
% ycoord: array of y-coordinates of (4 x segments) points on square
%         perimeter
% index: loop index representing current point on square perimeter
%        being processed
%
% This procedure expects the following arguments on the stack when
% invoked(the top of stack is at the right):
%
% segments sidelength offset
%
% The procedure draws the design and strokes it.
%
% NOTES: When segments is a even number and offset is segments / 2,
% this procedure draws a square with four standard-construction,
% non-overlapping curve-stitch parabolas inscribed in the corners of
% the square. Other designs result from manipulating the values of
% segments and offset. The value of segments should be positive, but it
% need not be even. The value of offset should be non-negative. Values
% greater than 2 x segments repeat designs achievable with smaller
% offsets.

/square2 {

	% Save entered and computed parameters in dictionary
	/offset exch def
	/sidelength exch def
	/segments exch def
	/points segments 4 mul def
	/xcoord points array def
	/ycoord points array def
	/seglength sidelength segments div def
	
	% Save coordinates of segment endpoints in arrays xcoord and
	% ycoord. The points are numbered, beginning with 0 at the
	% origin and moving counterclockwise around the square.
	0 1 segments 1 sub {
		dup
		/index exch def
		seglength mul /dist exch def
		xcoord index dist put
		xcoord index segments add sidelength put
		xcoord index segments 2 mul add sidelength dist sub put
		xcoord index segments 3 mul add 0 put
		ycoord index 0 put
		ycoord index segments add dist put
		ycoord index segments 2 mul add sidelength put
		ycoord index segments 3 mul add sidelength dist sub put }
		for

	% Draw square
	0 0 moveto
	sidelength 0 lineto
	sidelength sidelength lineto
	0 sidelength lineto
	0 0 lineto
	closepath

	% Draw internal lines
	0 1 points 1 sub {
		/index exch def
		xcoord index get
		ycoord index get
		moveto
		xcoord index offset add points mod get
		ycoord index offset add points mod get
		lineto }
		for

	% Paint path
	stroke }
	def % square2


% Main program starts here

% Set color for background
0.2 0.4 .8 setrgbcolor
	
% Translate origin to allow for entire picture in upper right quadrant
1 1 translate

% Define dimensions of square and area around square.
% side: width of square
% matwidth: width of background around square
% picwidth: with of entire figure, ignoring framing border
/side 300 def
/matwidth 50 def
/picwidth side matwidth matwidth add add def

% Draw and fill square for curve-stitch design background
0 0 moveto
picwidth 0 lineto
picwidth picwidth lineto
0 picwidth lineto
0 0 lineto
closepath
fill

% Draw black border around just-completed square
0 0 0 setrgbcolor
2 setlinewidth
0 0 moveto
picwidth 0 lineto
picwidth picwidth lineto
0 picwidth lineto
0 0 lineto
closepath

% Paint path
stroke

% Set color and line width for design
1 1 0 setrgbcolor
0.75 setlinewidth

% Translate origin to lower left corner of design
matwidth matwidth translate

% Draw design
24 side 18 square2

% Display page
showpage

%%EOF

%%EndDocument
%%Trailer

I hope that this discussion will discourage the fainthearted and encourage the bold. I have no intention of established a Famous PostScript Programmers’ School, but I will try to help any serious student get unstuck if he or she tries to use PostScript and runs into the proverbial brick wall. My e-mail address is below.

Happy coding!

— LED, 11/8/2007, rev. 2/24/2023

Previous Home Up

 
Send mail to Lionel Deimel with questions or comments about Lionel Deimel’s Farrago.
Copyright © 2000-2026 by Lionel Deimel. All rights reserved.