mirror of
https://github.com/crskycode/GARbro.git
synced 2024-12-24 20:04:13 +08:00
(Legacy): implemented encrypted GRD images.
This commit is contained in:
parent
c4cb8e2489
commit
030a65ac35
@ -125,7 +125,8 @@
|
||||
<Compile Include="Rune\ArcYK.cs" />
|
||||
<Compile Include="Sarang\ImageABC.cs" />
|
||||
<Compile Include="Sogna\ArcSGS.cs" />
|
||||
<None Include="Speed\ImageDAT.cs" />
|
||||
<Compile Include="StudioJikkenshitsu\ImageDAT.cs" />
|
||||
<Compile Include="StudioJikkenshitsu\ImageGRD.cs" />
|
||||
<Compile Include="Tako\ArcMPK.cs" />
|
||||
<Compile Include="Tetratech\ArcBND.cs" />
|
||||
<Compile Include="Tigerman\ArcCHR.cs" />
|
||||
@ -216,7 +217,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Bom\" />
|
||||
<Folder Include="StudioJikkenshitsu\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
|
@ -23,9 +23,13 @@
|
||||
// IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using GameRes.Compression;
|
||||
using GameRes.Utility;
|
||||
|
||||
// [030411][Studio Jikkenshitsu] Giin Oyako
|
||||
|
||||
@ -36,6 +40,7 @@ namespace GameRes.Formats.Jikkenshitsu
|
||||
public int PackedLength;
|
||||
public int AlphaLength;
|
||||
public bool IsEncrypted;
|
||||
public byte[] Key;
|
||||
}
|
||||
|
||||
[Export(typeof(ImageFormat))]
|
||||
@ -45,6 +50,9 @@ namespace GameRes.Formats.Jikkenshitsu
|
||||
public override string Description { get { return "Studio Jikkenshitsu image format"; } }
|
||||
public override uint Signature { get { return 0x20445247; } } // 'GRD '
|
||||
|
||||
// Giin Oyako
|
||||
static readonly byte[] DefaultKey = { 0xF, 0, 1, 2, 8, 5, 0xA, 0xB, 5, 9, 0xE, 0xD, 1, 8, 0, 6 };
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
var header = file.ReadHeader (0x18);
|
||||
@ -53,16 +61,16 @@ namespace GameRes.Formats.Jikkenshitsu
|
||||
Height = header.ToUInt16 (8),
|
||||
BPP = header[4],
|
||||
PackedLength = header.ToInt32 (0xC),
|
||||
AlphaLength = header.ToInt32 (0x10),
|
||||
AlphaLength = header.ToInt32 (0x14),
|
||||
IsEncrypted = (header[5] & 0x80) != 0,
|
||||
Key = DefaultKey,
|
||||
};
|
||||
}
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
var reader = new GrdReader (file, (GrdMetaData)info);
|
||||
var pixels = reader.Unpack();
|
||||
return ImageData.Create (info, reader.Format, null, pixels);
|
||||
return reader.Unpack();
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
@ -77,54 +85,102 @@ namespace GameRes.Formats.Jikkenshitsu
|
||||
GrdMetaData m_info;
|
||||
byte[] m_output;
|
||||
|
||||
public BitmapPalette Palette { get; private set; }
|
||||
public PixelFormat Format { get; private set; }
|
||||
public int Stride { get; private set; }
|
||||
|
||||
public GrdReader (IBinaryStream input, GrdMetaData info)
|
||||
{
|
||||
m_input = input;
|
||||
m_info = info;
|
||||
if (8 == m_info.BPP)
|
||||
Format = PixelFormats.Gray8;
|
||||
Format = PixelFormats.Indexed8;
|
||||
else if (24 == m_info.BPP)
|
||||
Format = PixelFormats.Bgr24;
|
||||
else
|
||||
throw new InvalidFormatException();
|
||||
int image_size = (int)m_info.Width * (int)m_info.Height;
|
||||
if (m_info.BPP >= 8)
|
||||
image_size *= (m_info.BPP + 1) / 8;
|
||||
else
|
||||
image_size = image_size * m_info.BPP / 8;
|
||||
m_output = new byte[image_size];
|
||||
int width = (int)m_info.Width;
|
||||
if (m_info.BPP <= 8)
|
||||
width = (width + 3) & ~3;
|
||||
Stride = width * m_info.BPP / 8;
|
||||
m_output = new byte[Stride * (int)m_info.Height];
|
||||
}
|
||||
|
||||
public byte[] Unpack ()
|
||||
public ImageData Unpack ()
|
||||
{
|
||||
m_input.Position = 0x18;
|
||||
var input = m_input.ReadBytes (m_info.PackedLength);
|
||||
Stream input = new StreamRegion (m_input.AsStream, 0x18, m_info.PackedLength, true);
|
||||
if (m_info.IsEncrypted)
|
||||
DecryptData (input, 0, input.Length & -8);
|
||||
using (var mem = new MemoryStream (input))
|
||||
using (var lzss = new LzssStream (mem))
|
||||
lzss.Read (m_output, 0, m_output.Length);
|
||||
if (m_info.AlphaLength > 0)
|
||||
input = new InputCryptoStream (input, new SjTransform (m_info.Key));
|
||||
using (input = new LzssStream (input))
|
||||
{
|
||||
var header = new byte[0x28];
|
||||
input.Read (header, 0, header.Length);
|
||||
if (8 == m_info.BPP)
|
||||
Palette = ImageFormat.ReadPalette (input);
|
||||
input.Read (m_output, 0, m_output.Length);
|
||||
}
|
||||
if (m_info.AlphaLength > 0 && m_info.BPP == 8)
|
||||
{
|
||||
m_input.Position = 0x18 + m_info.PackedLength;
|
||||
var alpha = new byte[m_info.AlphaLength];
|
||||
using (var lzss = new LzssStream (m_input.AsStream, LzssMode.Decompress, true))
|
||||
lzss.Read (alpha, 0, alpha.Length);
|
||||
return ApplyAlpha (alpha);
|
||||
}
|
||||
return m_output;
|
||||
return ImageData.CreateFlipped (m_info, Format, Palette, m_output, Stride);
|
||||
}
|
||||
|
||||
void DecryptData (byte[] data, int pos, int length)
|
||||
ImageData ApplyAlpha (byte[] alpha)
|
||||
{
|
||||
for (int i = 0; i < length; i += 8)
|
||||
{
|
||||
DecryptBlock (data, pos + i);
|
||||
}
|
||||
}
|
||||
int width = (int)m_info.Width;
|
||||
int height = (int)m_info.Height;
|
||||
int dst_stride = width * 4;
|
||||
var pixels = new byte[dst_stride * height];
|
||||
var colors = Palette.Colors;
|
||||
|
||||
void DecryptBlock (byte[] data, int pos)
|
||||
var row_table = new ushort[height];
|
||||
int row_table_size = row_table.Length * sizeof(ushort);
|
||||
Buffer.BlockCopy (alpha, 0, row_table, 0, row_table_size);
|
||||
var lines = new int[height];
|
||||
int lines_size = lines.Length * sizeof(int);
|
||||
Buffer.BlockCopy (alpha, row_table_size, lines, 0, lines_size);
|
||||
|
||||
int alpha_pos = row_table_size + lines_size;
|
||||
int src = m_output.Length - Stride;
|
||||
int dst_row = 0;
|
||||
for (int y = 0; y < height; ++y)
|
||||
{
|
||||
int dst = dst_row;
|
||||
for (int x = 0; x < width; ++x)
|
||||
{
|
||||
byte code = m_output[src+x];
|
||||
var color = colors[code];
|
||||
pixels[dst++] = color.B;
|
||||
pixels[dst++] = color.G;
|
||||
pixels[dst++] = color.R;
|
||||
pixels[dst++] = (byte)(code != 0 ? 0xFF : 0);
|
||||
}
|
||||
int asrc = alpha_pos + 4 * lines[y];
|
||||
for (int i = 0; i < row_table[y]; ++i)
|
||||
{
|
||||
byte a = Math.Min (alpha[asrc+3], (byte)0xF);
|
||||
dst = dst_row + LittleEndian.ToUInt16 (alpha, asrc) * 4;
|
||||
if (a > 0)
|
||||
{
|
||||
var color = colors[alpha[asrc+2]];
|
||||
pixels[dst ] = color.B;
|
||||
pixels[dst+1] = color.G;
|
||||
pixels[dst+2] = color.R;
|
||||
pixels[dst+3] = (byte)(a * 0x11);
|
||||
}
|
||||
else
|
||||
pixels[dst+3] = 0;
|
||||
asrc += 4;
|
||||
}
|
||||
dst_row += dst_stride;
|
||||
src -= Stride;
|
||||
}
|
||||
return ImageData.Create (m_info, PixelFormats.Bgra32, null, pixels, dst_stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user