1
votes

I'm combining 2 images, first image will be the canvas and the 2nd image will be the overlay. Both of the images doesn't have an actual file, instead it's generated and stored in memorystream.

Canvas

 MemoryStream canvasStream = new MemoryStream();
 var canvas =  new Bitmap(canvasWidth, canvasHeight, PixelFormat.Format32bppArgb);
 canvas.Save(canvasStream, ImageFormat.Png);

Overlay

This is a smaller than canvas and it will be place at the middle of the canvas. It will look like a picture frame or simply and image with 20px padding.

 MemoryStream overlayStream = new MemoryStream();
 var canvas =  new Bitmap(overlayWidth, overlayHeight, PixelFormat.Format32bppArgb);
 canvas.Save(overlayStream, ImageFormat.Png);

After saving to the memorystream, both of these images Imageformat defaults to Imageformat.MemoryBmp not Imageformat.PNG. Hence, losing the transparency.

Combine Canvas and Overlay

        Bitmap combinedImage = new Bitmap(canvas.Width, canvas.Height, PixelFormat.Format24bppRgb);

        using (Graphics graphic = Graphics.FromImage(combinedImage))
        {
            graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
            graphic.Clear(Color.White);

            int BGCanvasXCenter = 0;
            Rectangle rectDest = new Rectangle(0, 0, canvas.Width, canvas.Height);

            if (fixSize)
            {
                // center image
                BGCanvasXCenter = (canvas.Width / 2) - (overlay.Width / 2);
                rectDest = new Rectangle(BGCanvasXCenter, 0, overlay.Width, overlay.Height);
            }

            var imageAttributes = new ImageAttributes();
            imageAttributes.SetWrapMode(WrapMode.TileFlipXY);

            graphic.DrawImage(
                overlay,
                rectDest,
                0, 0, overlay.Width, overlay.Height,
                GraphicsUnit.Pixel,
                imageAttributes
            );
        }

Is there a way to preserve the transparency when using memorystream? How do I set the imageformat to PNG?

Please take note that the requirement is not save an actual file during the process, that's why i'm resorting to memorystream.

Thanks in advance!

This var canvas = new Bitmap(canvasWidth, canvasHeight, PixelFormat.Format32bppArgb); is enough to create a bitmap in memory. No need to create a MemoryStream nor canvas.Save(...);. Use them to create the output image then save the output image outputImage.Save(fileName, ImageFormat.png); - user10216583
Imageformat.MemoryBmp is unrelated to transparency; it just means a Bitmap object (Not file. Not BMP format. Just System.Drawing.Bitmap class object) created in memory, rather than loaded from file data. I suspect that if you are losing transparency, it is due to the way you combine them. Which you did not include in your question. - Nyerguds
@JQSOFT Thanks, I will do code clean up after. Btw, Im dealing with JPEG images and trying to save the PNG converted image to the stream for further processing. - Wreeecks
@Nyerguds I've updated the code. I've checked Imageformat.MemoryBmp rawformat attr and it's set to JPEG. But after combining the images, combinedImage rawformat is now PNG. However, when its rendered in the browser it becomes JPEG again. I'm suspecting this could be caused by response mime type. - Wreeecks
As mentioned though, Bitmap class is a GDI+ object, and those are, by their nature, not managed by the garbage collector. You have to be very careful to Dispose() any Bitmap object you create, from the moment you no longer need it (so probably right after you send it as data), otherwise you're creating a memory leak and your application will start crashing once the internal GDI+ object limit is reached. This is one of the reasons the use of System.Drawing is not advised for server applications. - Nyerguds