示例#1
0
 public ImgInfo(string npkFileName, NpkPath path, int frameCount)
     : this()
 {
     NpkFileName = npkFileName;
     Path        = path;
     FrameCount  = frameCount;
 }
示例#2
0
        private static List<ConstAnimationFrame> GetFrameInfo(CommandLineArgs cmdLine, NpkReader npk, NpkPath imgPath)
        {
            List<ConstAnimationFrame> frameInfo = new List<ConstAnimationFrame>();
            List<FrameInfo> frames = npk.Frames[imgPath].ToList();

            if (cmdLine.UseAllFrames)
            {
                for (int frameIndex = 0; frameIndex < frames.Count; frameIndex++)
                {
                    frameInfo.Add(new AnimationFrame() { DelayInMs = cmdLine.FrameDelayInMs, Image = new ImageIdentifier(imgPath, frameIndex) }.AsConst());
                }
            }
            else
            {
                foreach (int frameIndex in cmdLine.FrameIndexes)
                {
                    if (frameIndex >= frames.Count)
                    {
                        Console.Error.WriteLine("{0} in {1} has {2} frames in it, so frame index {3} is not valid.", imgPath, cmdLine.NpkPath, frames.Count, frameIndex);
                        Environment.Exit(1);
                    }
                    frameInfo.Add(new AnimationFrame() { DelayInMs = cmdLine.FrameDelayInMs, Image = new ImageIdentifier(imgPath, frameIndex) }.AsConst());
                }
            }

            return frameInfo;
        }
示例#3
0
 public ImgInfo(string npkFileName, NpkPath path, int frameCount)
     : this()
 {
     NpkFileName = npkFileName;
     Path = path;
     FrameCount = frameCount;
 }
        private static NpkPath GetNpkPath(string packageDir, string pkgName)
        {
            var newbePk = NugetHelper.GetLastestVersionPackage(packageDir, pkgName);
            var npkPath = new NpkPath(Path.Combine(packageDir, $"{newbePk.Id}.{newbePk.Version.ToFullString()}"));

            return(npkPath);
        }
示例#5
0
        /// <summary>
        /// Preloads frame metadata for the .img file with the given path with a leading sprite/ if present.
        /// If the metadata has already been loaded, does nothing.
        /// Metadata for an .img's frames are loaded on demand otherwise.
        /// </summary>
        /// <param name="spriteFilePath">NPK path of the .img file to preload. Must contain a leading sprite/ if present in the actual path.</param>
        /// <exception cref="System.IO.FileNotFoundException">There is no .img file in the NPK with the given path.</exception>
        /// <exception cref="System.IO.IOException">An I/O error occurred.</exception>
        /// <exception cref="Dfo.Npk.NpkException">The .npk file is corrupt or the format changed.</exception>
        public void PreLoadSpriteMetadata(NpkPath spriteFilePath)
        {
            NpkByteRange spriteFileLocation;

            if (!m_imageFileLocations.TryGetValue(spriteFilePath, out spriteFileLocation))
            {
                throw new FileNotFoundException(string.Format("There is no .img file with path {0} in this NPK.", spriteFilePath));
            }

            LoadSpriteFileMetaData(spriteFilePath, spriteFileLocation);
        }
示例#6
0
        private static NpkPath GetImgPath(CommandLineArgs cmdLine, NpkReader npk)
        {
            if (cmdLine.ImgPath != null)
            {
                NpkPath         imgPath           = new NpkPath(cmdLine.ImgPath);
                IList <NpkPath> imgPathComponents = imgPath.GetPathComponents();
                if (imgPathComponents.Count >= 1 && !imgPathComponents[0].Path.Equals("sprite", StringComparison.OrdinalIgnoreCase))
                {
                    // add sprite/ prefix if present
                    imgPath = NpkPath.Combine("sprite", imgPath);
                }

                if (!npk.Images.ContainsKey(imgPath))
                {
                    Console.Error.WriteLine("There is no img file with path {0} in NPK file {1}", cmdLine.ImgPath, cmdLine.NpkPath);
                    Environment.Exit(1);
                }

                return(imgPath);
            }
            else
            {
                List <NpkPath> matchingPaths = new List <NpkPath>();

                // Only the .img name was given. Look for it.
                foreach (NpkPath path in npk.Images.Keys)
                {
                    if (path.GetFileName().Path.Equals(cmdLine.ImgName, StringComparison.OrdinalIgnoreCase))
                    {
                        matchingPaths.Add(path);
                    }
                }

                if (matchingPaths.Count == 1)
                {
                    return(matchingPaths[0]);
                }
                else if (matchingPaths.Count == 0)
                {
                    Console.Error.WriteLine("There is no img file called {0} in NPK file {1}", cmdLine.ImgName, cmdLine.NpkPath);
                    Environment.Exit(1);
                    return(null); // not reached
                }
                else
                {
                    Console.Error.WriteLine("There are multiple img files matching the name {0} in NPK file {1}: {2}", cmdLine.ImgName, cmdLine.NpkPath, string.Join(", ", matchingPaths));
                    Environment.Exit(1);
                    return(null); // not reached
                }
            }
        }
示例#7
0
        private static NpkPath GetImgPath(CommandLineArgs cmdLine, NpkReader npk)
        {
            if (cmdLine.ImgPath != null)
            {
                NpkPath imgPath = new NpkPath(cmdLine.ImgPath);
                IList<NpkPath> imgPathComponents = imgPath.GetPathComponents();
                if (imgPathComponents.Count >= 1 && !imgPathComponents[0].Path.Equals("sprite", StringComparison.OrdinalIgnoreCase))
                {
                    // add sprite/ prefix if present
                    imgPath = NpkPath.Combine("sprite", imgPath);
                }

                if (!npk.Images.ContainsKey(imgPath))
                {
                    Console.Error.WriteLine("There is no img file with path {0} in NPK file {1}", cmdLine.ImgPath, cmdLine.NpkPath);
                    Environment.Exit(1);
                }

                return imgPath;
            }
            else
            {
                List<NpkPath> matchingPaths = new List<NpkPath>();

                // Only the .img name was given. Look for it.
                foreach (NpkPath path in npk.Images.Keys)
                {
                    if (path.GetFileName().Path.Equals(cmdLine.ImgName, StringComparison.OrdinalIgnoreCase))
                    {
                        matchingPaths.Add(path);
                    }
                }

                if (matchingPaths.Count == 1)
                {
                    return matchingPaths[0];
                }
                else if (matchingPaths.Count == 0)
                {
                    Console.Error.WriteLine("There is no img file called {0} in NPK file {1}", cmdLine.ImgName, cmdLine.NpkPath);
                    Environment.Exit(1);
                    return null; // not reached
                }
                else
                {
                    Console.Error.WriteLine("There are multiple img files matching the name {0} in NPK file {1}: {2}", cmdLine.ImgName, cmdLine.NpkPath, string.Join(", ", matchingPaths));
                    Environment.Exit(1);
                    return null; // not reached
                }
            }
        }
