diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj index 7b2e35f8..71d852f7 100644 --- a/ArcFormats/ArcFormats.csproj +++ b/ArcFormats/ArcFormats.csproj @@ -98,6 +98,7 @@ + diff --git a/ArcFormats/Majiro/ImageRC8.cs b/ArcFormats/Majiro/ImageRC8.cs new file mode 100644 index 00000000..40124508 --- /dev/null +++ b/ArcFormats/Majiro/ImageRC8.cs @@ -0,0 +1,162 @@ +//! \file ImageRC8.cs +//! \date Thu Jan 05 00:53:42 2017 +//! \brief RC8 image format implementation. +// +// Copyright (C) 2014-2017 by morkt +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// + +using System; +using System.ComponentModel.Composition; +using System.IO; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using GameRes.Utility; + +namespace GameRes.Formats.Majiro +{ + [Export(typeof(ImageFormat))] + public class Rc8Format : ImageFormat + { + public override string Tag { get { return "RC8"; } } + public override string Description { get { return "Majiro game engine indexed image format"; } } + public override uint Signature { get { return 0x9A925A98; } } + + public override ImageMetaData ReadMetaData (IBinaryStream stream) + { + var header = stream.ReadHeader (8); + if (!header.AsciiEqual (4, "8_00")) + return null; + uint width = stream.ReadUInt32(); + uint height = stream.ReadUInt32(); + if (width > 0x8000 || height > 0x8000) + return null; + return new ImageMetaData + { + Width = width, + Height = height, + OffsetX = 0, + OffsetY = 0, + BPP = 8, + }; + } + + public override ImageData Read (IBinaryStream file, ImageMetaData info) + { + using (var reader = new Reader (file, info)) + { + reader.Unpack(); + var palette = new BitmapPalette (reader.Palette); + return ImageData.Create (info, PixelFormats.Indexed8, palette, reader.Data, (int)info.Width); + } + } + + public override void Write (Stream file, ImageData image) + { + throw new NotImplementedException ("Rc8Format.Write is not implemented."); + } + + internal sealed class Reader : IDisposable + { + private IBinaryStream m_input; + private uint m_width; + private Color[] m_palette; + private byte[] m_data; + + public Color[] Palette { get { return m_palette; } } + public byte[] Data { get { return m_data; } } + + public Reader (IBinaryStream file, ImageMetaData info) + { + m_width = info.Width; + file.Position = 0x14; + var palette_data = new byte[0x300]; + if (palette_data.Length != file.Read (palette_data, 0, palette_data.Length)) + throw new InvalidFormatException(); + m_palette = new Color[0x100]; + for (int i = 0; i < 0x100; ++i) + { + m_palette[i] = Color.FromRgb (palette_data[i*3], palette_data[i*3+1], palette_data[i*3+2]); + } + m_data = new byte[m_width * info.Height]; + m_input = file; + } + + private static readonly sbyte[] ShiftTable = new sbyte[] { + -16, -32, -48, -64, + 49, 33, 17, 1, -15, -31, -47, + 34, 18, 2, -14, -30, + }; + + public void Unpack () + { + int data_pos = 0; + int eax = 0; + int pixels_remaining = m_data.Length; + while (pixels_remaining > 0) + { + int count = eax + 1; + if (count > pixels_remaining) + throw new InvalidFormatException(); + pixels_remaining -= count; + + if (count != m_input.Read (m_data, data_pos, count)) + throw new InvalidFormatException(); + data_pos += count; + + while (pixels_remaining > 0) + { + eax = m_input.ReadByte(); + if (0 == (eax & 0x80)) + { + if (0x7f == eax) + eax += m_input.ReadUInt16(); + break; + } + int shift_index = eax >> 3; + eax &= 7; + if (7 == eax) + eax += m_input.ReadUInt16(); + + count = eax + 3; + if (pixels_remaining < count) + throw new InvalidFormatException(); + pixels_remaining -= count; + int shift = ShiftTable[shift_index & 0x0f]; + int shift_row = shift & 0x0f; + shift >>= 4; + shift_row *= (int)m_width; + shift -= shift_row; + if (shift >= 0 || data_pos+shift < 0) + throw new InvalidFormatException(); + Binary.CopyOverlapped (m_data, data_pos+shift, data_pos, count); + data_pos += count; + } + } + } + + #region IDisposable Members + public void Dispose () + { + } + #endregion + } + } +} diff --git a/ArcFormats/Majiro/ImageRCT.cs b/ArcFormats/Majiro/ImageRCT.cs index c85583b2..dcb0d146 100644 --- a/ArcFormats/Majiro/ImageRCT.cs +++ b/ArcFormats/Majiro/ImageRCT.cs @@ -1,8 +1,8 @@ //! \file ImageRCT.cs //! \date Fri Aug 01 11:36:31 2014 -//! \brief RCT/RC8 image format implementation. +//! \brief RCT image format implementation. // -// Copyright (C) 2014-2016 by morkt +// Copyright (C) 2014-2017 by morkt // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to @@ -150,16 +150,18 @@ namespace GameRes.Formats.Majiro return ImageData.Create (meta, PixelFormats.Bgr24, null, pixels, (int)meta.Width*3); } + static readonly Lazy s_rc8_format = new Lazy (() => FindByTag ("RC8")); + ImageData ApplyMaskToImage (RctMetaData info, byte[] image, string mask_name) { using (var mask_file = VFS.OpenBinaryStream (mask_name)) { - var format = FindFormat (mask_file); - if (null == format || !(format.Item1 is Rc8Format) - || info.Width != format.Item2.Width || info.Height != format.Item2.Height) + var mask_info = s_rc8_format.Value.ReadMetaData (mask_file); + if (null == mask_info + || info.Width != mask_info.Width || info.Height != mask_info.Height) throw new InvalidFormatException(); - using (var reader = new Rc8Format.Reader (mask_file, format.Item2)) + using (var reader = new Rc8Format.Reader (mask_file, mask_info)) { reader.Unpack(); var palette = reader.Palette; @@ -592,143 +594,4 @@ namespace GameRes.Formats.Majiro #endregion } } - - [Export(typeof(ImageFormat))] - public class Rc8Format : ImageFormat - { - public override string Tag { get { return "RC8"; } } - public override string Description { get { return "Majiro game engine indexed image format"; } } - public override uint Signature { get { return 0x9a925a98; } } - - public override ImageMetaData ReadMetaData (IBinaryStream stream) - { - stream.Position = 4; - int id = stream.ReadByte(); - if (0x38 != id) - return null; - id = stream.ReadByte(); - if (0x5f != id) - return null; - int version = stream.ReadByte(); - if (0x30 != version) - return null; - version = stream.ReadByte() - 0x30; - if (version != 0) - return null; - - uint width = stream.ReadUInt32(); - uint height = stream.ReadUInt32(); - if (width > 0x8000 || height > 0x8000) - return null; - return new ImageMetaData - { - Width = width, - Height = height, - OffsetX = 0, - OffsetY = 0, - BPP = 8, - }; - } - - public override ImageData Read (IBinaryStream file, ImageMetaData info) - { - using (var reader = new Reader (file, info)) - { - reader.Unpack(); - var palette = new BitmapPalette (reader.Palette); - return ImageData.Create (info, PixelFormats.Indexed8, palette, reader.Data, (int)info.Width); - } - } - - public override void Write (Stream file, ImageData image) - { - throw new NotImplementedException ("Rc8Format.Write is not implemented."); - } - - internal sealed class Reader : IDisposable - { - private IBinaryStream m_input; - private uint m_width; - private Color[] m_palette; - private byte[] m_data; - - public Color[] Palette { get { return m_palette; } } - public byte[] Data { get { return m_data; } } - - public Reader (IBinaryStream file, ImageMetaData info) - { - m_width = info.Width; - file.Position = 0x14; - var palette_data = new byte[0x300]; - if (palette_data.Length != file.Read (palette_data, 0, palette_data.Length)) - throw new InvalidFormatException(); - m_palette = new Color[0x100]; - for (int i = 0; i < 0x100; ++i) - { - m_palette[i] = Color.FromRgb (palette_data[i*3], palette_data[i*3+1], palette_data[i*3+2]); - } - m_data = new byte[m_width * info.Height]; - m_input = file; - } - - private static readonly sbyte[] ShiftTable = new sbyte[] { - -16, -32, -48, -64, - 49, 33, 17, 1, -15, -31, -47, - 34, 18, 2, -14, -30, - }; - - public void Unpack () - { - int data_pos = 0; - int eax = 0; - int pixels_remaining = m_data.Length; - while (pixels_remaining > 0) - { - int count = eax + 1; - if (count > pixels_remaining) - throw new InvalidFormatException(); - pixels_remaining -= count; - - if (count != m_input.Read (m_data, data_pos, count)) - throw new InvalidFormatException(); - data_pos += count; - - while (pixels_remaining > 0) - { - eax = m_input.ReadByte(); - if (0 == (eax & 0x80)) - { - if (0x7f == eax) - eax += m_input.ReadUInt16(); - break; - } - int shift_index = eax >> 3; - eax &= 7; - if (7 == eax) - eax += m_input.ReadUInt16(); - - count = eax + 3; - if (pixels_remaining < count) - throw new InvalidFormatException(); - pixels_remaining -= count; - int shift = ShiftTable[shift_index & 0x0f]; - int shift_row = shift & 0x0f; - shift >>= 4; - shift_row *= (int)m_width; - shift -= shift_row; - if (shift >= 0 || data_pos+shift < 0) - throw new InvalidFormatException(); - Binary.CopyOverlapped (m_data, data_pos+shift, data_pos, count); - data_pos += count; - } - } - } - - #region IDisposable Members - public void Dispose () - { - } - #endregion - } - } }