我正在解析C中的Photoshop原始16位/通道RGB文件,并尝试记录异常数据点。我需要使用16位量子或216 MB Photoshop .RAW文件对多达36个MPix图像进行非常快速的C分析。
< 1%的点有奇怪的肤色,我想用PerlMagick或Perl GD绘制图形,看看它们来自哪里。
C数据文件的前4个字节包含uigned32_t的无符号图像宽度。在Perl中,我以二进制模式读取整个文件并提取前32位:
Xres=1779105792l = 0x6a0b0000
它看起来很像C日志文件:
DA: Color anomalies=14177=0.229%:
DA: II=1) raw PIDX=0x10000b25, XCols=[0]=0x00000b6a
Dec(0x00000b6a)= 2922,一个小测试文件的Exact X_Columns_Width。
显然是英特尔1972 8008 NUXI架构的案例。将0x6a0b0000转换为0x6a0b0000是多么困难;交换2个字节和2个半字节,你就完成了。切片8个字符并重新排列它们可以完成,但这是我试图避免的丑陋黑客。
从文件偏移零点抓取相同的32位向量并将其解压缩为" VAX"无符号长。
$xres = vec($bdat, 0, 32); # vec EXPR,OFFSET,BITS
$vul = unpack("V", vec($bdat, 0, 32));
printf("Length (\$bdat)=%d, xres=0x%08x, Vax ulong=%ul=0x%08x\n",
length($bdat), $xres, $vul, $vul);
Length ($bdat) = 56712, xres=0x6a0b0000, Vax ulong=959919921l=0x39373731
每一个十六进制字符都被破坏了。显然错了Endian,它不是VAX。 "其他"一个是Network Big-endian
http://perldoc.perl.org/functions/pack.html
N An unsigned long (32-bit) in "network" (big-endian) order.
V An unsigned long (32-bit) in "VAX" (little-endian) order.
$nul = unpack("N", vec($bdat, 0, 32)); # Network Unsigned Long 32b
printf("Xres=0x%08x, NET ulong=%ul=0x%08x\n", $xres, $nul, $nul);
Xres=0x6a0b0000, NET ulong=825702201l=0x31373739
$ XRES仍然以错误的顺序显示正确的十六进制。 " NETWORK"从相同位提取的长32位uint无法识别。尝试二进制
$bits = unpack("b*", vec($bdat, 0, 32));
printf("bits=$bits, len=%d\n", length $bits);
bits=10001100111011001110110010011100100011000000110010101100111011001001110001001100, len=80
我明确要求32位并获得80位。是什么赋予了?
尝试4,无符号,8位字节,不能交换:
for($ii = 0; $ii < 4; $ii++) {
$bit_off=$ii*8; # Bit offset
$uc = unpack("C", vec($bdat, $bit_off, 8)); # C An unsigned char
printf("II $ii, bo $bit_off, d=%d, u=%u, x=0x%x\n",
$uc,$uc, $uc);
}
II 0, bo 0, d=49, u=49, x=0x31
II 1, bo 8, d=51, u=51, x=0x33
II 2, bo 16, d=49, u=49, x=0x31
II 3, bo 24, d=49, u=49, x=0x31
我正在寻找十六进制0,6,a或b。正确答案中没有&#34; 3&#34;或#34; 1&#34; s。尝试从C文件盗版:
http://cpansearch.perl.org/src/MHX/Convert-Binary-C-0.76/tests/include/include/bits/byteswap.h
$x = $xres;
$x= (((($x) & 0xff000000) >> 24) | ((($x) & 0x00ff0000) >> 8) | ((($x) & 0x0000ff00) << 8) | ((($x) & 0x000000ff) << 24));
printf("\$xres=0x%08x -> \$x=0x%08x = %u\n", $xres, $x, $x);
$xres=0x6a0b0000 -> $x=0x00000b6a = 2922
它工作!但是,这比将原始的,错误的顺序十六进制数转换为字符串以解开它更为丑陋:
$stupid_str = sprintf("%08x", $xres);
$stupid_num = join('', reverse ($stupid_str =~ m/../g));
printf("Stupid_num '%s'->0x%08x=%d\n", $stupid_num, $dec=hex $stupid_num, $dec);
Stupid_num '00000b6a'->0x00000b6a=2922
这就像判断Ugliest Dog比赛一样,但我仍然宁愿维护文本版本而不是更恶劣的C版本。
我知道有很多方法可以在Java / Python / Go / Ruby /.....
中执行此操作我知道有一些命令行实用程序就是这样做的。
我必须弄清楚我是如何滥用VEC或Unpack,这两种情况都是我使用过的。这是Brain Teasing方面让我疯了! EndianNess == EndianMess !!!
TYVM!
=============================================== ==
鲍罗廷
感谢您寻找&#39;在这。
我的英特尔处理器是小端的。当我把它读回来的时候,它被vec转化为正确的&#34;正确的&#34; big-endian,网络格式。
我刚尝试从BINARY文件中读取它的VERBATIM,它运行正常:
($b4 = $bdat) =~ s/^(....).*$/$1/msg; # Give me my 4 bytes back without mutilation!
printf("B4='%s'=>0x%08x=<0x%08x\n", $b4, unpack("L>", $b4), unpack("L<", $b4));
B4='j...' = >0x6a0b0000 = <0x00000b6a <<< THE RIGHT ANSWER!!!
如果您尝试打开&#39; V&#39;,$ bdat,那么您会发现它有效
这是我的第一次尝试:
$ vul = unpack(&#34; V&#34;,vec($ bdat,0,32)); #UNPACK V!
printf(&#34;长度(\ $ bdat)=%d,xres = 0x%08x,Vax ulong =%ul = 0x%08x \ n&#34;,
长度($ bdat),$ xres,$ vul,$ vul);
长度($ bdat)= 56712,xres = 0x6a0b0000,Vax ulong = 959919921l = 0x39373731&lt;&lt;&lt;&lt;完全错了!
我已经验证了$ BDAT信息是错误格式的正确数据。它只需要一些重新安排。
我只是使用vec()生成1位和4位图形文件,它忠实地工作,返回我写的确切位。它必须将我的Intel i7误认为是我的IBM System / 370。 I7 / 37 ???容易犯错误。 :)
我读了[混淆]部分关于&#34;转换为数字与包...&#34;。这就是为什么我的号码落后了。 &gt;&gt;解压缩(&#34; V&#34;,vec($ bdat&#34;&lt;&lt; ... ...}是我错命的尝试,以错误的方式交换来自错误VEC的$ BDAT中的后向数字() - 将FORMAT优先添加到我的架构支持的本机格式。
现在我理解为什么我看到这么多人用字节提取的例子,以避免老大哥的帮助!
Data::BitStream::Vec "uses a Perl vec to store the data. The vector is accessed in 1-bit units"
感谢1E6,
B
答案 0 :(得分:0)
将vec
与unpack
正确的方法就是
unpack 'V', $bdat
按预期返回0x00000B6A
的值
vec($bdat, 0, 32)
相当于unpack 'N', $bdat
,您可以从第一个代码块中$xres
的值中看到,documentation for vec
通过
如果BITS为16或更多,则输入字符串的字节被分组为大小为BITS / 8的块,并且每个组都转换为与pack()/ unpack()一样的数字,具有大端格式n / N
该行
$vul = unpack("V", vec($bdat, 0, 32))
是非常错误的,因为vec($bdat, 0, 32)
的十进制值是1779105792,因此您在字符串 unpack
上调用"1779105792"
,而不是{{1}}。做任何有用的事情