There is a string in base64 format. This is an image. Keeping it, I have a black background behind. I don't see it in paint. Most likely this is the alpha channel. How to save an image without it?

public Image Base64ToImage() { // Convert base 64 string to byte[] byte[] imageBytes = Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAADIAAAAYCAYAAAC4CK7hAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB6UlEQVRYhe2WP0gdQRCHvwTREKwSEBER0i2PNLtlCJYWRmzShGBthBRiYSGSQixCihRBnqVgkyJFwEJikSZNSBF2rWSrFCJiEV5S2AhBLG7uPd+5rrfvD7G4r9nbYec3Nzc7uwcVFX3hTsholN4GXuRz691QWUGj9CxQB0bE1AAWrXefEjSmgQ1gXExHwGvr3d51PncDIgBTZYMG+EArCYAHwPtEjTqtJJDneszhSiLAUwn+KzF4zhhkVbxUyZHI+rIa45H1wUSeyfg5Mfh/JZTItIy73YobpYe71SjLQCHwBKCA38D3TgQLB8O6jMeJMofARMF2EnMoVmRGxj3rXWLsdozSj4F5ma4mur8CTo3SX4zS+c5YiTkUE8n7YycxcIgNsor/sN59TPR9DgyT7Y5a4d2CNLeWUfo+MAn8A74mBm7DKP0SeAKcA4sdSMwBWO8eid4ZMBtzuNwjNWBQnv/IfZKMNPg7mW5Z7/Y7kLkXsA0GbE1Cp1a3rJHdG3+BN33QD9KsiPXuJ9D2KyIlLY00+IJM16x3DdE4td497PZlY/S6Im/JPs4BsNlj7SgDNy9pkVco8hOZn/014Oy6PiuhcwKMFnZE0j1yW1gm67GcBrDU0whG6W+3SSenk4qk3tL91qmoqCjBBdK7cMdF6zotAAAAAElFTkSuQmCC"); // Convert byte[] to Image using (var ms = new MemoryStream(imageBytes, 0, imageBytes.Length)) { Image image = Image.FromStream(ms, true); return image; } } var img= Base64ToImage(); img.Save("checknew.jpg",ImageFormat.Jpeg); 

enter image description here

    1 answer 1

    Indeed, in this image, the alpha channel of all pixels is 0 - fully transparent.

    Each image viewer when rendering such an image comes in its own way: the background can be black, white, or some other. In particular, the Graphcis.DrawImage method Graphcis.DrawImage with the translucent background of the control to which the drawing is going. Set the BackColor property to red - and the background will be appropriate.

    You can make an image opaque with the following code:

     var bmp = (Bitmap)img; for (int y = 0; y < img.Height; y++) { for (int x = 0; x < img.Width; x++) { var color = bmp.GetPixel(x, y); // 255 - полностью непрозрачный альфа-канал color = Color.FromArgb(255, color); bmp.SetPixel(x, y, color); } } 

    All pixels will be made opaque, and the color will remain the same, that is, the background is black, the numbers are gray.

    However, the problem is this. Smoothing is done in this image using translucency. And after such a conversion, it will become "chopped", more rough.

    To avoid this, you can make only black pixels opaque without affecting the anti-aliasing figures:

     var color = bmp.GetPixel(x, y); if (color.R == 0 && color.G == 0 && color.B == 0) { color = Color.Black; // непрозрачный чёрный bmp.SetPixel(x, y, color); } 

    Such an image will appear "smooth", but only when outputting to a black (dark) background. When outputting to a white (light) or colored background, the view will be very poor.

    Naturally, the color can be set by any:

     color = Color.White; // непрозрачный белый 

    Now, on a white background, everything will be beautiful, but on black - roughly.

    Choose what suits you best.

    Naturally, you can completely remove the transparency and simultaneously change the background of the image:

     var color = bmp.GetPixel(x, y); if (color.R == 0 && color.G == 0 && color.B == 0) { color = Color.White; // меняем цвет фона (выберите нужный) bmp.SetPixel(x, y, color); } else // цвет цифр остаётся, но становится непрозрачным bmp.SetPixel(x, y, Color.FromArgb(255, color)); 

    Then the image will be equally "chopped" when outputting to any background. But always acceptable readable.


    The methods GetPixel , SetPixel very slow. In such a small picture it is imperceptible, but if you wish, you can speed up the code many times using the LockBits technique .

     var bmp = (Bitmap)img; Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat); IntPtr ptr = bmpData.Scan0; int bytes = Math.Abs(bmpData.Stride) * bmp.Height; byte[] rgbValues = new byte[bytes]; Marshal.Copy(ptr, rgbValues, 0, bytes); for (int counter = 0; counter < rgbValues.Length; counter += 4) { if (rgbValues[counter] == 0 && rgbValues[counter + 1] == 0 && rgbValues[counter + 2] == 0) { rgbValues[counter] = 255; // blue rgbValues[counter + 1] = 255; // green rgbValues[counter + 2] = 255; // red rgbValues[counter + 3] = 255; // alpha } } Marshal.Copy(rgbValues, 0, ptr, bytes); bmp.UnlockBits(bmpData); 

    This image is 32-bit, that is, 4 bytes per pixel. Therefore, the step in the cycle is 4.

    Well, on the snack, a version with pointers. Theoretically, it is even faster.

     var bmp = (Bitmap)img; Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat); IntPtr ptr = bmpData.Scan0; int bytes = Math.Abs(bmpData.Stride) * bmp.Height; unsafe { byte* b = (byte*)ptr.ToPointer(); for (int i = 0; i < bytes; i += 4, b += 4) { if (*b == 0 && *(b + 1) == 0 && *(b + 2) == 0) { *b = 255; // blue *(b + 1) = 255; // green *(b + 2) = 255; // red *(b + 3) = 255; // alpha } } } bmp.UnlockBits(bmpData); 

    In the project settings (Project> Properties> Build), it is necessary to enable unsafe code (Allow unsafe code).