Deep Dives

How to Convert BMP to JPG, PNG, and WebP: A Practical Guide

koboshiCo-founder
·7 min read
How to Convert BMP to JPG, PNG, and WebP: A Practical Guide
Summary

BMP is easy to read but bulky to store. This guide covers native OS tools, command-line workflows, and code-driven conversion in five languages so you can turn BMP into JPG, PNG, or WebP with confidence.

A 1920 × 1080 BMP saved at 24 bits weighs just under 6 MB. The same image as a quality-90 JPEG is usually under 500 KB. That roughly ten-to-one gap is why BMP files still show up in legacy scanners, medical software, and Windows internals — and why they usually need to be converted before they can be used anywhere else.

BMP's real advantage is simplicity. Converting it well means knowing when that simplicity helps, when it gets in the way, and which target format actually fits the job.

Why BMP Still Exists

BMP stores pixels with minimal header overhead. No Huffman tables, no DEFLATE state machine, no chroma subsampling. For embedded systems, legacy Windows tools, and any situation where the whole task is "read the header, copy the bytes," that simplicity is genuinely useful.

The same limitations are what pushed it out of everyday use:

  • No effective compression. Uncompressed BMPs are large. RLE variants exist, but they rarely beat modern codecs.
  • No reliable alpha channel. The 32-bit BMP alpha byte is inconsistently supported across tools.
  • Bottom-up row order. Most BMPs store rows from the bottom of the image upward, which adds a small conversion step for anything expecting top-down data.
  • No metadata ecosystem. No EXIF, no ICC profile support in the classic header, no animation.

For archival or compatibility, BMP is fine. For web, email, mobile, or storage efficiency, it needs to become something else.

Picking the Right Output Format

Before running a command or writing code, decide what you are optimizing for.

TargetUse whenTrade-off
JPGPhotographs, previews, any screen displayLossy, but file sizes are tiny
PNGGraphics, screenshots, anything needing transparencyLossless, larger than JPG for photos
WebPModern web, apps, anywhere bandwidth mattersSmaller than JPG/PNG, broad browser support

If you are converting a scanned document with text and diagrams, PNG keeps edges sharp. If you are converting a photo from a legacy device, JPG or WebP is the right call. For web delivery, WebP usually wins on size.

Our browser-based BMP to JPG, BMP to PNG, and BMP to WebP converters handle all three cases locally — the file never leaves your device.

Converting on Windows

Paint

  1. Open the BMP in Paint.
  2. Choose File > Save as.
  3. Select JPEG picture, PNG picture, or WebP image.
  4. Save.

Paint works for one-off files. It offers no quality control and no batch option, so it is not practical for folders of images.

PowerShell (ImageMagick)

Install ImageMagick from the official installer, then:

magick input.bmp output.jpg
magick input.bmp output.png
magick input.bmp output.webp

For batch conversion in a folder:

Get-ChildItem *.bmp | ForEach-Object {
    magick $_.FullName ($_.BaseName + ".jpg")
}

PowerShell without external tools

Windows 10 and 11 include the .NET imaging stack. This works for BMP to JPG and PNG, but not WebP without an extra library:

Add-Type -AssemblyName System.Drawing
$img = [System.Drawing.Image]::FromFile("input.bmp")
$img.Save("output.jpg", [System.Drawing.Imaging.ImageFormat]::Jpeg)
$img.Dispose()

Converting on macOS

Preview

  1. Open the BMP in Preview.
  2. Choose File > Export.
  3. Pick the format from the dropdown.
  4. Adjust quality for JPEG if needed.

Preview is fast and private, but like Paint it handles one file at a time.

Terminal with sips

sips is built into macOS and supports BMP, JPEG, PNG, and TIFF:

sips -s format jpeg input.bmp --out output.jpg
sips -s format png input.bmp --out output.png

WebP requires ImageMagick or cwebp from the webp Homebrew package:

brew install webp

# cwebp does not read BMP directly, so convert to PNG first
sips -s format png input.bmp --out temp.png
cwebp temp.png -o output.webp
rm temp.png

Batch shell loop

for f in *.bmp; do
    sips -s format jpeg "$f" --out "${f%.bmp}.jpg"
done

Converting on Linux

ImageMagick

sudo apt install imagemagick

magick input.bmp output.jpg
magick input.bmp output.png
magick input.bmp output.webp

Adjust JPEG quality:

magick input.bmp -quality 90 output.jpg

Batch conversion

for f in *.bmp; do
    magick "$f" "${f%.bmp}.jpg"
done

If you only need the smallest possible WebP output, use cwebp directly:

for f in *.bmp; do
    cwebp -q 85 "$f" -o "${f%.bmp}.webp"
done

Converting with Code

