A transparent logo can look fine in a browser preview and acquire a dark rectangle when exported as JPEG. In the preview, the page itself may supply the background. The downloaded file has to contain its own background because ordinary JPEG does not store an alpha channel.
I work on Morphio, which provides HEIC conversion tools. This article describes a small Canvas example, separate from Morphio's implementation. It is useful whenever a conversion workflow mixes photographs with transparent graphics.
What the preview hides
A PNG can store a partially transparent edge around a shape. When a viewer places that edge over white, the visible pixel blends with white. Over a dark page, the same stored edge blends with a dark color. A change in the background changes the visible edge.
Once you flatten the image, the chosen background becomes part of its pixels. Changing the page background afterwards cannot make those pixels transparent again. Keep the PNG source if the asset needs to work on several backgrounds.
The PNG specification describes its alpha representation. For a practical test, use a small transparent image with a circle and a soft edge. A photograph that fills its rectangular frame will hide the problem this example is meant to expose.
Paint the destination first
The function below accepts an already decoded image with positive integer width and height. Set the canvas dimensions before drawing. A fresh context uses normal source-over compositing, so the image is drawn over the background rectangle.
function flattenToJpeg(source, width, height, background = '#ffffff') {
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
if (!ctx) throw new Error('2D canvas is unavailable');
ctx.fillStyle = background;
ctx.fillRect(0, 0, width, height);
ctx.drawImage(source, 0, 0, width, height);
return new Promise((resolve, reject) => {
canvas.toBlob(blob => {
if (!blob) return reject(new Error('JPEG export failed'));
if (blob.type !== 'image/jpeg') {
return reject(new Error('Unexpected output format'));
}
resolve(blob);
}, 'image/jpeg', 0.9);
});
}
Choose the background from the intended destination. White makes sense for a document with a white page; it may leave a visible rectangle in a dark interface. If the destination genuinely needs transparency, keep a format that supports it instead of producing JPEG.
The quality argument controls a lossy encoding setting. It cannot preserve transparency. MDN documents the callback and fallback behavior of toBlob. This snippet checks the resulting type before a caller assigns a JPEG filename.
Inspect curved edges and small text
Export the same source over white and over a dark gray. Open both outputs at their actual pixel size. Compare the curved boundary and any small text. The center of an opaque shape may look identical while its partially transparent edge changes visibly.
Save a test case with the original asset, background color, expected output, and browser used. Avoid assuming that encoded JPEG bytes will be identical across browser engines. The type check catches an unexpected format; opening the image catches an unsuitable background.
This function also assumes the source is safe to draw and export. Remote images require appropriate cross-origin handling; a tainted canvas cannot be exported. The example does not decode HEIC, preserve camera metadata, or promise a particular color-management result. Test those parts separately when integrating the function into a converter.
Keep conversion and presentation separate
For a HEIC photograph, a tool such as Morphio provides a conversion step before upload. For a transparent graphic, decide whether flattening is acceptable before choosing JPEG. Ask for a background only when the input and output require that choice.
Save the original asset separately from the output intended for a particular page. If the page later changes from white to charcoal, regenerate the flattened version from that source. Reopening the previous JPEG and painting behind it will leave the old background in place.