anon
anon

Reputation:

Remove transparency in images with C#

does anyone know a smooth / fast way of removing transparency from e.g. pngs/tiffs etc and replacing it with a white background?

Basically what I need this for is I need to create PDF/A compatible images, which may, according to the spec, have -no- transparency (and therefore a fixed white background is fine).

Any ideas / suggestions?

Cheers & thanks, -Jörg

Upvotes: 14

Views: 24211

Answers (7)

K J
K J

Reputation: 11730

PDF in general uses 2 storage types for 2 basic older compressions. One is /Flate (a gzip variant) for bitmaps of any number of colour layers. The other is /DCT (older baseline JPEG).

The better of the two for storage is /DCT as it is one reversible (extractable) compressed insertion. (Whereas transparent bitmaps may be divided into 2 overlays). Thus if you convert, all images to 100% quality.JPEG with "NO subsampling", it will be as crisp as a PNG or TIFF OR GIF, but significantly less bytes and stripped of its transparency.

Here is a very small JPEG test piece to show there are no noticeable aberrations as single pixels. The main remaining issue then to watch out for is colour shift, which is why we aim for no subsampling of colours.

JPEG, quality: 100, subsampling OFF: enter image description here

You will need to zoom in to see the single pixels are not fuzzy or "haloed" by artefacts, simply should look like 6 colors. However due to JPEG recoding even at 100% quality it is seen as a 33 colour count.

Injected into a PDF at any scale it will be as good as any lossless image, but much smaller so this PDF is at any scale only 3,788 bytes and no transparency.

enter image description here

Upvotes: 0

Stormenet
Stormenet

Reputation: 26468

You could create a bitmap the same size as the png, draw a white rectangle and then draw the image on top of it.

void RemoveImageTransparancy(string file) {
    Bitmap src = new Bitmap(file);
    Bitmap target = new Bitmap(src.Size.Width,src.Size.Height);
    Graphics g = Graphics.FromImage(target);
    g.DrawRectangle(new Pen(new SolidBrush(Color.White)), 0, 0, target.Width, target.Height);
    g.DrawImage(src, 0, 0);
    target.Save("Your target path");
}

Upvotes: 24

pr0gg3r
pr0gg3r

Reputation: 4433

You have to remove the alpha channel. Otherwise you'll still have a transparent image - just without transparent areas.

class Program
{
    static void Main(string[] args)
    {
        //this also works for different file formats
        ReplaceTransparency(@"C:\Y\transparent.png", System.Drawing.Color.White).Save(@"C:\Y\no_transparency.png");
        ReplaceTransparency(@"C:\Y\transparent.gif", System.Drawing.Color.White).Save(@"C:\Y\no_transparency.gif");
    }

    public static System.Drawing.Bitmap ReplaceTransparency(string file, System.Drawing.Color background)
    {
        return ReplaceTransparency(System.Drawing.Image.FromFile(file), background);
    }

    public static System.Drawing.Bitmap ReplaceTransparency(System.Drawing.Image image, System.Drawing.Color background)
    {
        return ReplaceTransparency((System.Drawing.Bitmap)image, background);
    }

