mirror of
https://github.com/crskycode/GARbro.git
synced 2025-01-12 04:49:32 +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="Rune\ArcYK.cs" />
|
||||||
<Compile Include="Sarang\ImageABC.cs" />
|
<Compile Include="Sarang\ImageABC.cs" />
|
||||||
<Compile Include="Sogna\ArcSGS.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="Tako\ArcMPK.cs" />
|
||||||
<Compile Include="Tetratech\ArcBND.cs" />
|
<Compile Include="Tetratech\ArcBND.cs" />
|
||||||
<Compile Include="Tigerman\ArcCHR.cs" />
|
<Compile Include="Tigerman\ArcCHR.cs" />
|
||||||
@ -216,7 +217,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Bom\" />
|
<Folder Include="Bom\" />
|
||||||
<Folder Include="StudioJikkenshitsu\" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
@ -23,9 +23,13 @@
|
|||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.ComponentModel.Composition;
|
using System.ComponentModel.Composition;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using GameRes.Compression;
|
||||||
|
using GameRes.Utility;
|
||||||
|
|
||||||
// [030411][Studio Jikkenshitsu] Giin Oyako
|
// [030411][Studio Jikkenshitsu] Giin Oyako
|
||||||
|
|
||||||
@ -36,6 +40,7 @@ namespace GameRes.Formats.Jikkenshitsu
|
|||||||
public int PackedLength;
|
public int PackedLength;
|
||||||
public int AlphaLength;
|
public int AlphaLength;
|
||||||
public bool IsEncrypted;
|
public bool IsEncrypted;
|
||||||
|
public byte[] Key;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Export(typeof(ImageFormat))]
|
[Export(typeof(ImageFormat))]
|
||||||
@ -45,6 +50,9 @@ namespace GameRes.Formats.Jikkenshitsu
|
|||||||
public override string Description { get { return "Studio Jikkenshitsu image format"; } }
|
public override string Description { get { return "Studio Jikkenshitsu image format"; } }
|
||||||
public override uint Signature { get { return 0x20445247; } } // 'GRD '
|
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)
|
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||||
{
|
{
|
||||||
var header = file.ReadHeader (0x18);
|
var header = file.ReadHeader (0x18);
|
||||||
@ -53,16 +61,16 @@ namespace GameRes.Formats.Jikkenshitsu
|
|||||||
Height = header.ToUInt16 (8),
|
Height = header.ToUInt16 (8),
|
||||||
BPP = header[4],
|
BPP = header[4],
|
||||||
PackedLength = header.ToInt32 (0xC),
|
PackedLength = header.ToInt32 (0xC),
|
||||||
AlphaLength = header.ToInt32 (0x10),
|
AlphaLength = header.ToInt32 (0x14),
|
||||||
IsEncrypted = (header[5] & 0x80) != 0,
|
IsEncrypted = (header[5] & 0x80) != 0,
|
||||||
|
Key = DefaultKey,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||||
{
|
{
|
||||||
var reader = new GrdReader (file, (GrdMetaData)info);
|
var reader = new GrdReader (file, (GrdMetaData)info);
|
||||||
var pixels = reader.Unpack();
|
return reader.Unpack();
|
||||||
return ImageData.Create (info, reader.Format, null, pixels);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Write (Stream file, ImageData image)
|
public override void Write (Stream file, ImageData image)
|
||||||
@ -77,54 +85,102 @@ namespace GameRes.Formats.Jikkenshitsu
|
|||||||
GrdMetaData m_info;
|
GrdMetaData m_info;
|
||||||
byte[] m_output;
|
byte[] m_output;
|
||||||
|
|
||||||
|
public BitmapPalette Palette { get; private set; }
|
||||||
public PixelFormat Format { get; private set; }
|
public PixelFormat Format { get; private set; }
|
||||||
|
public int Stride { get; private set; }
|
||||||
|
|
||||||
public GrdReader (IBinaryStream input, GrdMetaData info)
|
public GrdReader (IBinaryStream input, GrdMetaData info)
|
||||||
{
|
{
|
||||||
m_input = input;
|
m_input = input;
|
||||||
m_info = info;
|
m_info = info;
|
||||||
if (8 == m_info.BPP)
|
if (8 == m_info.BPP)
|
||||||
Format = PixelFormats.Gray8;
|
Format = PixelFormats.Indexed8;
|
||||||
else if (24 == m_info.BPP)
|
else if (24 == m_info.BPP)
|
||||||
Format = PixelFormats.Bgr24;
|
Format = PixelFormats.Bgr24;
|
||||||
else
|
else
|
||||||
throw new InvalidFormatException();
|
throw new InvalidFormatException();
|
||||||
int image_size = (int)m_info.Width * (int)m_info.Height;
|
int width = (int)m_info.Width;
|
||||||
if (m_info.BPP >= 8)
|
if (m_info.BPP <= 8)
|
||||||
image_size *= (m_info.BPP + 1) / 8;
|
width = (width + 3) & ~3;
|
||||||
else
|
Stride = width * m_info.BPP / 8;
|
||||||
image_size = image_size * m_info.BPP / 8;
|
m_output = new byte[Stride * (int)m_info.Height];
|
||||||
m_output = new byte[image_size];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] Unpack ()
|
public ImageData Unpack ()
|
||||||
{
|
{
|
||||||
m_input.Position = 0x18;
|
Stream input = new StreamRegion (m_input.AsStream, 0x18, m_info.PackedLength, true);
|
||||||
var input = m_input.ReadBytes (m_info.PackedLength);
|
|
||||||
if (m_info.IsEncrypted)
|
if (m_info.IsEncrypted)
|
||||||
DecryptData (input, 0, input.Length & -8);
|
input = new InputCryptoStream (input, new SjTransform (m_info.Key));
|
||||||
using (var mem = new MemoryStream (input))
|
using (input = new LzssStream (input))
|
||||||
using (var lzss = new LzssStream (mem))
|
|
||||||
lzss.Read (m_output, 0, m_output.Length);
|
|
||||||
if (m_info.AlphaLength > 0)
|
|
||||||
{
|
{
|
||||||
|
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];
|
var alpha = new byte[m_info.AlphaLength];
|
||||||
using (var lzss = new LzssStream (m_input.AsStream, LzssMode.Decompress, true))
|
using (var lzss = new LzssStream (m_input.AsStream, LzssMode.Decompress, true))
|
||||||
lzss.Read (alpha, 0, alpha.Length);
|
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)
|
int width = (int)m_info.Width;
|
||||||
{
|
int height = (int)m_info.Height;
|
||||||
DecryptBlock (data, pos + i);
|
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