diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj
index 8a976045..3cc76428 100644
--- a/ArcFormats/ArcFormats.csproj
+++ b/ArcFormats/ArcFormats.csproj
@@ -127,6 +127,7 @@
+
diff --git a/ArcFormats/ImageISG.cs b/ArcFormats/ImageISG.cs
new file mode 100644
index 00000000..a58c27ca
--- /dev/null
+++ b/ArcFormats/ImageISG.cs
@@ -0,0 +1,217 @@
+//! \file ImageISG.cs
+//! \date Tue Mar 17 10:01:44 2015
+//! \brief ISM engine image format.
+//
+// Copyright (C) 2015 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.Collections.Generic;
+using System.ComponentModel.Composition;
+using System.IO;
+using System.Text;
+using System.Windows;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using GameRes.Utility;
+
+namespace GameRes.Formats.ISM
+{
+ internal class IsgMetaData : ImageMetaData
+ {
+ public byte Type;
+ public int Colors;
+ public uint Packed;
+ public uint Unpacked;
+ }
+
+ [Export(typeof(ImageFormat))]
+ public class IsgFormat : ImageFormat
+ {
+ public override string Tag { get { return "ISG"; } }
+ public override string Description { get { return "ISM engine image format"; } }
+ public override uint Signature { get { return 0x204d5349u; } } // 'ISM '
+
+ public override void Write (Stream file, ImageData image)
+ {
+ throw new NotImplementedException ("IsgFormat.Write not implemented");
+ }
+
+ public override ImageMetaData ReadMetaData (Stream stream)
+ {
+ var header = new byte[0x24];
+ if (header.Length != stream.Read (header, 0, header.Length))
+ return null;
+ if (!Binary.AsciiEqual (header, "ISM IMAGEFILE\x00"))
+ return null;
+ int colors = header[0x23];
+ if (0 == colors)
+ colors = 256;
+ return new IsgMetaData
+ {
+ Width = LittleEndian.ToUInt16 (header, 0x1d),
+ Height = LittleEndian.ToUInt16 (header, 0x1f),
+ BPP = 8,
+ Type = header[0x10],
+ Colors = colors,
+ Packed = LittleEndian.ToUInt32 (header, 0x11),
+ Unpacked = LittleEndian.ToUInt32 (header, 0x15),
+ };
+ }
+
+ public override ImageData Read (Stream stream, ImageMetaData info)
+ {
+ var meta = info as IsgMetaData;
+ if (null == meta)
+ throw new ArgumentException ("IsgFormat.Read should be supplied with IsgMetaData", "info");
+ if (0x21 != meta.Type && 0x10 != meta.Type)
+ throw new InvalidFormatException ("Unsupported ISM image type");
+
+ stream.Position = 0x30;
+ using (var input = new Reader (stream, meta))
+ {
+ if (0x21 == meta.Type)
+ input.Unpack21();
+ else
+ input.Unpack10();
+ byte[] pixels = input.Data;
+ var palette = new BitmapPalette (input.Palette);
+ var bitmap = BitmapSource.Create ((int)info.Width, (int)info.Height, 96, 96,
+ PixelFormats.Indexed8, palette, pixels, (int)info.Width);
+ var flipped = new TransformedBitmap (bitmap, new ScaleTransform { ScaleY = -1 });
+ flipped.Freeze();
+ return new ImageData (flipped, info);
+ }
+ }
+
+ internal class Reader : IDisposable
+ {
+ BinaryReader m_input;
+ byte[] m_data;
+ Color[] m_palette;
+ int m_input_size;
+
+ public Color[] Palette { get { return m_palette; } }
+ public byte[] Data { get { return m_data; } }
+
+ public Reader (Stream file, IsgMetaData info)
+ {
+ int palette_size = (int)info.Colors*4;
+ var palette_data = new byte[Math.Max (0x400, palette_size)];
+ if (palette_size != file.Read (palette_data, 0, palette_size))
+ throw new InvalidFormatException();
+ m_palette = new Color[0x100];
+ for (int i = 0; i < m_palette.Length; ++i)
+ {
+ m_palette[i] = Color.FromRgb (palette_data[i*4+2], palette_data[i*4+1], palette_data[i*4]);
+ }
+ m_input = new BinaryReader (file, Encoding.ASCII, true);
+ m_input_size = (int)info.Packed;
+ m_data = new byte[info.Width * info.Height];
+ }
+
+ public void Unpack21 ()
+ {
+ int dst = 0;
+ var frame = new byte[2048];
+ int frame_pos = 2039;
+ int remaining = m_input_size;
+ byte ctl = m_input.ReadByte();
+ --remaining;
+ int bit = 0x80;
+ while (remaining > 0)
+ {
+ if (0 != (ctl & bit))
+ {
+ byte hi = m_input.ReadByte();
+ byte lo = m_input.ReadByte();
+ remaining -= 2;
+ int offset = (hi & 7) << 8 | lo;
+ for (int count = (hi >> 3) + 3; count > 0; --count)
+ {
+ byte p = frame[offset];
+ frame[frame_pos] = p;
+ m_data[dst++] = p;
+ offset = (offset + 1) & 0x7ff;
+ frame_pos = (frame_pos + 1) & 0x7ff;
+ }
+ }
+ else
+ {
+ byte p = m_input.ReadByte();
+ --remaining;
+ m_data[dst++] = p;
+ frame[frame_pos] = p;
+ frame_pos = (frame_pos + 1) & 0x7ff;
+ }
+ if (0 == (bit >>= 1))
+ {
+ ctl = m_input.ReadByte();
+ --remaining;
+ bit = 0x80;
+ }
+ }
+ }
+
+ public void Unpack10 ()
+ {
+ int dst = 0;
+ int remaining = m_input_size;
+ byte ctl = m_input.ReadByte();
+ --remaining;
+ int bit = 1;
+ while (remaining > 0)
+ {
+ byte p = m_input.ReadByte();
+ --remaining;
+ if (0 != (ctl & bit))
+ {
+ for (int count = 2 + m_input.ReadByte(); count > 0; --count)
+ m_data[dst++] = p;
+ --remaining;
+ }
+ else
+ {
+ m_data[dst++] = p;
+ }
+ if (0x100 == (bit <<= 1))
+ {
+ ctl = m_input.ReadByte();
+ --remaining;
+ bit = 1;
+ }
+ }
+ }
+
+ #region IDisposable Members
+ public void Dispose ()
+ {
+ if (null != m_input)
+ {
+ m_input.Dispose();
+ m_input = null;
+ }
+ GC.SuppressFinalize (this);
+ }
+ #endregion
+ }
+ }
+}
diff --git a/ArcFormats/Properties/AssemblyInfo.cs b/ArcFormats/Properties/AssemblyInfo.cs
index fdb30862..7720a934 100644
--- a/ArcFormats/Properties/AssemblyInfo.cs
+++ b/ArcFormats/Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion ("1.0.4.31")]
-[assembly: AssemblyFileVersion ("1.0.4.31")]
+[assembly: AssemblyVersion ("1.0.4.32")]
+[assembly: AssemblyFileVersion ("1.0.4.32")]