Reputation:
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
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:
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.
Upvotes: 0
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
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
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
Reputation: 559
Adding to Stormenet's answer; remember to wrap all Bitmap and Graphics objects with "using" statement to dispose unmanaged resources.
Upvotes: 1
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
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