【问题标题】:Splitting a binary file on binary delimiter?在二进制分隔符上拆分二进制文件?
【发布时间】:2010-09-06 15:10:06
【问题描述】:

我正在编写一个将 MPO 立体 3D 图像转换为标准 JPEG 图像的 shell 脚本。一个 MPO 文件只是两个 JPEG 图像,连接在一起。

因此,您可以通过查找第二个 JPEG 幻数标头 (0xFFD8FFE1) 的字节偏移量来拆分 JPEG 文件。我已经使用 hexdump/xxd、grep、head 和 tail 手动完成了这项工作。

这里的问题是 grep:我可以使用什么来直接在二进制文件中搜索特定的幻数,并取回字节偏移量?还是我根本不应该为此使用 shell 脚本?谢谢。

【问题讨论】:

  • 为了记录,这些文件是由 Fujifilm FinePix Real 3D W3 相机制作的。
  • 另外,左镜头图像似乎在 MPO 文件中排在第一位。

标签: bash unix shell binary grep


【解决方案1】:

您可以使用 bbe (http://bbe-.sourceforge.net/) 执行此操作,这是一个类似于 sed 的二进制文件程序:

为了提取第一个JPEG使用:

bbe -b '/\xFF\xD8\xFF\xE1/:' -e 'D 2' -o first_jpeg mpo_file

第二个:

bbe -b '/\xFF\xD8\xFF\xE1/:' -e 'D 1' -o second_jpeg mpo_file

请注意,如果 JPEG 的幻数出现在 MPO 文件的其他位置,这将不起作用。

【讨论】:

  • 感谢您引起我的注意!顺便说一句,您的 Sourceforge 链接已损坏,bbe.sf.net 是一个不同的项目。
【解决方案2】:

我认为 Bart 解决了您最大的问题。如果该二进制序列在此过程中重复,您将获得部分 JPEG。

我做了一个快速测试,连接了一些 JPEG,然后用 awk 提取它们(请注意,我文件中的幻数以 0xE0 而不是 0xE1 结尾):

   # for i in *.jpg ; do cat $i ; done > test.mpo 
   # awk 'BEGIN {RS="\xFF\xD8\xFF\xE0"; FILENUM=-1} {FILENUM++; if (FILENUM == 0) {next}; FILENAME="image0"FILENUM".jpg"; printf "%s",RS$0 > FILENAME;}' test.mpo  
   # file image0*.jpg
    image01.jpg:  JPEG image data, JFIF standard 1.01
    image010.jpg: JPEG image data, JFIF standard 1.01
    image011.jpg: JPEG image data, JFIF standard 1.01

这对我来说似乎没问题,但是上面提到的问题仍然没有处理并且非常真实。

【讨论】:

  • 我猜幻数中的 0xE1 表示它是序列中的第二个图像,并且您永远不会有超过 2 个图像。根据需要进行调整。 =)
  • 我不确定,因为我还在文件开头看到了 0xE1。
  • 我给你答案检查是因为 awk 在每个 Unix 系统上都可用(它提醒我我需要了解更多关于它的信息 :)。我的 shell 脚本目前正在对 image03.jpg 或缺少 image02.jpg 和中止进行一些基本检查,这有助于处理幻数问题。我还可以检查 EXIF 标头。不幸的是,我只知道一个可以本地读取这些文件的程序——Fujifilm Windows 应用程序——尽管维基百科声称 Digikam 支持 MPO。将不得不查看它们的来源,以及我相机的文档。现在,这很好。
  • 很高兴它为你解决了。en.wikipedia.org/wiki/Magic_number_%28programming%29#Examples 说 0xFF 0xD8 是 JPEG 幻数的开头,所以它后面的内容取决于实现。
【解决方案3】:

我在http://www.davidglover.org/2010/09/using-the-fuji-finepix-real-3d-w3-camera-on-a-mac-or-linuxunix.html 找到了关于 MPO 文件结构(以及如何正确处理它)的更好解释

编辑,2019 年 10 月:

由于现在的博文是404s,这里是我根据它写的脚本。好多年没用过了。

#!/usr/bin/env bash

# Script to convert 3D MPO files, as used in the Fuji FinePix series of 3D cameras, into standard JPEG files.
# Based on work by David Glover, posted at http://www.davidglover.org/2010/09/using-the-fuji-finepix-real-3d-w3-camera-on-a-mac-or-linuxunix.html
# This script requires exiftool and ImageMagick.

FULLNAME="$1"
FILENAME="$(basename $FULLNAME)"
DIRNAME="$(dirname $FULLNAME)"
BASENAME="${FILENAME%.*}"