示例#8
0
        static void Main(string[] args)
        {
            try
            {
                CommandLineArgs cmdLine = new CommandLineArgs(args);

                using (NpkReader npk = LoadNpk(cmdLine.NpkPath))
                {
                    NpkPath imgPath = GetImgPath(cmdLine, npk);

                    RawAnimation animationData = new RawAnimation();
                    animationData.Loop = true;

                    List <ConstAnimationFrame> frameInfo = GetFrameInfo(cmdLine, npk, imgPath);
                    animationData.Frames = frameInfo;

                    CreateOutputDir(cmdLine.OutputPath);

                    using (FileStream gifOutputStream = OpenOutput(cmdLine.OutputPath))
                        using (GifMaker giffer = new GifMaker(npk, disposeImageSource: false))
                        {
                            try
                            {
                                giffer.Create(animationData.AsConst(), gifOutputStream);
                            }
                            catch (Exception ex)
                            {
                                Console.Error.WriteLine("Error creating GIF: {0}", Utils.GetExceptionMessageWithInnerExceptions(ex));
                                Console.Error.WriteLine(ex.StackTrace);
                                giffer.Dispose();
                                gifOutputStream.Dispose();
                                npk.Dispose();
                                Environment.Exit(1);
                            }
                        }
                }

                Console.WriteLine("GIF saved to {0}", cmdLine.OutputPath);
            }
            catch (OptionException ex)
            {
                Console.Error.WriteLine(ex.Message);
                Console.Error.WriteLine("Run with -h for help");
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine("Unexpected error: {0}", Utils.GetExceptionMessageWithInnerExceptions(ex));
                Console.Error.WriteLine(ex.StackTrace);
            }
        }
 public bool TryGetValue(NpkPath key, out IReadOnlyList <FrameInfo> value)
 {
     if (m_npk.Images.ContainsKey(key))
     {
         m_npk.PreLoadSpriteMetadata(key);
         value = m_npk.m_frames[key];
         return(true);
     }
     else
     {
         value = null;
         return(false);
     }
 }
示例#10
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());
            }
        }
            public IReadOnlyList <FrameInfo> this[NpkPath key]
            {
                get
                {
                    try
                    {
                        m_npk.PreLoadSpriteMetadata(key);
                    }
                    catch (FileNotFoundException ex)
                    {
                        throw new KeyNotFoundException(ex.Message, ex);
                    }

                    return(m_npk.m_frames[key]);
                }
            }
示例#12
0
        /// <summary>
        /// Exports a frame as a PNG file.
        /// </summary>
        /// <param name="imageSource">Source of images. Normally an NPK reader, but could be also be a source that reads from
        /// an extraction or a mock source.</param>
        /// <param name="imgPath"></param>
        /// <param name="frameIndex"></param>
        /// <param name="outputStream">stream to write the PNG to</param>
        /// <exception cref="System.IO.FileNotFoundException">Image with the given path and frame index does not exist.</exception>
        public static void ToPng(IImageSource imageSource, NpkPath imgPath, int frameIndex, Stream outputStream)
        {
            Image image = imageSource.GetImage(imgPath, frameIndex);

            MagickReadSettings pixelDataSettings = new MagickReadSettings()
            {
                ColorSpace   = ColorSpace.RGB,
                Width        = image.Attributes.Width,
                Height       = image.Attributes.Height,
                PixelStorage = new PixelStorageSettings(StorageType.Char, "RGBA")
            };

            using (MagickImage magickImage = new MagickImage(image.PixelData, pixelDataSettings))
            {
                magickImage.Write(outputStream, MagickFormat.Png);
            }
        }
示例#13
0
        public void TestGetNpkName()
        {
            NpkPath testPath = "Interface/Emoticon/Against.img";

            Assert.That(testPath.GetImageNpkName(), Is.EqualTo("sprite_Interface_Emoticon.npk"));

            testPath = "sprite/Interface/Emoticon/Against.img";
            Assert.That(testPath.GetImageNpkName(), Is.EqualTo("sprite_Interface_Emoticon.npk"));

            testPath = "equip/armor/cloth_touch.wav";
            Assert.That(testPath.GetSoundNpkName(), Is.EqualTo("sounds_equip_armor.npk"));

            testPath = "sounds/equip/armor/cloth_touch.wav";
            Assert.That(testPath.GetSoundNpkName(), Is.EqualTo("sounds_equip_armor.npk"));

            testPath = "/";
            Assert.That(testPath.GetImageNpkName(), Is.EqualTo("sprite.npk"));
            Assert.That(testPath.GetSoundNpkName(), Is.EqualTo("sounds.npk"));
        }
示例#14
0
        private void WriteEditedNPK(FileStream tempFileStream, NpkPath imgPath, NpkFileTableEntry entryOfImgEditing, int editedFrameIndex,
                                    IReadOnlyList <FrameInfo> frameListOfImgEditing, FrameInfo frameMetadataOfFrameEditing,
                                    FrameInfo newFrameMetadata, byte[] newPixelData, int newPixelDataLength, byte[] frameMetadataBytes)
        {
            int imgByteCountChange = GetImgByteCountChange(frameMetadataOfFrameEditing, newFrameMetadata, newPixelDataLength);
            List <NpkByteRange> frameLocationsOfImgEditing = _reader.FrameLocations[imgPath];

            // Header is same
            tempFileStream.Write(NpkReader.s_headerBytes, 0, NpkReader.s_headerBytes.Length);

            // number of files is same
            tempFileStream.WriteUnsigned32Le((uint)_reader.Files.Count, _intWriteBuffer);

            byte[] imgPathBytes = new byte[256];

            // Write file table
            WritedEditedFileTable(tempFileStream, entryOfImgEditing, imgByteCountChange, imgPathBytes);

            // Write from original stream until offset of file we're changing
            // Write from current until currentEntry.Location.FileOffset
            _npkStream.Seek(tempFileStream.Position, SeekOrigin.Begin);
            int numBytesToCopy = (int)(entryOfImgEditing.Location.FileOffset - tempFileStream.Position);

            _npkStream.CopyToPartially(tempFileStream, numBytesToCopy);

            // Now write the new .img

            WriteEditedImg(tempFileStream, editedFrameIndex, frameListOfImgEditing, frameMetadataOfFrameEditing, newFrameMetadata, newPixelData, newPixelDataLength, frameMetadataBytes, frameLocationsOfImgEditing);

            // now write the rest of the original file that's after this .img
            if (entryOfImgEditing.Location.FileOffset + entryOfImgEditing.Location.Size < _npkStream.Length)
            {
                _npkStream.Seek(entryOfImgEditing.Location.FileOffset + entryOfImgEditing.Location.Size, SeekOrigin.Begin);
                numBytesToCopy = (int)_npkStream.Length - (entryOfImgEditing.Location.FileOffset + entryOfImgEditing.Location.Size);
                _npkStream.CopyToPartially(tempFileStream, numBytesToCopy);
            }
        }
