# White-Background Packshots in ComfyUI, No Photoshop

How I cut the background out of product photos and make packshots locally with ComfyUI on a laptop GPU: a few seconds a photo, no Photoshop and no subscription.

**Canonical:** https://spoko.space/blog/packshots-white-background-comfyui/  
**Language:** en  
**Published:** 2026-10-11  
**Updated:** 2026-10-12  
**Tags:** ComfyUI, packshot, BiRefNet, AI, automation, e-commerce  
**Category:** Guide

---
**You do not need Photoshop or a subscription to put a product on a clean white background.** A laptop with an NVIDIA graphics card, ComfyUI and one open model do it in a few seconds per photo, and a short graph handles the rest: the crop, the margin and the proportions.

## Why I stopped using online tools {#why-i-stopped-using-online-tools}

I need packshots often. Products get photographed wherever they happen to lie: in a box, on the lawn, on the workshop floor. A shop, a catalogue or an offer looks better when every cover is the product alone on white.

I tried online background removers first, among them [iloveimg](https://www.iloveimg.com/remove-background) and [Adobe Firefly's remove background](https://www.adobe.com/products/firefly/features/remove-background.html). The second one did not work well for me. The best result still comes from selecting the part by hand in Photoshop with the Pen Tool. That is the right method for a professional photo session, and the wrong one for hundreds of product thumbnails: it takes too long.

So I did it locally. ComfyUI turned out to be a good fit, because the whole job is a graph that I build once and then run on every photo.

## What ComfyUI is {#what-comfyui-is}

ComfyUI is a free, open-source program that runs AI image models on your own computer. Instead of a single "remove background" button you build a graph: you connect nodes, each doing one thing (load a photo, cut out the background, resize), and the whole graph is your tool. It runs as a local server with a browser interface and an HTTP API, so the same graph works by hand and from a script.

## What you need {#what-you-need}

| | What I use |
| --- | --- |
| Laptop | Lenovo, Intel Core Ultra 9 275HX, 64 GB RAM, Windows 11 |
| Graphics card | NVIDIA RTX PRO 3000 Blackwell Laptop GPU, 12 GB VRAM |
| ComfyUI | 0.13.0 (Python 3.13, PyTorch 2.10 with CUDA) |
| Model | BiRefNet-General |
| Custom nodes | `ComfyUI_LayerStyle_Advance` (runs BiRefNet), `ComfyUI_essentials` (`MaskBoundingBox+`) |

I have not tried it on weaker hardware, so I will not promise numbers there.

## How the graph works {#how-the-graph-works}

The numbers below match the labels on the screenshot.

1. **Source photo.** A `LoadImage` node. It is the only place the graph changes from one photo to the next.
2. **BiRefNet model.** Loads `BiRefNet-General`.
3. **Cut out the part.** `BiRefNetUltraV2` returns a mask: white where the part is, black elsewhere. I use `GuidedFilter` for the edge, erode 4, dilate 2, black point 0.01 and white point 0.99. The node works on at most 4 megapixels internally.
4. **White canvas, then the part on white (4 and 5).** An empty white canvas the size of the photo, and the original pasted onto it through the mask, so everything outside the mask stays white.
5. **Crop to the outline (6).** `MaskBoundingBox+` cuts the image to the box around the mask. This is why the margin is even, whatever the framing of the original.
6. **Fit it into the final frame (7a–7c and 8a–8c).** `ResizeAndPadImage` scales the part into 1800×1300, and a composite node places it at x=100, y=100 on a white 2000×1500 canvas, which leaves a 100 px margin on every side. A second branch does the same into 2000×2000.

I make two files from one pass: a 4:3 one and a square. Tiles and galleries often use different proportions, 3:2 and 4:3 in my case, and a 4:3 image fits both without cutting the part. The square is for anywhere the photo has to fit a square box, such as a thumbnail. The two `PreviewImage` nodes are titled **packshot 4:3** and **packshot 1:1**. Keep those titles if you call the graph from a script, because that is how the script finds the outputs.

Download the graph: [packshot-birefnet.workflow.json](https://spoko.space/downloads/packshot-birefnet.workflow.json) opens in ComfyUI (drop it on the canvas), and [packshot-birefnet.api.json](https://spoko.space/downloads/packshot-birefnet.api.json) is the same graph in the API format for scripts.

### A transparent background instead of white {#a-transparent-background-instead-of-white}

The same mask gives you a transparent background. Invert it with `InvertMask`, feed it to `JoinImageWithAlpha` together with the original photo (that node inverts the mask itself, so the double inversion keeps the part opaque) and save the result as PNG. The cover of this article in dark mode is made this way. Only the cropping and centring I did outside ComfyUI, with ImageMagick.

### Pitfalls I hit {#pitfalls-i-hit}

- **The BiRefNet-General weights have to be downloaded by hand.** The node fetches only a different model on its own:

  ```bash
  python -c "from huggingface_hub import snapshot_download; snapshot_download(repo_id='ZhengPeng7/BiRefNet', local_dir=r'\models\BiRefNet\BiRefNet-General', ignore_patterns=['*.md', '*.txt'])"
  ```

- **With transformers 5 the BiRefNet node failed for me** with `Input type (float) and bias type (c10::Half) should be the same`. Passing `dtype=torch.float32` to `from_pretrained(...)` in the node's `birefnet_ultra_v2.py` fixed it. A newer version of the node may not need this, and an update can undo the change.
- **Do not crop with `CropByMask V2`.** In `min_bounding_rect` mode it keeps only the largest contour, and it cut off the headrests of car seats that are joined to the backrest by thin rods.

## What it looks like while it runs {#what-it-looks-like-while-it-runs}

You press Run and watch. The progress bar fills at the top of the window, the node being computed is outlined in blue, and the job queue on the right lists every finished job with its time. The tab title shows the percentage and the name of the current node, which is handy when ComfyUI sits in the background.

On my laptop a photo of about 2000 px, the size I usually keep, takes 2–4 seconds. A full 3800 px phone photo takes about 5 seconds. The first run after starting ComfyUI is slower, about 6 seconds, because the model has to load first.

## Examples {#examples}

All of these are the raw output of the graph, with no retouching afterwards. The source photo is on the left.

![A fuel filter lying on a grey surface, and the same filter on white](https://spoko.space/_spoko/packshot-example-fuel-filter.BdSTJhW4.webp)

![An engine cover lying on bubble wrap next to a metal wall that reflects everything, with shipping labels beside it, and the same cover cut out on white in the square 1:1 version](https://spoko.space/_spoko/packshot-example-engine-cover.CoX0CVev.webp)

This one came out especially well. The Audi engine cover lay on bubble wrap next to a metal wall that reflects everything like a mirror, with shipping labels next to it, and only the cover was cut out, with the rings and the TFSI lettering sharp. Here you see the square output; the 4:3 one comes from the same pass.

![A pressure pipe with a red hose clamp on grass, and the same part on white](https://spoko.space/_spoko/packshot-example-pressure-pipe.DYmNM8hq.webp)

![A gearbox bracket on a blue cutting mat with a grid, and the same part on white](https://spoko.space/_spoko/packshot-example-gearbox-bracket.CtWr20yX.webp)

![Two front seats on grass, and both seats on white](https://spoko.space/_spoko/packshot-example-front-seats.BxqCW6Qh.webp)

The model is not thrown by a grey table, the grid of a cutting mat, shadows on the grass or a red clamp either. The last pair shows where it goes wrong:

![A fuel filter standing on its cardboard box, and the same filter on white with the box still in the picture](https://spoko.space/_spoko/packshot-example-fuel-filter-on-box.BqV5Ehu3.webp)

The filter stands on its box, and the box stayed in the picture, because the model does not know which object is for sale.

## From one photo to a few hundred {#from-one-photo-to-a-few-hundred}

You can call the graph from any language, because ComfyUI exposes an HTTP API. A script has to do three things: upload the photo and point the `LoadImage` node at it, queue the graph and wait for it to finish, then download the two outputs. This is the whole thing in Python, with the API version of the graph saved next to it:

```python

If the site runs on a server with no graphics card, do not move the work there. Let the computer with the GPU ask the server for waiting jobs instead, one at a time, so the server never has to connect to it. In my [Laravel](https://spoko.space/glossary/laravel/) code the loop looks like this (abridged):

```php
$job = $api->claim(1)[0] ?? null;                       // ask production for a queued render
$packshot = $renderer->render($api->download($job['source_url'])); // run the graph in ComfyUI
$upload = $api->uploadUrl($productId);                  // presigned URL on the CDN
$api->upload($upload['upload_url'], $packshot->jpeg, $upload['content_type']);
$api->upload($upload['square_upload_url'], $packshot->squareJpeg, $upload['content_type']);
$api->complete($productId, $upload['key'], $packshot->workflowVersion->value);
```

If the laptop is off, the jobs wait in the queue and nothing is lost. The graph file is versioned in the repository, and every packshot records which version of the graph made it, so after a change I know which photos to redo. The system around this worker is described in an [inventory system case study](https://spoko.space/garage-inventory-system/).

## Where the model gets it wrong, so I check every result

The model removes everything that looks like foreground. In practice that means a few kinds of photos give a bad result:

- **A part marked with a frame or an arrow on a larger assembly.** An intercooler circled on a stack of radiators comes out as the whole stack.
- **A part photographed on a car.** Wheels on a car come out as the whole car.
- **Other objects or labels in the frame.** They are cut out together with the part, like the cardboard box above.
- **Openings and holes.** The model decides on its own whether what shows through an opening is part of the object. The engine cover above has a round hole: on the 1200×1600 copy the graph cut it out, on the 3028×4038 original it left the packing foil visible in it. The result also changed with the size I scaled the photo to, so check the holes and, if one matters, draw it by hand.
- **Clear lenses, thin wires and chrome.** These can be misjudged, so no packshot is published without my approval.

A finished packshot waits next to its source photo and becomes the cover only after I approve it. If it is wrong, I order it again from another photo where the part lies alone, or I reject it and the page keeps the original photo.

## Comparison with online tools

To test this on something difficult, I ran the same photos through two online tools, [iloveimg](https://www.iloveimg.com/remove-background) (free version, no account) and [Adobe Firefly's remove background](https://www.adobe.com/products/firefly/features/remove-background.html) (also without logging in), and through my graph. Both photos went through all three tools.

### An engine cover on bubble wrap

The first photo is the Audi engine cover from above. It lies on bubble wrap next to a metal wall that reflects everything like a mirror, with shipping labels beside it.

Adobe Firefly took away only the outer edge of the scene and kept 51% of the frame. The bubble wrap, the reflections in the wall and the labels stayed, so the result is still a photo of the whole scene with the cover somewhere in it. iloveimg and the ComfyUI graph both isolated the cover itself, keeping about 15% of the frame.

### An air filter housing on grass

The second photo is an air filter housing lying on grass in strong sun, with a hard shadow, a thin pipe and a connector with cut wires sticking out.

All three tools handled the overall shape, including the pipe and the wires. iloveimg and Adobe return the cutout in the original frame, so the part stays in it and still needs cropping and centring. The graph does that in the same pass and returns a finished 4:3 file with an even margin.

The cutouts of iloveimg and ComfyUI overlap in 99.5% of their pixels, and Adobe's overlaps with each of them in about 98%. Zoomed in, the differences are about sharpness: iloveimg's edges are a little softer than the graph's, and Adobe's are the softest, with bits of grass left between the wires. Adobe also returned the image at 800×600, half the size of the photo I gave it. For the cutting alone iloveimg and the graph are level. What the graph adds is the finished framing and the automation, not a better cutout, and what separates it from iloveimg is the free plan: the service itself says that unlimited image processing comes only with Premium. Adobe Firefly also failed on the first photo, but two photos and one attempt each are an observation, not a ranking.

## When something else is the better choice

- **Photoshop with the Pen Tool** still gives the best edge. It is the right choice for a professional photo session, where a single picture matters and there is time to perfect it.
- **An online remover** is quicker for a single photo, because there is nothing to install. With many photos you have to reckon with the limits of the free plan or with a paid one.
- **A local ComfyUI graph** pays off when you do it often and have an NVIDIA card: the setup takes some time once, and every photo after that takes a few seconds.

## Summary

- ComfyUI with BiRefNet turns a photo of a part into a packshot on white in 2–4 seconds on a laptop GPU. It is free, and the processing happens on your own computer.
- The graph is short: cut out, paste on white, crop to the outline, fit into a frame with a margin. One pass gives a 4:3 file and a square one.
- A short Python script runs it on a whole folder, and a small worker can feed it from a shop or site on a server without a GPU.
- The model does not know which object is for sale, so every result needs a quick look before it goes live.
- For a single photo or for a professional session, an online tool or Photoshop is the better tool.

I use the same tool to upscale photos, too. How do you make your packshots: by hand, with an online tool, or locally? I am curious what works for you and what this graph is missing.

## Frequently Asked Questions {#faq}

### Do I need an NVIDIA graphics card? {#faq-do-i-need-an-nvidia-graphics-card}

I run the graph on an NVIDIA GPU (the BiRefNet node is set to <strong>cuda</strong>). I have not tried a CPU or an AMD card, so I cannot give you numbers for them.

### Is this really free? {#faq-is-this-really-free}

ComfyUI is free and open source, and the BiRefNet weights are downloaded from Hugging Face. Check the licence of the model you use before using the results commercially.

### Can it handle hundreds of photos? {#faq-can-it-handle-hundreds-of-photos}

Yes. The script below sends one photo at a time, because a single GPU gains nothing from a batch: it would only make later photos wait. At 3 seconds a photo, 300 photos take 15 minutes.

### Can I change the margin or the size? {#faq-can-i-change-the-margin-or-the-size}

Yes. The numbers live in nodes 7a–7c and 8a–8c: the canvas (2000×1500 and 2000×2000), the size the part is fitted into (1800 px side) and the position (100 px margin).

### Does it cut every part correctly? {#faq-does-it-cut-every-part-correctly}

No. The model removes everything that looks like foreground and does not know which part is for sale, so I check every result before it goes live. The section on mistakes below shows where it goes wrong.


## Sources {#sources}

- [ComfyUI](https://github.com/comfyanonymous/ComfyUI) — The node-based interface and server that runs the graph.
- [ComfyUI server routes and API](https://docs.comfy.org/development/comfyui-server/comms_routes) — The /upload/image, /prompt, /history and /view endpoints the script uses.
- [BiRefNet](https://github.com/ZhengPeng7/BiRefNet) — The segmentation model that cuts the part out.
- [Bilateral Reference for High-Resolution Dichotomous Image Segmentation](https://arxiv.org/abs/2401.03407) — The paper behind BiRefNet.
- [ComfyUI_LayerStyle_Advance](https://github.com/chflame163/ComfyUI_LayerStyle_Advance) — Custom nodes that load and run BiRefNet.
- [ComfyUI_essentials](https://github.com/cubiq/ComfyUI_essentials) — Custom nodes with MaskBoundingBox+, which crops to the outline of the mask.
- [iLoveIMG pricing](https://www.iloveimg.com/pricing) — The free and Premium plans, including the statement that Premium unlocks unlimited image processing.
