mirror of
https://github.com/crskycode/GARbro.git
synced 2025-01-12 04:49:32 +08:00
(CmFormat): implemented 8bpp images with alpha-channel.
This commit is contained in:
parent
a73471c0b5
commit
f11dae97ab
@ -2,7 +2,7 @@
|
|||||||
//! \date Sun May 03 10:26:35 2015
|
//! \date Sun May 03 10:26:35 2015
|
||||||
//! \brief MAI image formats implementation.
|
//! \brief MAI image formats implementation.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2015 by morkt
|
// Copyright (C) 2015-2016 by morkt
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to
|
// of this software and associated documentation files (the "Software"), to
|
||||||
@ -33,7 +33,7 @@ using GameRes.Utility;
|
|||||||
|
|
||||||
namespace GameRes.Formats.MAI
|
namespace GameRes.Formats.MAI
|
||||||
{
|
{
|
||||||
internal class CmpMetaData : ImageMetaData
|
internal class CmMetaData : ImageMetaData
|
||||||
{
|
{
|
||||||
public int Colors;
|
public int Colors;
|
||||||
public bool IsCompressed;
|
public bool IsCompressed;
|
||||||
@ -42,20 +42,20 @@ namespace GameRes.Formats.MAI
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Export(typeof(ImageFormat))]
|
[Export(typeof(ImageFormat))]
|
||||||
public class CmpFormat : ImageFormat
|
public class CmFormat : ImageFormat
|
||||||
{
|
{
|
||||||
public override string Tag { get { return "CMP/MAI"; } }
|
public override string Tag { get { return "CM/MAI"; } }
|
||||||
public override string Description { get { return "MAI image format"; } }
|
public override string Description { get { return "MAI image format"; } }
|
||||||
public override uint Signature { get { return 0; } }
|
public override uint Signature { get { return 0; } }
|
||||||
|
|
||||||
public CmpFormat ()
|
public CmFormat ()
|
||||||
{
|
{
|
||||||
Extensions = new string[] { "cmp" };
|
Extensions = new string[] { "cm" };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Write (Stream file, ImageData image)
|
public override void Write (Stream file, ImageData image)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException ("CmpFormat.Write not implemented");
|
throw new NotImplementedException ("CmFormat.Write not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ImageMetaData ReadMetaData (Stream stream)
|
public override ImageMetaData ReadMetaData (Stream stream)
|
||||||
@ -70,7 +70,7 @@ namespace GameRes.Formats.MAI
|
|||||||
uint size = LittleEndian.ToUInt32 (header, 0);
|
uint size = LittleEndian.ToUInt32 (header, 0);
|
||||||
if (size != stream.Length)
|
if (size != stream.Length)
|
||||||
return null;
|
return null;
|
||||||
var info = new CmpMetaData();
|
var info = new CmMetaData();
|
||||||
info.Width = LittleEndian.ToUInt16 (header, 4);
|
info.Width = LittleEndian.ToUInt16 (header, 4);
|
||||||
info.Height = LittleEndian.ToUInt16 (header, 6);
|
info.Height = LittleEndian.ToUInt16 (header, 6);
|
||||||
info.Colors = LittleEndian.ToUInt16 (header, 8);
|
info.Colors = LittleEndian.ToUInt16 (header, 8);
|
||||||
@ -85,11 +85,7 @@ namespace GameRes.Formats.MAI
|
|||||||
|
|
||||||
public override ImageData Read (Stream stream, ImageMetaData info)
|
public override ImageData Read (Stream stream, ImageMetaData info)
|
||||||
{
|
{
|
||||||
var meta = info as CmpMetaData;
|
var reader = new Reader (stream, (CmMetaData)info);
|
||||||
if (null == meta)
|
|
||||||
throw new ArgumentException ("CmpFormat.Read should be supplied with CmpMetaData", "info");
|
|
||||||
|
|
||||||
var reader = new Reader (stream, meta);
|
|
||||||
reader.Unpack();
|
reader.Unpack();
|
||||||
return ImageData.CreateFlipped (info, reader.Format, reader.Palette, reader.Data, reader.Stride);
|
return ImageData.CreateFlipped (info, reader.Format, reader.Palette, reader.Data, reader.Stride);
|
||||||
}
|
}
|
||||||
@ -109,7 +105,7 @@ namespace GameRes.Formats.MAI
|
|||||||
public byte[] Data { get { return m_pixels; } }
|
public byte[] Data { get { return m_pixels; } }
|
||||||
public int Stride { get { return m_width * m_pixel_size; } }
|
public int Stride { get { return m_width * m_pixel_size; } }
|
||||||
|
|
||||||
public Reader (Stream stream, CmpMetaData info)
|
public Reader (Stream stream, CmMetaData info)
|
||||||
{
|
{
|
||||||
m_input = stream;
|
m_input = stream;
|
||||||
m_width = (int)info.Width;
|
m_width = (int)info.Width;
|
||||||
@ -124,9 +120,12 @@ namespace GameRes.Formats.MAI
|
|||||||
case 4: Format = PixelFormats.Bgr32; break;
|
case 4: Format = PixelFormats.Bgr32; break;
|
||||||
default: throw new InvalidFormatException ("Invalid color depth");
|
default: throw new InvalidFormatException ("Invalid color depth");
|
||||||
}
|
}
|
||||||
m_input.Position = info.DataOffset;
|
|
||||||
if (info.Colors > 0)
|
if (info.Colors > 0)
|
||||||
|
{
|
||||||
|
m_input.Position = 0x20;
|
||||||
Palette = RleDecoder.ReadPalette (m_input, info.Colors, 3);
|
Palette = RleDecoder.ReadPalette (m_input, info.Colors, 3);
|
||||||
|
}
|
||||||
|
m_input.Position = info.DataOffset;
|
||||||
int size = info.IsCompressed ? m_width*m_height*m_pixel_size : (int)info.DataLength;
|
int size = info.IsCompressed ? m_width*m_height*m_pixel_size : (int)info.DataLength;
|
||||||
m_pixels = new byte[size];
|
m_pixels = new byte[size];
|
||||||
}
|
}
|
||||||
@ -141,7 +140,7 @@ namespace GameRes.Formats.MAI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class AmiMetaData : CmpMetaData
|
internal class AmiMetaData : CmMetaData
|
||||||
{
|
{
|
||||||
public uint MaskWidth;
|
public uint MaskWidth;
|
||||||
public uint MaskHeight;
|
public uint MaskHeight;
|
||||||
@ -200,11 +199,7 @@ namespace GameRes.Formats.MAI
|
|||||||
|
|
||||||
public override ImageData Read (Stream stream, ImageMetaData info)
|
public override ImageData Read (Stream stream, ImageMetaData info)
|
||||||
{
|
{
|
||||||
var meta = info as AmiMetaData;
|
var reader = new Reader (stream, (AmiMetaData)info);
|
||||||
if (null == meta)
|
|
||||||
throw new ArgumentException ("AmiFormat.Read should be supplied with AmiMetaData", "info");
|
|
||||||
|
|
||||||
var reader = new Reader (stream, meta);
|
|
||||||
reader.Unpack();
|
reader.Unpack();
|
||||||
return ImageData.Create (info, reader.Format, reader.Palette, reader.Data);
|
return ImageData.Create (info, reader.Format, reader.Palette, reader.Data);
|
||||||
}
|
}
|
||||||
@ -231,7 +226,7 @@ namespace GameRes.Formats.MAI
|
|||||||
m_width = (int)info.Width;
|
m_width = (int)info.Width;
|
||||||
m_height = (int)info.Height;
|
m_height = (int)info.Height;
|
||||||
m_pixel_size = info.BPP/8;
|
m_pixel_size = info.BPP/8;
|
||||||
if (m_pixel_size != 3 && m_pixel_size != 4)
|
if (m_pixel_size != 3 && m_pixel_size != 4 && m_pixel_size != 1)
|
||||||
throw new InvalidFormatException ("Invalid color depth");
|
throw new InvalidFormatException ("Invalid color depth");
|
||||||
Format = PixelFormats.Bgra32;
|
Format = PixelFormats.Bgra32;
|
||||||
int size = info.IsCompressed ? m_width*m_height*m_pixel_size : (int)info.DataLength;
|
int size = info.IsCompressed ? m_width*m_height*m_pixel_size : (int)info.DataLength;
|
||||||
@ -256,17 +251,32 @@ namespace GameRes.Formats.MAI
|
|||||||
else
|
else
|
||||||
m_input.Read (m_alpha, 0, m_alpha.Length);
|
m_input.Read (m_alpha, 0, m_alpha.Length);
|
||||||
|
|
||||||
int stride = m_width * m_pixel_size;
|
Action<int, int, byte> copy_pixel;
|
||||||
|
if (m_pixel_size > 1)
|
||||||
|
copy_pixel = (src, dst, alpha) => {
|
||||||
|
m_pixels[dst] = m_output[src];
|
||||||
|
m_pixels[dst+1] = m_output[src+1];
|
||||||
|
m_pixels[dst+2] = m_output[src+2];
|
||||||
|
m_pixels[dst+3] = alpha;
|
||||||
|
};
|
||||||
|
else
|
||||||
|
copy_pixel = (src, dst, alpha) => {
|
||||||
|
var color = Palette.Colors[m_output[src]];
|
||||||
|
m_pixels[dst] = color.B;
|
||||||
|
m_pixels[dst+1] = color.G;
|
||||||
|
m_pixels[dst+2] = color.R;
|
||||||
|
m_pixels[dst+3] = alpha;
|
||||||
|
};
|
||||||
|
int src_stride = m_width * m_pixel_size;
|
||||||
for (int y = 0; y < m_height; ++y)
|
for (int y = 0; y < m_height; ++y)
|
||||||
{
|
{
|
||||||
int dst_line = y*m_width;
|
int dst_line = y*m_width*4;
|
||||||
int src_line = (m_height-1-y)*m_width;
|
int src_line = (m_height-1-y)*src_stride;;
|
||||||
for (int x = 0; x < m_width; ++x)
|
for (int x = 0; x < m_width; ++x)
|
||||||
{
|
{
|
||||||
m_pixels[(dst_line+x)*4] = m_output[(src_line+x)*m_pixel_size];
|
copy_pixel (src_line, dst_line, m_alpha[y*m_width+x]);
|
||||||
m_pixels[(dst_line+x)*4+1] = m_output[(src_line+x)*m_pixel_size+1];
|
src_line += m_pixel_size;
|
||||||
m_pixels[(dst_line+x)*4+2] = m_output[(src_line+x)*m_pixel_size+2];
|
dst_line += 4;
|
||||||
m_pixels[(dst_line+x)*4+3] = m_alpha[dst_line+x];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -287,7 +297,7 @@ namespace GameRes.Formats.MAI
|
|||||||
|
|
||||||
public override void Write (Stream file, ImageData image)
|
public override void Write (Stream file, ImageData image)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException ("AmiFormat.Write not implemented");
|
throw new NotImplementedException ("MaskFormat.Write not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ImageMetaData ReadMetaData (Stream stream)
|
public override ImageMetaData ReadMetaData (Stream stream)
|
||||||
@ -299,23 +309,33 @@ namespace GameRes.Formats.MAI
|
|||||||
return null;
|
return null;
|
||||||
uint width = input.ReadUInt32();
|
uint width = input.ReadUInt32();
|
||||||
uint height = input.ReadUInt32();
|
uint height = input.ReadUInt32();
|
||||||
if ((width*height + 0x410) != size)
|
int compressed = input.ReadInt32();
|
||||||
|
if (compressed > 1 || 0 == compressed && (width*height + 0x410) != size)
|
||||||
return null;
|
return null;
|
||||||
return new ImageMetaData {
|
return new CmMetaData {
|
||||||
Width = width,
|
Width = width,
|
||||||
Height = height,
|
Height = height,
|
||||||
BPP = 8
|
BPP = 8,
|
||||||
|
IsCompressed = 1 == compressed,
|
||||||
|
DataOffset = 0x10,
|
||||||
|
DataLength = size,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ImageData Read (Stream stream, ImageMetaData info)
|
public override ImageData Read (Stream stream, ImageMetaData info)
|
||||||
{
|
{
|
||||||
stream.Position = 0x10;
|
var meta = (CmMetaData)info;
|
||||||
|
stream.Position = meta.DataOffset;
|
||||||
var palette = RleDecoder.ReadPalette (stream, 0x100, 4);
|
var palette = RleDecoder.ReadPalette (stream, 0x100, 4);
|
||||||
|
|
||||||
byte[] pixels = new byte[info.Width*info.Height];
|
var pixels = new byte[info.Width*info.Height];
|
||||||
if (pixels.Length != stream.Read (pixels, 0, pixels.Length))
|
if (meta.IsCompressed)
|
||||||
|
{
|
||||||
|
int packed_size = (int)(stream.Length - meta.DataOffset);
|
||||||
|
RleDecoder.Unpack (stream, packed_size, pixels, 1);
|
||||||
|
}
|
||||||
|
else if (pixels.Length != stream.Read (pixels, 0, pixels.Length))
|
||||||
throw new InvalidFormatException();
|
throw new InvalidFormatException();
|
||||||
|
|
||||||
return ImageData.Create (info, PixelFormats.Indexed8, palette, pixels);
|
return ImageData.Create (info, PixelFormats.Indexed8, palette, pixels);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user