示例#15
0
 /// <summary>
 /// Preloads frame metadata for the .img file with the given path with a leading sprite/ if present.
 /// If the metadata has already been loaded, does nothing.
 /// Metadata for an .img's frames are loaded on demand otherwise.
 /// </summary>
 /// <param name="spriteFilePath">NPK path of the .img file to preload. Must contain a leading sprite/ if present in the actual path.</param>
 /// <exception cref="System.IO.FileNotFoundException">There is no .img file in the NPK with the given path.</exception>
 /// <exception cref="System.IO.IOException">An I/O error occurred.</exception>
 /// <exception cref="Dfo.Npk.NpkException">The .npk file is corrupt or the format changed.</exception>
 public void PreLoadSpriteMetadata(NpkPath spriteFilePath)
 {
     ThrowIfDisposed();
     ThrowIfNoFileOpen();
     _reader.PreLoadSpriteMetadata(spriteFilePath);
 }
示例#16
0
 /// <summary>
 /// Loads the pixels of a frame.
 /// </summary>
 /// <param name="imgPath">The Npk Path of the .img file, with the leading sprite/ if present</param>
 /// <param name="frameIndex"></param>
 /// <returns></returns>
 /// <exception cref="System.IO.FileNotFoundException">The img file does not exist in this .npk file
 /// or no frame with the given index exists in the img file.</exception>
 /// <exception cref="System.IO.IOException">An I/O error occurred.</exception>
 /// <exception cref="Dfo.Npk.NpkException">The .npk file is corrupt or the format changed.</exception>
 public Image GetImage(NpkPath imgPath, int frameIndex)
 {
     ThrowIfDisposed();
     ThrowIfNoFileOpen();
     return(_reader.GetImage(imgPath, frameIndex));
 }
示例#17
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="imgPath"></param>
        /// <param name="frameIndex"></param>
        /// <param name="newFrameMetadata">If this indicates a link frame, <paramref name="newFramePixels"/> is ignored. The IsCompressed flag is honored, compressing the image if it is set. The CompressedLength field is not used.</param>
        /// <param name="newFramePixels">Readable stream consisting solely of the pixel data, in the format indicated by the metadata.</param>
        public void EditFrame(NpkPath imgPath, int frameIndex, FrameInfo newFrameMetadata, Stream newFramePixels)
        {
            ThrowIfDisposed();
            ThrowIfNoFileOpen();

            if (!_reader.Frames.ContainsKey(imgPath))
            {
                throw new ArgumentException("{0} is not in the NPK.".F(imgPath));
            }

            if (frameIndex >= _reader.Frames[imgPath].Count)
            {
                throw new ArgumentException("{0} does not have a frame {1}.".F(imgPath, frameIndex));
            }

            NpkFileTableEntry         entryOfImgEditing     = _reader.Files.Where(f => f.Name.Equals(imgPath)).First();
            IReadOnlyList <FrameInfo> frameListOfImgEditing = _reader.Frames[imgPath];
            FrameInfo frameMetadataOfFrameEditing           = frameListOfImgEditing[frameIndex];

            // Render the new frame in memory

            // pixelData is null if it's a link frame
            // pixelData length may be bigger than the actual pixel data. Use newPixelDataLength instead of newPixelData.Length
            int newPixelDataLength;

            byte[] newPixelData       = GetPixelData(newFrameMetadata, newFramePixels, out newPixelDataLength);
            byte[] frameMetadataBytes = GetFrameMetadataBytes(newFrameMetadata, newPixelDataLength);

            string tempNpkPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".NPK");

            using (FileStream tempFileStream = File.OpenWrite(tempNpkPath))
            {
                WriteEditedNPK(tempFileStream, imgPath, entryOfImgEditing, frameIndex, frameListOfImgEditing, frameMetadataOfFrameEditing, newFrameMetadata, newPixelData, newPixelDataLength, frameMetadataBytes);
            }

            // temp file now has the new NPK!
            // close _reader
            // close _npkStream
            // delete original file
            // move temp file

            // TODO: "refresh" it
            _reader.Dispose();
            _npkStream.Dispose();

            // TODO: Error handling
            File.Delete(_openFilePath);

            File.Move(tempNpkPath, _openFilePath);

            // reopen
            try
            {
                _reader = new NpkReader(_openFilePath);
            }
            catch (Exception)
            {
                _openFilePath = null;
                _reader       = null;
                _npkStream    = null;
                throw;
            }

            try
            {
                _npkStream = new FileStream(_openFilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
            }
            catch (Exception)
            {
                _openFilePath = null;
                _reader.Dispose();
                _reader    = null;
                _npkStream = null;
                throw;
            }
        }
