我的应用程序允许用户从相机胶卷中多选图像并对这些图像应用编辑。但是,它会提示用户对每个图像编辑的权限。编辑用户图像时是否可以只显示一个权限对话框?如果是,我该如何将我的编辑分组为一个权限?这是我的应用程序的截图。
我发现应用程序商店上的另一个应用程序只需一个权限提示即可批量删除照片。这是该应用程序的屏幕截图。有没有人知道这是否可以“修改”而不仅仅是“删除”?
以下是我修改每项资产的代码。
func selectImageFromCameraRoll() {
let newImagePicker = BSImagePickerViewController()
newImagePicker.doneButton = UIBarButtonItem(title: "Stamp", style: UIBarButtonItemStyle.done, target: self, action: nil)
bs_presentImagePickerController(newImagePicker, animated: true,
select: { (asset: PHAsset) -> Void in
print("Selected")
}, deselect: { (asset: PHAsset) -> Void in
print("Deselected")
}, cancel: { (assets: [PHAsset]) -> Void in
print("Cancel")
}, finish: { (assets: [PHAsset]) -> Void in
for asset in assets {
self.saveUpdatedAsset(asset: asset)
}
print("Finished")
}, completion: nil)
}
func saveUpdatedAsset(asset: PHAsset) {
let options = PHContentEditingInputRequestOptions()
options.canHandleAdjustmentData = { adjustmentData in
print("here")
return adjustmentData.formatIdentifier == self.myIdentifier
}
var id: PHContentEditingInputRequestID = 0
id = asset.requestContentEditingInput(with: options) {
input, info in
guard let input = input else {
asset.cancelContentEditingInputRequest(id)
return
}
let act = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
act.backgroundColor = .darkGray
act.layer.cornerRadius = 3
act.center = self.view.center
self.view.addSubview(act)
act.startAnimating()
DispatchQueue.global(qos: .userInitiated).async {
let inurl = input.fullSizeImageURL!
let inorient = input.fullSizeImageOrientation
let output = PHContentEditingOutput(contentEditingInput: input)
let outurl = output.renderedContentURL
guard var ci = CIImage(contentsOf: inurl)?.applyingOrientation(inorient) else {
act.removeFromSuperview()
let ac = UIAlertController(title: "Save error", message: "Failed to edit image ", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
self.present(ac, animated: true)
return
}
let space = ci.colorSpace!
let uim = UIImage(ciImage: ci)
let width = uim.size.width
let height = uim.size.height
let location = Locations(rawValue: UserDefaults.standard.value(forKey: "location") as! String)!
var point = CGPoint(x: 0, y: 0)
switch location {
case .topLeft:
point = CGPoint(x: 30, y: 50)
case .topRight:
point = CGPoint(x: width - 30, y: 50)
case .bottomLeft:
point = CGPoint(x: 30, y: height - 50)
case .bottomRight:
point = CGPoint(x: width - 30, y: height - 50)
case .center:
point = CGPoint(x: width / 2, y: height / 2)
case .topCenter:
point = CGPoint(x: width / 2, y: 50)
case .bottomCenter:
point = CGPoint(x: width / 2, y: height - 50)
}
let savedFormat = UserDefaults.standard.value(forKey: "format") as! String
var date = Date()
if !self.currentDateBool {
date = UserDefaults.standard.value(forKey: "selectedDate") as! Date
}
let timestampText = getFormattedDateFromFormatType(formatType: savedFormat, date: date) as NSString
let timestampImage = self.textToImage(drawText: timestampText, inImage: uim, atPoint: point)
ci = CIImage(image: timestampImage)!
try! CIContext().writeJPEGRepresentation(of: ci, to: outurl, colorSpace: space)
let data = NSKeyedArchiver.archivedData(withRootObject: timestampText)
output.adjustmentData = PHAdjustmentData(
formatIdentifier: self.myIdentifier, formatVersion: "1.0", data: data)
PHPhotoLibrary.shared().performChanges({
print("finishing")
typealias Req = PHAssetChangeRequest
let req = Req(for: asset)
req.contentEditingOutput = output
}) { ok, err in
DispatchQueue.main.async {
act.removeFromSuperview()
print("in completion handler")
if ok {
print("changed!")
} else {
print("phasset change request error: \(err)")
}
}
}
}
}
}
答案 0 :(得分:1)
来自PHPhotoLibrary
的文档:
注意
对于
performChanges:completionHandler:
或performChangesAndWait:error:
方法的每次调用,照片会显示一条警告,要求用户允许编辑照片库的内容。如果您的应用需要一次提交多个更改,请将它们合并到一个更改块中。...
要编辑多个现有照片的内容,请创建多个
PHAssetChangeRequest
个对象,并将每个contentEditingOutput
属性设置为独立的PHContentEditingOutput
对象。
答案 1 :(得分:0)
@ dave-weston是正确的-您需要将这些请求合并到一个PHPhotoLibrary.performChanges()
块中。
问题是如何—我自己才弄清楚这一点。我是菜鸟,所以如果有更好的方法可以做到这一点,请告诉我。
// Create a dictionary with PHAsset as keys and PHContentEditingOutput as values.
var changeDict: [PHAsset: PHContentEditingOutput] = [:]
// Use two local variables to to the counting work
var _i = 0
let _n = <#YOUR_ARRAY_OF_ASSETS#>.count
// Get dict and perform changes
<#YOUR_ARRAY_OF_ASSETS#>.forEach { (asset) in
asset.requestContentEditingInput(with: nil) { (optionalInput, info) in
guard let input = optionalInput else {return}
guard let url = input.fullSizeImageURL else {return}
// perform the editing operation, which applies a noir filter in this case
let ciImage = CIImage(contentsOf: url, options: nil)!
.oriented(forExifOrientation: input.fullSizeImageOrientation)
// write to output location
let output = PHContentEditingOutput(contentEditingInput: input)
let adjustmentData = PHAdjustmentData(formatIdentifier: "s",
formatVersion: "1.2",
data: "CIPhotoEffectTransfer".data(using: .utf8)!)
output.adjustmentData = adjustmentData
if let data = <#YOUR_CIIMAGE_TO_DATA_METHOD#> {
do {
try data.write(to: output.renderedContentURL, options: .atomic)
} catch {
fatalError("Cannot write ciImage to disk.")
}
changeDict[asset] = output
}
// Count + 1
_i += 1
// Check if this is the last PHAsset to process. If so, we commit all the changes.
if _i >= _n {
// Commit the changes
PHPhotoLibrary.shared().performChanges({
for (asset, output) in changeDict {
let request = PHAssetChangeRequest(for: asset)
request.contentEditingOutput = output
}
}, completionHandler: { (success, error) in
if success {
} else {
print("Error Saving Edits:", error?.localizedDescription ?? "Unknown Error")
}
})
}
}
}
这种方法存在一些问题,但目前对我来说还行。同样,请让我知道是否有更好的方法,可能使用Grand Central Dispatch为处理流程增加了更多控制权...目前,它仅计算所有已处理照片的数量,而无法控制照片的顺序得到处理。
答案 2 :(得分:0)
寻找相同的问题比我以前想象的要容易得多
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.deleteAssets(your_array_of_assets as NSFastEnumeration)
}) { (success, error) in }