打开 MPO 文件并提取嵌入的图像
Open MPO file and extract the embedded images
有点想用这个项目——或者更确切地说是两个。一种是尝试使用 Xcode 编写 macOS 应用程序,另一种是处理 3D 照片(或者 StereoPhotos,如果你完全正确的话)。
我确实在 LiveCode 中尝试过这个,但是它很慢而且很麻烦。我得到了我喜欢的东西,但你很快就遇到了性能瓶颈。所以我决定在 Xcode 重新开始。我想做的一件事是从 Fuji 3D 相机导入 MPO 文件,提取左右图像,并将它们显示在我的应用程序中。在 LiveCode 中,这很容易(可能太简单了)——您将 MPO 文件作为文本字符串导入,使用 JPEG 标记将其拆分为一个数组,然后将该数据设置为一个图像对象。结果是两个 JPEG 文件。
我在 Swift 一直在尝试这个,但失败得很厉害。到目前为止,在将其添加到我的应用程序之前,先在 Playground 中尝试想法。我一直采用与我在 LiveCode 中相同的逻辑 - 加载数据,用标记分割文件,保存数据。
import Cocoa
import Foundation
// Files and destinations
let MPOString = "/path/to/DSCF0523.MPO"
let myLeft = URL(string:"file:///path/to/left.jpg")
let myRight = URL(string:"file:///path/to/right.jpg")
var leftImage:NSImage
var rightImage:NSImage
//JPEG Marker FFD8FFE1
let myJpegMarker = "\u{FF}\u{D8}\u{FF}\u{E1}"
do {
myMPOData = try String(contentsOfFile: MPOString , encoding:String.Encoding.isoLatin1) as NSString
}
catch {
print("Error getting MPO - \(myMPOData)\n\(MPOString)")
}
/*
At this point, I realise that while the data has been split,
the markers are removed, so I add them back.
This is wrong (but worked in LiveCode)
*/
let imageArray = myMPOData.components(separatedBy: myJpegMarker)
var myLeftImage = myJpegMarker+imageArray[1]
var myRightImage = myJpegMarker+imageArray[2]
do {
try myLeftImage.write(to: myLeft! , atomically: false, encoding: String.Encoding.utf8)
}
catch {
print("Error writing file: " + error.localizedDescription)
}
print ("Saving image \(myRight)")
do {
try myRightImage.write(to: myRight! , atomically: false, encoding: String.Encoding.utf8)
}
catch {
print("Error writing file: " + error.localizedDescription)
}
上面的代码做了一些事情接近但不够接近。我的意思是它将数据分开,并转储出两个文件。但是文件不正确。十六进制转储显示 JPEG 标记不正确(我在文件开头寻找 FFD8FFE1,但不存在 - 有 8 个额外字符,我认为这是编码的结果)。此外,文件大小太小了 - 6.5Mb 而不是预期的 4,这告诉我有些地方不太对劲。
我花了相当多的时间试图找到解决这个问题的方法,但我发现自己在原地打转,却突然出现了相同的 Google 结果。
有人告诉我,我应该能够将图像加载到一个对象中,并通过引用对象[0] 和对象[1] 来获取它们。无论如何,无论解决方案如何,我希望它可能比我预期的更简单。
我已经在 DropBox 上放置了一个示例 MPO 文件以供参考,如果有人觉得他们可以提供帮助。 https://dl.dropboxusercontent.com/u/613685/DSCF0523.MPO.zip
我认为问题在于使用 (NS)String 而不是 (NS)Data 作为方法的基础。
虽然可能不是最巧妙的解决方案(我的想法处于 Objective-C 模式,所以我 非常 非常怀疑以下 Swift 可能是一个令人不安的组合两者之一),但这应该提取嵌入的图像:
import Foundation
let jpegMarker:Data = Data(bytes: UnsafePointer<UInt8>([0xFF, 0xD8, 0xFF, 0xE1] as [uint8]), count: 4)
let baseURL = "file:///path/to/images/"
let mpoURL = URL(string: baseURL + "DSCF0523.MPO")
var mpoData:Data
do {
try mpoData = Data.init(contentsOf: mpoURL!)
var markerLocations:[Int] = []
var markerOffset:Range? = mpoData.range(of: jpegMarker, options:[], in:0 ..< mpoData.count)
while (markerOffset != nil) {
// We've found a marker - add it to our array
markerLocations.append(markerOffset!.lowerBound)
// Update our current offset before we iterate
markerOffset = mpoData.range(of: jpegMarker as Data, options:[], in:markerOffset!.upperBound ..< mpoData.count)
}
// Did we find any markers?
if (markerLocations.count != 0) {
// Time to extract the data betwen the markers
for (index, currentMarkerOffset) in markerLocations.enumerated() {
let endDataOffset = index == markerLocations.count - 1 ? mpoData.count : markerLocations[index + 1]
let imageBytes:Data = mpoData.subdata(in:currentMarkerOffset ..< endDataOffset)
// Write the image data to disk
do {
let outputPath = baseURL + "Image-" + String(index) + ".jpeg"
try imageBytes.write(to: URL(string: outputPath)!)
}
catch {
print("Unable to write image file - " + error.localizedDescription)
}
}
} else {
print("JPEG marker not found in source MPO file.")
}
} catch {
print("Unable to open source MPO file - " + error.localizedDescription)
}
我正在做的是首先在 while 循环中获取文件中的所有标记(因为可能有两个以上的嵌入图像),然后遍历这些标记并一个一个地提取它们。
在此迭代期间,我们必须处理最终标记的情况,因此使用了相当难看的三元条件运算符。
顺便说一下,这里使用了Swift 3的数据(而不是2.x风格的NSData)等
有点想用这个项目——或者更确切地说是两个。一种是尝试使用 Xcode 编写 macOS 应用程序,另一种是处理 3D 照片(或者 StereoPhotos,如果你完全正确的话)。
我确实在 LiveCode 中尝试过这个,但是它很慢而且很麻烦。我得到了我喜欢的东西,但你很快就遇到了性能瓶颈。所以我决定在 Xcode 重新开始。我想做的一件事是从 Fuji 3D 相机导入 MPO 文件,提取左右图像,并将它们显示在我的应用程序中。在 LiveCode 中,这很容易(可能太简单了)——您将 MPO 文件作为文本字符串导入,使用 JPEG 标记将其拆分为一个数组,然后将该数据设置为一个图像对象。结果是两个 JPEG 文件。
我在 Swift 一直在尝试这个,但失败得很厉害。到目前为止,在将其添加到我的应用程序之前,先在 Playground 中尝试想法。我一直采用与我在 LiveCode 中相同的逻辑 - 加载数据,用标记分割文件,保存数据。
import Cocoa
import Foundation
// Files and destinations
let MPOString = "/path/to/DSCF0523.MPO"
let myLeft = URL(string:"file:///path/to/left.jpg")
let myRight = URL(string:"file:///path/to/right.jpg")
var leftImage:NSImage
var rightImage:NSImage
//JPEG Marker FFD8FFE1
let myJpegMarker = "\u{FF}\u{D8}\u{FF}\u{E1}"
do {
myMPOData = try String(contentsOfFile: MPOString , encoding:String.Encoding.isoLatin1) as NSString
}
catch {
print("Error getting MPO - \(myMPOData)\n\(MPOString)")
}
/*
At this point, I realise that while the data has been split,
the markers are removed, so I add them back.
This is wrong (but worked in LiveCode)
*/
let imageArray = myMPOData.components(separatedBy: myJpegMarker)
var myLeftImage = myJpegMarker+imageArray[1]
var myRightImage = myJpegMarker+imageArray[2]
do {
try myLeftImage.write(to: myLeft! , atomically: false, encoding: String.Encoding.utf8)
}
catch {
print("Error writing file: " + error.localizedDescription)
}
print ("Saving image \(myRight)")
do {
try myRightImage.write(to: myRight! , atomically: false, encoding: String.Encoding.utf8)
}
catch {
print("Error writing file: " + error.localizedDescription)
}
上面的代码做了一些事情接近但不够接近。我的意思是它将数据分开,并转储出两个文件。但是文件不正确。十六进制转储显示 JPEG 标记不正确(我在文件开头寻找 FFD8FFE1,但不存在 - 有 8 个额外字符,我认为这是编码的结果)。此外,文件大小太小了 - 6.5Mb 而不是预期的 4,这告诉我有些地方不太对劲。
我花了相当多的时间试图找到解决这个问题的方法,但我发现自己在原地打转,却突然出现了相同的 Google 结果。
有人告诉我,我应该能够将图像加载到一个对象中,并通过引用对象[0] 和对象[1] 来获取它们。无论如何,无论解决方案如何,我希望它可能比我预期的更简单。
我已经在 DropBox 上放置了一个示例 MPO 文件以供参考,如果有人觉得他们可以提供帮助。 https://dl.dropboxusercontent.com/u/613685/DSCF0523.MPO.zip
我认为问题在于使用 (NS)String 而不是 (NS)Data 作为方法的基础。
虽然可能不是最巧妙的解决方案(我的想法处于 Objective-C 模式,所以我 非常 非常怀疑以下 Swift 可能是一个令人不安的组合两者之一),但这应该提取嵌入的图像:
import Foundation
let jpegMarker:Data = Data(bytes: UnsafePointer<UInt8>([0xFF, 0xD8, 0xFF, 0xE1] as [uint8]), count: 4)
let baseURL = "file:///path/to/images/"
let mpoURL = URL(string: baseURL + "DSCF0523.MPO")
var mpoData:Data
do {
try mpoData = Data.init(contentsOf: mpoURL!)
var markerLocations:[Int] = []
var markerOffset:Range? = mpoData.range(of: jpegMarker, options:[], in:0 ..< mpoData.count)
while (markerOffset != nil) {
// We've found a marker - add it to our array
markerLocations.append(markerOffset!.lowerBound)
// Update our current offset before we iterate
markerOffset = mpoData.range(of: jpegMarker as Data, options:[], in:markerOffset!.upperBound ..< mpoData.count)
}
// Did we find any markers?
if (markerLocations.count != 0) {
// Time to extract the data betwen the markers
for (index, currentMarkerOffset) in markerLocations.enumerated() {
let endDataOffset = index == markerLocations.count - 1 ? mpoData.count : markerLocations[index + 1]
let imageBytes:Data = mpoData.subdata(in:currentMarkerOffset ..< endDataOffset)
// Write the image data to disk
do {
let outputPath = baseURL + "Image-" + String(index) + ".jpeg"
try imageBytes.write(to: URL(string: outputPath)!)
}
catch {
print("Unable to write image file - " + error.localizedDescription)
}
}
} else {
print("JPEG marker not found in source MPO file.")
}
} catch {
print("Unable to open source MPO file - " + error.localizedDescription)
}
我正在做的是首先在 while 循环中获取文件中的所有标记(因为可能有两个以上的嵌入图像),然后遍历这些标记并一个一个地提取它们。
在此迭代期间,我们必须处理最终标记的情况,因此使用了相当难看的三元条件运算符。
顺便说一下,这里使用了Swift 3的数据(而不是2.x风格的NSData)等