added other image metadata

This commit is contained in:
Thorsten Claus 2021-01-08 19:06:19 +01:00
parent a51aa1ef97
commit 25cd72c5f4
10 changed files with 309 additions and 70 deletions

View File

@ -59,15 +59,8 @@ public class FileHandling {
}
/// Unpack image metadata after a file was opened
public static func metaData(rawdata: UnsafeMutablePointer<libraw_data_t>) {
// To be done
}
/// Returns image paraneters from opened file
public static func imageParameters(rawdata : UnsafeMutablePointer<libraw_data_t> ) -> ImageParameters {
return ImageParameters(iparams: rawdata.pointee.idata)
public static func metaData(rawdata: UnsafeMutablePointer<libraw_data_t>) -> MetaDataInformation {
return MetaDataInformation(rawdata)
}
/// Unpacked Images must be released at end of processing

View File

@ -0,0 +1,78 @@
//
// ImageOtherInformation.swift
// SwiftLibRaw
//
// Created by Thorsten Claus on 08.01.21.
//
import Foundation
import libraw
/// Other image information like ISO, Aperture, Shutter Time
public struct ImageOtherInformation {
public let analogBalance : [Float]
/// ISO sensitivity.
public let iso_speed : Float
/// Shutter speed in seconds
public let shutter : Float
/// Aperture
public let aperture: Float
public let description: String
///Focal length
public let focal_length: Float
/// Date of shooting.
public let shooted_at: Date
/// Serial number of image.
public let shot_order : Int
/// GPS data (unparsed block, to write to output as is).
// public let unsigned gpsdata[32]
/// Parsed GPS-data: longitude/latitude/altitude and time stamp.
// libraw_gps_info_t parsed_gps;
// char desc[512];
/// Author of image.
public let artist : String
init(otherInformation: libraw_imgother_t) {
analogBalance = withUnsafePointer(to: otherInformation.analogbalance){
$0.withMemoryRebound(to: Float.self, capacity: 36) {
return [Float](UnsafeBufferPointer(start: $0, count: MemoryLayout.size(ofValue: otherInformation.analogbalance)))
}
}
aperture = otherInformation.aperture
artist = withUnsafePointer(to: otherInformation.artist) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
String(cString: $0)
}
}
description = withUnsafePointer(to: otherInformation.desc) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
String(cString: $0)
}
}
focal_length = otherInformation.focal_len
// TODO: Implement detailed GPS Data
// otherInformation.parsed_gps
// otherInformation.gpsdata
iso_speed = Float(otherInformation.iso_speed)
shot_order = Int(otherInformation.shot_order)
shutter = otherInformation.shutter
shooted_at = Date(timeIntervalSince1970: Double(otherInformation.timestamp))
}
}

View File

