Пример #1
0
        /// <summary>
        /// Creates an animated GIF and writes it to <paramref name="outputStream"/>.
        /// </summary>
        /// <param name="animation"></param>
        /// <param name="outputStream"></param>
        public void Create(ConstRawAnimation animation, Stream outputStream)
        {
            List <Image> rawFrames = new List <Image>();

            // Load each image in the animation.
            foreach (ConstAnimationFrame frame in animation.Frames)
            {
                NpkPath frameImagePath           = frame.Image.ImageFilePath;
                DFO.Common.Images.Image rawFrame = m_imageSource.GetImage(frameImagePath, frame.Image.FrameIndex);
                rawFrames.Add(rawFrame);
            }

            int smallestX;
            int largestX;
            int smallestY;
            int largestY;

            // Frames can have different start positions and widths/heights. Normalize the images to a common coordinate system.
            FrameInfo.GetNormalizedCoordinates(rawFrames.Select(image => image.Attributes), out smallestX, out largestX, out smallestY, out largestY);

            int normalizedWidth  = largestX - smallestX + 1;
            int normalizedHeight = largestY - smallestY + 1;

            List <MagickImage> renderedFrames = new List <MagickImage>();

            try
            {
                // Composite each frame on top of a canvas of normalized width and height.
                for (int frameIndex = 0; frameIndex < animation.Frames.Count; frameIndex++)
                {
                    Image rawFrameImage = rawFrames[frameIndex];
                    ConstAnimationFrame frameAnimationInfo = animation.Frames[frameIndex];

                    MagickImage renderedFrame = RenderFrame(rawFrameImage, frameAnimationInfo, smallestX, largestX, smallestY, largestY, normalizedWidth, normalizedHeight);
                    renderedFrames.Add(renderedFrame);
                }

                // Make the GIF from the frames and write it out to the stream.
                using (MagickImageCollection frameCollection = new GraphicsMagick.MagickImageCollection(renderedFrames))
                {
                    frameCollection.Write(outputStream, MagickFormat.Gif);
                }
            }
            finally
            {
                renderedFrames.ForEach(f => f.Dispose());
            }
        }
Пример #2
0
        private void SelectedFrameChanged(object sender, EventArgs e)
        {
            FrameMetadata frame = FrameList.Current;

            if (frame == null)
            {
                CurrentFrameImage = null;
                return;
            }

            InnerNpkFile selectedFile = InnerFileList.Current;

            DFO.Common.Images.Image image = null;
            try
            {
                image = _editor.GetImage(selectedFile.Path, frame.Index);
            }
            catch (Exception)
            {
                // TODO: Log this and maybe display something
                CurrentFrameImage = null;
                return;
            }

            // Adjust position in bounding box according to frame coordinates
            // go from (0, 0) based coordinates to (_smallestX, _smallestY) based coordinates
            // (0, 0) -> (45, 50)
            // (60, 55) -> (15, 5)
            // frame x - _smallestX = bounding box X
            // frame y - _smallestY = bounding box y
            // Paint image in bounding box

            // RGBA -> BGRA (for little endian platforms), (BGRA for big endian platforms) - seems to not be reversed for little endian???
            // TODO: Make NpkReader able to output in variable format so it doesn't need to be converted
            byte[] frameBytes = new byte[_width * _height * 4];

            // Get X in frame
            // bounding box X + _smallestX = frame x
            // (5, 0) 5x5
            // (3, 1), 10x6
            // smallest x: 3
            // smallest y: 0
            // (0, 0): 0 + 3
            for (int boundingBoxY = 0; boundingBoxY < _height; boundingBoxY++)
            {
                int frameY    = boundingBoxY + _smallestY;
                int rowOffset = boundingBoxY * _width * 4;

                // if this row is above or below the current frame, draw a row of transparent pixels
                if (frameY < image.Attributes.LocationY || frameY > image.Attributes.LocationY + image.Attributes.Height - 1)
                {
                    for (int boundingBoxX = 0; boundingBoxX < _width; boundingBoxX++)
                    {
                        int pixelOffset = rowOffset + (boundingBoxX * 4);
                        frameBytes[pixelOffset]     = 0;
                        frameBytes[pixelOffset + 1] = 0;
                        frameBytes[pixelOffset + 2] = 0;
                        frameBytes[pixelOffset + 3] = 0;
                    }
                }
                else
                {
                    for (int boundingBoxX = 0; boundingBoxX < _width; boundingBoxX++)
                    {
                        int frameX      = boundingBoxX + _smallestX;
                        int pixelOffset = rowOffset + (boundingBoxX * 4);

                        // if this column is to the left or right of the current frame, draw a transparent pixel
                        if (frameX < image.Attributes.LocationX || frameX > image.Attributes.LocationX + image.Attributes.Width - 1)
                        {
                            frameBytes[pixelOffset]     = 0;
                            frameBytes[pixelOffset + 1] = 0;
                            frameBytes[pixelOffset + 2] = 0;
                            frameBytes[pixelOffset + 3] = 0;
                        }
                        else
                        {
                            // RGBA -> BGRA
                            int zeroBasedFrameY  = frameY - image.Attributes.LocationY;
                            int zeroBasedFrameX  = frameX - image.Attributes.LocationX;
                            int framePixelOffset = zeroBasedFrameY * image.Attributes.Width * 4 + zeroBasedFrameX * 4;
                            frameBytes[pixelOffset]     = image.PixelData[framePixelOffset + 2]; // B
                            frameBytes[pixelOffset + 1] = image.PixelData[framePixelOffset + 1]; // G
                            frameBytes[pixelOffset + 2] = image.PixelData[framePixelOffset];     // R
                            frameBytes[pixelOffset + 3] = image.PixelData[framePixelOffset + 3]; // A
                        }
                    }
                }
            }

            CurrentFrameImage = BitmapSource.Create(_width, _height, dpiX: 96, dpiY: 96, pixelFormat: PixelFormats.Bgra32, palette: null, pixels: frameBytes, stride: 4 * _width);
        }
