Example #1
0
        /// <summary>
        /// Creates an Animated PNG from a Image.
        /// </summary>
        /// <returns>The file.</returns>
        /// <param name="image">Image.</param>
        public static APNG FromImage(Image image)
        {
            APNG apng = new APNG();

            apng.Load(APNG.ImageToStream(image));
            return(apng);
        }
Example #2
0
        /// <summary>
        /// Creates an Animated PNG from a stream.
        /// </summary>
        /// <returns>The file.</returns>
        /// <param name="stream">The stream.</param>
        public static APNG FromStream(MemoryStream stream)
        {
            APNG apng = new APNG();

            apng.Load(stream);
            return(apng);
        }
Example #3
0
        /// <summary>
        /// Creates an Animated PNG from a file.
        /// </summary>
        /// <returns>The file.</returns>
        /// <param name="filename">Filename.</param>
        public static APNG FromFile(string filename)
        {
            APNG apng = new APNG();

            apng.Load(filename);
            return(apng);
        }
Example #4
0
        private static void ProcessingThread(byte[] apngData, AnimationInfo animationInfo)
        {
            APNG.APNG apng       = APNG.APNG.FromStream(new System.IO.MemoryStream(apngData));
            int       frameCount = apng.FrameCount;

            animationInfo.frameCount  = frameCount;
            animationInfo.initialized = true;

            animationInfo.frames = new System.Collections.Generic.List <FrameInfo>(frameCount);

            FrameInfo prevFrame = default;

            for (int i = 0; i < frameCount; i++)
            {
                Frame apngFrame = apng.Frames[i];

                using (Bitmap bitmap = apngFrame.ToBitmap()) {
                    FrameInfo frameInfo = new FrameInfo(bitmap.Width, bitmap.Height);

                    bitmap.MakeTransparent(System.Drawing.Color.Black);
                    bitmap.RotateFlip(RotateFlipType.Rotate180FlipX);

                    BitmapData frame = bitmap.LockBits(new Rectangle(Point.Empty, apng.ActualSize), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

                    Marshal.Copy(frame.Scan0, frameInfo.colors, 0, frameInfo.colors.Length);

                    bitmap.UnlockBits(frame);

                    if (apngFrame.fcTLChunk.BlendOp == APNG.Chunks.BlendOps.APNGBlendOpOver && i > 0)
                    {
                        // BGRA
                        var last = prevFrame.colors;
                        var src  = frameInfo.colors;

                        for (var clri = frameInfo.colors.Length - 1; i > 2; i -= 4)
                        {
                            var srcA  = src[clri - 3] * byteInverse;
                            var lastA = last[clri - 3] * byteInverse;

                            float blendedA = srcA + (1 - srcA) * lastA;
                            src[clri - 3] = (byte)Math.Round(blendedA * 255);

                            for (var c = 0; c < 3; c++)
                            {
                                var srcC  = src[clri - i] * byteInverse;
                                var lastC = last[clri - i] * byteInverse;

                                src[clri - i] = (byte)Math.Round((srcA * srcC + (1 - srcA) * lastA * lastC * 255f) / blendedA);
                            }
                        }
                    }

                    frameInfo.delay = apngFrame.FrameRate;
                    animationInfo.frames.Add(frameInfo);
                    prevFrame = frameInfo;
                }
            }
        }
Example #5
0
        private static void ProcessingThread(byte[] apngData, AnimationInfo animationInfo)
        {
            APNG.APNG apng       = APNG.APNG.FromStream(new System.IO.MemoryStream(apngData));
            int       frameCount = apng.FrameCount;

            animationInfo.frameCount  = frameCount;
            animationInfo.initialized = true;

            for (int i = 0; i < frameCount; i++)
            {
                Frame frame = apng.Frames[i];
                System.Drawing.Bitmap bitmap     = frame.ToBitmap();
                LockBitmap            lockBitmap = new LockBitmap(bitmap);
                lockBitmap.LockBits();
                FrameInfo frameInfo = new FrameInfo(bitmap.Width, bitmap.Height);
                for (int x = 0; x < frameInfo.width; x++)
                {
                    for (int y = 0; y < frameInfo.height; y++)
                    {
                        System.Drawing.Color sourceColor = lockBitmap.GetPixel(x, y);
                        Color32 lastFrame = new Color32();
                        if (i > 0)
                        {
                            lastFrame = animationInfo.frames.Last().colors[(frameInfo.height - y - 1) * frameInfo.width + x];
                        }

                        if (frame.fcTLChunk.BlendOp == APNG.Chunks.BlendOps.APNGBlendOpSource)
                        {
                            frameInfo.colors[(frameInfo.height - y - 1) * frameInfo.width + x] = new Color32(sourceColor.R, sourceColor.G, sourceColor.B, sourceColor.A);
                        }
                        if (frame.fcTLChunk.BlendOp == APNG.Chunks.BlendOps.APNGBlendOpOver)
                        {
                            float blendedA = ((sourceColor.A / 255f + (1 - (sourceColor.A / 255f)) * (lastFrame.a / 255f)));
                            float blendedR = ((sourceColor.A / 255f) * (sourceColor.R / 255f) + (1 - (sourceColor.A / 255f)) * (lastFrame.a / 255f) * (lastFrame.r / 255f)) / blendedA;
                            float blendedG = ((sourceColor.A / 255f) * (sourceColor.G / 255f) + (1 - (sourceColor.A / 255f)) * (lastFrame.a / 255f) * (lastFrame.g / 255f)) / blendedA;
                            float blendedB = ((sourceColor.A / 255f) * (sourceColor.B / 255f) + (1 - (sourceColor.A / 255f)) * (lastFrame.a / 255f) * (lastFrame.b / 255f)) / blendedA;

                            frameInfo.colors[(frameInfo.height - y - 1) * frameInfo.width + x] = new Color32((byte)(blendedR * 255), (byte)(blendedG * 255), (byte)(blendedB * 255), (byte)(blendedA * 255));
                        }
                    }
                }
                frameInfo.delay = frame.FrameRate;
                animationInfo.frames.Add(frameInfo);
            }
        }
Example #6
0
        /// <summary>
        /// Adds an image as the next frame.
        /// </summary>
        /// <param name="image">Png frame.</param>
        public void AddFrame(Image image)
        {
            //TODO: Handle different sizes
            //Temporarily reject improper sizes.
            if (IHDRChunk != null && (image.Width > IHDRChunk.Width || image.Height > IHDRChunk.Height))
            {
                throw new InvalidDataException("Frame must be less than or equal to the size of the other frames.");
            }

            APNG apng = APNG.FromImage(image);

            if (IHDRChunk == null)
            {
                IHDRChunk = apng.IHDRChunk;
            }

            //Create acTL Chunk.
            if (acTLChunk == null)
            {
                acTLChunk           = new acTLChunk();
                acTLChunk.PlayCount = 0;
            }

            uint sequenceNumber = (frames.Count == 0) ? 0 : (uint)(frames[frames.Count - 1].fcTLChunk.SequenceNumber + frames[frames.Count - 1].IDATChunks.Count);
            //Create fcTL Chunk
            fcTLChunk fctl = new fcTLChunk
            {
                SequenceNumber   = sequenceNumber,
                Width            = (uint)image.Width,
                Height           = (uint)image.Height,
                XOffset          = 0,
                YOffset          = 0,
                DelayNumerator   = 100,
                DelayDenominator = 1000,
                DisposeOp        = DisposeOps.APNGDisposeOpNone,
                BlendOp          = BlendOps.APNGBlendOpSource
            };

            //Set the default image if needed.
            if (defaultImage.IDATChunks.Count == 0)
            {
                defaultImage           = apng.DefaultImage;
                defaultImage.fcTLChunk = fctl;
                DefaultImageIsAnimated = true;
            }

            //Add all the frames from the png.
            if (apng.IsSimplePNG)
            {
                Frame frame = apng.DefaultImage;
                frame.fcTLChunk = fctl;

                foreach (OtherChunk chunk in frame.OtherChunks)
                {
                    if (!defaultImage.OtherChunks.Contains(chunk))
                    {
                        defaultImage.OtherChunks.Add(chunk);
                    }
                }
                frame.OtherChunks.Clear();
                frames.Add(frame);
            }
            else
            {
                for (int i = 0; i < apng.FrameCount; ++i)
                {
                    Frame frame = apng.Frames[i];
                    frame.fcTLChunk.SequenceNumber = sequenceNumber;
                    foreach (OtherChunk chunk in frame.OtherChunks)
                    {
                        if (!defaultImage.OtherChunks.Contains(chunk))
                        {
                            defaultImage.OtherChunks.Add(chunk);
                        }
                    }
                    frame.OtherChunks.Clear();
                    frames.Add(frame);
                }
            }
            List <OtherChunk> otherChunks = defaultImage.OtherChunks;

            // Now we should apply every chunk in otherChunks to every frame.
            if (defaultImage != frames[0])
            {
                frames.ForEach(f => otherChunks.ForEach(f.AddOtherChunk));
            }
            else
            {
                for (int i = 1; i < frames.Count; ++i)
                {
                    otherChunks.ForEach(frames[i].AddOtherChunk);
                }
            }

            acTLChunk.FrameCount = (uint)frames.Count;
        }