示例#18
0
        /// <summary>
        /// Loads a sprite file's metadata, setting its value in m_images and
        /// m_frameLocations. The .npk file is assumed to be open.
        /// </summary>
        /// <param name="lookForErrors">Do some extra checks to look for errors in the NPK reading code. For use by automated tests.</param>
        /// <exception cref="System.IO.IOException">I/O error.</exception>
        /// <exception cref="Dfo.Npk.NpkException">The .npk file appears to be corrupt or the format has changed.</exception>
        private void LoadSpriteFileMetaData(NpkPath spriteFilePath, NpkByteRange spriteFileLocation)
        {
            // If already loaded, return
            if (m_frames.ContainsKey(spriteFilePath))
            {
                return;
            }

            try
            {
                // Seek to the sprite file's location in the .npk
                Seek(spriteFileLocation.FileOffset, SeekOrigin.Begin);

                // .img files begin with "Neople Img File\0" in ASCII
                byte[] headerBuffer = new byte[s_imgHeaderBytes.Length];
                m_npkStream.ReadOrDie(headerBuffer, headerBuffer.Length);
                string headerString = Encoding.ASCII.GetString(headerBuffer);
                if (!string.Equals(s_imgHeaderString, headerString, StringComparison.Ordinal))
                {
                    throw new NpkException("Did not find expected image file header when reading {0}.".F(spriteFilePath));
                }

                // 32-bit unsigned int - this field seems to be 36 * (# non-link frames) + 8 * (# link frames). A scan of all NPKs bears this out.
                uint field1 = GetUnsigned32Le();

                // 32-bit unsigned int - this field seems to be always 0. A scan of all NPKs bears this out.
                uint field2 = GetUnsigned32Le();

                if (DoExtraErrorChecks && field2 != 0)
                {
                    OnErrorDetected(string.Format("Field 2 in {0} is {1}, not 0 as expected.", spriteFilePath, field2));
                }

                // 32-bit unsigned int - this field seems to be always 2 (some sort of version number perhaps?). A scan of all NPKs bears this out.
                uint field3 = GetUnsigned32Le();

                if (DoExtraErrorChecks && field3 != 2)
                {
                    OnErrorDetected(string.Format("Field 3 in {0} is {1}, not 2 as expected.", spriteFilePath, field3));
                }

                // 32-bit unsigned int - number of frames in the .img file
                uint numFrames = GetUnsigned32Le();

                List<FrameInfo> frames = new List<FrameInfo>((int)numFrames);
                List<NpkByteRange> frameLocations = new List<NpkByteRange>((int)numFrames);

                // Next is each frame's metadata, one after the other.
                for (uint frameIndex = 0; frameIndex < numFrames; frameIndex++)
                {
                    FrameInfo frame = ReadFrameMetadata();
                    frames.Add(frame);
                }

                if (DoExtraErrorChecks)
                {
                    int numLinkFrames = frames.Where(f => f.LinkFrame != null).Count();
                    int numNonLinkFrames = frames.Count - numLinkFrames;
                    int expectedField1Value = 36 * numNonLinkFrames + 8 * numLinkFrames;
                    if (field1 != expectedField1Value)
                    {
                        OnErrorDetected(string.Format("Field 1 in {0} is {1}, not {2} as expected.", spriteFilePath, field1, expectedField1Value));
                    }
                }

                // Next is each non-reference frame's pixel data, one after the other.
                int currentFramePosition = (int)m_npkStream.Position;
                for (uint frameIndex = 0; frameIndex < numFrames; frameIndex++)
                {
                    FrameInfo frame = frames[(int)frameIndex];
                    if (frame.LinkFrame != null)
                    {
                        // Link frames have no pixel data
                        // Could set this to referenced frame's data to simplify code elsewhere?
                        frameLocations.Add(new NpkByteRange(0, 0));
                        continue;
                    }

                    NpkByteRange frameByteRange;
                    if (frame.IsCompressed)
                    {
                        frameByteRange = new NpkByteRange(currentFramePosition, frame.CompressedLength);
                    }
                    else
                    {
                        int length = frame.Width * frame.Height * s_formatToBytesPerPixel[frame.PixelFormat];
                        frameByteRange = new NpkByteRange(currentFramePosition, length);
                    }

                    frameLocations.Add(frameByteRange);

                    currentFramePosition += frameByteRange.Size;

                    // No need to seek through the pixel data normally.
                    // Do it when doing extra error checks to verify that after the pixel data of all the frames
                    // is either another img file or EOF.
                    if (DoExtraErrorChecks)
                    {
                        Seek(frameByteRange.Size, SeekOrigin.Current);
                    }
                }

                if (DoExtraErrorChecks)
                {
                    // Check for invalid link frames
                    for (uint frameIndex = 0; frameIndex < numFrames; frameIndex++)
                    {
                        FrameInfo frame = frames[(int)frameIndex];
                        if (frame.LinkFrame != null && (frame.LinkFrame.Value >= numFrames || frame.LinkFrame.Value < 0))
                        {
                            OnErrorDetected("{0}, invalid link frame index from {1} to {2}.".F(spriteFilePath, frameIndex, frame.LinkFrame.Value));
                        }

                        if (frame.LinkFrame != null)
                        {
                            FrameInfo linkedFrame = frames[frame.LinkFrame.Value];
                            if (linkedFrame.LinkFrame != null)
                            {
                                OnErrorDetected("{0}, link frame to a link frame, {1} to {2}.".F(spriteFilePath, frameIndex, frame.LinkFrame.Value));
                            }
                        }
                    }

                    // Should be "Neople Img File" or EOF
                    byte[] nextImgHeaderBuf = new byte[15];
                    int bytesRead = m_npkStream.Read(nextImgHeaderBuf, 0, 15);
                    if (bytesRead == 0)
                    {
                        // EOF, we're ok
                    }
                    else if (bytesRead != 15)
                    {
                        OnErrorDetected(string.Format("{0}, {1} bytes read instead of 15 or 0.", spriteFilePath.Path, bytesRead));
                    }
                    else
                    {
                        string nextImgHeader = Encoding.ASCII.GetString(nextImgHeaderBuf);
                        if (nextImgHeader != "Neople Img File")
                        {
                            OnErrorDetected(string.Format("{0}, header is not Neople Img File.", spriteFilePath.Path));
                        }
                    }
                }

                m_frames[spriteFilePath] = frames;
                m_frameLocations[spriteFilePath] = frameLocations;
            }
            catch (EndOfStreamException ex)
            {
                throw new NpkException("Unexpected end of file.", ex);
            }
        }
