Guides / Tutorials
Make a dog silhouette for any breed
By the Dog Image API team. Updated .
A dog silhouette is the filled outline of a dog in one flat color. Because every preview on this site has a transparent background, you can get one in a browser with a single CSS filter, or with a canvas fill that lets you pick any color and save a PNG.
What you need
- A preview URL for one breed and one view. You get it from
GET /api/v1/breeds/{breed}, which needs no key. - A browser. Preview files allow cross-origin reads, so a page on any domain can draw them to a canvas.
- The side view for the classic look. Its id is
left(Left side) orright(Right side).
The images are AI-generated illustrations, so the silhouette is an illustration too, not a trace of a real dog.
Method 1: a CSS filter
filter: brightness(0) sets every color channel to zero. Opaque pixels turn black and transparent pixels stay transparent. That is a silhouette.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Pug silhouette</title>
<style>
body { font-family: sans-serif; display: grid; place-items: center; gap: 8px; padding: 24px; background: #f4ecd8; }
img { width: 320px; height: 320px; }
img.sil { filter: brightness(0); }
.row { display: flex; gap: 24px; align-items: center; }
</style>
</head>
<body>
<div class="row">
<img id="original" alt="Pug, left side view">
<img id="silhouette" class="sil" alt="Pug silhouette">
</div>
<a href="https://dogimage.dev/dogs/pug">Pug image: Dog Image API</a>
<script>
async function previewUrl(breed, view) {
const res = await fetch("https://dogimage.dev/api/v1/breeds/" + breed);
const data = await res.json();
const variant = data.variants.find((v) => v.slug === data.default_variant);
return variant.views[view].preview_512;
}
previewUrl("pug", "left").then((url) => {
document.getElementById("original").src = url;
document.getElementById("silhouette").src = url;
});
</script>
</body>
</html>
Save the file as silhouette.html and open it in a browser. The left image is the preview, the right one is the silhouette.
The filter gives you black. To get another color with CSS alone you have to chain filters and tune them by eye, which is fiddly. The canvas method below is exact.
Method 2: canvas and source-in
Draw the preview on a canvas, then set globalCompositeOperation to "source-in" and fill a rectangle. With source-in, the new fill only shows where something already exists on the canvas. The transparent area stays empty and the dog's shape takes the new color.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Colored silhouette</title>
<style>
body { font-family: sans-serif; display: grid; place-items: center; gap: 12px; padding: 24px; }
canvas { width: 320px; height: 320px; background: #fff7e0; }
</style>
</head>
<body>
<canvas id="c" width="512" height="512"></canvas>
<label>Color <input id="color" type="color" value="#2d4a3e"></label>
<button id="save">Save PNG</button>
<a href="https://dogimage.dev/dogs/samoyed">Samoyed image: Dog Image API</a>
<script>
const canvas = document.getElementById("c");
const ctx = canvas.getContext("2d");
const img = new Image();
function paint() {
ctx.globalCompositeOperation = "source-over";
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = "source-in";
ctx.fillStyle = document.getElementById("color").value;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
async function load(breed, view) {
const res = await fetch("https://dogimage.dev/api/v1/breeds/" + breed);
const data = await res.json();
const variant = data.variants.find((v) => v.slug === data.default_variant);
img.crossOrigin = "anonymous"; // set before src
img.onload = paint;
img.src = variant.views[view].preview_512;
}
document.getElementById("color").addEventListener("input", paint);
document.getElementById("save").addEventListener("click", () => {
canvas.toBlob((blob) => {
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = "samoyed-silhouette.png";
a.click();
URL.revokeObjectURL(a.href);
}, "image/png");
});
load("samoyed", "left");
</script>
</body>
</html>
The canvas CSS background is only for your eyes. The exported PNG keeps a transparent background, because toBlob writes the canvas pixels and not the page styles.
Why crossOrigin matters
Drawing an image from another origin taints the canvas unless the server allows it and the image asks for it. This site allows cross-origin reads on preview files, and img.crossOrigin = "anonymous" is the request. Without it, toBlob throws a security error. Set the property before src, or the browser loads the image the first time without permission.
Use the preview URLs from the JSON, not a redirected API URL, so the file you draw is the file the browser loads.
Other views and breeds
Change the two arguments to load("beagle", "right") or load("dachshund", "left"). Each dog fills at most 80% of a square canvas, so silhouettes come out centered with room around them. The head view makes a good round badge. See the side view reference for what the side view shows.
Credit when you publish
The exported PNG is a derivative of a preview. If you publish it, keep a visible link crediting Dog Image API on the same page. The license is the reference. If you want a silhouette for print, the paid 2048 pixel PNGs give you a larger source. See pricing.
Questions
Why does a silhouette work so well with these images?
The background is transparent, so only the dog's pixels carry color. A filter or a canvas fill that repaints those pixels gives you the outline of the dog and nothing else.
Why does my canvas export fail with a security error?
The image was loaded without cross-origin permission, so the browser marks the canvas as tainted. Set crossOrigin to anonymous on the image before you set its src.
Do I need to credit Dog Image API for a silhouette?
If you publish a page that shows or is built from a preview, keep the credit link on that page. The breed page gives you the exact snippet.
Which view makes the best silhouette?
The left side view (id left) or right side view (id right). The outline shows legs, tail, ears and snout at once.
Next steps
- API docs: endpoints, keys, limits and errors.
- All dog breeds, each with nine views.
- Pricing for full-size transparent PNG files.
- A dog breed card with Tailwind CSS
- A dog breed gallery in SvelteKit
- A dog breed picker in Angular
- A dog breed selector in Vue 3