From 4410f006f1882407fa15ff2bd47ac6a6f40601d6 Mon Sep 17 00:00:00 2001 From: morkt Date: Fri, 15 Apr 2016 12:20:02 +0400 Subject: [PATCH] (LimFormat): moved to separate file. --- ArcFormats/ArcFormats.csproj | 1 + ArcFormats/Liar/ImageLIM.cs | 344 +++++++++++++++++++++++++++++++++++ ArcFormats/Liar/ImageWCG.cs | 311 ------------------------------- 3 files changed, 345 insertions(+), 311 deletions(-) create mode 100644 ArcFormats/Liar/ImageLIM.cs diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj index fa13de32..2126c32b 100644 --- a/ArcFormats/ArcFormats.csproj +++ b/ArcFormats/ArcFormats.csproj @@ -86,6 +86,7 @@ + diff --git a/ArcFormats/Liar/ImageLIM.cs b/ArcFormats/Liar/ImageLIM.cs new file mode 100644 index 00000000..8b222876 --- /dev/null +++ b/ArcFormats/Liar/ImageLIM.cs @@ -0,0 +1,344 @@ +//! \file ImageLIM.cs +//! \date Fri Apr 15 12:16:20 2016 +//! \brief Liar-soft LIM image format implementation. +// +// Copyright (C) 2015-2016 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 GameRes.Utility; + +namespace GameRes.Formats.Liar +{ + [Export(typeof(ImageFormat))] + public class LimFormat : ImageFormat + { + public override string Tag { get { return "LIM"; } } + public override string Description { get { return "Liar-soft image format"; } } + public override uint Signature { get { return 0; } } + + public override ImageMetaData ReadMetaData (Stream stream) + { + if (0x4C != stream.ReadByte() || 0x4D != stream.ReadByte()) + return null; + int flag = stream.ReadByte() & 0xF; + if (flag != 2 && flag != 3) + return null; + stream.ReadByte(); + using (var file = new ArcView.Reader (stream)) + { + int bpp = 0x10 == file.ReadUInt16() ? 16 : 32; + var meta = new ImageMetaData { BPP = bpp }; + file.ReadUInt16(); + meta.Width = file.ReadUInt32(); + meta.Height = file.ReadUInt32(); + return meta; + } + } + + public override ImageData Read (Stream file, ImageMetaData info) + { + file.Position = 0x10; + using (var reader = new Reader (file, info)) + { + reader.Unpack(); + return ImageData.Create (info, reader.Format, null, reader.Data); + } + } + + public override void Write (Stream file, ImageData image) + { + throw new NotImplementedException ("LimFormat.Write not implemented"); + } + + internal class Reader : IDisposable + { + BinaryReader m_input; + byte[] m_output; + byte[] m_index; + byte[] m_image; + int m_width; + int m_height; + int m_bpp; + + public byte[] Data { get { return m_image; } } + public PixelFormat Format { get; private set; } + + public Reader (Stream file, ImageMetaData info) + { + m_input = new ArcView.Reader (file); + m_width = (int)info.Width; + m_height = (int)info.Height; + m_bpp = info.BPP; + if (32 == m_bpp) + Format = PixelFormats.Bgra32; + else if (16 == m_bpp) + Format = PixelFormats.Bgr565; + else + throw new InvalidFormatException(); + m_image = new byte[m_width*m_height*m_bpp/8]; + } + + int m_remaining; + int m_current; + int m_bits; + + public void Unpack () + { + if (32 == m_bpp) + Unpack32bpp(); + else + Unpack16bpp(); + } + + void Unpack32bpp () + { + byte mask = 0xFF; + for (int i = 3; i >= 0; --i) + { + UnpackChannel (3); + int src = 0; + for (int p = i; p < m_image.Length; p += 4) + { + m_image[p] = (byte)(m_output[src++] ^ mask); + } + mask = 0; + } + } + + void Unpack16bpp () + { + int image_size = m_input.ReadInt32(); + m_output = m_image; + + m_remaining = m_input.ReadInt32(); + int index_size = m_input.ReadUInt16() * 2; + if (null == m_index || index_size > m_index.Length) + m_index = new byte[index_size]; + m_input.ReadInt16(); // ignored + if (index_size != m_input.Read (m_index, 0, index_size)) + throw new InvalidFormatException ("Unexpected end of file"); + + int card; + if (index_size > 8192) + { + m_index_threshold = 14; + m_index_length_limit = 16; + card = 4; + } + else + { + m_index_threshold = 6; + m_index_length_limit = 12; + card = 3; + } + m_current = 0; + int dst = 0; + while (dst < m_output.Length) + { + int bits = GetBits (card); + if (-1 == bits) + break; + + if (0 != bits) + { + int index = GetIndex (bits); + if (index < 0) + break; + if (dst + 1 >= m_output.Length) + break; + + m_output[dst++] = m_index[index*2]; + m_output[dst++] = m_index[index*2+1]; + } + else + { + int count = GetBits (4); + if (-1 == count) + break; + + bits = GetBits (card); + if (-1 == bits) + break; + + int index = GetIndex (bits); + if (-1 == index) + break; + count += 2; + index *= 2; + for (int i = 0; i < count; i++) + { + if (dst + 1 >= m_output.Length) + return; + m_output[dst++] = m_index[index]; + m_output[dst++] = m_index[index+1]; + } + } + } + if (m_input.BaseStream.Position < m_input.BaseStream.Length) + { + m_output = null; + UnpackChannel (3); + var pixels = new byte[m_width*m_height*4]; + int alpha_src = 0; + dst = 0; + for (int i = 0; i < m_image.Length; i += 2) + { + int color = LittleEndian.ToUInt16 (m_image, i); + pixels[dst++] = (byte)((color & 0x001F) * 0xFF / 0x1F); + pixels[dst++] = (byte)((color & 0x07E0) * 0xFF / 0x7E0); + pixels[dst++] = (byte)((color & 0xF800) * 0xFF / 0xF800); + pixels[dst++] = (byte)~m_output[alpha_src++]; + } + m_image = pixels; + Format = PixelFormats.Bgra32; + } + } + + void UnpackChannel (int card) + { + m_index_threshold = 6; + m_index_length_limit = 12; + + int channel_size = m_input.ReadInt32(); + if (null == m_output || m_output.Length < channel_size) + m_output = new byte[channel_size]; + m_remaining = m_input.ReadInt32(); + + int index_size = m_input.ReadUInt16(); + if (null == m_index || index_size > m_index.Length) + m_index = new byte[index_size]; + m_input.ReadInt16(); // ignored + if (index_size != m_input.Read (m_index, 0, index_size)) + throw new InvalidFormatException ("Unexpected end of file"); + + m_current = 0; + int dst = 0; + while (dst < m_output.Length) + { + int bits = GetBits (card); + if (-1 == bits) + break; + + if (0 != bits) + { + int index = GetIndex (bits); + if (index < 0) + break; + if (dst + 1 >= m_output.Length) + break; + + m_output[dst++] = m_index[index]; + } + else + { + int count = GetBits (4); + if (-1 == count) + break; + + bits = GetBits (card); + if (-1 == bits) + break; + + int index = GetIndex (bits); + if (-1 == index) + break; + count += 2; + for (int i = 0; i < count; i++) + { + if (dst + 1 >= m_output.Length) + return; + m_output[dst++] = m_index[index]; + } + } + } + } + + private int GetBits (int n) + { + int v = 0; + while (n > 0) + { + if (0 == m_current) + { + if (0 == m_remaining) + return 0; + m_bits = m_input.ReadByte(); + --m_remaining; + m_current = 8; + } + v <<= 1; + m_bits <<= 1; + v |= (m_bits >> 8) & 1; + --m_current; + --n; + } + return v; + } + + int m_index_threshold; + int m_index_length_limit; + + private int GetIndex (int bits) + { + if (bits <= m_index_threshold) + { + if (0 == bits) + return -1; + if (1 == bits--) + return GetBits (1); + return (1 << bits) | GetBits (bits); + } + for (int i = m_index_threshold; i < m_index_length_limit; ++i) + { + bits = GetBits (1); + if (-1 == bits) + return -1; + if (0 == bits) + return (1 << i) | GetBits (i); + } + return -1; + } + + #region IDisposable Members + bool disposed = false; + + public void Dispose () + { + Dispose (true); + GC.SuppressFinalize (this); + } + + protected virtual void Dispose (bool disposing) + { + if (!disposed) + { + if (disposing) + m_input.Dispose(); + } + } + #endregion + } + } +} diff --git a/ArcFormats/Liar/ImageWCG.cs b/ArcFormats/Liar/ImageWCG.cs index 5114a646..27a40045 100644 --- a/ArcFormats/Liar/ImageWCG.cs +++ b/ArcFormats/Liar/ImageWCG.cs @@ -464,315 +464,4 @@ namespace GameRes.Formats.Liar #endregion } } - - [Export(typeof(ImageFormat))] - public class LimFormat : ImageFormat - { - public override string Tag { get { return "LIM"; } } - public override string Description { get { return "Liar-soft image format"; } } - public override uint Signature { get { return 0; } } - - public override ImageMetaData ReadMetaData (Stream stream) - { - if (0x4C != stream.ReadByte() || 0x4D != stream.ReadByte()) - return null; - int flag = stream.ReadByte() & 0xF; - if (flag != 2 && flag != 3) - return null; - stream.ReadByte(); - using (var file = new ArcView.Reader (stream)) - { - int bpp = 0x10 == file.ReadUInt16() ? 16 : 32; - var meta = new ImageMetaData { BPP = bpp }; - file.ReadUInt16(); - meta.Width = file.ReadUInt32(); - meta.Height = file.ReadUInt32(); - return meta; - } - } - - public override ImageData Read (Stream file, ImageMetaData info) - { - file.Position = 0x10; - using (var reader = new Reader (file, info)) - { - reader.Unpack(); - return ImageData.Create (info, reader.Format, null, reader.Data); - } - } - - public override void Write (Stream file, ImageData image) - { - throw new NotImplementedException ("LimFormat.Write not implemented"); - } - - internal class Reader : IDisposable - { - BinaryReader m_input; - byte[] m_output; - byte[] m_index; - byte[] m_image; - int m_width; - int m_height; - int m_bpp; - - public byte[] Data { get { return m_image; } } - public PixelFormat Format { get; private set; } - - public Reader (Stream file, ImageMetaData info) - { - m_input = new ArcView.Reader (file); - m_width = (int)info.Width; - m_height = (int)info.Height; - m_bpp = info.BPP; - if (32 == m_bpp) - Format = PixelFormats.Bgra32; - else if (16 == m_bpp) - Format = PixelFormats.Bgr565; - else - throw new InvalidFormatException(); - m_image = new byte[m_width*m_height*m_bpp/8]; - } - - int m_remaining; - int m_current; - int m_bits; - - public void Unpack () - { - if (32 == m_bpp) - Unpack32bpp(); - else - Unpack16bpp(); - } - - void Unpack32bpp () - { - byte mask = 0xFF; - for (int i = 3; i >= 0; --i) - { - UnpackChannel (3); - int src = 0; - for (int p = i; p < m_image.Length; p += 4) - { - m_image[p] = (byte)(m_output[src++] ^ mask); - } - mask = 0; - } - } - - void Unpack16bpp () - { - int image_size = m_input.ReadInt32(); - m_output = m_image; - - m_remaining = m_input.ReadInt32(); - int index_size = m_input.ReadUInt16() * 2; - if (null == m_index || index_size > m_index.Length) - m_index = new byte[index_size]; - m_input.ReadInt16(); // ignored - if (index_size != m_input.Read (m_index, 0, index_size)) - throw new InvalidFormatException ("Unexpected end of file"); - - int card; - if (index_size > 8192) - { - m_index_threshold = 14; - m_index_length_limit = 16; - card = 4; - } - else - { - m_index_threshold = 6; - m_index_length_limit = 12; - card = 3; - } - m_current = 0; - int dst = 0; - while (dst < m_output.Length) - { - int bits = GetBits (card); - if (-1 == bits) - break; - - if (0 != bits) - { - int index = GetIndex (bits); - if (index < 0) - break; - if (dst + 1 >= m_output.Length) - break; - - m_output[dst++] = m_index[index*2]; - m_output[dst++] = m_index[index*2+1]; - } - else - { - int count = GetBits (4); - if (-1 == count) - break; - - bits = GetBits (card); - if (-1 == bits) - break; - - int index = GetIndex (bits); - if (-1 == index) - break; - count += 2; - index *= 2; - for (int i = 0; i < count; i++) - { - if (dst + 1 >= m_output.Length) - return; - m_output[dst++] = m_index[index]; - m_output[dst++] = m_index[index+1]; - } - } - } - if (m_input.BaseStream.Position < m_input.BaseStream.Length) - { - m_output = null; - UnpackChannel (3); - var pixels = new byte[m_width*m_height*4]; - int alpha_src = 0; - dst = 0; - for (int i = 0; i < m_image.Length; i += 2) - { - int color = LittleEndian.ToUInt16 (m_image, i); - pixels[dst++] = (byte)((color & 0x001F) * 0xFF / 0x1F); - pixels[dst++] = (byte)((color & 0x07E0) * 0xFF / 0x7E0); - pixels[dst++] = (byte)((color & 0xF800) * 0xFF / 0xF800); - pixels[dst++] = (byte)~m_output[alpha_src++]; - } - m_image = pixels; - Format = PixelFormats.Bgra32; - } - } - - void UnpackChannel (int card) - { - m_index_threshold = 6; - m_index_length_limit = 12; - - int channel_size = m_input.ReadInt32(); - if (null == m_output || m_output.Length < channel_size) - m_output = new byte[channel_size]; - m_remaining = m_input.ReadInt32(); - - int index_size = m_input.ReadUInt16(); - if (null == m_index || index_size > m_index.Length) - m_index = new byte[index_size]; - m_input.ReadInt16(); // ignored - if (index_size != m_input.Read (m_index, 0, index_size)) - throw new InvalidFormatException ("Unexpected end of file"); - - m_current = 0; - int dst = 0; - while (dst < m_output.Length) - { - int bits = GetBits (card); - if (-1 == bits) - break; - - if (0 != bits) - { - int index = GetIndex (bits); - if (index < 0) - break; - if (dst + 1 >= m_output.Length) - break; - - m_output[dst++] = m_index[index]; - } - else - { - int count = GetBits (4); - if (-1 == count) - break; - - bits = GetBits (card); - if (-1 == bits) - break; - - int index = GetIndex (bits); - if (-1 == index) - break; - count += 2; - for (int i = 0; i < count; i++) - { - if (dst + 1 >= m_output.Length) - return; - m_output[dst++] = m_index[index]; - } - } - } - } - - private int GetBits (int n) - { - int v = 0; - while (n > 0) - { - if (0 == m_current) - { - if (0 == m_remaining) - return 0; - m_bits = m_input.ReadByte(); - --m_remaining; - m_current = 8; - } - v <<= 1; - m_bits <<= 1; - v |= (m_bits >> 8) & 1; - --m_current; - --n; - } - return v; - } - - int m_index_threshold; - int m_index_length_limit; - - private int GetIndex (int bits) - { - if (bits <= m_index_threshold) - { - if (0 == bits) - return -1; - if (1 == bits--) - return GetBits (1); - return (1 << bits) | GetBits (bits); - } - for (int i = m_index_threshold; i < m_index_length_limit; ++i) - { - bits = GetBits (1); - if (-1 == bits) - return -1; - if (0 == bits) - return (1 << i) | GetBits (i); - } - return -1; - } - - #region IDisposable Members - bool disposed = false; - - public void Dispose () - { - Dispose (true); - GC.SuppressFinalize (this); - } - - protected virtual void Dispose (bool disposing) - { - if (!disposed) - { - if (disposing) - m_input.Dispose(); - } - } - #endregion - } - } }