Пример #3
0
        static void Main(string[] args)
        {
            using (NpkReader npk = new NpkReader(@"C:\Neople\DFO\ImagePacks2\sprite_character_fighter_equipment_avatar_cap.NPK"))
            {
                npk.PreLoadAllSpriteFrameMetadata();
                List <NpkPath> imgs = npk.Frames.Where(kvp => kvp.Value.Any(f => f.CompressedLength == 84)).Select(kvp => kvp.Key).ToList();
                foreach (NpkPath img in imgs)
                {
                    IReadOnlyList <FrameInfo> frames = npk.Frames[img];
                    for (int i = 0; i < frames.Count; i++)
                    {
                        if (frames[i].CompressedLength == 84 && !frames[i].IsCompressed)
                        {
                            Console.WriteLine(string.Format("{0} {1}", img, i));
                        }
                    }
                }
            }

            Environment.Exit(0);

            foreach (string path in Directory.GetFiles(@"C:\Neople\DFO\ImagePacks2", "*.NPK"))
            {
                Console.WriteLine(path);
                using (NpkReader npk = new NpkReader(path))
                {
                    npk.PreLoadAllSpriteFrameMetadata();
                    foreach (NpkPath npkPath in npk.Frames.Keys)
                    {
                        var x = npk.Frames[npkPath];
                        for (int i = 0; i < x.Count; i++)
                        {
                            FrameInfo frame = x[i];
                            if (!frame.IsCompressed && frame.LinkFrame == null)
                            {
                                string pixelFormatString = frame.PixelFormat.ToString();
                                int    actualLength      = frame.Width * frame.Height * 2;
                                if (frame.PixelFormat == PixelDataFormat.EightEightEightEight)
                                {
                                    actualLength *= 2;
                                }
                                if (frame.CompressedLength != actualLength)
                                {
                                    Console.WriteLine("Pixel Format: {0,22}, Compressed Length: {1,9}, Actual Length: {2,9} {3} {4}", pixelFormatString, frame.CompressedLength, actualLength, npkPath, i);
                                }
                            }
                        }
                    }
                }
            }

            Environment.Exit(0);

            using (NpkReader npkReader = new NpkReader(@"C:\Neople\DFO\ImagePacks2\sprite_monster_impossible_bakal.NPK"))
                using (NpkReader coolReader = new NpkReader(@"C:\Neople\DFO\ImagePacks2\sprite_character_swordman_effect_sayaex.NPK"))
                {
                    DFO.Common.Images.Image image = npkReader.GetImage("monster/impossible_bakal/ashcore.img", 0);
                    //Image image2 = npkReader.GetImage("worldmap/act1/elvengard.img", 1);
                    using (Bitmap bitmap = new Bitmap(image.Attributes.Width, image.Attributes.Height))
                    {
                        BitmapData raw = bitmap.LockBits(new Rectangle(0, 0, image.Attributes.Width, image.Attributes.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
                        unsafe
                        {
                            byte *ptr = (byte *)raw.Scan0;
                            // RGBA -> BGRA (pixels in the bitmap have endianness)
                            int width  = image.Attributes.Width;
                            int height = image.Attributes.Height;
                            int stride = raw.Stride;
                            for (int x = 0; x < width; x++)
                            {
                                for (int y = 0; y < height; y++)
                                {
                                    ptr[y * stride + x * 4 + 0] = image.PixelData[y * width * 4 + x * 4 + 2];
                                    ptr[y * stride + x * 4 + 1] = image.PixelData[y * width * 4 + x * 4 + 1];
                                    ptr[y * stride + x * 4 + 2] = image.PixelData[y * width * 4 + x * 4 + 0];
                                    ptr[y * stride + x * 4 + 3] = image.PixelData[y * width * 4 + x * 4 + 3];
                                }
                            }
                        }
                        bitmap.UnlockBits(raw);
                        bitmap.Save(@"output.png", System.Drawing.Imaging.ImageFormat.Png);


                        RawAnimation animationData = new RawAnimation();
                        animationData.Loop   = true;
                        animationData.Frames = new List <ConstAnimationFrame>()
                        {
                            new AnimationFrame()
                            {
                                DelayInMs = 1000, Image = new ImageIdentifier("worldmap/act1/elvengard.img", 0)
                            }.AsConst(),
                            new AnimationFrame()
                            {
                                DelayInMs = 1000, Image = new ImageIdentifier("worldmap/act1/elvengard.img", 1)
                            }.AsConst()
                        };

                        RawAnimation cool = new RawAnimation();
                        cool.Loop   = true;
                        cool.Frames = new List <ConstAnimationFrame>()
                        {
                            new AnimationFrame()
                            {
                                DelayInMs = 100, Image = new ImageIdentifier("character/swordman/effect/sayaex/wingdodge.img", 0)
                            }.AsConst(),
                            new AnimationFrame()
                            {
                                DelayInMs = 100, Image = new ImageIdentifier("character/swordman/effect/sayaex/wingdodge.img", 1)
                            }.AsConst(),
                            new AnimationFrame()
                            {
                                DelayInMs = 100, Image = new ImageIdentifier("character/swordman/effect/sayaex/wingdodge.img", 2)
                            }.AsConst(),
                            new AnimationFrame()
                            {
                                DelayInMs = 100, Image = new ImageIdentifier("character/swordman/effect/sayaex/wingdodge.img", 3)
                            }.AsConst(),
                            new AnimationFrame()
                            {
                                DelayInMs = 100, Image = new ImageIdentifier("character/swordman/effect/sayaex/wingdodge.img", 4)
                            }.AsConst(),
                            new AnimationFrame()
                            {
                                DelayInMs = 100, Image = new ImageIdentifier("character/swordman/effect/sayaex/wingdodge.img", 5)
                            }.AsConst(),
                            new AnimationFrame()
                            {
                                DelayInMs = 100, Image = new ImageIdentifier("character/swordman/effect/sayaex/wingdodge.img", 6)
                            }.AsConst(),
                            new AnimationFrame()
                            {
                                DelayInMs = 100, Image = new ImageIdentifier("character/swordman/effect/sayaex/wingdodge.img", 7)
                            }.AsConst(),
                            new AnimationFrame()
                            {
                                DelayInMs = 100, Image = new ImageIdentifier("character/swordman/effect/sayaex/wingdodge.img", 8)
                            }.AsConst(),
                            new AnimationFrame()
                            {
                                DelayInMs = 100, Image = new ImageIdentifier("character/swordman/effect/sayaex/wingdodge.img", 9)
                            }.AsConst(),
                        };

                        using (GifMaker giffer = new GifMaker(npkReader, disposeImageSource: false))
                            using (GifMaker coolGiffer = new GifMaker(coolReader, disposeImageSource: false))
                                using (FileStream gifOutputStream = new FileStream("output.gif", FileMode.Create, FileAccess.ReadWrite, FileShare.None))
                                    using (FileStream coolGifOutputStream = new FileStream("cool.gif", FileMode.Create, FileAccess.ReadWrite, FileShare.None))
                                    {
                                        giffer.Create(animationData.AsConst(), gifOutputStream);
                                        coolGiffer.Create(cool.AsConst(), coolGifOutputStream);
                                    }
                    }

                    Console.WriteLine("Success!");
                }
        }