# Create output directories
mkdir -p "$DIRNAME"/stereoscopic-rl/
mkdir -p "$DIRNAME"/stereoscopic-mpo/
mkdir -p "$DIRNAME"/stereoscopic-anaglyph/
mkdir -p "$DIRNAME"/monoscopic-l/
mkdir -p "$DIRNAME"/monoscopic-r/

# Create separate left and right images
exiftool -trailer:all= "$FULLNAME" -o "$DIRNAME"/monoscopic-l/"$BASENAME"-left.jpg
exiftool "$FULLNAME" -mpimage2 -b > "$DIRNAME"/monoscopic-r/"$BASENAME"-right.jpg

# Move the MPO file to its new home
mv "$FULLNAME" "$DIRNAME"/stereoscopic-mpo/

# Determine parallax value and create cropped images for stereo generation
# 36 is only appropriate for 4:3 or 3:2 images
parallax=$(exiftool -b -Parallax "$DIRNAME"/monoscopic-r/"$BASENAME"-right.jpg)
parallax=$(echo "$parallax"*36+0.5 | bc | cut -d . -f 1)

# The above pipeline can't deal with a parallax of zero
# In theory, this fix doesn't cover values between zero and -1
# TODO improve the calculation
if [ ! $parallax ]; then
    parallax=0
fi

echo $parallax

if [ $parallax -ge 0 ]; then
    convert "$DIRNAME"/monoscopic-l/"$BASENAME"-left.jpg -crop +"$parallax"+0 "$DIRNAME"/monoscopic-l/"$BASENAME"-left-cropped.jpg
    convert "$DIRNAME"/monoscopic-r/"$BASENAME"-right.jpg -crop -"$parallax"+0 "$DIRNAME"/monoscopic-r/"$BASENAME"-right-cropped.jpg
else
    convert "$DIRNAME"/monoscopic-l/"$BASENAME"-left.jpg -crop -"$((-1*$parallax))"+0 "$DIRNAME"/monoscopic-l/"$BASENAME"-left-cropped.jpg
    convert "$DIRNAME"/monoscopic-r/"$BASENAME"-right.jpg -crop +"$((-1*$parallax))"+0 "$DIRNAME"/monoscopic-r/"$BASENAME"-right-cropped.jpg
fi

# Create stereoscopic images for cross-eye (right-left) and anaglyph (red-cyan) viewing
convert "$DIRNAME"/monoscopic-r/"$BASENAME"-right-cropped.jpg "$DIRNAME"/monoscopic-l/"$BASENAME"-left-cropped.jpg +append "$DIRNAME"/stereoscopic-rl/"$BASENAME"-stereoscopic-rl.jpg

composite -stereo 0 "$DIRNAME"/monoscopic-r/"$BASENAME"-right-cropped.jpg "$DIRNAME"/monoscopic-l/"$BASENAME"-left-cropped.jpg "$DIRNAME"/stereoscopic-anaglyph/"$BASENAME"-stereoscopic-anaglyph.jpg

# Clean up separated parallax-corrected images
rm "$DIRNAME"/monoscopic-l/"$BASENAME"-left-cropped.jpg
rm "$DIRNAME"/monoscopic-r/"$BASENAME"-right-cropped.jpg

exit 0

【讨论】:

  • 对不起... 错误 404
  • 我已将我在 2010 年编写的脚本添加到答案中;希望对您有所帮助。
【解决方案4】:

我认为一种非常简单的自制方法将是您的最佳选择。执行此操作的代码将非常小,具体取决于二进制文件格式的所有特殊情况。

  1. 使用mmap 可以方便地查看内存中的文件。
  2. 开始扫描,并将字节偏移量保存在变量中,例如start
  3. 扫描直到到达分隔符,保存结束偏移量,例如end
  4. 创建一个新文件
  5. 内存映射新文件
  6. 将字节范围从start 复制到end 到新文件中。
  7. 关闭新文件并重新开始扫描。

【讨论】:

    【解决方案5】:

    FFE1 不是一些 jpeg“幻数”的一部分,它是 APP1 标记。并且不能保证在 SOI 标记 FFD8 之后立即出现。此外,您应该小心一些 jpeg 图像在 EXIF 块中嵌入缩略图 jpeg。这很可能还包含一个 APP1 标记。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-01
      • 2015-05-26
      • 2015-06-10
      • 2012-01-22
      • 2010-09-30
      • 1970-01-01
      相关资源
      最近更新 更多