示例#19
0
        /// <summary>
        /// Helper function that loads the first part of the .npk header. m_imagefileLocations and
        /// m_soundFileLocations are loaded when this function completes. The stream's read pointer will
        /// be right after the file table part of the header after completion. This function is only
        /// intended to be called from LoadNpkHeader().
        /// </summary>
        /// <exception cref="System.IO.EndOfStreamException">Unexpected end of file.</exception>
        /// <exception cref="System.IO.IOException">I/O error.</exception>
        /// <exception cref="DFO.Npk.NpkException">The file is corrupt or the format has changed.</exception>
        private void LoadNpkFileTable()
        {
            // file starts with "NeoplePack_Bill\0" in ASCII
            try
            {
                string dirListingHeader = "NeoplePack_Bill\0";
                byte[] headerBuffer = new byte[dirListingHeader.Length];
                m_npkStream.ReadOrDie(headerBuffer, headerBuffer.Length);
                string headerString = Encoding.ASCII.GetString(headerBuffer);
                if (!string.Equals(dirListingHeader, headerString, StringComparison.Ordinal))
                {
                    throw new NpkException("Did not find expected directory listing header.");
                }

                // Next is a 32-bit unsigned int that is the number of files packed in the .npk
                uint numFiles = GetUnsigned32Le();
                _files = new List<NpkFileTableEntry>((int)numFiles);

                byte[] subNameBuffer = new byte[256];
                // Next is a listing of all the files and their location inside the file.
                for (uint fileIndex = 0; fileIndex < numFiles; fileIndex++)
                {
                    // First is a 32-bit unsigned int that is the byte offset in the .npk of where the file is located.
                    uint absoluteLocation = GetUnsigned32Le();
                    // Followed by the size of the file in bytes
                    uint size = GetUnsigned32Le();
                    // And then the path of the file, including the prefix indicating whether it is an image
                    // (sprite/) or a sound (sounds/)
                    // There are always 256 bytes to be read here.
                    // Each byte read is XOR'ed with the corresponding byte in the key.
                    // Then the bytes can be treated as a null-terminated ASCII string.
                    m_npkStream.ReadOrDie(subNameBuffer, subNameBuffer.Length);

                    for (int keyIndex = 0; keyIndex < subNameBuffer.Length; keyIndex++)
                    {
                        subNameBuffer[keyIndex] ^= s_key[keyIndex];
                    }

                    string subNameString = Encoding.ASCII.GetString(subNameBuffer);
                    subNameString = subNameString.TrimEnd('\0');
                    NpkPath pathWithPrefix = new NpkPath(subNameString);

                    _files.Add(new NpkFileTableEntry(pathWithPrefix, new NpkByteRange((int)absoluteLocation, (int)size)));

                    // That gives a path like sprite/character/gunner/effect/aerialdashattack.img
                    IList<NpkPath> pathComponents = pathWithPrefix.GetPathComponents();
                    if (pathComponents.Count >= 1)
                    {
                        NpkByteRange fileLocation = new NpkByteRange((int)absoluteLocation, (int)size);
                        if (pathComponents[0].Equals("sprite"))
                        {
                            m_imageFileLocations[pathWithPrefix] = fileLocation;
                            m_imagesInFile[pathWithPrefix] = true;
                        }
                        else if (pathComponents[0].Equals("sounds"))
                        {
                            m_soundFileLocations[pathWithPrefix] = fileLocation;
                        }
                        else
                        {
                            // Not an image or a sound. Ignore it I guess, no sense throwing an exception.
                            // Don't break any programs just because a new file type was added or something.
                            OnErrorDetected("Something other than a sprite or sounds file at packed file index {0}: {1}".F(fileIndex, pathComponents[0]));
                        }
                    }
                    else
                    {
                        // empty path? O_o Ignore it I guess.
                        OnErrorDetected("Empty path at packed file index {0}.".F(fileIndex));
                    }
                }
            }
            catch (EndOfStreamException ex)
            {
                throw new NpkException("Unexpected end of file.", ex);
            }
        }
示例#20
0
        /// <summary>
        /// Preloads frame metadata for the .img file with the given path with a leading sprite/ if present.
        /// If the metadata has already been loaded, does nothing.
        /// Metadata for an .img's frames are loaded on demand otherwise.
        /// </summary>
        /// <param name="spriteFilePath">NPK path of the .img file to preload. Must contain a leading sprite/ if present in the actual path.</param>
        /// <exception cref="System.IO.FileNotFoundException">There is no .img file in the NPK with the given path.</exception>
        /// <exception cref="System.IO.IOException">An I/O error occurred.</exception>
        /// <exception cref="Dfo.Npk.NpkException">The .npk file is corrupt or the format changed.</exception>
        public void PreLoadSpriteMetadata(NpkPath spriteFilePath)
        {
            NpkByteRange spriteFileLocation;
            if (!m_imageFileLocations.TryGetValue(spriteFilePath, out spriteFileLocation))
            {
                throw new FileNotFoundException(string.Format("There is no .img file with path {0} in this NPK.", spriteFilePath));
            }

            LoadSpriteFileMetaData(spriteFilePath, spriteFileLocation);
        }
示例#21
0
        /// <summary>
        /// Helper function that loads the first part of the .npk header. m_imagefileLocations and
        /// m_soundFileLocations are loaded when this function completes. The stream's read pointer will
        /// be right after the file table part of the header after completion. This function is only
        /// intended to be called from LoadNpkHeader().
        /// </summary>
        /// <exception cref="System.IO.EndOfStreamException">Unexpected end of file.</exception>
        /// <exception cref="System.IO.IOException">I/O error.</exception>
        /// <exception cref="DFO.Npk.NpkException">The file is corrupt or the format has changed.</exception>
        private void LoadNpkFileTable()
        {
            // file starts with "NeoplePack_Bill\0" in ASCII
            try
            {
                string dirListingHeader = "NeoplePack_Bill\0";
                byte[] headerBuffer     = new byte[dirListingHeader.Length];
                m_npkStream.ReadOrDie(headerBuffer, headerBuffer.Length);
                string headerString = Encoding.ASCII.GetString(headerBuffer);
                if (!string.Equals(dirListingHeader, headerString, StringComparison.Ordinal))
                {
                    throw new NpkException("Did not find expected directory listing header.");
                }

                // Next is a 32-bit unsigned int that is the number of files packed in the .npk
                uint numFiles = GetUnsigned32Le();
                _files = new List <NpkFileTableEntry>((int)numFiles);

                byte[] subNameBuffer = new byte[256];
                // Next is a listing of all the files and their location inside the file.
                for (uint fileIndex = 0; fileIndex < numFiles; fileIndex++)
                {
                    // First is a 32-bit unsigned int that is the byte offset in the .npk of where the file is located.
                    uint absoluteLocation = GetUnsigned32Le();
                    // Followed by the size of the file in bytes
                    uint size = GetUnsigned32Le();
                    // And then the path of the file, including the prefix indicating whether it is an image
                    // (sprite/) or a sound (sounds/)
                    // There are always 256 bytes to be read here.
                    // Each byte read is XOR'ed with the corresponding byte in the key.
                    // Then the bytes can be treated as a null-terminated ASCII string.
                    m_npkStream.ReadOrDie(subNameBuffer, subNameBuffer.Length);

                    for (int keyIndex = 0; keyIndex < subNameBuffer.Length; keyIndex++)
                    {
                        subNameBuffer[keyIndex] ^= s_key[keyIndex];
                    }

                    string subNameString = Encoding.ASCII.GetString(subNameBuffer);
                    subNameString = subNameString.TrimEnd('\0');
                    NpkPath pathWithPrefix = new NpkPath(subNameString);

                    _files.Add(new NpkFileTableEntry(pathWithPrefix, new NpkByteRange((int)absoluteLocation, (int)size)));

                    // That gives a path like sprite/character/gunner/effect/aerialdashattack.img
                    IList <NpkPath> pathComponents = pathWithPrefix.GetPathComponents();
                    if (pathComponents.Count >= 1)
                    {
                        NpkByteRange fileLocation = new NpkByteRange((int)absoluteLocation, (int)size);
                        if (pathComponents[0].Equals("sprite"))
                        {
                            m_imageFileLocations[pathWithPrefix] = fileLocation;
                            m_imagesInFile[pathWithPrefix]       = true;
                        }
                        else if (pathComponents[0].Equals("sounds"))
                        {
                            m_soundFileLocations[pathWithPrefix] = fileLocation;
                        }
                        else
                        {
                            // Not an image or a sound. Ignore it I guess, no sense throwing an exception.
                            // Don't break any programs just because a new file type was added or something.
                            OnErrorDetected("Something other than a sprite or sounds file at packed file index {0}: {1}".F(fileIndex, pathComponents[0]));
                        }
                    }
                    else
                    {
                        // empty path? O_o Ignore it I guess.
                        OnErrorDetected("Empty path at packed file index {0}.".F(fileIndex));
                    }
                }
            }
            catch (EndOfStreamException ex)
            {
                throw new NpkException("Unexpected end of file.", ex);
            }
        }
