You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复使用BitmapData将全黑PNG转换为全白PNG时无效的问题

Why isn't my BitmapData code converting a black PNG to white?

I built a small test example with the goal of changing all pixels in a PNG image to white. I chose to use BitmapData because I heard it has better performance. If this example works correctly, I plan to adjust the target pixel range and add different pixel color modification conditions later.

However, I'm having an issue with this simple test: after inputting a 50×50 all-black PNG image, the output is still an all-black PNG instead of the expected all-white PNG. Here's my C# code:

public static void TestConvertAllBlackBitmapToAllWhite() {
    string allBlackPNGFullFilePath = @"C:\Users\{Username}\Desktop\50x50AllBlack.png";
    Bitmap allBlackBitmap = new Bitmap(allBlackPNGFullFilePath);
    Bitmap newBitmap = (Bitmap)allBlackBitmap.Clone();
    Size size = newBitmap.Size;
    PixelFormat pixelFormat = newBitmap.PixelFormat;
    byte bitDepth = (byte)(pixelFormat == PixelFormat.Format32bppArgb ? 4 : 3);
    Rectangle rectangle = new Rectangle(Point.Empty, size);
    BitmapData bitmapData = newBitmap.LockBits(rectangle, ImageLockMode.ReadOnly, pixelFormat);
    int dataSize = bitmapData.Stride * bitmapData.Height;
    byte[] data = new byte[dataSize];
    Marshal.Copy(bitmapData.Scan0, data, 0, dataSize);
    Color white = Color.White;
    for (int y = 0; y < size.Height; y++) {
        for (int x = 0; x < size.Width; x++) {
            // Get Index
            int index = y * bitmapData.Stride + x * bitDepth;
            // Set Pixel Color
            data[index] = white.B;
            data[index + 1] = white.G;
            data[index + 2] = white.R;
        }
    }
    Marshal.Copy(data, 0, bitmapData.Scan0, data.Length);
    newBitmap.UnlockBits(bitmapData);
    // Save New Converted Bitmap
    string originalFileName = Path.GetFileNameWithoutExtension(allBlackPNGFullFilePath);
    string directory = Path.GetDirectoryName(allBlackPNGFullFilePath);
    string newBitmapFileName = originalFileName + "_Converted";
    string newBitmapFullFileName = directory + Path.DirectorySeparatorChar.ToString() + newBitmapFileName + ".png";
    newBitmap.Save(newBitmapFullFileName, ImageFormat.Png);
}

Could someone help me figure out how to modify this code to get an all-white PNG output?


Solution

The main issue in your code is the ImageLockMode.ReadOnly flag you’re using when locking the bitmap bits. When you lock the bitmap in read-only mode, any changes you make to the underlying data won’t be written back to the bitmap—that’s why your output stays black.

Here are the key fixes and improvements:

  1. Switch to ImageLockMode.ReadWrite: This mode lets you both read existing pixel data and write your modifications back to the bitmap.
  2. Handle the Alpha channel (for 32bppArgb format): If your image uses 32-bit ARGB, set the alpha value to 255 (fully opaque) to ensure the white pixels are visible.
  3. Simplify file path construction: Use Path.Combine instead of string concatenation to avoid cross-platform path separator issues.
  4. Dispose bitmap objects: Prevent memory leaks by disposing of Bitmap instances when you’re done with them.

Here’s the modified code:

using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.IO;

public static void TestConvertAllBlackBitmapToAllWhite() {
    string allBlackPNGFullFilePath = @"C:\Users\{Username}\Desktop\50x50AllBlack.png";
    Bitmap allBlackBitmap = new Bitmap(allBlackPNGFullFilePath);
    Bitmap newBitmap = (Bitmap)allBlackBitmap.Clone();
    Size size = newBitmap.Size;
    PixelFormat pixelFormat = newBitmap.PixelFormat;
    byte bitDepth = (byte)(pixelFormat == PixelFormat.Format32bppArgb ? 4 : 3);
    Rectangle rectangle = new Rectangle(Point.Empty, size);
    
    // Fix 1: Use ReadWrite mode to allow modifying the bitmap
    BitmapData bitmapData = newBitmap.LockBits(rectangle, ImageLockMode.ReadWrite, pixelFormat);
    int dataSize = bitmapData.Stride * bitmapData.Height;
    byte[] data = new byte[dataSize];
    Marshal.Copy(bitmapData.Scan0, data, 0, dataSize);
    
    Color white = Color.White;
    for (int y = 0; y < size.Height; y++) {
        for (int x = 0; x < size.Width; x++) {
            int index = y * bitmapData.Stride + x * bitDepth;
            // Set RGB values
            data[index] = white.B;
            data[index + 1] = white.G;
            data[index + 2] = white.R;
            
            // Fix 2: Set alpha channel for 32-bit images to ensure opacity
            if (bitDepth == 4) {
                data[index + 3] = white.A; // 255 for fully opaque white
            }
        }
    }
    
    Marshal.Copy(data, 0, bitmapData.Scan0, data.Length);
    newBitmap.UnlockBits(bitmapData);
    
    // Fix 3: Use Path.Combine for safe, cross-platform path building
    string originalFileName = Path.GetFileNameWithoutExtension(allBlackPNGFullFilePath);
    string directory = Path.GetDirectoryName(allBlackPNGFullFilePath);
    string newBitmapFullFileName = Path.Combine(directory, $"{originalFileName}_Converted.png");
    
    newBitmap.Save(newBitmapFullFileName, ImageFormat.Png);
    
    // Fix 4: Dispose bitmaps to free up system resources
    allBlackBitmap.Dispose();
    newBitmap.Dispose();
}

Quick Notes:

  • For larger images, you could optimize performance by processing the byte array in a single flat loop instead of nested x/y loops, but your current approach works perfectly for small 50x50 images.
  • Always double-check the pixel format of your input image—some PNGs might use indexed color modes, which would require additional handling, but your code covers the most common 24/32-bit formats.

内容的提问来源于stack exchange,提问作者Shiasu-sama

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 05:22:46