diff --git a/ArcFormats/Favorite/ArcHZC.cs b/ArcFormats/Favorite/ArcHZC.cs index b30ec06f..3844c06a 100644 --- a/ArcFormats/Favorite/ArcHZC.cs +++ b/ArcFormats/Favorite/ArcHZC.cs @@ -69,6 +69,12 @@ namespace GameRes.Formats.FVP if (null == image_info) return null; } + // This is a atlas image, all clips are placed into a single TLG image + if (file.View.AsciiEqual (0x2C, "TLG")) + return null; + // This is a diff image + if (0x64 == file.View.ReadByte (0x2C)) + return null; int count = file.View.ReadInt32 (0x20); if (0 == count) count = 1; diff --git a/ArcFormats/Favorite/ImageHZC.cs b/ArcFormats/Favorite/ImageHZC.cs index 93f036e2..5f004aa4 100644 --- a/ArcFormats/Favorite/ImageHZC.cs +++ b/ArcFormats/Favorite/ImageHZC.cs @@ -28,6 +28,8 @@ using GameRes.Utility; using System; using System.ComponentModel.Composition; using System.IO; +using System.Text; +using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; @@ -66,14 +68,111 @@ namespace GameRes.Formats.FVP }; } + private static ImageFormat s_TlgFormat = null; + public override ImageData Read (IBinaryStream stream, ImageMetaData info) { + stream.Position = 0x2C; + PixelFormat format = PixelFormats.Bgra32; + WriteableBitmap bitmap = null; + if (0x64 == stream.PeekByte ()) + { + // This is a diff image, try to read base image + stream.Position += 1; + var name = stream.ReadCString (Encoding.UTF8); + if (!string.IsNullOrEmpty (name)) + { + var entry = VFS.FindFile (Path.ChangeExtension (name, "hzc")); + if (null != entry) + { + var decoder = VFS.OpenImage (entry); + var image = decoder.Image; + if (null == image) + throw new InvalidFormatException ("Failed to decode base image."); + var converted = image.Bitmap; + if (converted.Format != format) + converted = new FormatConvertedBitmap (converted, format, null, 0); + var stride = converted.PixelWidth * 4; + var size = stride * converted.PixelHeight; + var pixels = new byte[size]; + converted.CopyPixels (pixels, stride, 0); + bitmap = new WriteableBitmap (converted.PixelWidth, converted.PixelHeight, + ImageData.DefaultDpiX, ImageData.DefaultDpiY, format, null); + var rect = new Int32Rect (0, 0, converted.PixelWidth, converted.PixelHeight); + bitmap.WritePixels (rect, pixels, stride, 0); + } + } + } + if (stream.ReadBytes (3).AsciiEqual ("TLG")) + { + // Read the TLG image + var tlg_stream = new BinaryStream (new StreamRegion (stream.AsStream, stream.Position-3, true), stream.Name); + if (null == s_TlgFormat) + s_TlgFormat = FindByTag ("TLG"); + var tlg_info = s_TlgFormat.ReadMetaData (tlg_stream); + var image = s_TlgFormat.Read (tlg_stream, tlg_info); + // No base image + if (null == bitmap) + return image; + // Size should be the same as the base image + if (image.Width != bitmap.PixelWidth || image.Height != bitmap.PixelHeight) + return image; + // Blend two images + var converted = image.Bitmap; + if (converted.Format != format) + converted = new FormatConvertedBitmap (converted, format, null, 0); + var rect = new Int32Rect (0, 0, converted.PixelWidth, converted.PixelHeight); + BlendBitmap (converted, rect, bitmap, 0, 0); + bitmap.Freeze (); + return new ImageData (bitmap, tlg_info); + } var meta = (HzcMetaData)info; stream.Position = 12 + meta.HeaderSize; using (var decoder = new HzcDecoder (stream, meta, true)) return decoder.Image; } + void BlendBitmap (BitmapSource bitmap, Int32Rect source, WriteableBitmap output, int x, int y) + { + int src_stride = source.Width * 4; + var pixels = new byte[src_stride * source.Height]; + bitmap.CopyPixels (source, pixels, src_stride, 0); + unsafe + { + int dst_stride = output.BackBufferStride; + int offset = y * dst_stride + x * 4; + byte* buffer = (byte*)(output.BackBuffer + offset); + int src = 0; + for (int h = 0; h < source.Height; ++h) + { + int dst = 0; + for (int w = 0; w < source.Width; ++w) + { + byte src_alpha = pixels[src+3]; + if (src_alpha > 0) + { + if (0xFF == src_alpha || 0 == buffer[dst+3]) + { + buffer[dst ] = pixels[src]; + buffer[dst+1] = pixels[src+1]; + buffer[dst+2] = pixels[src+2]; + } + else + { + buffer[dst+0] = (byte)((pixels[src+0] * src_alpha + buffer[dst+0] * (0xFF - src_alpha)) / 0xFF); + buffer[dst+1] = (byte)((pixels[src+1] * src_alpha + buffer[dst+1] * (0xFF - src_alpha)) / 0xFF); + buffer[dst+2] = (byte)((pixels[src+2] * src_alpha + buffer[dst+2] * (0xFF - src_alpha)) / 0xFF); + } + buffer[dst+3] = src_alpha; + } + dst += 4; + src += 4; + } + buffer += dst_stride; + } + } + } + public override void Write (Stream file, ImageData image) { throw new System.NotImplementedException ("HzcFormat.Write not implemented");