示例#22
0
        private static List <ConstAnimationFrame> GetFrameInfo(CommandLineArgs cmdLine, NpkReader npk, NpkPath imgPath)
        {
            List <ConstAnimationFrame> frameInfo = new List <ConstAnimationFrame>();
            List <FrameInfo>           frames    = npk.Frames[imgPath].ToList();

            if (cmdLine.UseAllFrames)
            {
                for (int frameIndex = 0; frameIndex < frames.Count; frameIndex++)
                {
                    frameInfo.Add(new AnimationFrame()
                    {
                        DelayInMs = cmdLine.FrameDelayInMs, Image = new ImageIdentifier(imgPath, frameIndex)
                    }.AsConst());
                }
            }
            else
            {
                foreach (int frameIndex in cmdLine.FrameIndexes)
                {
                    if (frameIndex >= frames.Count)
                    {
                        Console.Error.WriteLine("{0} in {1} has {2} frames in it, so frame index {3} is not valid.", imgPath, cmdLine.NpkPath, frames.Count, frameIndex);
                        Environment.Exit(1);
                    }
                    frameInfo.Add(new AnimationFrame()
                    {
                        DelayInMs = cmdLine.FrameDelayInMs, Image = new ImageIdentifier(imgPath, frameIndex)
                    }.AsConst());
                }
            }

            return(frameInfo);
        }
示例#23
0
 public NpkFileTableEntry(NpkPath name, NpkByteRange location)
 {
     _name     = name;
     _location = location;
 }
示例#24
0
        /// <summary>
        /// Loads the pixels of a frame.
        /// </summary>
        /// <param name="imgPath">The Npk Path of the .img file, with the leading sprite/ if present</param>
        /// <param name="frameIndex"></param>
        /// <returns></returns>
        /// <exception cref="System.IO.FileNotFoundException">The img file does not exist in this .npk file
        /// or no frame with the given index exists in the img file.</exception>
        /// <exception cref="System.IO.IOException">An I/O error occurred.</exception>
        /// <exception cref="Dfo.Npk.NpkException">The .npk file is corrupt or the format changed.</exception>
        public Image GetImage(NpkPath imgPath, int frameIndex)
        {
            imgPath.ThrowIfNull("imgPath");

            try
            {
                PreLoadSpriteMetadata(imgPath);

                IList <FrameInfo> imgFrames = m_frames[imgPath];

                if (frameIndex >= imgFrames.Count || frameIndex < 0)
                {
                    throw new FileNotFoundException("Cannot get frame index {0} of {1}. It only has {2} frames."
                                                    .F(frameIndex, imgPath, imgFrames.Count));
                }

                FrameInfo frameData      = imgFrames[frameIndex];
                int       realFrameIndex = frameIndex;

                // Follow frame links
                if (frameData.LinkFrame != null)
                {
                    realFrameIndex = frameData.LinkFrame.Value;
                    if (realFrameIndex >= imgFrames.Count || realFrameIndex < 0)
                    {
                        throw new FileNotFoundException("Cannot get linked frame index {0} of {1}. It only has {2} frames."
                                                        .F(realFrameIndex, imgPath, imgFrames.Count));
                    }
                    frameData = imgFrames[realFrameIndex];

                    if (frameData.LinkFrame != null)
                    {
                        throw new NpkException(
                                  "There is a link frame to another link frame which is not allowed. {0} frame {1} links to frame {2}."
                                  .F(imgPath, frameIndex, realFrameIndex));
                    }
                }

                NpkByteRange pixelDataLocation = m_frameLocations[imgPath][realFrameIndex];
                // Seek to the pixel data and read it
                Seek(pixelDataLocation.FileOffset, SeekOrigin.Begin);
                byte[] pixelData = new byte[pixelDataLocation.Size];
                m_npkStream.ReadOrDie(pixelData, pixelData.Length);

                if (frameData.IsCompressed)
                {
                    using (MemoryStream pixelDataMemoryStream = new MemoryStream(pixelData))
                    {
                        try
                        {
                            using (InflaterInputStream decompressStream = new InflaterInputStream(pixelDataMemoryStream))
                            {
                                byte[] decompressedPixelData = decompressStream.ReadFully();
                                pixelData = decompressedPixelData;
                            }
                        }
                        catch (SharpZipBaseException ex)
                        {
                            throw new NpkException(string.Format("Inflate error: {0}", ex.Message), ex);
                        }
                    }
                }

                pixelData = ExpandPixelData(pixelData, frameData);

                return(new Image(pixelData, frameData));
            }
            catch (EndOfStreamException ex)
            {
                throw new NpkException("Unexpected end of file.", ex);
            }
        }
 public bool ContainsKey(NpkPath key)
 {
     return(m_npk.Images.ContainsKey(key));
 }
示例#26
0
 public ImageIdentifier(NpkPath imageFilePath, int frameIndex)
 {
     ImageFilePath = imageFilePath;
     FrameIndex = frameIndex;
 }
