DEV Community

Taylor zhu
Taylor zhu

Posted on

How I Turned Photos into Printable Cross-Stitch Patterns in the Browser

Turning a photo into a cross-stitch chart sounds like a simple pixelation task. Resize the image, draw a grid, and you are finished.

That approach can produce something that looks like pixel art, but it does not necessarily produce a pattern that someone can actually stitch.

A usable cross-stitch pattern needs to answer several practical questions:

  • Which embroidery thread corresponds to each color?
  • How many colors should the pattern contain?
  • How large will the finished project be?
  • How can similar colors be distinguished on a printed chart?
  • How many stitches of each color are required?

I encountered these questions while building PhotoToPattern, a browser-based tool that converts photographs and illustrations into printable cross-stitch patterns.

Designing the Conversion Pipeline

I divided the conversion process into several stages:

  1. Load the source image.
  2. Resize it to the selected stitch dimensions.
  3. Sample a representative color for every grid cell.
  4. Match sampled colors to an embroidery-thread palette.
  5. Optionally reduce the total number of colors.
  6. Assign a symbol to each remaining thread color.
  7. Calculate stitch counts and finished dimensions.
  8. Generate printable PNG and PDF charts.

Keeping these stages separate made it easier to adjust the output without rebuilding the entire workflow.

Resizing an Image to a Stitch Grid

Every cell in the resized image represents one cross stitch.

If a user selects a chart width of 80 stitches, the image needs to be resized while preserving its aspect ratio. A simplified Canvas implementation looks like this:

function resizeToGrid(image, gridWidth) {
  const aspectRatio = image.height / image.width;
  const gridHeight = Math.round(gridWidth * aspectRatio);

  const canvas = document.createElement("canvas");
  canvas.width = gridWidth;
  canvas.height = gridHeight;

  const context = canvas.getContext("2d");

  context.drawImage(
    image,
    0,
    0,
    gridWidth,
    gridHeight
  );

  return {
    width: gridWidth,
    height: gridHeight,
    pixels: context.getImageData(0, 0, gridWidth, gridHeight)
  };
}
Enter fullscreen mode Exit fullscreen mode

A larger grid keeps more visual detail but increases the number of stitches. A smaller grid creates a more manageable project but can remove facial features and fine outlines.

This is why PhotoToPattern lets users change the chart size and preview the result before exporting it.

Matching Pixels to Thread Colors

A screen can display millions of colors, but embroidery projects use a limited set of physical threads.

Each sampled pixel therefore needs to be mapped to the closest available thread color. A basic RGB distance calculation might look like this:

function colorDistance(colorA, colorB) {
  const red = colorA.r - colorB.r;
  const green = colorA.g - colorB.g;
  const blue = colorA.b - colorB.b;

  return Math.sqrt(
    red * red +
    green * green +
    blue * blue
  );
}
Enter fullscreen mode Exit fullscreen mode

This is useful as a starting point, but RGB distance does not always reflect how humans perceive color differences. Two colors with a similar numeric distance can look noticeably different, while other colors with a larger distance may appear almost identical.

A more practical conversion system needs to consider perceptual color similarity and then map the result to the available DMC thread palette.

Limiting the Number of Colors

Matching every pixel independently can create patterns containing too many thread colors.

A photograph may contain many slightly different shades of brown, gray, or skin tone. Using all of them would make the project expensive and difficult to stitch without producing a meaningful visual improvement.

Color reduction helps merge similar shades before the final chart is generated.

The difficult part is finding the right balance:

  • Too many colors make the pattern unnecessarily complicated.
  • Too few colors remove important details.
  • Aggressive reduction can merge the subject with the background.
  • Weak reduction can leave several nearly identical thread colors.

Instead of assuming one setting works for every image, I let users adjust the color count and compare the preview.

Why Printed Patterns Need Symbols

A colored grid is useful on a screen, but it may not be sufficient when printed.

Similar thread colors can be difficult to distinguish, especially on a grayscale printer. To address this, every thread color receives a separate symbol.

The final chart combines:

  • The stitch grid
  • Thread colors
  • Unique symbols
  • DMC color references
  • Stitch quantities
  • Finished-size estimates
  • A material list

This turns the processed image into an actual working document rather than just a pixelated preview.

Calculating the Finished Size

The dimensions of a completed cross-stitch project depend on the selected fabric count.

The basic calculation is:

const widthInches = stitchWidth / fabricCount;
const heightInches = stitchHeight / fabricCount;
Enter fullscreen mode Exit fullscreen mode

For example, an 84 × 112-stitch chart on 14-count fabric produces a design measuring approximately 6 × 8 inches.

Showing this estimate before export helps users select an appropriate grid size and fabric.

Keeping Image Processing in the Browser

The main conversion workflow runs locally in the browser.

This allows users to experiment with personal photos without uploading the original image to a separate image-processing server. It also provides immediate previews when grid size, color count, or other settings change.

Browser processing does introduce performance constraints, particularly with large images. Resizing the image before detailed color analysis helps reduce unnecessary work and keeps the interface responsive.

The Working Tool

The resulting converter is available here:

👉 Try the PhotoToPattern cross-stitch pattern maker

It can convert a photo into a chart, match it with DMC thread colors, assign printable symbols, estimate the finished size, generate a material list, and export the result as PNG or PDF.

What I Learned

The biggest lesson was that image conversion and pattern creation are not the same problem.

An image-processing algorithm tries to preserve visual accuracy. A craft-pattern generator also needs to consider cost, readability, available materials, printing, and the amount of work required from the maker.

The technically closest color is not always the most practical choice, and the most detailed chart is not always the best pattern.

I am continuing to improve the balance between image accuracy and stitchability. If you work with image processing or create cross-stitch patterns, I would be interested to hear how you would approach color reduction and palette matching.

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.