gpt4 book ai didi

c# - 实现 APNG 渲染函数

转载 作者:太空狗 更新时间:2023-10-30 01:09:41 26 4
gpt4 key购买 nike

大家好,所以,我目前正在尝试实现 APNG Specification ,但在帧渲染方面遇到了一些问题。我的功能是

    private void UpdateUI()
{
foreach (PictureBox pb in pics)
{
APNGBox box = (APNGBox)pb.Tag;
APNGLib.APNG png = box.png;
if (box.buffer == null)
{
box.buffer = new Bitmap((int)png.Width, (int)png.Height);
}
APNGLib.Frame f = png.GetFrame(box.frameNum);
using (Graphics g = Graphics.FromImage(box.buffer))
{
switch (f.DisposeOp)
{
case APNGLib.Frame.DisposeOperation.NONE:
break;
case APNGLib.Frame.DisposeOperation.BACKGROUND:
g.Clear(Color.Transparent);
break;
case APNGLib.Frame.DisposeOperation.PREVIOUS:
if (box.prevBuffer != null)
{
g.DrawImage(box.prevBuffer, Point.Empty);
}
else
{
g.Clear(Color.Transparent);
}
break;
default:
break;
}
Bitmap read = png.ToBitmap(box.frameNum++);
switch (f.BlendOp)
{
case APNGLib.Frame.BlendOperation.OVER:
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
break;
case APNGLib.Frame.BlendOperation.SOURCE:
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
break;
default:
break;
}
g.DrawImage(read, new Point((int)f.XOffset, (int)f.YOffset));
}

box.prevBuffer = box.buffer;
pb.Image = box.buffer;

if (box.frameNum >= box.png.FrameCount)
{
box.frameNum = 0;
box.buffer = null;
box.prevBuffer = null;
}
}
}

APNGBox

internal class APNGBox
{
public int frameNum = 0;
public APNGLib.APNG png;
public Bitmap buffer;
public Bitmap prevBuffer;
}

我认为这大部分是正确的,因为我已经针对 APNG Gallery 中的所有图像运行了它.但是,其中一些渲染不正确(This 有伪影问题,this 没有始终保留左侧的红色条)。请注意,您可以在 Firefox 3 或更高版本中查看页面以查看动画。

我相信这个问题与我处理 DISPOSE_OP_PREVIOUS 的方式有关,但我无法弄清楚我做错了什么。谁能建议我可能遗漏了什么?

最佳答案

所以,我最终弄明白了,如果以后有人遇到类似问题,我会在这里发帖。事实证明,这个问题主要有三个方面:

  1. 如果帧类型是“PREVIOUS”,则不应更改“previous buffer”
  2. 应该使用前一帧的 dispose_op 而不是当前帧的 dispose_op 来确定它如何处理
  3. 应该确保只处理旧框架的区域,而不是整个框架

新代码是:

    internal class APNGBox
{
public int frameNum { get; set; }
public APNGLib.APNG apng { get; set; }
public Bitmap buffer { get; set; }
public Bitmap prevBuffer { get; set; }

public APNGBox(APNGLib.APNG png)
{
frameNum = 0;
apng = png;
buffer = apng.ToBitmap(0);
prevBuffer = null;
}
}

private void UpdateUI()
{
foreach (PictureBox pb in pics)
{
APNGBox box = (APNGBox)pb.Tag;
APNGLib.APNG png = box.apng;
if (!png.IsAnimated)
{
if (pb.Image == null)
{
pb.Image = png.ToBitmap();
}
}
else
{
if (box.frameNum != png.FrameCount - 1)
{
Bitmap prev = box.prevBuffer == null ? null : new Bitmap(box.prevBuffer);
APNGLib.Frame f1 = png.GetFrame(box.frameNum);
if (f1.DisposeOp != APNGLib.Frame.DisposeOperation.PREVIOUS)
{
box.prevBuffer = new Bitmap(box.buffer);
}
DisposeBuffer(box.buffer, new Rectangle((int)f1.XOffset, (int)f1.YOffset, (int)f1.Width, (int)f1.Height), f1.DisposeOp, prev);
box.frameNum++;
APNGLib.Frame f2 = png.GetFrame(box.frameNum);
RenderNextFrame(box.buffer, new Point((int)f2.XOffset, (int)f2.YOffset), png.ToBitmap(box.frameNum), f2.BlendOp);
}
else
{
box.frameNum = 0;
box.prevBuffer = null;
ClearFrame(box.buffer);
RenderNextFrame(box.buffer, Point.Empty, png.ToBitmap(box.frameNum), APNGLib.Frame.BlendOperation.SOURCE);
}
pb.Invalidate();
}
}
}

private void DisposeBuffer(Bitmap buffer, Rectangle region, APNGLib.Frame.DisposeOperation dispose, Bitmap prevBuffer)
{
using (Graphics g = Graphics.FromImage(buffer))
{
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;

Brush b = new SolidBrush(Color.Transparent);
switch (dispose)
{
case APNGLib.Frame.DisposeOperation.NONE:
break;
case APNGLib.Frame.DisposeOperation.BACKGROUND:
g.FillRectangle(b, region);
break;
case APNGLib.Frame.DisposeOperation.PREVIOUS:
if(prevBuffer != null)
{
g.FillRectangle(b, region);
g.DrawImage(prevBuffer, region, region, GraphicsUnit.Pixel);
}
break;
default:
break;
}
}
}

private void RenderNextFrame(Bitmap buffer, Point point, Bitmap nextFrame, APNGLib.Frame.BlendOperation blend)
{
using(Graphics g = Graphics.FromImage(buffer))
{
switch(blend)
{
case APNGLib.Frame.BlendOperation.OVER:
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
break;
case APNGLib.Frame.BlendOperation.SOURCE:
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
break;
default:
break;
}
g.DrawImage(nextFrame, point);
}
}

private void ClearFrame(Bitmap buffer)
{
using(Graphics g = Graphics.FromImage(buffer))
{
g.Clear(Color.Transparent);
}
}

关于c# - 实现 APNG 渲染函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6216094/

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