When you need conversion inside an application, pipeline, or backend service, calling a library is usually cleaner than shelling out to ImageMagick.

TypeScript / Node.js

Use sharp. It handles BMP input and outputs JPG, PNG, and WebP.

import sharp from "sharp"

async function convertBmp(
  input: string,
  output: string,
  format: "jpg" | "png" | "webp"
) {
  await sharp(input)
    .toFormat(format, format === "jpg" ? { quality: 90 } : undefined)
    .toFile(output)
}

await convertBmp("input.bmp", "output.jpg", "jpg")
await convertBmp("input.bmp", "output.png", "png")
await convertBmp("input.bmp", "output.webp", "webp")

In the browser, where you cannot run sharp, our BMP to WebP converter uses WebAssembly to decode and encode entirely on the client.

PHP

PHP has built-in image functions if the GD extension is enabled.

<?php

function bmpToJpg(string $input, string $output, int $quality = 90): void {
    $image = imagecreatefrombmp($input);
    imagejpeg($image, $output, $quality);
    imagedestroy($image);
}

function bmpToPng(string $input, string $output): void {
    $image = imagecreatefrombmp($input);
    imagepng($image, $output);
    imagedestroy($image);
}

function bmpToWebp(string $input, string $output, int $quality = 90): void {
    $image = imagecreatefrombmp($input);
    imagewebp($image, $output, $quality);
    imagedestroy($image);
}

bmpToJpg("input.bmp", "output.jpg");
bmpToPng("input.bmp", "output.png");
bmpToWebp("input.bmp", "output.webp");

Go

Go's standard library does not read BMP, but golang.org/x/image/bmp does. For output, use image/jpeg, image/png, and golang.org/x/image/webp.

package main

import (
	"image/jpeg"
	"image/png"
	"os"

	"golang.org/x/image/bmp"
	"golang.org/x/image/webp"
)

func bmpToJpg(input, output string, quality int) error {
	f, err := os.Open(input)
	if err != nil {
		return err
	}
	defer f.Close()

	img, err := bmp.Decode(f)
	if err != nil {
		return err
	}

	out, err := os.Create(output)
	if err != nil {
		return err
	}
	defer out.Close()

	return jpeg.Encode(out, img, &jpeg.Options{Quality: quality})
}

PNG and WebP follow the same pattern with png.Encode and webp.Encode.

Java

Java's ImageIO reads BMP out of the box. For WebP output you need a library such as webp-imageio or cwebp bindings.

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class BmpConverter {
    public static void bmpToJpg(String input, String output, float quality) throws IOException {
        BufferedImage image = ImageIO.read(new File(input));
        File out = new File(output);
        ImageIO.write(image, "jpg", out);
    }

    public static void bmpToPng(String input, String output) throws IOException {
        BufferedImage image = ImageIO.read(new File(input));
        File out = new File(output);
        ImageIO.write(image, "png", out);
    }
}

For finer JPEG quality control, use the JPEGImageWriteParam API.

Python

With Pillow, Python is the most straightforward way to convert BMP to any common format.

from PIL import Image

with Image.open("input.bmp") as img:
    img.convert("RGB").save("output.jpg", quality=90)

with Image.open("input.bmp") as img:
    img.save("output.png")

with Image.open("input.bmp") as img:
    img.save("output.webp", quality=90)

For transparency-aware conversion to PNG, preserve the original mode instead of forcing RGB:

with Image.open("input.bmp") as img:
    img.save("output.png")

Common Pitfalls

  • Indexed-color BMPs. 8-bit or lower BMPs use a palette. Some decoders return palette indexes instead of RGB values if you do not explicitly convert. In Pillow, img.convert("RGB") solves this before saving to JPEG or WebP.
  • Bottom-up orientation. Most libraries handle this automatically, but if you are writing a manual BMP decoder, remember that a positive height field means rows are stored bottom-up.
  • JPEG quality defaults. Many tools default to 75–80. For photos that will be viewed full screen, 90 is a safer default. For thumbnails, 70–80 is fine.
  • WebP compatibility. WebP has excellent browser support but still fails in some older desktop image viewers. If the destination is a native Windows app, PNG or JPG is safer.

What to Use Where

  • Legacy archives: Keep the original BMP. Storage is cheap; losing the canonical version is not.
  • Web uploads: Convert to WebP. If you need a fallback, keep a JPG copy.
  • Print or editing workflows: PNG keeps the image lossless and avoids compression artifacts.
  • Email and messaging: JPG is the safest universal format.

If you want a fast path with no install, no command line, and no upload, use our BMP to JPG, BMP to PNG, and BMP to WebP converters. Everything runs in the browser, so the file stays on your machine from start to finish.

More blog posts to read