gpt4 book ai didi

c# - Windows/.NET 的 System.Drawing.Save(Stream, ImageFormat) 中的错误。生成损坏的 PNG

转载 作者:可可西里 更新时间:2023-11-01 14:33:17 28 4
gpt4 key购买 nike

在某些非常特殊的情况下,System.Drawing.Save(Stream, Imageformat) 会创建损坏的 PNG 图像。

有没有办法避免它,例如:

  1. 我不需要使用第三方库,并且
  2. 我不需要检查 PNG 字节来知道我是否需要“修复”某些东西?

重现步骤

  1. 创建一个 System.Drawing.BitMap
  2. 向图像添加内容,使其生成非常具体的 PNG 文件大小(“何时发生”)
  3. 调用Save(Stream, Imageformat) -- 选择PNG格式

问题是什么?

问题是最后一个图像数据后的 IDAT block 不正确。它不包含数据,但长度字节为 00 00 ff f4。可以用https://github.com/jsummers/tweakpng检测到.我们注意到 Linux 上的图像库(不确定是哪些)无法处理此类错误。据我们所知,在 Windows 中这个错误会被忽略,您不会注意到任何问题。

什么时候发生?

这取决于 PNG 文件的大小。仅当生成的 PNG 文件大小(以字节为单位)为0x1001C + n * 0x10000,n 为 0、1、2、3、4,可能更大。

可重现

可以调整第二步以生成特定的 PNG 文件大小(例如,为空位图中的不同数量的像素着色)。当尺寸为上述尺寸时,一直出现错误。

重现代码

在干净的控制台应用程序中替换 Program.cs 的内容。运行该程序时,它会尝试创建具有精确指定大小的 PNG 并将其保存为“constructed.png”。

顺便说一句:第二个 PNG 保存为“constructedReExport.png”:这是通过加载第一个并再次保存创建的。我想我记得这是一个潜在的解决方法,但是当我现在运行它时,第二个文件包含相同的错误...

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

namespace CreateCorruptPng
{
class Program
{
static void Main(string[] args)
{
// Choose 0x1001C + 0x10000 * n; with n = 0, 1, 2, 3, 4 to get corrupt PNG
int targetOutputSizeBytes = 0x5001C;

// You may need to fiddle with these parameters to
// successfully create an image of the exact size.
int widthPixels = 2000;
int height = 1200;

var creator = new PngCreator(widthPixels, height);

string outputPath = ".";
creator.TryCreateWithSize(targetOutputSizeBytes);
creator.SaveCurrentImage(Path.Combine(outputPath, "constructed.png"));
creator.SaveAfterSecondExport(Path.Combine(outputPath, "constructedReExport.png"));
}
}

public class PngCreator
{
Bitmap _img;
int _width;
int _height;
int _maxPixcount;

public PngCreator(int w, int h)
{
_width = w;
_height = h;
_maxPixcount = w * h;
}

public void TryCreateWithSize(int requiredByteCount)
{
Console.WriteLine($"Attempting to create png file of exactly {requiredByteCount} bytes.");
Console.WriteLine($"Image size (w x h) = {_width} x {_height}.");

int lowerBound = 0;
int upperBound = _maxPixcount;

bool success = false;
while (upperBound > lowerBound + 1)
{
InitImage();
int pixelCount = (upperBound + lowerBound) / 2;
AddPixels(pixelCount);

int currentSize = GetPngByteCount();
if (currentSize == requiredByteCount)
{
success = true;
break;
}

if (currentSize < requiredByteCount)
lowerBound = pixelCount;
else
upperBound = pixelCount;
}
Console.WriteLine("Search stopped.");

if (success)
Console.WriteLine($"SUCCESS.\n Created PNG with exact file size {requiredByteCount} bytes.");
else
Console.WriteLine($"WARNING.\n" +
$" Could not produce PNG with file size {requiredByteCount} bytes.\n" +
" Try to run again with different resolution.\n" +
" If the file size in the last iteration is too small, try larger resolution.");
}

private void InitImage()
{
_img?.Dispose();
_img = new Bitmap(_width, _height, PixelFormat.Format16bppArgb1555);
}

private void AddPixels(int n)
{
Console.WriteLine($"Coloring {n} pixels...");
for (int i = 0; i < n; i++)
{
int x = i % _width;
int y = i / _width;
_img.SetPixel(x, y, Color.FromArgb((i / 2) % 255, 0, 0));
}
}

private int GetPngByteCount()
{
using (MemoryStream s = new MemoryStream())
{
_img.Save(s, ImageFormat.Png);

byte[] imgBytes = s.ToArray();
Console.WriteLine($"Png file size {imgBytes.Length}");
return imgBytes.Length;
}
}

public void SaveCurrentImage(string path)
{
SaveImage(path, _img);
}

public void SaveAfterSecondExport(string path)
{
using (Bitmap imgReimported = ToPngBytesAndLoadAgain(_img))
{
SaveImage(path, imgReimported);
}
}

private Bitmap ToPngBytesAndLoadAgain(Bitmap img)
{
return new Bitmap(new MemoryStream(ToPngBytes(img)));
}

private static byte[] ToPngBytes(Bitmap img)
{
using (MemoryStream s = new MemoryStream())
{
img.Save(s, ImageFormat.Png);
return s.ToArray();
}
}

private static void SaveImage(string path, Bitmap img)
{
Console.WriteLine($"Saving file to {path}");
File.WriteAllBytes(path, ToPngBytes(img));

}
}
}

最佳答案

我在处理由 Adob​​e 产品创建的一些文件时遇到了问题,不同的 adobe 产品有不同的引擎,有时这会破坏 GDI+,并使用类似的解决方法来保留文件。使用不使用 GDI+ 的第三方图像处理工具可能是最佳选择,例如 ImageMagic(或 .net 包装器 Magic.Net)

当您为内容做广告时,是指绘制图像还是添加文件,请检查添加的文件是否有问题。

关于c# - Windows/.NET 的 System.Drawing.Save(Stream, ImageFormat) 中的错误。生成损坏的 PNG,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52100703/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com