首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >实现APNG渲染功能

实现APNG渲染功能
EN

Stack Overflow用户
提问于 2011-06-02 22:44:03
回答 1查看 2.7K关注 0票数 5

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

代码语言:javascript
复制
    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

代码语言:javascript
复制
internal class APNGBox
    {
        public int frameNum = 0;
        public APNGLib.APNG png;
        public Bitmap buffer;
        public Bitmap prevBuffer;
    }

我认为这在很大程度上是正确的,因为我已经对APNG Gallery中的所有图像运行过它。然而,其中一些渲染不正确(This one有瑕疵问题,this one不能始终保留左侧的红色条)。请注意,您将在Firefox3或更高版本中查看页面以查看动画。

我相信这个问题与我处理DISPOSE_OP_PREVIOUS的方式有关,但我不知道我做错了什么。有没有人能告诉我我可能遗漏了什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2011-06-03 02:43:18

所以,我最终弄明白了这一点,并将在这里发布,以防将来有人遇到类似的问题。事实证明,这个问题主要有三个方面:

如果帧类型为‘’,则

  1. 不应更改'previous buffer‘
  2. 应使用上一帧的dispose_op,而不是当前帧的dispose_op,以确定如何处置
  3. 应确保仅处置旧帧的区域,而不是整个帧

新的代码是:

代码语言:javascript
复制
    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);
        }
    }
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6216094

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档