示例#27
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="imgPath"></param>
        /// <param name="frameIndex"></param>
        /// <param name="pngFilePath"></param>
        /// <exception cref="DFOToolbox.DFOToolboxException">Something went wrong while editing. Message is suitable for UI display.</exception>
        /// <exception cref="System.Exception">Other errors resulting from incorrect usage of this function, such as passing null arguments or trying to edit a frame while no file is open.</exception>
        public void EditFrame(string imgPath, int frameIndex, string pngFilePath)
        {
            // validate that we have a file open for editing, that it has the img, that it has the frame index, that the file exists
            imgPath.ThrowIfNull("imgPath");
            pngFilePath.ThrowIfNull("pngFileName");
            if (!_editor.IsOpen)
            {
                throw new InvalidOperationException("Cannot edit a frame because no file is currently open.");
            }

            NpkPath npkPath = imgPath;

            if (!_editor.Frames.ContainsKey(npkPath))
            {
                throw new KeyNotFoundException("There is no img with path {0}.".F(imgPath));
            }

            if (frameIndex >= _editor.Frames[npkPath].Count)
            {
                throw new ArgumentOutOfRangeException("{0} does not have a frame with index {1}.".F(imgPath, frameIndex));
            }

            FrameInfo uneditedFrameMetadata = _editor.Frames[npkPath][frameIndex];

            // Use same pixel format as original.
            // If it's a link frame, we're turning it into a non-link frame, so use 8888 as that will preserve the colors of the new image.
            PixelDataFormat pixelFormatToUse = uneditedFrameMetadata.PixelFormat;

            if (pixelFormatToUse == PixelDataFormat.Link)
            {
                pixelFormatToUse = PixelDataFormat.EightEightEightEight;
            }

            if (!File.Exists(pngFilePath))
            {
                throw new DFOToolboxException("{0} does not exist.".F(pngFilePath));
            }

            byte[] newImageBytesInCorrectFormat;
            int    newImageWidth;
            int    newImageHeight;

            // Load image pixels into memory
            // TODO: catch exceptions
            using (System.Drawing.Bitmap inputImage = new System.Drawing.Bitmap(pngFilePath))
            {
                // need to get pixels into format used by image
                newImageBytesInCorrectFormat = PixelConversion.Convert(inputImage, pixelFormatToUse);
                newImageWidth  = inputImage.Width;
                newImageHeight = inputImage.Height;
            }

            using (MemoryStream newImageBytesInCorrectFormatStream = new MemoryStream(newImageBytesInCorrectFormat))
            {
                FrameInfo newFrameMetadata = new FrameInfo(
                    isCompressed: uneditedFrameMetadata.IsCompressed,
                    compressedLength: -1, // not used
                    pixelFormat: pixelFormatToUse,
                    width: newImageWidth,
                    height: newImageHeight,
                    locationX: uneditedFrameMetadata.LocationX,
                    locationY: uneditedFrameMetadata.LocationY,
                    maxWidth: uneditedFrameMetadata.MaxWidth,
                    maxHeight: uneditedFrameMetadata.MaxHeight
                    );

                _editor.EditFrame(npkPath, frameIndex, newFrameMetadata, newImageBytesInCorrectFormatStream);
            }

            // XXX: This code assumes the imgPath passed in is currently selected
            RefreshFrameList();
            FrameList.MoveCurrentToPosition(frameIndex);
        }
示例#28
0
        /// <summary>
        /// Loads the pixels of a frame.
        /// </summary>
        /// <param name="imgPath">The Npk Path of the .img file, with the leading sprite/ if present</param>
        /// <param name="frameIndex"></param>
        /// <returns></returns>
        /// <exception cref="System.IO.FileNotFoundException">The img file does not exist in this .npk file
        /// or no frame with the given index exists in the img file.</exception>
        /// <exception cref="System.IO.IOException">An I/O error occurred.</exception>
        /// <exception cref="Dfo.Npk.NpkException">The .npk file is corrupt or the format changed.</exception>
        public Image GetImage(NpkPath imgPath, int frameIndex)
        {
            imgPath.ThrowIfNull("imgPath");

            try
            {
                PreLoadSpriteMetadata(imgPath);

                IList<FrameInfo> imgFrames = m_frames[imgPath];

                if (frameIndex >= imgFrames.Count || frameIndex < 0)
                {
                    throw new FileNotFoundException("Cannot get frame index {0} of {1}. It only has {2} frames."
                        .F(frameIndex, imgPath, imgFrames.Count));
                }

                FrameInfo frameData = imgFrames[frameIndex];
                int realFrameIndex = frameIndex;

                // Follow frame links
                if (frameData.LinkFrame != null)
                {
                    realFrameIndex = frameData.LinkFrame.Value;
                    if (realFrameIndex >= imgFrames.Count || realFrameIndex < 0)
                    {
                        throw new FileNotFoundException("Cannot get linked frame index {0} of {1}. It only has {2} frames."
                            .F(realFrameIndex, imgPath, imgFrames.Count));
                    }
                    frameData = imgFrames[realFrameIndex];

                    if (frameData.LinkFrame != null)
                    {
                        throw new NpkException(
                            "There is a link frame to another link frame which is not allowed. {0} frame {1} links to frame {2}."
                            .F(imgPath, frameIndex, realFrameIndex));
                    }
                }

                NpkByteRange pixelDataLocation = m_frameLocations[imgPath][realFrameIndex];
                // Seek to the pixel data and read it
                Seek(pixelDataLocation.FileOffset, SeekOrigin.Begin);
                byte[] pixelData = new byte[pixelDataLocation.Size];
                m_npkStream.ReadOrDie(pixelData, pixelData.Length);

                if (frameData.IsCompressed)
                {
                    using (MemoryStream pixelDataMemoryStream = new MemoryStream(pixelData))
                    {
                        try
                        {
                            using (InflaterInputStream decompressStream = new InflaterInputStream(pixelDataMemoryStream))
                            {
                                byte[] decompressedPixelData = decompressStream.ReadFully();
                                pixelData = decompressedPixelData;
                            }
                        }
                        catch (SharpZipBaseException ex)
                        {
                            throw new NpkException(string.Format("Inflate error: {0}", ex.Message), ex);
                        }
                    }
                }

                pixelData = ExpandPixelData(pixelData, frameData);

                return new Image(pixelData, frameData);
            }
            catch (EndOfStreamException ex)
            {
                throw new NpkException("Unexpected end of file.", ex);
            }
        }
示例#29
0
 public NpkFileTableEntry(NpkPath name, NpkByteRange location)
 {
     _name = name;
     _location = location;
 }
