/// <summary> /// Extracts the HG-3 image information from the KIFINT entry's open KIFINT archive stream and saves all /// images to the output <paramref name="directory"/>. /// </summary> /// <param name="kifintStream">The stream to the open KIFINT archive.</param> /// <param name="entry">The KIFINT entry information used to extract the HG-3 file.</param> /// <param name="directory">The output directory to save the images to.</param> /// <param name="expand">True if the images are expanded to their full size when saving.</param> /// <returns>The extracted <see cref="Hg3"/> information.</returns> /// /// <exception cref="ArgumentNullException"> /// <paramref name="kifintStream"/>, <paramref name="entry"/>, or <paramref name="directory"/> is null. /// </exception> public static Hg3 ExtractHg3AndImages(KifintStream kifintStream, KifintEntry entry, string directory, bool expand) { if (directory == null) { throw new ArgumentNullException(nameof(directory)); } byte[] buffer = Extract(kifintStream, entry); using (MemoryStream ms = new MemoryStream(buffer)) return(Hg3.ExtractImages(ms, entry.FileName, directory, expand)); }
/// <summary> /// Constructs an HG-3 image with the specified file name, image index, <see cref="Hg3.HG3STDINFO"/>, and /// bitmap frames. /// </summary> /// <param name="imageIndex">The frame index of the image.</param> /// <param name="stdInfo">The HG3STDINFO struct containing image dimension information.</param> /// <param name="frameOffsets">The frame offsets for each frame entry in the HG-3 file.</param> /// <param name="hg3">The HG-3 containing this image set.</param> internal Hg3Image(int imageIndex, Hg3.HG3STDINFO stdInfo, long[] frameOffsets, Hg3 hg3) { Hg3 = hg3; ImageIndex = imageIndex; FrameOffsets = Array.AsReadOnly(frameOffsets); FrameCount = FrameOffsets.Count; // Todo: Eliminate frame offsets Width = stdInfo.Width; Height = stdInfo.Height; TotalWidth = stdInfo.TotalWidth; TotalHeight = stdInfo.TotalHeight; OffsetX = stdInfo.OffsetX; OffsetY = stdInfo.OffsetY; DepthBits = stdInfo.DepthBits; HasTransparency = stdInfo.HasTransparency; Center = stdInfo.Center; Baseline = stdInfo.Baseline; }
/// <summary> /// Extracts the HG-3 image information ONLY from open KIFINT archive stream and does not extract the actual /// images. /// </summary> /// <param name="kifintStream">The stream to the open KIFINT archive.</param> /// <param name="entry">The KIFINT entry used to locate the file.</param> /// <returns>The extracted <see cref="Hg3"/> information.</returns> /// /// <exception cref="ArgumentNullException"> /// <paramref name="kifintStream"/> or <paramref name="entry"/> is null. /// </exception> public static Hg3 ExtractHg3(KifintStream kifintStream, KifintEntry entry) { byte[] buffer = Extract(kifintStream, entry); using (MemoryStream ms = new MemoryStream(buffer)) return(Hg3.Extract(ms, entry.FileName)); }
private static Hg3 Extract(Stream stream, string fileName, string directory, bool saveFrames, bool expand) { BinaryReader reader = new BinaryReader(stream); HG3HDR hdr = reader.ReadUnmanaged <HG3HDR>(); if (hdr.Signature != "HG-3") { throw new UnexpectedFileTypeException(fileName, "HG-3"); } //int backtrack = Marshal.SizeOf<HG3TAG>() - 1; List <KeyValuePair <HG3STDINFO, List <long> > > imageOffsets = new List <KeyValuePair <HG3STDINFO, List <long> > >(); for (int i = 0; ; i++) { // NEW-NEW METHOD: We now know the next offset ahead // of time from the HG3OFFSET we're going to read. // Usually skips 0 bytes, otherwise usually 1-7 bytes. long startPosition = stream.Position; HG3OFFSET offset = reader.ReadUnmanaged <HG3OFFSET>(); HG3TAG tag = reader.ReadUnmanaged <HG3TAG>(); if (!HG3STDINFO.HasTagSignature(tag.Signature)) { throw new Exception("Expected \"stdinfo\" tag!"); } // NEW METHOD: Keep searching for the next stdinfo // This way we don't miss any images /*int offset = 0; * while (!tag.Signature.StartsWith("stdinfo")) { * if (stream.IsEndOfStream()) * break; * stream.Position -= backtrack; * tag = reader.ReadStruct<HG3TAG>(); * offset++; * } * if (stream.IsEndOfStream()) * break;*/ // OLD METHOD: Missed entries in a few files //if (!tag.signature.StartsWith(StdInfoSignature)) // break; HG3STDINFO stdInfo = reader.ReadUnmanaged <HG3STDINFO>(); List <long> frameOffsets = new List <long>(); imageOffsets.Add(new KeyValuePair <HG3STDINFO, List <long> >(stdInfo, frameOffsets)); while (tag.OffsetNext != 0) { tag = reader.ReadUnmanaged <HG3TAG>(); string signature = tag.Signature; if (HG3IMG.HasTagSignature(signature)) // "img####" { frameOffsets.Add(stream.Position); // Skip this tag stream.Position += tag.Length; } /*else if (HG3ATS.HasTagSignature(signature)) { // "ats####" * // Skip this tag * stream.Position += tag.Length; * } * else if (HG3CPTYPE.HasTagSignature(signature)) { // "cptype" * // Skip this tag * stream.Position += tag.Length; * } * else if (HG3IMG_AL.HasTagSignature(signature)) { // "img_al" * // Skip this tag * stream.Position += tag.Length; * } * else if (HG3IMG_JPG.HasTagSignature(signature)) { // "img_jpg" * // Skip this tag * stream.Position += tag.Length; * } * else if (HG3IMGMODE.HasTagSignature(signature)) { // "imgmode" * // Skip this tag * stream.Position += tag.Length; * }*/ else { // Skip this unknown tag stream.Position += tag.Length; } } if (offset.OffsetNext == 0) { break; // End of stream } stream.Position = startPosition + offset.OffsetNext; } HG3STDINFO[] stdInfos = imageOffsets.Select(p => p.Key).ToArray(); long[][] allFrameOffsets = imageOffsets.Select(p => p.Value.ToArray()).ToArray(); Hg3 hg3 = new Hg3(Path.GetFileName(fileName), hdr, stdInfos, allFrameOffsets, saveFrames && expand); // Save any frames after we've located them all. // This way we truely know if something is an animation. if (saveFrames) { for (int imgIndex = 0; imgIndex < hg3.Count; imgIndex++) { HG3STDINFO stdInfo = stdInfos[imgIndex]; Hg3Image hg3Image = hg3.Images[imgIndex]; for (int frmIndex = 0; frmIndex < hg3Image.FrameCount; frmIndex++) { stream.Position = hg3Image.FrameOffsets[frmIndex]; HG3IMG imghdr = reader.ReadUnmanaged <HG3IMG>(); string pngFile = hg3.GetFrameFilePath(directory, imgIndex, frmIndex); ExtractBitmap(reader, stdInfo, imghdr, expand, pngFile); } } } return(hg3); }
/// <summary> /// Gets the file path for the PNG image with the specified image and frame indecies. /// </summary> /// <param name="directory">The directory of the <see cref="Hg3"/> images.</param> /// <param name="frmIndex"> /// The second index, which is associated to a frame inside an <see cref="Hg3Image"/>. /// </param> /// <returns>The file path of the frame.</returns> public string GetFrameFilePath(string directory, int frmIndex) { return(Hg3.GetFrameFilePath(directory, ImageIndex, frmIndex)); }
/// <summary> /// Gets the file name for the PNG image with the specified image and frame indecies. /// </summary> /// <param name="frmIndex"> /// The second index, which is associated to a frame inside an <see cref="Hg3Image"/>. /// </param> /// <returns>The file name of the frame.</returns> public string GetFrameFileName(int frmIndex) { return(Hg3.GetFrameFileName(ImageIndex, frmIndex)); }