more IImageDecoder implementations.

This commit is contained in:
morkt
2016-10-27 19:32:58 +04:00
parent c771b13d4e
commit 02e1ee11dd
3 changed files with 94 additions and 46 deletions

View File

@@ -27,6 +27,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.Composition; using System.ComponentModel.Composition;
using System.IO; using System.IO;
using System.Windows.Media;
using GameRes.Utility; using GameRes.Utility;
namespace GameRes.Formats.Lilim namespace GameRes.Formats.Lilim
@@ -92,7 +93,7 @@ namespace GameRes.Formats.Lilim
for (int i = 0; i < count; ++i) for (int i = 0; i < count; ++i)
{ {
var entry = new AbmEntry { var entry = new AbmEntry {
Name = string.Format ("{0}#{1:D4}.tga", base_name, i), Name = string.Format ("{0}#{1:D4}", base_name, i),
Type = "image", Type = "image",
Offset = next_offset, Offset = next_offset,
Index = i, Index = i,
@@ -123,12 +124,12 @@ namespace GameRes.Formats.Lilim
return new AbmArchive (file, this, dir, image_info); return new AbmArchive (file, this, dir, image_info);
} }
public override Stream OpenEntry (ArcFile arc, Entry entry) public override IImageDecoder OpenImage (ArcFile arc, Entry entry)
{ {
var abm = arc as AbmArchive; var abm = arc as AbmArchive;
var frame = entry as AbmEntry; var frame = entry as AbmEntry;
if (null == abm || null == frame) if (null == abm || null == frame)
return arc.File.CreateStream (entry.Offset, entry.Size); return base.OpenImage (arc, entry);
var frame_info = abm.FrameInfo; var frame_info = abm.FrameInfo;
if (frame.Index != 0) if (frame.Index != 0)
@@ -136,40 +137,45 @@ namespace GameRes.Formats.Lilim
frame_info = frame_info.Clone(); frame_info = frame_info.Clone();
frame_info.FrameOffset = (uint)frame.Offset; frame_info.FrameOffset = (uint)frame.Offset;
} }
using (var input = arc.File.CreateStream (0, (uint)arc.File.MaxOffset)) var input = arc.File.CreateStream (0, (uint)arc.File.MaxOffset);
using (var reader = new AbmReader (input, frame_info)) return new AbmReader (input, frame_info);
{
// emulate TGA image
var header = new byte[0x12];
header[2] = 2;
LittleEndian.Pack ((ushort)frame_info.Width, header, 0xC);
LittleEndian.Pack ((ushort)frame_info.Height, header, 0xE);
header[0x10] = (byte)reader.BPP;
header[0x11] = 0x20;
var pixels = reader.Unpack();
return new PrefixStream (header, new MemoryStream (pixels));
}
} }
} }
internal sealed class AbmReader : IDisposable internal sealed class AbmReader : IImageDecoder
{ {
IBinaryStream m_input; IBinaryStream m_input;
byte[] m_output; byte[] m_output;
AbmImageData m_info; AbmImageData m_info;
ImageData m_image;
int m_bpp; int m_bpp;
public byte[] Data { get { return m_output; } } public Stream Source { get { return m_input.AsStream; } }
public int BPP { get { return m_bpp; } } public ImageFormat SourceFormat { get { return null; } }
public ImageMetaData Info { get { return m_info; } }
public ImageData Image
{
get
{
if (null == m_image)
m_image = ReadImage();
return m_image;
}
}
public AbmReader (IBinaryStream file, AbmImageData info) public AbmReader (IBinaryStream file, AbmImageData info)
{ {
m_info = info; m_info = info;
m_input = file;
}
ImageData ReadImage ()
{
if (2 == m_info.Mode) if (2 == m_info.Mode)
{ {
m_bpp = 32; m_bpp = 32;
file.Position = m_info.BaseOffset; m_input.Position = m_info.BaseOffset;
m_output = UnpackV2 (file); m_output = UnpackV2 (m_input);
} }
else if (1 == m_info.Mode || 32 == m_info.Mode || 24 == m_info.Mode) else if (1 == m_info.Mode || 32 == m_info.Mode || 24 == m_info.Mode)
{ {
@@ -180,23 +186,23 @@ namespace GameRes.Formats.Lilim
int total_length = (int)(m_info.Width * m_info.Height * m_bpp / 8); int total_length = (int)(m_info.Width * m_info.Height * m_bpp / 8);
m_output = new byte[total_length]; m_output = new byte[total_length];
file.Position = m_info.BaseOffset; m_input.Position = m_info.BaseOffset;
if (1 == m_info.Mode) if (1 == m_info.Mode)
{ {
if (total_length != file.Read (m_output, 0, (total_length))) if (total_length != m_input.Read (m_output, 0, (total_length)))
throw new EndOfStreamException (); throw new EndOfStreamException ();
} }
else if (24 == m_bpp) else if (24 == m_bpp)
UnpackStream24 (file, m_output, total_length); UnpackStream24 (m_input, m_output, total_length);
else else
UnpackStream32 (file, m_output, total_length); UnpackStream32 (m_input, m_output, total_length);
} }
else else
throw new NotImplementedException(); throw new NotImplementedException();
if (0 != m_info.FrameOffset) if (0 != m_info.FrameOffset)
{ m_output = Unpack();
m_input = file; PixelFormat format = 24 == m_bpp ? PixelFormats.Bgr24 : PixelFormats.Bgra32;
} return ImageData.Create (m_info, format, null, m_output);
} }
int frame_x; int frame_x;
@@ -204,11 +210,8 @@ namespace GameRes.Formats.Lilim
int frame_w; int frame_w;
int frame_h; int frame_h;
public byte[] Unpack () byte[] Unpack ()
{ {
if (null == m_input)
return m_output;
m_input.Position = m_info.FrameOffset; m_input.Position = m_info.FrameOffset;
if (1 == m_info.Mode) if (1 == m_info.Mode)
return UnpackStream24 (m_input, m_output, m_output.Length); return UnpackStream24 (m_input, m_output, m_output.Length);
@@ -334,8 +337,14 @@ namespace GameRes.Formats.Lilim
} }
#region IDisposable Members #region IDisposable Members
bool m_disposed = false;
public void Dispose () public void Dispose ()
{ {
if (!m_disposed)
{
m_input.Dispose();
m_disposed = true;
}
GC.SuppressFinalize (this); GC.SuppressFinalize (this);
} }
#endregion #endregion

View File

@@ -76,11 +76,7 @@ namespace GameRes.Formats.Lilim
public override ImageData Read (IBinaryStream stream, ImageMetaData info) public override ImageData Read (IBinaryStream stream, ImageMetaData info)
{ {
using (var reader = new AbmReader (stream, (AbmImageData)info)) using (var reader = new AbmReader (stream, (AbmImageData)info))
{ return reader.Image;
var pixels = reader.Unpack();
PixelFormat format = 32 == reader.BPP ? PixelFormats.Bgra32 : PixelFormats.Bgr24;
return ImageData.Create (info, format, null, pixels);
}
} }
public override void Write (Stream file, ImageData image) public override void Write (Stream file, ImageData image)

View File

@@ -68,7 +68,7 @@ namespace GameRes.Formats.Will
BPP = 32, BPP = 32,
}; };
var entry = new PnaEntry { var entry = new PnaEntry {
Name = string.Format ("{0}#{1:D3}.tga", base_name, i), Name = string.Format ("{0}#{1:D3}", base_name, i),
Size = size, Size = size,
Offset = current_offset, Offset = current_offset,
Info = imginfo, Info = imginfo,
@@ -83,14 +83,47 @@ namespace GameRes.Formats.Will
return new ArcFile (file, this, dir); return new ArcFile (file, this, dir);
} }
public override Stream OpenEntry (ArcFile arc, Entry entry) public override IImageDecoder OpenImage (ArcFile arc, Entry entry)
{ {
var pent = entry as PnaEntry; var pent = (PnaEntry)entry;
if (null == pent) var input = arc.File.CreateStream (entry.Offset, entry.Size);
return base.OpenEntry (arc, entry); return new PnaDecoder (input, pent.Info);
ImageData image; }
using (var input = arc.File.CreateStream (entry.Offset, entry.Size)) }
image = ImageFormat.Read (input);
internal sealed class PnaDecoder : IImageDecoder
{
IBinaryStream m_input;
ImageMetaData m_info;
ImageData m_image;
public Stream Source { get { m_input.Position = 0; return m_input.AsStream; } }
public ImageFormat SourceFormat { get { return null; } }
public ImageMetaData Info { get { return m_info; } }
public ImageData Image
{
get
{
if (null == m_image)
{
var pixels = ReadPixels();
m_image = ImageData.Create (m_info, PixelFormats.Bgra32, null, pixels);
}
return m_image;
}
}
public PnaDecoder (IBinaryStream input, ImageMetaData info)
{
m_input = input;
m_info = info;
}
byte[] ReadPixels ()
{
var image = ImageFormat.Read (m_input);
if (null == image)
throw new InvalidFormatException();
var bitmap = image.Bitmap; var bitmap = image.Bitmap;
if (bitmap.Format.BitsPerPixel != 32) if (bitmap.Format.BitsPerPixel != 32)
{ {
@@ -111,7 +144,17 @@ namespace GameRes.Formats.Will
pixels[i+2] = (byte)(pixels[i+2] * 0xFF / alpha); pixels[i+2] = (byte)(pixels[i+2] * 0xFF / alpha);
} }
} }
return TgaStream.Create (pent.Info, pixels); return pixels;
}
bool m_disposed = false;
public void Dispose ()
{
if (!m_disposed)
{
m_input.Dispose();
m_disposed = true;
}
} }
} }
} }