有谁知道一种平滑/快速的方法来消除透明度,例如png/tiff 等并将其替换为白色背景?
基本上我需要这个的目的是我需要创建 PDF/A 兼容的图像,根据规范,这些图像可能没有透明度(因此固定的白色背景就可以了)。
有什么想法/建议吗?
干杯&谢谢, -约尔格
您可以创建一个与 png 大小相同的位图,绘制一个白色矩形,然后在其上绘制图像。
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");
}
您必须删除 Alpha 通道。否则,您仍然会得到一个透明图像 - 只是没有透明区域。
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;
}
}
添加Stormenet的答案;记得用“using”语句包装所有 Bitmap 和 Graphics 对象来处置非托管资源。
1)创建一个白色背景且与图像大小相同的位图
2) 加载图像并将其绘制在“白色”位图之上
3)保存新创建的图像
PNG 具有 Alpha 通道,因此简单的重新着色是行不通的。创建相同大小的白色图像,并创建合成图像,将您的图像覆盖在其上。
命名空间:
using Microsoft.Win32;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using PdfSharp;
using PdfSharp.Pdf;
using PdfSharp.Drawing;
从文件创建 PNG 或 TIFF 位图源:
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);
}
}
}
按钮点击功能:
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);
}
}
}
功能:
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;
}
将 A 通道转换为 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;
}
将 BitmapSource 保存为 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);
}
}
}
PDF 通常使用 2 种存储类型来进行 2 种基本的旧压缩。一种是 /Flate(gzip 变体),用于任意数量颜色层的位图。另一个是 /DCT(较旧的基线 JPEG)。
这两种存储方式中更好的是 /DCT,因为它是一种可逆(可提取)压缩插入。 (而透明位图可以分为 2 个覆盖层)。因此,如果您将所有图像转换为 100% 质量的 JPEG 且“无子采样”,它将像 PNG 或 TIFF 或 GIF 一样清晰,但字节数明显减少,并失去透明度。
这是一个非常小的 JPEG 测试片,显示单个像素没有明显的像差。接下来需要注意的主要问题是颜色偏移,这就是为什么我们的目标是不对颜色进行二次采样。
您需要放大才能看到单个像素没有模糊或被伪影“晕染”,应该看起来像 6 种颜色。然而,由于 JPEG 重新编码,即使在 100% 质量下,它也被视为 33 色计数。
以任何比例注入 PDF,它都会与任何无损图像一样好,但要小得多,所以这个 PDF 是
在任何规模下都只有 3,788 字节并且没有透明度。