修改多张照片时只有一个iOS权限对话框

时间:2017-02-21 21:00:13

标签: ios swift photosframework

我的应用程序允许用户从相机胶卷中多选图像并对这些图像应用编辑。但是,它会提示用户对每个图像编辑的权限。编辑用户图像时是否可以只显示一个权限对话框?如果是,我该如何将我的编辑分组为一个权限?这是我的应用程序的截图。

Single Modify

我发现应用程序商店上的另一个应用程序只需一个权限提示即可批量删除照片。这是该应用程序的屏幕截图。有没有人知道这是否可以“修改”而不仅仅是“删除”?

Multiple Delete

以下是我修改每项资产的代码。

  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)")
            }
          }
        }
      }
    }
}

3 个答案:

答案 0 :(得分:1)

来自PHPhotoLibrary的文档:

  

注意

     

对于performChanges:completionHandler:performChangesAndWait:error:方法的每次调用,照片会显示一条警告,要求用户允许编辑照片库的内容。如果您的应用需要一次提交多个更改,请将它们合并到一个更改块中。

     

...

     

要编辑多个现有照片的内容,请创建多个PHAssetChangeRequest个对象,并将每个contentEditingOutput属性设置为独立的PHContentEditingOutput对象。

https://developer.apple.com/reference/photos/phphotolibrary

答案 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为处理流程增加了更多控制权...目前,它仅计算所有已处理照片的数量,而无法控制照片的顺序得到处理。

enter image description here

答案 2 :(得分:0)

寻找相同的问题比我以前想象的要容易得多

    PHPhotoLibrary.shared().performChanges({
        PHAssetChangeRequest.deleteAssets(your_array_of_assets as NSFastEnumeration)
    }) { (success, error) in }