    public static System.Drawing.Bitmap ReplaceTransparency(System.Drawing.Bitmap bitmap, System.Drawing.Color background)
    {
        /* Important: you have to set the PixelFormat to remove the alpha channel.
         * Otherwise you'll still have a transparent image - just without transparent areas */
        var result = new System.Drawing.Bitmap(bitmap.Size.Width, bitmap.Size.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
        var g = System.Drawing.Graphics.FromImage(result);

        g.Clear(background);
        g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
        g.DrawImage(bitmap, 0, 0);

        return result;
    }
}

Upvotes: 12

amyasoedov88
amyasoedov88

Reputation: 36

namespaces:

using Microsoft.Win32;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using PdfSharp;
using PdfSharp.Pdf;
using PdfSharp.Drawing;

Creating PNG or TIFF BitmapSource from File:

BitmapSource BitmapSource;
private void OpenFile(Object sender, RoutedEventArgs e)
    {
        OpenFileDialog OpenFileDialog = new OpenFileDialog();
        OpenFileDialog.Filter = "PNG files (*.png)|*.png|TIFF files (*.tif)|*.tif";            

        if (OpenFileDialog.ShowDialog() == true)
        {
            try
            {
                if (OpenFileDialog.OpenFile() != null)
                {
                    String InitialPath = OpenFileDialog.FileName;                       
                    FileStream InitialFileStream = new FileStream(InitialPath, FileMode.Open, FileAccess.Read, FileShare.Read);

                    switch (OpenFileDialog.FilterIndex)
                    {
                        case 1:
                            PngBitmapDecoder PngBitmapDecoder = new PngBitmapDecoder(InitialFileStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
                            BitmapSource = PngBitmapDecoder.Frames[0];
                            InitialFileStream.Close();
                            break;
                        case 2:
                            TiffBitmapDecoder TiffBitmapDecoder = new TiffBitmapDecoder(InitialFileStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
                            BitmapSource = TiffBitmapDecoder.Frames[0];
                            InitialFileStream.Close();
                            break;
                    }  
                }
            }
            catch (Exception Exception)
            {
                MessageBox.Show("Error: Could not read file from disk. Original error: ", Exception.Message, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
    }

Functions on Button Click:

private void ButtonClick(Object sender, RoutedEventArgs e)
    {
        PixelFormat PixelFormat = BitmapSource.Format;
        if (PixelFormat == PixelFormats.Bgra32)
        {
            try
            {
                BitmapSource = Bgra32ToBgra24(BitmapSource);
                //BitmapSource = Bgra32ToGray8(BitmapSource);
            }

            catch (Exception Exception)
            {
                MessageBox.Show("Error: Could not convert BitmapSource. Original error: ", Exception.Message, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
    }

Function:

public static BitmapSource Bgra32ToBgr24(BitmapSource BitmapSource)
    {
        Int32 PixelWidth = BitmapSource.PixelWidth;
        Int32 PixelHeight = BitmapSource.PixelHeight;
        Double DpiX = BitmapSource.DpiX;
        Double DpiY = BitmapSource.DpiY;

        PixelFormat InputPixelFormat = BitmapSource.Format;
        BitmapPalette InputPalette = BitmapSource.Palette;
        Int32 InputBitsPerPixel = BitmapSource.Format.BitsPerPixel;
        Int32 InputStride = PixelWidth * InputBitsPerPixel / 8;
        Byte[] InputPixelsArray = new Byte[InputStride * PixelHeight];
        BitmapSource.CopyPixels(InputPixelsArray, InputStride, 0);

        PixelFormat PixelFormat = PixelFormats.Bgr24;
        BitmapPalette Palette = null;
        Int32 BitsPerPixel = 24;
        Int32 Stride = PixelWidth * BitsPerPixel / 8;
        Byte[] PixelsArray = new Byte[InputStride * PixelHeight / 4 * 3]; 

        Int32 i = 0; Int32 j = 0; Int32 k = 0;
        while (i < InputPixelsArray.Length / 4)
        {
            PixelsArray[k] = InputPixelsArray[j];
            PixelsArray[k + 1] = InputPixelsArray[j + 1];
            PixelsArray[k + 2] = InputPixelsArray[j + 2];

            i = i + 1;
            j = j + 4;
            k = k + 3;
        }

        BitmapSource = BitmapSource.Create(PixelWidth, PixelHeight, DpiX, DpiY, PixelFormat, Palette, PixelsArray, Stride);
        return BitmapSource;
    }

Converting A channel to Gray8 BitmapSource

public static BitmapSource Bgra32ToGray8(BitmapSource BitmapSource)
    {
        Int32 PixelWidth = BitmapSource.PixelWidth;
        Int32 PixelHeight = BitmapSource.PixelHeight;
        Double DpiX = BitmapSource.DpiX;
        Double DpiY = BitmapSource.DpiY;

        PixelFormat InputPixelFormat = BitmapSource.Format;
        BitmapPalette InputPalette = BitmapSource.Palette;
        Int32 InputBitsPerPixel = BitmapSource.Format.BitsPerPixel;
        Int32 InputStride = PixelWidth * InputBitsPerPixel / 8;
        Byte[] InputPixelsArray = new Byte[InputStride * PixelHeight];
        BitmapSource.CopyPixels(InputPixelsArray, InputStride, 0);

        PixelFormat PixelFormat = PixelFormats.Gray8;
        BitmapPalette Palette = null;
        Int32 BitsPerPixel = 8;
        Int32 Stride = PixelWidth * BitsPerPixel / 8;
        Byte[] A_PixelsArray = new Byte[InputStride * PixelHeight / 4];

        Int32 i = 0; Int32 j = 3;
        while (i < InputPixelsArray.Length / 4)
        {
            A_PixelsArray[i] = InputPixelsArray[j];

            i = i + 1;
            j = j + 4;
        }

        BitmapSource = BitmapSource.Create(PixelWidth, PixelHeight, DpiX, DpiY, PixelFormat, Palette, A_PixelsArray, Stride);
        return BitmapSource;
    }

Saving BitmapSource to PDF:

private void SaveFileAs(Object sender, RoutedEventArgs e)
    {
        SaveFileDialog SaveFileDialog = new SaveFileDialog();
        SaveFileDialog.Filter = "PDF files (*.pdf)|*.pdf";
        if (SaveFileDialog.ShowDialog() == true)
        {
            try
            {
                if (SaveFileDialog.FileName != null)
                {
                    String DestinationPath = SaveFileDialog.FileName;
                    FileStream DestinationFileStream = new FileStream(DestinationPath, FileMode.Create, FileAccess.Write, FileShare.Write);

                    switch (SaveFileDialog.FilterIndex)
                    {   
                        case 1:
                            PdfDocument PdfDocument = new PdfDocument();
                            PdfPage PdfPage = new PdfPage();
                            PdfDocument.Pages.Add(PdfPage);
                            XImage Image = XImage.FromBitmapSource(BitmapSource);
                            XGraphics XGraphic = XGraphics.FromPdfPage(PdfDocument.Pages[0]);

                            Double VerticalMargin = 20;
                            Double HorizontalMargin = 20;
                            Double Ratio = BitmapSource.Height / BitmapSource.Width;
                            Double ImageWidth = PdfPage.Width - 2 * VerticalMargin;
                            Double ImageHeight = Ratio * (PdfPage.Width - 2 * HorizontalMargin);

                            XGraphic.DrawImage(Image, VerticalMargin, HorizontalMargin, ImageWidth, ImageHeight);
                            PdfDocument.Save(DestinationFileStream);
                            PdfDocument.Close();
                            DestinationFileStream.Close();
                            break;
                    }
                }
            }
            catch (Exception Exception)
            {
                MessageBox.Show("Error: Could not write file to disk. Original error: ", Exception.Message, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
    }

Upvotes: 0

tmorell
tmorell

Reputation: 559

Adding to Stormenet's answer; remember to wrap all Bitmap and Graphics objects with "using" statement to dispose unmanaged resources.

Upvotes: 1

vartec
vartec

Reputation: 134601

PNGs have alpha channel, so simple recoloring won't do. Create white image of same size, and create composite image overlay your image over it.

Upvotes: 0

Dan Bystr&#246;m
Dan Bystr&#246;m

Reputation: 9244

1) Create a bitmap with a white background and with the same size as your image
2) Load you image and paint it on top of your "white" bitmap
3) Save the newly created image

Upvotes: 0

Related Questions