我无法自拔,所以我再次请求你的帮助。这次我希望能比上次更好地展示问题。我希望。
我正在编写一个程序来检查量化是否对图像大小有任何影响。要做到这一点,我需要实施:
PNG过滤器方法0定义了五种基本过滤器类型:类型名称
0 - 无,1 - Sub,2 - Up,3 - Average,4 - Paeth
现在,我站在内存中的图像,我想使用其中一个过滤器保存,但在检查了多个PNG库之后,没有一个允许我选择一个。任何人都可以帮助我或至少使用一个过滤器? 在这里你可以使用一些代码:
private void btnSelectImg_Click(object sender, EventArgs e)
{
openFileDialog1.Filter = "PNG Image | *.png";
DialogResult result = openFileDialog1.ShowDialog();
if (result == DialogResult.OK)
{
string imgPath = openFileDialog1.FileName;
tbSourceImageFile.Text = imgPath;
string[] NameCutter = imgPath.Split('\\');
lblFileName.Text = NameCutter.Last();
ImageToWork = Image.FromFile(imgPath);
System.Drawing.Imaging.ImageFormat Format = ImageToWork.RawFormat;
tbInfo.Text += string.Format("Resolution : {0}x{1} | Bits : {2:n0} | Format : {3}", ImageToWork.Width, ImageToWork.Height, ImageToWork.Width * ImageToWork.Height, GetFilenameExtension(Format));
}
}
private void btnSave_Click(object sender, EventArgs e)
{
#region Check Image
if (tbSourceImageFile.Text == "")
{
MessageBox.Show("File not selected. Select file first.");
return;
}
#endregion
#region Operations on image
Bitmap Image111 = new Bitmap(tbSourceImageFile.Text, true);
#region Progress Bar Settings
ProgressBar.Visible = true;
ProgressBar.Value = 1;
ProgressBar.Maximum = Image111.Width;
ProgressBar.Step = 1;
#endregion
if (cboxEnableScale.Checked == true)
{
int red, green, blue, red2=0, blue2=0, green2=0;
int scale = int.Parse(cbSelectorScale.SelectedItem.ToString());
for (int w = 0; w < Image111.Width; w++)
{
for (int h = 0; h < Image111.Height; h++)
{
Color PixelColor = Image111.GetPixel(w, h);
#region Quantization
red = PixelColor.R;
green = PixelColor.G;
blue = PixelColor.B;
Color newColor = Color.FromArgb(Valuator_v3(red, scale), Valuator_v3(green, scale), Valuator_v3(blue, scale));
Image111.SetPixel(w, h, newColor);
#endregion
}
ProgressBar.PerformStep();
}
}
#endregion
#region Saving
string SaveDirectory = tbSaveDestination.Text + '\\' + tbSaveFileName.Text + ".bmp";
SaveDirectory = tbSaveDestination.Text + '\\' + tbSaveFileName.Text + ".jpeg";
Image111.Save(SaveDirectory, System.Drawing.Imaging.ImageFormat.Png);
ProgressBar.Visible = false;
MessageBox.Show("Saved successfully.");
#endregion
}
在区域“保存”中我想选择使用哪个过滤器并使用它保存。
答案 0 :(得分:0)
但在检查了多个PNG库之后,其中没有一个允许我选择一个
你试过PngCs吗? (那里有几把叉子)。请参阅PngWriter. FilterWriteStrategy(...)
方法
答案 1 :(得分:0)
如果PNG图书馆没有做你想做的事情,只需滚动自己的过滤器。这并不困难。
过滤应在#region量化中进行。据我所知,Valuator_v3()方法分别转换RGB通道,然后用Image111.SetPixel()存储转换后的像素。需要在两次调用之间插入PNG过滤器。
PNG滤镜处理当前像素颜色和一个,两个或三个先前读取的相邻像素。他们从不向前看。因此,您只需使用Image111.GetPixel()来检索以前的像素,并使用它们来转换当前像素。对于过滤器类型&#34;无&#34;,没有任何关系,你只需存储量化像素。
在&#34; Sub&#34;的情况下,您测试您是否在最左边的列中(即,w == 0)。如果是这样,则保持像素不变。否则,您调用Image111.GetPixel(w-1,h)并从当前像素中减去生成的RGB值:
Color pixelLeft = Image111.GetPixel (w-1, h);
newColor.R -= pixelLeft.R;
newColor.G -= pixelLeft.G;
newColor.B -= pixelLeft.B;
那就是它。 &#34; Up&#34;变换同样微不足道。你这次只检查h == 0,如果当前像素不在顶行,则调用Image111.GetPixel(w,h-1)。 &#34;平均&#34;滤波器需要左上像素和上像素,并计算RGB通道值的算术平均值。注意,在w == 0的情况下pixelLeft = 0,在h == 0的情况下pixelTop = 0:
Color pixelLeft = Image111.GetPixel (w-1, h);
Color pixelTop = Image111.GetPixel (w, h-1);
newColor.R -= (Byte) (((UInt64) pixelLeft.R + (UInt64) pixelTop.R) >> 1);
newColor.G -= (Byte) (((UInt64) pixelLeft.G + (UInt64) pixelTop.G) >> 1);
newColor.B -= (Byte) (((UInt64) pixelLeft.B + (UInt64) pixelTop.B) >> 1);
Paeth过滤器更复杂。它使用三个相邻像素,pixelLeft,pixelTop和pixelTopLeft。您需要再次适当地检查特殊边界情况。对于每个信道,单独计算以下预测值,例如,红色:
Int64 valueLeft = pixelLeft.R;
Int64 valueTop = pixelTop.R;
Int64 valueTopLeft = pixelTopLeft.R;
Int64 valueCombined = valueLeft + valueTop - valueTopLeft;
Int64 deltaLeft = Math.Abs (valueCombined - valueLeft);
Int64 deltaTop = Math.Abs (valueCombined - valueTop);
Int64 deltaTopLeft = Math.Abs (valueCombined - valueTopLeft);
newColor.R -= (deltaLeft <= deltaTop) && (deltaLeft <= deltaTopLeft)
? pixelLeft.R
: deltaTop <= deltaTopLeft ? pixelTop.R : pixelTopLeft.R);
尽管Paeth过滤器看起来非常有前景,但我自己的测试表明,&#34; Up&#34;在大多数情况下,过滤器产生最佳结果。不知道为什么。因此,默认情况下,我使用&#34; Sub&#34;过滤第一行,&#34; Up&#34;过滤所有后续的。
所以现在你已经在内存中获得了过滤后的图像。您现在需要的是标准的DEFLATE编码器,就像ZLIB一样。编码器输入是滤波后的RGB数据。请注意,PNG要求您在每行的开头发出过滤器类型(0..4)作为文字代码。 压缩的DEFLATE流被打包到PNG容器的IDAT块中,这不是一项艰巨的任务。