Kagamia / WzComparerR2

Maplestory online Extractor
MIT License
423 stars 134 forks source link

zlib.Read not read whole data in WzLib::WzPng::GetRawData #195

Closed Bear2leaf closed 2 years ago

Bear2leaf commented 2 years ago

在使用Wz_Png的ExtractPng解析并保存bitmap时,发现图片不完整,调试发现zlib.Read在读取的过程中,一次性只读取部分数据,导致图像数据不完整。

例如Png图像就只有部分顶部区域可见,其余部分透明,大概变成这样:

Expected Result             Save Image Result
+----------------+          +----------------+
|   ,---,        |          |   ,---,        |
|  '  .' \       |          |  '  .' \       |
| /  ;    '.     |          | /  ;    '.     |
|:  :       \    |          |:  :       \    |
|:  |   /\   \   |    ->    |:  |   /        |
||  :  ' ;.   :  |          |                |
||  |  ;/  \   \ |          |                |
|'  :  | \  \ ,' |          |                |
||  |  '  '--'   |          |                |
||  :  :         |          |                |
||  | ,'         |          |                |
|`--''           |          |                |
+----------------+          +----------------+

工程配置(macos 12.2.1, dotnet sdk 6.0, console app):

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="System.Drawing.Common" Version="5.0.3" />
    <Compile Include="path/to/WzComparerR2/WzComparerR2.WzLib/*.cs" />
  </ItemGroup>
</Project>

测试代码(Program.cs):

using WzComparerR2.WzLib;
using System.Drawing.Imaging;

var structure = new Wz_Structure();
structure.Load("path/to/Base.wz", true);
var png = structure.WzNode.FindNodeByPath("Map\\Back\\grassySoil.img\\back\\3", true).GetValue<Wz_Png>();
var bitmap = png.ExtractPng();

bitmap.Save("img.png", ImageFormat.Png);

原始代码: https://github.com/Kagamia/WzComparerR2/blob/5ce3a924260a35442b81754fd539d3ba868c0c37/WzComparerR2.WzLib/Wz_Png.cs#L128

经过以下调整后,图像就可以正常解析并解决问题:


var offset = zlib.Read(plainData, 0, plainData.Length);
var ended = offset == plainData.Length;
while (!ended)
{
    offset += zlib.Read(plainData, offset, plainData.Length - offset);
    ended = offset == plainData.Length;
}

不知道是否是框架版本的问题,请问其他人遇到过类似问题吗?

Kagamia commented 2 years ago

.net 6 breaking change: Partial and zero-byte reads in DeflateStream, GZipStream, and CryptoStream

Bear2leaf commented 2 years ago

了解了,感谢,刚接触dotnet,这块不是很熟悉,

Kagamia commented 2 years ago

非常感谢您提交的issue,事实上wcR2正在迁移至.net 6(WzComparerX),势必会遇到同样的问题,算是提前解决了未来的bug 😆