@ -5,33 +5,34 @@
// Created by Thorsten Claus on 07.01.21.
//
import SwiftUI
import Foundation
import libraw
/// Meta Data about Camera and Image
public struct ImageParameters {
public var camera_manufacturer : String?
/// There is a huge number of identical cameras sold under different names, depending on the market (e.g. multiple Panasonic or Canon models) and even some identical cameras sold under different brands (Panasonic -> Leica, Sony -> Hasselblad). normalized_make contains primary vendor name (e.g. Panasonic for Leica re-branded cameras).
public var camera_normalized_manufacturer : String?
public var camera_model : String?
public let camera_manufacturer : String
/// There is a huge number of identical cameras sold under different names, depending on the market (e.g. multiple Panasonic or Canon models) and even some identical cameras sold under different brands (Panasonic -> Leica, Sony -> Hasselblad). normalized_make contains primary vendor name (e.g. Panasonic for Leica re-branded cameras).
public let camera_normalized_manufacturer : String
public let camera_model : String
/// Primary camera model name.
public var camera_normalized_model : String?
public let camera_normalized_model : String
/// Softwary name/version (mostly for DNG files, to distinguish in-camera DNGs from Adobe DNG Converter produced ones).
public var software : String?
public let software : String
/// Number of RAW images in file (0 means that the file has not been recognized).
public var raw_count : Int = 0
public let raw_count : Int
/// Number of colors in the file
public var number_of_colors : Int
public let number_of_colors : Int
/// Description of colors numbered from 0 to 3 (RGBG,RGBE,GMCY, or GBTG)
public var color_description : String
public let color_description : String
/// Nonzero for Sigma Foveon images
public var isFOV_on : Int
public let isFOV_on : Int
/*
Bit mask describing the order of color pixels in the matrix (0 for full-color images). 32 bits of this field describe 16 pixels (8 rows with two pixels in each, from left to right and from top to bottom). Each two bits have values 0 to 3, which correspond to four possible colors. Convenient work with this field is ensured by the COLOR(row,column) function, which returns the number of the active color for a given pixel.
@ -49,61 +50,61 @@ public struct ImageParameters {
public var xtrans_abs_6x6 : [UInt8] = Array(repeating: 0, count: 6 * 6)
init(iparams : libraw_iparams_t) {
init(parameters: libraw_iparams_t) {
camera_manufacturer = withUnsafePointer(to: iparams.make) {
camera_manufacturer = withUnsafePointer(to: parameters.make) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
String(cString: $0)
}
}
camera_normalized_manufacturer = withUnsafePointer(to: iparams.normalized_make) {
camera_normalized_manufacturer = withUnsafePointer(to: parameters.normalized_make) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
String(cString: $0)
}
}
camera_model = withUnsafePointer(to: iparams.model) {
camera_model = withUnsafePointer(to: parameters.model) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
String(cString: $0)
}
}
camera_normalized_model = withUnsafePointer(to: iparams.normalized_model) {
camera_normalized_model = withUnsafePointer(to: parameters.normalized_model) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
String(cString: $0)
}
}
software = withUnsafePointer(to: iparams.software) {
software = withUnsafePointer(to: parameters.software) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
String(cString: $0)
}
}
raw_count = Int(iparams.raw_count)
raw_count = Int(parameters.raw_count)
number_of_colors = Int(iparams.colors)
filters = Int(iparams.filters)
number_of_colors = Int(parameters.colors)
filters = Int(parameters.filters)
color_description = withUnsafePointer(to: iparams.cdesc) {
color_description = withUnsafePointer(to: parameters.cdesc) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
String(cString: $0)
}
}
isFOV_on = Int(iparams.is_foveon)
isFOV_on = Int(parameters.is_foveon)
// 6x6 matrix
xtrans_6x6 = withUnsafePointer(to: iparams.xtrans){
xtrans_6x6 = withUnsafePointer(to: parameters.xtrans){
$0.withMemoryRebound(to: UInt8.self, capacity: 36) {
return [UInt8](UnsafeBufferPointer(start: $0, count: MemoryLayout.size(ofValue: iparams.xtrans)))
return [UInt8](UnsafeBufferPointer(start: $0, count: MemoryLayout.size(ofValue: parameters.xtrans)))
}
}
// 6x6 Matrix
xtrans_abs_6x6 = withUnsafePointer(to: iparams.xtrans_abs){
xtrans_abs_6x6 = withUnsafePointer(to: parameters.xtrans_abs){
$0.withMemoryRebound(to: UInt8.self, capacity: 36) {
return [UInt8](UnsafeBufferPointer(start: $0, count: MemoryLayout.size(ofValue: iparams.xtrans_abs)))
return [UInt8](UnsafeBufferPointer(start: $0, count: MemoryLayout.size(ofValue: parameters.xtrans_abs)))
}
}

View File

@ -0,0 +1,53 @@
//
// ImageSizes.swift
// SwiftLibRaw
//
// Created by Thorsten Claus on 07.01.21.
//
import Foundation
import libraw
/// The structure describes the geometrical parameters of the image.
public struct ImageSizes {
/// Full size of RAW image (including the frame) in pixels.
public let heigth, width : UInt16
/// Size of visible ("meaningful") part of the image (without the frame).
public let raw_heigth, raw_width : UInt16
/// Coordinates of the top left corner of the frame (the second corner is calculated from the full size of the image and size of its visible part)
public let top_margin, left_margin : UInt16
/// Size of the output image (may differ from height/width for cameras that require image rotation or have non-square pixels).
public let iheight, iwidth : UInt16
/// Full size of raw data row in bytes
public let raw_pitch : UInt32
/// Pixel width/height ratio. If it is not unity, scaling of the image along one of the axes is required during output.
public let pixel_aspect : Double
/// Image orientation (0 if does not require rotation; 3 if requires 180-deg rotation; 5 if 90 deg counterclockwise, 6 if 90 deg clockwise).
public let flip: Int
public init(sizes: libraw_image_sizes_t) {
heigth = sizes.height
width = sizes.width
raw_heigth = sizes.raw_width
raw_width = sizes.raw_height
top_margin = sizes.top_margin
left_margin = sizes.left_margin
iheight = sizes.iheight
iwidth = sizes.iwidth
raw_pitch = sizes.raw_pitch
pixel_aspect = sizes.pixel_aspect
flip = Int(sizes.flip) // TODO: Build as enum
}
}

View File

@ -0,0 +1,17 @@
//
// Lenses.swift
// SwiftLibRaw
//
// Created by Thorsten Claus on 07.01.21.
//
import Foundation
import libraw
/// Lensinfo
public struct Lense {
init(lensInfo: libraw_lensinfo_t) {
}
}

View File

@ -0,0 +1,26 @@
//
// MetaDataInformation.swift
// SwiftLibRaw
//
// Created by Thorsten Claus on 07.01.21.
//
import Foundation
import libraw
public struct MetaDataInformation {
public let lensinfo : Lense
public let sizes : ImageSizes
public let parameters : ImageParameters
public let otherInformation : ImageOtherInformation
init(_ rawdata: UnsafeMutablePointer<libraw_data_t>) {
let data = rawdata.pointee
lensinfo = Lense(lensInfo: data.lens)
sizes = ImageSizes(sizes: data.sizes)
parameters = ImageParameters(parameters: data.idata)
otherInformation = ImageOtherInformation(otherInformation: data.other)
}
}

View File

@ -13,14 +13,7 @@ import libraw
class TestFileHandling : XCTestCase {
// During Test its not the main bundle
var testfilePath : URL! {
get {
let bundle = Bundle.init(for: TestFileHandling.self)
return bundle.url(forResource: "Moon", withExtension: "RAF")!
}
}
func testOpenFile_notFound() {
let rawdata = libraw_init(0)!;
let fileOpenresult = FileHandling.openFile(fileUrl: URL(fileURLWithPath: ""),rawdata: rawdata)
@ -45,31 +38,5 @@ class TestFileHandling : XCTestCase {
let unpackResult = FileHandling.unpackFile(rawdata: rawdata)
XCTAssertEqual(unpackResult, LIBRAW_SUCCESS)
}
func testgetImageParameters() {
let rawdata = libraw_init(0)!;
let fileOpenresult = FileHandling.openFile(fileUrl: testfilePath,rawdata: rawdata)
XCTAssertEqual(fileOpenresult, LIBRAW_SUCCESS)
let imageData : ImageParameters = FileHandling.imageParameters(rawdata: rawdata)
XCTAssertNotNil(imageData)
XCTAssertEqual(imageData.camera_manufacturer, "Fujifilm")
XCTAssertEqual(imageData.camera_model, "X-E2")
XCTAssertNotNil(imageData.camera_normalized_model)
XCTAssertNotNil(imageData.camera_normalized_manufacturer)
XCTAssertTrue(imageData.number_of_colors > 0)
XCTAssertTrue(imageData.raw_count > 0) // 0 means file could not be read
XCTAssertNotNil(imageData.color_description)
print("Camera: \(imageData.camera_manufacturer!) \(imageData.camera_model!)")
print("Software: \(imageData.software!)")
print("Filter: \(imageData.filters)")
print("Number of colors: \(imageData.number_of_colors)")
print("Color description: \(imageData.color_description)")
print("Fuji Xtrans: \(imageData.xtrans_6x6)")
print("Fuji Xtrans (Sensor-Edge relative): \(imageData.xtrans_abs_6x6)")
}
}

View File

@ -0,0 +1,88 @@
//
// TestMetadata.swift
// SwiftLibRawTests
//
// Created by Thorsten Claus on 08.01.21.
//
import XCTest
import Foundation
import libraw
class TestMetadata: XCTestCase {
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
func testgetImageParameters() {
let rawdata = libraw_init(0)!;
let fileOpenresult = FileHandling.openFile(fileUrl: testfilePath,rawdata: rawdata)
XCTAssertEqual(fileOpenresult, LIBRAW_SUCCESS)
let imageData : ImageParameters = ImageParameters(parameters: rawdata.pointee.idata)
XCTAssertNotNil(imageData)
XCTAssertEqual(imageData.camera_manufacturer, "Fujifilm")
XCTAssertEqual(imageData.camera_model, "X-E2")
XCTAssertNotNil(imageData.camera_normalized_model)
XCTAssertNotNil(imageData.camera_normalized_manufacturer)
XCTAssertTrue(imageData.number_of_colors > 0)
XCTAssertTrue(imageData.raw_count > 0) // 0 means file could not be read
XCTAssertEqual(imageData.color_description, "RGBG")
print("Camera: \(imageData.camera_manufacturer) \(imageData.camera_model)")
print("Software: \(imageData.software)")
print("Filter: \(imageData.filters)")
print("Number of colors: \(imageData.number_of_colors)")
print("Color description: \(imageData.color_description)")
print("Fuji Xtrans: \(imageData.xtrans_6x6)")
print("Fuji Xtrans (Sensor-Edge relative): \(imageData.xtrans_abs_6x6)")
}
func testImageSizes() {
let rawdata = libraw_init(0)!;
let fileOpenresult = FileHandling.openFile(fileUrl: testfilePath,rawdata: rawdata)
XCTAssertEqual(fileOpenresult, LIBRAW_SUCCESS)
let imageSizes : ImageSizes = ImageSizes(sizes: rawdata.pointee.sizes)
XCTAssertNotNil(imageSizes)
XCTAssertEqual(imageSizes.heigth, 3296)
XCTAssertEqual(imageSizes.width, 4934)
XCTAssertEqual(imageSizes.raw_heigth, 4992)
XCTAssertEqual(imageSizes.raw_width, 3296)
XCTAssertEqual(imageSizes.top_margin, 0)
XCTAssertEqual(imageSizes.left_margin, 6)
XCTAssertEqual(imageSizes.iheight, 3296)
XCTAssertEqual(imageSizes.iwidth, 4934)
print("Image size: w/h \(imageSizes.width)x\(imageSizes.heigth)")
}
func testMetaInformation() {
let rawdata = libraw_init(0)!;
let fileOpenresult = FileHandling.openFile(fileUrl: testfilePath,rawdata: rawdata)
XCTAssertEqual(fileOpenresult, LIBRAW_SUCCESS)
let metaInformation = MetaDataInformation(rawdata)
XCTAssertNotNil(metaInformation)
XCTAssertNotNil(metaInformation.parameters)
XCTAssertNotNil(metaInformation.sizes)
XCTAssertNotNil(metaInformation.lensinfo)
XCTAssertNotNil(metaInformation.otherInformation)
}
func testPerformanceExample() throws {
// This is an example of a performance test case.
self.measure {
// Put the code you want to measure the time of here.
}
}
}

View File

@ -0,0 +1,16 @@
//
// TestSetup.swift
// SwiftLibRawTests
//
// Created by Thorsten Claus on 08.01.21.
//
import Foundation
// During Test its not the main bundle
var testfilePath : URL! {
get {
let bundle = Bundle.init(for: TestFileHandling.self)
return bundle.url(forResource: "Moon", withExtension: "RAF")!
}
}