diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj index e4a716ef..ed19f7ec 100644 --- a/ArcFormats/ArcFormats.csproj +++ b/ArcFormats/ArcFormats.csproj @@ -131,7 +131,9 @@ + + WidgetDXA.xaml diff --git a/ArcFormats/DigitalWorks/ArcPACsingle.cs b/ArcFormats/DigitalWorks/ArcPACsingle.cs new file mode 100644 index 00000000..310823c1 --- /dev/null +++ b/ArcFormats/DigitalWorks/ArcPACsingle.cs @@ -0,0 +1,88 @@ +//! \file ArcPACPS2.cs +//! \date 2018 Sep 18 +//! \brief Digital Works PS2 resource archive. +// +// Copyright (C) 2018 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.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; +using GameRes.Compression; + +namespace GameRes.Formats.DigitalWorks +{ + [Export(typeof(ArchiveFormat))] + public class PacSingleOpener : ArchiveFormat + { + public override string Tag { get { return "PAC/LZS-TIM2"; } } + public override string Description { get { return "LZS-TIM2 Image archive"; } } + public override uint Signature { get { return 0x535A4C; } } // 'LZS' + public override bool IsHierarchic { get { return false; } } + public override bool CanWrite { get { return false; } } + + /** + Target games: + Cafe Little Wish SLPM-65294 + F Fanatic SLPM-65296 + */ + + public override ArcFile TryOpen (ArcView file) + { + if (!file.View.AsciiEqual(9, "TIM2")) + return null; + var dir = new List (1); + var entry = FormatCatalog.Instance.Create (file.Name); + entry.Offset = 0L; + entry.Size = (uint)file.MaxOffset; + if (!entry.CheckPlacement (file.MaxOffset)) + return null; + dir.Add (entry); + + return new ArcFile (file, this, dir); + } + + public override Stream OpenEntry (ArcFile arc, Entry entry) + { + var pent = entry as PackedEntry; + if (null == pent) + return base.OpenEntry (arc, entry); + if (!pent.IsPacked) + { + if (!arc.File.View.AsciiEqual (entry.Offset, "LZS\0")) + return base.OpenEntry (arc, entry); + pent.IsPacked = true; + pent.UnpackedSize = arc.File.View.ReadUInt32 (entry.Offset+4); + } + var input = arc.File.CreateStream (entry.Offset+8, entry.Size-8); + bool embedded_lzs = (input.Signature & ~0xF0u) == 0x535A4C0F; // 'LZS' + var lzs = new LzssStream (input); + if (embedded_lzs) + { + var header = new byte[8]; + lzs.Read (header, 0, 8); + pent.UnpackedSize = header.ToUInt32 (4); + lzs = new LzssStream (lzs); + } + return lzs; + } + } +} diff --git a/ArcFormats/DigitalWorks/ImageTM2.cs b/ArcFormats/DigitalWorks/ImageTM2.cs index 2c3a6afc..0be8eab1 100644 --- a/ArcFormats/DigitalWorks/ImageTM2.cs +++ b/ArcFormats/DigitalWorks/ImageTM2.cs @@ -23,6 +23,7 @@ // IN THE SOFTWARE. // +using GameRes.Formats.Strings; using System; using System.ComponentModel.Composition; using System.IO; @@ -36,6 +37,7 @@ internal class Tim2MetaData : ImageMetaData public int PaletteSize; public int HeaderSize; public int Colors; + public byte Alpha; } [Export(typeof(ImageFormat))] @@ -48,8 +50,16 @@ public class Tim2Format : ImageFormat public Tim2Format () { Extensions = new string[] { "tm2", "ext" }; + Settings = new[] { AlphaFormat }; } + FixedSetSetting AlphaFormat = new FixedSetSetting(Properties.Settings.Default) + { + Name = "TIM2AlphaFormat", + Text = arcStrings.Tim2AlphaFormat, + ValuesSet = new[] { "No Alpha", "RGBX", "RGBA" }, + }; + public override ImageMetaData ReadMetaData (IBinaryStream file) { var header = file.ReadHeader (0x40); @@ -62,6 +72,14 @@ public override ImageMetaData ReadMetaData (IBinaryStream file) case 5: bpp = 8; break; default: return null; } + byte alpha; + switch (AlphaFormat.Get()) + { + case "No Alpha": alpha = 0; break; + case "RGBX": alpha = 7; break; + case "RGBA": + default: alpha = 8; break; + } return new Tim2MetaData { Width = header.ToUInt16 (0x24), Height = header.ToUInt16 (0x26), @@ -69,6 +87,7 @@ public override ImageMetaData ReadMetaData (IBinaryStream file) PaletteSize = header.ToInt32 (0x14), HeaderSize = header.ToUInt16 (0x1C), Colors = header.ToUInt16 (0x1E), + Alpha = alpha, //header.ToUInt16(0x30) == 0?// not so sure, there will be omissions }; } @@ -113,9 +132,9 @@ public byte[] Unpack () int image_size = (int)m_info.Width * (int)m_info.Height * pixel_size; var output = m_input.ReadBytes (image_size); if (pixel_size <= 8 && m_info.Colors > 0) - Palette = ReadPalette (m_info.Colors); + Palette = ReadPalette (m_info.Colors, m_info.Alpha); - if (pixel_size >= 3) + if (pixel_size == 3 || pixel_size == 4 && m_info.Alpha == 8) { for (int i = 0; i < image_size; i += pixel_size) { @@ -124,12 +143,36 @@ public byte[] Unpack () output[i+2] = r; } } + if (pixel_size == 4 && m_info.Alpha == 7) + { + for (int i = 0; i < image_size; i += 4) + { + byte r = output[i]; + output[i] = output[i + 2]; + output[i + 2] = r; + if (output[i + 3] >= byte.MaxValue / 2) + output[i + 3] = byte.MaxValue; + else + output[i + 3] = (byte)(output[i + 3] << 1); + } + } + if (pixel_size == 4 && m_info.Alpha == 0) + { + for (int i = 0; i < image_size; i += 4) + { + byte r = output[i]; + output[i] = output[i + 2]; + output[i + 2] = r; + output[i + 3] = byte.MaxValue; + } + } return output; } - BitmapPalette ReadPalette (int color_num) + BitmapPalette ReadPalette (int color_num, byte X_A = 8) { - var source = ImageFormat.ReadColorMap (m_input.AsStream, color_num, PaletteFormat.RgbA); + var source = ImageFormat.ReadColorMap (m_input.AsStream, + color_num, X_A == 7 ? PaletteFormat.RgbA7 : X_A == 0 ? PaletteFormat.RgbX : PaletteFormat.RgbA); var color_map = new Color[color_num]; int parts = color_num / 32; diff --git a/ArcFormats/DigitalWorks/ImageTM2arc.cs b/ArcFormats/DigitalWorks/ImageTM2arc.cs new file mode 100644 index 00000000..f7be9250 --- /dev/null +++ b/ArcFormats/DigitalWorks/ImageTM2arc.cs @@ -0,0 +1,53 @@ +using GameRes.Compression; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; + +namespace GameRes.Formats.DigitalWorks +{ + [Export(typeof(ImageFormat))] + public class TM2ArkFormat : Tim2Format + { + public override string Tag { get { return "TIM2/PS2 compressed"; } } + public override string Description { get { return "PlayStation/2 image format with LZSS compress"; } } + public override uint Signature { get { return 0x535A4C; } } // 'LZS' + public TM2ArkFormat() + { + Extensions = new string[] { "tm2" }; + Settings = null; + } + + public override ImageMetaData ReadMetaData(IBinaryStream stream) + { + stream.Position = 9; + uint real_sign = stream.ReadUInt32(); + //Tim2Format tm2raw = new Tim2Format(); + if (real_sign != base.Signature) + { + return null; + } + stream.Position = 4; + uint unpacked_size = stream.ReadUInt32(); + if (unpacked_size <= 0x20 || unpacked_size > 0x5000000) // ~83MB + return null; + stream.Position = 8; + using (var lzss = new LzssStream(stream.AsStream, LzssMode.Decompress, true)) + using (var input = new SeekableStream(lzss)) + using (var tm2 = new BinaryStream(input, stream.Name)) + return base.ReadMetaData(tm2); + } + public override ImageData Read(IBinaryStream stream, ImageMetaData info) + { + stream.Position = 8; + using (var lzss = new LzssStream(stream.AsStream, LzssMode.Decompress, true)) + using (var input = new SeekableStream(lzss)) + using (var tm2 = new BinaryStream(input, stream.Name)) + return base.Read(tm2, info); + } + public override void Write(Stream file, ImageData image) + { + throw new System.NotImplementedException("TM2ArkFormat.Write not implemented"); + } + } +} diff --git a/ArcFormats/MAGES/ArcARC20.cs b/ArcFormats/MAGES/ArcARC20.cs index a8c3f1cd..9c7a16c5 100644 --- a/ArcFormats/MAGES/ArcARC20.cs +++ b/ArcFormats/MAGES/ArcARC20.cs @@ -11,7 +11,7 @@ public class ARC20Opener : ArchiveFormat public override string Tag { get { return "ARC/Princess Soft ARC20"; } } public override string Description { get { return "Princess Soft PS2 resource archive"; } } public override uint Signature { get { return 0x20435241; } } // 'ARC\x20' - public override bool IsHierarchic { get { return false; } } + public override bool IsHierarchic { get { return true; } } public override bool CanWrite { get { return false; } } public override ArcFile TryOpen(ArcView file) diff --git a/ArcFormats/Properties/Settings.Designer.cs b/ArcFormats/Properties/Settings.Designer.cs index f22c61a8..4bad779b 100644 --- a/ArcFormats/Properties/Settings.Designer.cs +++ b/ArcFormats/Properties/Settings.Designer.cs @@ -837,5 +837,17 @@ public int NexasEncodingCP { this["NexasEncodingCP"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("RGBA")] + public string TIM2AlphaFormat { + get { + return ((string)(this["TIM2AlphaFormat"])); + } + set { + this["TIM2AlphaFormat"] = value; + } + } } } diff --git a/ArcFormats/Properties/Settings.settings b/ArcFormats/Properties/Settings.settings index a6aa5543..50457412 100644 --- a/ArcFormats/Properties/Settings.settings +++ b/ArcFormats/Properties/Settings.settings @@ -206,5 +206,8 @@ 932 + + RGBA + \ No newline at end of file diff --git a/ArcFormats/Strings/arcStrings.Designer.cs b/ArcFormats/Strings/arcStrings.Designer.cs index c42b4340..accb3959 100644 --- a/ArcFormats/Strings/arcStrings.Designer.cs +++ b/ArcFormats/Strings/arcStrings.Designer.cs @@ -752,6 +752,16 @@ public static string SGLabelEncoding { } } + /// + /// Looks up a localized string similar to Choose Tim2 image alpha format. + /// It can't be read correctly from the file. + /// + public static string Tim2AlphaFormat { + get { + return ResourceManager.GetString("Tim2AlphaFormat", resourceCulture); + } + } + /// /// Looks up a localized string similar to Hex number. /// diff --git a/ArcFormats/Strings/arcStrings.ja-JP.resx b/ArcFormats/Strings/arcStrings.ja-JP.resx index 09cb1f5f..ea90ba37 100644 --- a/ArcFormats/Strings/arcStrings.ja-JP.resx +++ b/ArcFormats/Strings/arcStrings.ja-JP.resx @@ -501,4 +501,8 @@ Choose encryption scheme or enter a passphrase. Default audio sampling rate + + Tim2画像のAlpha形式を選択してください。 +ファイルから正しく読み取ることができません。 + \ No newline at end of file diff --git a/ArcFormats/Strings/arcStrings.resx b/ArcFormats/Strings/arcStrings.resx index 435a145e..8543086c 100644 --- a/ArcFormats/Strings/arcStrings.resx +++ b/ArcFormats/Strings/arcStrings.resx @@ -401,4 +401,8 @@ Choose encryption scheme or enter a passphrase. Default audio sampling rate + + Choose Tim2 image alpha format. +It can't be read correctly from the file. + \ No newline at end of file diff --git a/ArcFormats/Strings/arcStrings.zh-Hans.resx b/ArcFormats/Strings/arcStrings.zh-Hans.resx index 97a8a221..056eb3ec 100644 --- a/ArcFormats/Strings/arcStrings.zh-Hans.resx +++ b/ArcFormats/Strings/arcStrings.zh-Hans.resx @@ -399,4 +399,8 @@ 默认音频采样率 + + 选择Tim2图片透明度格式。 +这无法从文件中正确获取。 + \ No newline at end of file diff --git a/ArcFormats/app.config b/ArcFormats/app.config index eb7f9ea8..ef1cc161 100644 --- a/ArcFormats/app.config +++ b/ArcFormats/app.config @@ -208,6 +208,9 @@ 932 + + RGBA +