Search code examples
imageencodinggraphicsbitmapbase64

Unable to display a specific image decoded from a Base 64 String


I'm building a program that generates images and sends them to a webpage as a base64 encoded string through a REST call. All the images are generated and pulled in without issue, except for one so far.

I have rendered one image that doesn't seem able to be decoded despite any effort to do a encode/decode cycle with it. I've tried using .NET, Python, and various base64 validation websites to find if I could properly decode an encoded string made from this image and I'm at a loss to what could be happening. The image will save a .png of the result that looks correct, but any attempts to convert the bitmap into a base64 encoded string will result in a string that doesn't seem to be able to load into an image. The string is validated to be proper base64 encoding, and the encoding process works fine in all other cases, but I'm needing to know what's incorrect about the image that's being rendered and why it can't work as encoded data.

The process of rendering these images is that an original image is pulled from files and is cropped and scaled based on user parameters. The new altered file is encoded as a base64 string and sent as a result of a REST call.

Here's the code I'm using in ASP.NET Core:

private string GetResizedMapString(Map map, CanvasDisplaySettings disp)
{
    string path = GetUploadPath(map.SourceName);

    if (path != string.Empty)
    {
        Image srcImg = Image.FromFile(path);
        RectangleF[] imgSizes = GetRenderAreas(srcImg, map, disp);

        if (imgSizes != null)
        {
            Bitmap destImg = new((int)imgSizes[0].Width, (int)imgSizes[0].Height);
            using var graphics = Graphics.FromImage(destImg);
            graphics.DrawImage(srcImg, imgSizes[0], imgSizes[1], GraphicsUnit.Pixel);

            // CREATING TESTING IMAGE AND ENCODED STRING FILES:
            string testImgName = "TestImgFrom" + disp.DisplayID;
            string filePath = Path.Combine(DepoCollection, testImgName);

            String imageString = ConvertBitmapToString(destImg); // New Image String
            String imageStringPath = filePath + ".txt"; // New Encoded String File
            String imagePngPath = filePath + ".png"; // New Image File

            // Save to PNG
            destImg.Save(imagePngPath);
            graphics.Dispose();

            // Save to .txt to test the encoded string
            using (StreamWriter outputFile = new StreamWriter(imageStringPath))
            {
                outputFile.WriteLine("data:image/png;base64," + imageString);
            }
            return imageString;
        }
        else return "";
    }
}

static string ConvertBitmapToString(Bitmap bitmap)
{
    // Convert the bitmap to a byte array
    MemoryStream ms = new MemoryStream();
    bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
    byte[] byteImage = ms.ToArray();

    // Convert the byte array to a base64 string
    string base64String = Convert.ToBase64String(byteImage);

    return base64String;
}

This process has been working with many other images, and the original image before scaling is able to be encoded/decoded. I've tried a similar process of encoding/decoding using Python, as well as loading the image into other base64 encoding software found online.

The images the program generates are way larger than the source image, so I can't upload it here. I'm wondering why what's happening is increasing the file size so much and if it could possibly be related.
Source Image: 1.34MB, 2200 x 2200 pixels
Rendered Image: 24.00 MB, 2998 x 2998 pixels

Here's a Google Drive link of the rendered file: https://drive.google.com/file/d/1wxkWCEx3DyUG2yenWoEfOsi9QNEK38FK/view?usp=sharing

Thank you for any clue as to what's happening and any suggestions of how to avoid these problems!


Solution

  • First of all, the size issues may have to do with the image format, in BMP it is almost raw, and the size may be correct, if you ask for KB sizes even after the conversion you should use Jpeg or Png under certain conditions.

    This code example works correctly, I don't see much difference with yours except that it calls the memory stream buffer.

    private string BmpTobase64(Bitmap bmp)
    {
        using (var ms = new MemoryStream())
        {
            bmp.Save(ms, ImageFormat.Jpeg);
            return Convert.ToBase64String(ms.GetBuffer());
        }
    }
    
    // --- ToBase64String(...) parameter --- 
    //    ms.GetBuffer();
    

    Keep in mind that you are saving the image file not the bitmap object, that is, you are converting the resulting file with a header and possibly a color palette, etc.

    Another thing, when you convert again you should remove your header before saving the image to storage or uploading it to a stream for visualization:

    "data:image/png;base64,"