ios/SpectrumKitSample/SpectrumKitSample-iOS/SpectrumController.swift (105 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
import Photos
import UIKit.UIImage
final class SpectrumController {
struct Options {
let encodeRequirement: EncodeRequirement?
let rotateRequirement: RotateRequirement?
let cropRequirement: CropRequirementProviding?
let resizeRequirement: ResizeRequirement?
let outputImagePixelSpecification: ImagePixelSpecification?
let configuration: Configuration?
let metadata: ImageMetadata?
func makeEncodeOptions() -> EncodeOptions {
return EncodeOptions(encodeRequirement: self.encodeRequirement!,
transformations: self.makeTransformations(),
metadata: self.metadata,
configuration: self.configuration,
outputPixelSpecificationRequirement: self.outputImagePixelSpecification)
}
func makeTranscodeOptions() -> TranscodeOptions {
return TranscodeOptions(encodeRequirement: self.encodeRequirement!,
transformations: self.makeTransformations(),
metadata: self.metadata,
configuration: self.configuration,
outputPixelSpecificationRequirement: self.outputImagePixelSpecification)
}
private func makeTransformations() -> Transformations {
return Transformations(resizeRequirement: self.resizeRequirement,
rotateRequirement: self.rotateRequirement,
cropRequirement: self.cropRequirement)
}
}
typealias Completion = (Result<ImageRepresentation>) -> Void
// MARK: Public Methods
static func transcode(options: Options,
source: ImageSource,
inputType: IOType,
outputType: IOType,
completion: @escaping Completion) {
DispatchQueue.global().async {
let result: Result<ImageRepresentation>
do {
let imageRepresentation = try SpectrumController.makeTranscodeResult(options: options,
source: source,
inputType: inputType,
outputType: outputType)
result = .success(imageRepresentation)
} catch {
SpectrumController.printError(error)
result = .error(error)
}
DispatchQueue.main.async {
completion(result)
}
}
}
// MARK: Private Methods
private static func makeTranscodeResult(options: Options,
source: ImageSource,
inputType: IOType,
outputType: IOType) throws -> ImageRepresentation {
let dateStarted = Date()
var error: NSError?
var resultData: ResultData?
switch (inputType, outputType) {
case (.bitmap, .file):
resultData = Spectrum.shared.encodeImage(source.image,
options: options.makeEncodeOptions(),
error: &error)
case (.file, .file):
if let sourceUrl = source.url {
resultData = Spectrum.shared.transcodeImage(fromFileAt: sourceUrl,
options: options.makeTranscodeOptions(),
error: &error)
} else {
throw Error.noImageInInfo
}
case (_, .bitmap):
// This will be tacked as soon as FSPSpectrum supports decoding / transforming.
throw Error.unsupportedBitmapOutput
}
if let resultData = resultData, let data = resultData.data, resultData.result.didSucceed {
SpectrumController.printResult(resultData, dateStarted: dateStarted)
return .bytes(data)
} else {
throw error ?? Error.unknown
}
}
private static func printResult(_ resultData: ResultData, dateStarted: Date) {
print("# Operation completed")
print("# Operation duration: \(-dateStarted.timeIntervalSinceNow)")
print("# Did succeed: \(resultData.result.didSucceed)")
print("# Rule: \(resultData.result.ruleName ?? "none")")
if
let data = resultData.data,
let source = CGImageSourceCreateWithData(data as CFData, nil),
let properties = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) {
print("# Exif: \(properties)")
}
}
private static func printError(_ error: Swift.Error) {
print("# Operation failed")
print("# Error: \(error.localizedDescription)")
let nsError = error as NSError
if nsError.userInfo.isEmpty == false {
print("# Error Info: \(nsError.userInfo)")
}
}
}