示例#30
0
        /// <summary>
        /// Loads a sprite file's metadata, setting its value in m_images and
        /// m_frameLocations. The .npk file is assumed to be open.
        /// </summary>
        /// <param name="lookForErrors">Do some extra checks to look for errors in the NPK reading code. For use by automated tests.</param>
        /// <exception cref="System.IO.IOException">I/O error.</exception>
        /// <exception cref="Dfo.Npk.NpkException">The .npk file appears to be corrupt or the format has changed.</exception>
        private void LoadSpriteFileMetaData(NpkPath spriteFilePath, NpkByteRange spriteFileLocation)
        {
            // If already loaded, return
            if (m_frames.ContainsKey(spriteFilePath))
            {
                return;
            }

            try
            {
                // Seek to the sprite file's location in the .npk
                Seek(spriteFileLocation.FileOffset, SeekOrigin.Begin);

                // .img files begin with "Neople Img File\0" in ASCII
                byte[] headerBuffer = new byte[s_imgHeaderBytes.Length];
                m_npkStream.ReadOrDie(headerBuffer, headerBuffer.Length);
                string headerString = Encoding.ASCII.GetString(headerBuffer);
                if (!string.Equals(s_imgHeaderString, headerString, StringComparison.Ordinal))
                {
                    throw new NpkException("Did not find expected image file header when reading {0}.".F(spriteFilePath));
                }

                // 32-bit unsigned int - this field seems to be 36 * (# non-link frames) + 8 * (# link frames). A scan of all NPKs bears this out.
                uint field1 = GetUnsigned32Le();

                // 32-bit unsigned int - this field seems to be always 0. A scan of all NPKs bears this out.
                uint field2 = GetUnsigned32Le();

                if (DoExtraErrorChecks && field2 != 0)
                {
                    OnErrorDetected(string.Format("Field 2 in {0} is {1}, not 0 as expected.", spriteFilePath, field2));
                }

                // 32-bit unsigned int - this field seems to be always 2 (some sort of version number perhaps?). A scan of all NPKs bears this out.
                uint field3 = GetUnsigned32Le();

                if (DoExtraErrorChecks && field3 != 2)
                {
                    OnErrorDetected(string.Format("Field 3 in {0} is {1}, not 2 as expected.", spriteFilePath, field3));
                }

                // 32-bit unsigned int - number of frames in the .img file
                uint numFrames = GetUnsigned32Le();

                List <FrameInfo>    frames         = new List <FrameInfo>((int)numFrames);
                List <NpkByteRange> frameLocations = new List <NpkByteRange>((int)numFrames);

                // Next is each frame's metadata, one after the other.
                for (uint frameIndex = 0; frameIndex < numFrames; frameIndex++)
                {
                    FrameInfo frame = ReadFrameMetadata();
                    frames.Add(frame);
                }

                if (DoExtraErrorChecks)
                {
                    int numLinkFrames       = frames.Where(f => f.LinkFrame != null).Count();
                    int numNonLinkFrames    = frames.Count - numLinkFrames;
                    int expectedField1Value = 36 * numNonLinkFrames + 8 * numLinkFrames;
                    if (field1 != expectedField1Value)
                    {
                        OnErrorDetected(string.Format("Field 1 in {0} is {1}, not {2} as expected.", spriteFilePath, field1, expectedField1Value));
                    }
                }

                // Next is each non-reference frame's pixel data, one after the other.
                int currentFramePosition = (int)m_npkStream.Position;
                for (uint frameIndex = 0; frameIndex < numFrames; frameIndex++)
                {
                    FrameInfo frame = frames[(int)frameIndex];
                    if (frame.LinkFrame != null)
                    {
                        // Link frames have no pixel data
                        // Could set this to referenced frame's data to simplify code elsewhere?
                        frameLocations.Add(new NpkByteRange(0, 0));
                        continue;
                    }

                    NpkByteRange frameByteRange;
                    if (frame.IsCompressed)
                    {
                        frameByteRange = new NpkByteRange(currentFramePosition, frame.CompressedLength);
                    }
                    else
                    {
                        int length = frame.Width * frame.Height * s_formatToBytesPerPixel[frame.PixelFormat];
                        frameByteRange = new NpkByteRange(currentFramePosition, length);
                    }

                    frameLocations.Add(frameByteRange);

                    currentFramePosition += frameByteRange.Size;

                    // No need to seek through the pixel data normally.
                    // Do it when doing extra error checks to verify that after the pixel data of all the frames
                    // is either another img file or EOF.
                    if (DoExtraErrorChecks)
                    {
                        Seek(frameByteRange.Size, SeekOrigin.Current);
                    }
                }

                if (DoExtraErrorChecks)
                {
                    // Check for invalid link frames
                    for (uint frameIndex = 0; frameIndex < numFrames; frameIndex++)
                    {
                        FrameInfo frame = frames[(int)frameIndex];
                        if (frame.LinkFrame != null && (frame.LinkFrame.Value >= numFrames || frame.LinkFrame.Value < 0))
                        {
                            OnErrorDetected("{0}, invalid link frame index from {1} to {2}.".F(spriteFilePath, frameIndex, frame.LinkFrame.Value));
                        }

                        if (frame.LinkFrame != null)
                        {
                            FrameInfo linkedFrame = frames[frame.LinkFrame.Value];
                            if (linkedFrame.LinkFrame != null)
                            {
                                OnErrorDetected("{0}, link frame to a link frame, {1} to {2}.".F(spriteFilePath, frameIndex, frame.LinkFrame.Value));
                            }
                        }
                    }

                    // Should be "Neople Img File" or EOF
                    byte[] nextImgHeaderBuf = new byte[15];
                    int    bytesRead        = m_npkStream.Read(nextImgHeaderBuf, 0, 15);
                    if (bytesRead == 0)
                    {
                        // EOF, we're ok
                    }
                    else if (bytesRead != 15)
                    {
                        OnErrorDetected(string.Format("{0}, {1} bytes read instead of 15 or 0.", spriteFilePath.Path, bytesRead));
                    }
                    else
                    {
                        string nextImgHeader = Encoding.ASCII.GetString(nextImgHeaderBuf);
                        if (nextImgHeader != "Neople Img File")
                        {
                            OnErrorDetected(string.Format("{0}, header is not Neople Img File.", spriteFilePath.Path));
                        }
                    }
                }

                m_frames[spriteFilePath]         = frames;
                m_frameLocations[spriteFilePath] = frameLocations;
            }
            catch (EndOfStreamException ex)
            {
                throw new NpkException("Unexpected end of file.", ex);
            }
        }
示例#31
0
 public ImageIdentifier(NpkPath imageFilePath, int frameIndex)
 {
     ImageFilePath = imageFilePath;
     FrameIndex    = frameIndex;
 }