如何让git diff支持HALCON的 .hdict(二进制字典)文件?

编程语言 2026-07-10

有没有办法让git diff对包含图像的.hdict文件在终端和像Git Extensions这样的GUI工具中显示有意义、易读的差异吗?

当使用git时,对这些文件进行diff的结果只是显示:Binary files a/Labels.hdict and b/Labels.hdict differ

解决方案

Yes. Git支持textconv过滤器,在diff之前将二进制文件转换为文本。对于Halcon的 .hdict文件,可以在将标志性对象(图像、区域、形状模型)替换为序列化摘要后,使用dict_to_json将其转换为JSON。

工作原理

  1. Git会对每个版本的.hdict文件调用textconv脚本
  2. 脚本使用HALCON安装自带的hrun将字典读取进来,将标志性对象替换为类型和大小的摘要,并输出JSON
  3. Git使用其普通的diff引擎对这两个JSON文本进行差异比较

设置

创建HDevelop脚本(hdict_to_json.hdev):

global tuple DictPath
global tuple OutputFile

read_dict (DictPath, [], [], Dict)
copy_dict (Dict, [], [], DictOut)

* Stack-based iterative replacement of iconic objects
DictStack := {DictOut}
while (DictStack.length() > 0)
    CurrentDict := DictStack.at(DictStack.length() - 1)
    DictStack.remove(DictStack.length() - 1)
    get_dict_param (CurrentDict, 'keys', [], Keys)
    for Index := 0 to |Keys| - 1 by 1
        get_dict_param (CurrentDict, 'key_data_type', Keys[Index], DataType)
        if (DataType == 'tuple')
            get_dict_tuple (CurrentDict, Keys[Index], Tuple)
            tuple_sem_type (Tuple, SemType)
            if (SemType == 'dict')
                DictStack.at(DictStack.length()) := Tuple
            elseif (SemType == 'shape_model' or SemType == 'handle')
                serialize_tuple (Tuple, SerializedItemHandle)
                get_handle_tuple (SerializedItemHandle, 'Size', Size)
                CurrentDict.[Keys[Index]] := ['SemType:', SemType, 'Size:', Size]
            endif
        else
            get_dict_object (Object, CurrentDict, Keys[Index])
            get_obj_class (Object, Class)
            serialize_object (Object, SerializedItemHandle)
            get_handle_tuple (SerializedItemHandle, 'Size', Size)
            CurrentDict.[Keys[Index]] := ['ObjClass', Class, 'Size:', Size]
        endif
    endfor
endwhile

dict_to_json (DictOut, [], [], Output)

* Pretty print
tuple_regexp_replace (Output, ['}', 'replace_all'], '}\n', Output)
tuple_regexp_replace (Output, ['\\]', 'replace_all'], ']\n', Output)

open_file (OutputFile, 'output', FileHandle)
fwrite_string (FileHandle, Output)
close_file (FileHandle)

脚本读取字典,逐层遍历所有嵌套的字典,将标志性对象替换为 ['ObjClass', class, 'Size:', bytes] 或 ['SemType:', type, 'Size:', bytes],然后输出带换行符的JSON,便于可读的差异比较。

创建PowerShell textconv包装脚本(hdict-textconv.ps1):

Param($FilePath)

$HdevPath = Join-Path -Path $PSScriptRoot -ChildPath "hdict_to_json.hdev"
$TempFile = [System.IO.Path]::GetTempFileName()

# Ensure path is absolute (git may pass relative paths)
if (-not [System.IO.Path]::IsPathRooted($FilePath)) {
  $FilePath = Join-Path -Path (Get-Location) -ChildPath $FilePath
}

# Ensure input has .hdict extension (git passes temp files without extension)
if ($FilePath -notmatch '\.hdict$') {
  $TempInput = $TempFile + ".hdict"
  Copy-Item -Path $FilePath -Destination $TempInput -Force
  $FilePath = $TempInput
}

& hrun $HdevPath -D "DictPath=$FilePath" -D "OutputFile=$TempFile" 2>$null

if (Test-Path $TempFile) {
  (Get-Content -Raw $TempFile) -replace "`0", ""
  Remove-Item $TempFile -ErrorAction SilentlyContinue
}

if ($TempInput -and (Test-Path $TempInput)) {
  Remove-Item $TempInput -ErrorAction SilentlyContinue
}

配置git(.gitconfig):

[diff "hdict"]
  textconv = powershell -ExecutionPolicy Bypass -File /path/to/hdict-textconv.ps1

将其添加到项目中的.gitattributes:

*.hdict diff=hdict

结果:

终端(git diff):

@@ -14,6 +14,7 @@
,"PreposC1":[5223.46240234375,2180.46240234375]
,"HomMatToOrig":{"1":[1,0,-1508,0,1,-912]
}
+,"ModelID":["SemType:","shape_model","Size:",22324]

}

在GitExtensions以及任何支持git textconv过滤器的工具中都能工作。

为什么使用textconv而不是diff.command?

Git的 diff命令会完全替换diff引擎。它在终端中有效,但GUI工具如GitExtensions会忽略它。textconv将二进制转换为文本,让各自的diff渲染器来处理,因此在所有工具中都能工作。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章