diff --git a/ArcFormats/Entis/ArcERI.cs b/ArcFormats/Entis/ArcERI.cs index 097259d5..29e70050 100644 --- a/ArcFormats/Entis/ArcERI.cs +++ b/ArcFormats/Entis/ArcERI.cs @@ -29,6 +29,7 @@ using System.ComponentModel.Composition; using System.IO; using System.Linq; using System.Windows.Media; +using System.Windows.Media.Imaging; using GameRes.Utility; namespace GameRes.Formats.Entis @@ -92,7 +93,7 @@ namespace GameRes.Formats.Entis else if ("ImageFrm" == id || "DiffeFrm" == id) { var entry = new EriEntry { - Name = string.Format ("{0}#{1:D4}.tga", base_name, i++), + Name = string.Format ("{0}#{1:D4}", base_name, i++), Type = "image", Offset = current_offset, Size = (uint)section_size, @@ -110,17 +111,15 @@ namespace GameRes.Formats.Entis return new EriMultiImage (file, this, dir, info, palette); } - public override Stream OpenEntry (ArcFile arc, Entry entry) + public override IImageDecoder OpenImage (ArcFile arc, Entry entry) { var earc = (EriMultiImage)arc; var eent = (EriEntry)entry; var pixels = earc.GetFrame (eent.FrameIndex); - if (32 == earc.Info.BPP && 0 == (earc.Info.FormatType & EriType.WithAlpha)) - { - for (int p = 3; p < pixels.Length; p += 4) - pixels[p] = 0xFF; - } - return TgaStream.Create (earc.Info, pixels); + BitmapPalette palette = null; + if (8 == earc.Info.BPP && earc.Palette != null) + palette = new BitmapPalette (earc.Palette); + return new BitmapDecoder (pixels, earc.Info, earc.Format, palette); } } @@ -128,6 +127,7 @@ namespace GameRes.Formats.Entis { public readonly EriMetaData Info; public readonly Color[] Palette; + public readonly PixelFormat Format; byte[][] Frames; public EriMultiImage (ArcView arc, ArchiveFormat impl, ICollection dir, EriMetaData info, Color[] palette) @@ -136,6 +136,24 @@ namespace GameRes.Formats.Entis Info = info; Palette = palette; Frames = new byte[dir.Count][]; + if (8 == Info.BPP) + { + if (null == Palette) + Format = PixelFormats.Gray8; + else + Format = PixelFormats.Indexed8; + } + else if (32 == Info.BPP) + { + if (0 == (Info.FormatType & EriType.WithAlpha)) + Format = PixelFormats.Bgr32; + else + Format = PixelFormats.Bgra32; + } + else if (16 == Info.BPP) + Format = PixelFormats.Bgr555; + else + Format = PixelFormats.Bgr24; } public byte[] GetFrame (int index) @@ -166,4 +184,22 @@ namespace GameRes.Formats.Entis public int FrameIndex; public bool IsDiff; } + + internal class BitmapDecoder : IImageDecoder + { + public Stream Source { get { return null; } } + public ImageFormat SourceFormat { get { return null; } } + public ImageMetaData Info { get; private set; } + public ImageData Image { get; private set; } + + public BitmapDecoder (byte[] pixels, ImageMetaData info, PixelFormat format, BitmapPalette palette) + { + Info = info; + Image = ImageData.Create (info, format, palette, pixels); + } + + public void Dispose () + { + } + } } diff --git a/ArcFormats/FC01/ArcMCA.cs b/ArcFormats/FC01/ArcMCA.cs index c29f514e..61fb4a5a 100644 --- a/ArcFormats/FC01/ArcMCA.cs +++ b/ArcFormats/FC01/ArcMCA.cs @@ -29,6 +29,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.IO; +using System.Windows.Media; namespace GameRes.Formats.FC01 { @@ -69,7 +70,7 @@ namespace GameRes.Formats.FC01 index_offset += 4; var entry = new Entry { - Name = string.Format ("{0}#{1:D4}.tga", base_name, i), + Name = string.Format ("{0}#{1:D4}", base_name, i), Offset = next_offset, Type = "image", }; @@ -84,31 +85,19 @@ namespace GameRes.Formats.FC01 return new McaArchive (file, this, dir, options.Key); } - public override Stream OpenEntry (ArcFile arc, Entry entry) + public override IImageDecoder OpenImage (ArcFile arc, Entry entry) { - var mca = arc as McaArchive; - int method = arc.File.View.ReadInt32 (entry.Offset); - if (null == mca || method < 0 || method > 1) - return base.OpenEntry (arc, entry); - uint width = arc.File.View.ReadUInt32 (entry.Offset+0xC); - uint height = arc.File.View.ReadUInt32 (entry.Offset+0x10); - uint packed_size = arc.File.View.ReadUInt32 (entry.Offset+0x14); - int unpacked_size = arc.File.View.ReadInt32 (entry.Offset+0x18); - - var data = arc.File.View.ReadBytes (entry.Offset+0x20, packed_size); - MrgOpener.Decrypt (data, 0, data.Length, mca.Key); - if (method > 0) + var mca = (McaArchive)arc; + var input = arc.File.CreateStream (entry.Offset, entry.Size); + try { - using (var input = new BinMemoryStream (data)) - using (var lzss = new MrgLzssReader (input, data.Length, unpacked_size)) - { - lzss.Unpack(); - data = lzss.Data; - } + return new McaDecoder (input, mca.Key); + } + catch + { + input.Dispose(); + throw; } - int stride = ((int)width * 3 + 3) & ~3; - var info = new ImageMetaData { Width = width, Height = height, BPP = 24 }; - return TgaStream.Create (info, stride, data); } public override ResourceOptions GetDefaultOptions () @@ -129,4 +118,44 @@ namespace GameRes.Formats.FC01 return new GUI.WidgetMCG(); } } + + internal sealed class McaDecoder : BinaryImageDecoder + { + byte m_key; + int m_method; + int m_packed_size; + int m_unpacked_size; + + public McaDecoder (IBinaryStream input, byte key) : base (input) + { + m_key = key; + var header = m_input.ReadHeader (0x20); + m_method = header.ToInt32 (0); + if (m_method < 0 || m_method > 1) + throw new InvalidFormatException(); + uint width = header.ToUInt32 (0xC); + uint height = header.ToUInt32 (0x10); + m_packed_size = header.ToInt32 (0x14); + m_unpacked_size = header.ToInt32 (0x18); + Info = new ImageMetaData { Width = width, Height = height, BPP = 24 }; + } + + protected override ImageData GetImageData () + { + m_input.Position = 0x20; + var data = m_input.ReadBytes (m_packed_size); + MrgOpener.Decrypt (data, 0, data.Length, m_key); + if (m_method > 0) + { + using (var input = new BinMemoryStream (data)) + using (var lzss = new MrgLzssReader (input, data.Length, m_unpacked_size)) + { + lzss.Unpack(); + data = lzss.Data; + } + } + int stride = ((int)Info.Width * 3 + 3) & ~3; + return ImageData.Create (Info, PixelFormats.Bgr24, null, data, stride); + } + } } diff --git a/ArcFormats/Favorite/ArcHZC.cs b/ArcFormats/Favorite/ArcHZC.cs index 4feb5eeb..b30ec06f 100644 --- a/ArcFormats/Favorite/ArcHZC.cs +++ b/ArcFormats/Favorite/ArcHZC.cs @@ -78,10 +78,10 @@ namespace GameRes.Formats.FVP for (int i = 0; i < count; ++i) { var entry = new Entry { - Name = string.Format ("{0}#{1:D3}.tga", base_name, i), + Name = string.Format ("{0}#{1:D3}", base_name, i), Type = "image", Offset = frame_size * i, - Size = 0x12 + (uint)frame_size, + Size = (uint)frame_size, }; dir.Add (entry); } @@ -94,24 +94,33 @@ namespace GameRes.Formats.FVP using (var input = arc.File.CreateStream (0xC+hzc.ImageInfo.HeaderSize)) using (var z = new ZLibStream (input, CompressionMode.Decompress)) { - uint frame_size = entry.Size - 0x12; + uint frame_size = entry.Size; var pixels = new byte[frame_size]; uint offset = 0; for (;;) { if (pixels.Length != z.Read (pixels, 0, pixels.Length)) - break; + throw new EndOfStreamException(); if (offset >= entry.Offset) break; offset += frame_size; } - if (4 == hzc.ImageInfo.Type) - { - for (int i = 0; i < pixels.Length; ++i) - if (1 == pixels[i]) - pixels[i] = 0xFF; - } - return TgaStream.Create (hzc.ImageInfo, pixels); + return new BinMemoryStream (pixels, entry.Name); + } + } + + public override IImageDecoder OpenImage (ArcFile arc, Entry entry) + { + var hzc = (HzcArchive)arc; + var input = arc.File.CreateStream (0xC+hzc.ImageInfo.HeaderSize); + try + { + return new HzcDecoder (input, hzc.ImageInfo, entry); + } + catch + { + input.Dispose(); + throw; } } } diff --git a/ArcFormats/Favorite/ImageHZC.cs b/ArcFormats/Favorite/ImageHZC.cs index a0a71166..93f036e2 100644 --- a/ArcFormats/Favorite/ImageHZC.cs +++ b/ArcFormats/Favorite/ImageHZC.cs @@ -69,32 +69,9 @@ namespace GameRes.Formats.FVP public override ImageData Read (IBinaryStream stream, ImageMetaData info) { var meta = (HzcMetaData)info; - BitmapPalette palette = null; - int stride = (int)meta.Width * meta.BPP / 8; - PixelFormat format; - switch (meta.Type) - { - default: throw new NotSupportedException(); - case 0: format = PixelFormats.Bgr24; break; - case 1: - case 2: format = PixelFormats.Bgra32; break; - case 3: format = PixelFormats.Gray8; break; - case 4: - { - format = PixelFormats.Indexed8; - var colors = new Color[2] { Color.FromRgb (0,0,0), Color.FromRgb (0xFF,0xFF,0xFF) }; - palette = new BitmapPalette (colors); - break; - } - } stream.Position = 12 + meta.HeaderSize; - using (var z = new ZLibStream (stream.AsStream, CompressionMode.Decompress, true)) - { - var pixels = new byte[stride * (int)meta.Height]; - if (pixels.Length != z.Read (pixels, 0, pixels.Length)) - throw new EndOfStreamException(); - return ImageData.Create (info, format, palette, pixels, stride); - } + using (var decoder = new HzcDecoder (stream, meta, true)) + return decoder.Image; } public override void Write (Stream file, ImageData image) @@ -102,4 +79,87 @@ namespace GameRes.Formats.FVP throw new System.NotImplementedException ("HzcFormat.Write not implemented"); } } + + internal sealed class HzcDecoder : IImageDecoder + { + HzcMetaData m_info; + ImageData m_image; + int m_stride; + long m_frame_offset; + int m_frame_size; + + public Stream Source { get; private set; } + public ImageFormat SourceFormat { get { return null; } } + public ImageMetaData Info { get { return m_info; } } + public PixelFormat Format { get; private set; } + public BitmapPalette Palette { get; private set; } + public ImageData Image + { + get + { + if (null == m_image) + { + var pixels = ReadPixels(); + m_image = ImageData.Create (Info, Format, Palette, pixels, m_stride); + } + return m_image; + } + } + + public HzcDecoder (IBinaryStream input, HzcMetaData info, Entry entry) : this (input, info) + { + m_frame_offset = entry.Offset; + m_frame_size = (int)entry.Size; + } + + public HzcDecoder (IBinaryStream input, HzcMetaData info, bool leave_open = false) + { + m_info = info; + m_stride = (int)m_info.Width * m_info.BPP / 8; + switch (m_info.Type) + { + default: throw new NotSupportedException(); + case 0: Format = PixelFormats.Bgr24; break; + case 1: + case 2: Format = PixelFormats.Bgra32; break; + case 3: Format = PixelFormats.Gray8; break; + case 4: + { + Format = PixelFormats.Indexed8; + var colors = new Color[2] { Color.FromRgb (0,0,0), Color.FromRgb (0xFF,0xFF,0xFF) }; + Palette = new BitmapPalette (colors); + break; + } + } + Source = new ZLibStream (input.AsStream, CompressionMode.Decompress, leave_open); + m_frame_offset = 0; + m_frame_size = m_stride * (int)Info.Height; + } + + byte[] ReadPixels () + { + var pixels = new byte[m_frame_size]; + long offset = 0; + for (;;) + { + if (pixels.Length != Source.Read (pixels, 0, pixels.Length)) + throw new EndOfStreamException(); + if (offset >= m_frame_offset) + break; + offset += m_frame_size; + } + return pixels; + } + + bool m_disposed = false; + public void Dispose () + { + if (!m_disposed) + { + Source.Dispose(); + m_disposed = true; + } + GC.SuppressFinalize (this); + } + } } diff --git a/ArcFormats/Patisserie/ArcRAW.cs b/ArcFormats/Patisserie/ArcRAW.cs index 36cb107c..7637cd82 100644 --- a/ArcFormats/Patisserie/ArcRAW.cs +++ b/ArcFormats/Patisserie/ArcRAW.cs @@ -26,6 +26,7 @@ using System.Collections.Generic; using System.ComponentModel.Composition; using System.IO; +using System.Windows.Media; namespace GameRes.Formats.Patisserie { @@ -55,7 +56,7 @@ namespace GameRes.Formats.Patisserie while (current_offset < end) { var entry = new Entry { - Name = string.Format ("{0:D4}.tga", i++), + Name = string.Format ("{0:D4}", i++), Type = "image", Offset = current_offset, }; @@ -70,7 +71,7 @@ namespace GameRes.Formats.Patisserie return new ArcFile (file, this, dir); } - public override Stream OpenEntry (ArcFile arc, Entry entry) + public override IImageDecoder OpenImage (ArcFile arc, Entry entry) { var info = new ImageMetaData { @@ -81,7 +82,25 @@ namespace GameRes.Formats.Patisserie BPP = 32, }; var pixels = arc.File.View.ReadBytes (entry.Offset+0x14, entry.Size-0x14); - return TgaStream.Create (info, pixels); + return new RawDecoder (info, pixels); + } + } + + internal sealed class RawDecoder : IImageDecoder + { + public Stream Source { get { return null; } } + public ImageFormat SourceFormat { get { return null; } } + public ImageMetaData Info { get; private set; } + public ImageData Image { get; private set; } + + public RawDecoder (ImageMetaData info, byte[] pixels) + { + Info = info; + Image = ImageData.Create (info, PixelFormats.Bgra32, null, pixels); + } + + public void Dispose () + { } } }