3

I've written an iOS plugin in swift for flutter which I have to pass two images to it. I'm trying to access an Image from my flutter assets via swift Code.

I've checked the documents and there is only some code in objective-c for my problem. https://flutter.dev/docs/development/ui/assets-and-images#asset-variants

The code given in flutter documents is this:

NSString* key = [registrar lookupKeyForAsset:@"icons/heart.png"];
NSString* path = [[NSBundle mainBundle] pathForResource:key 
ofType:nil];

I want to get a URL to the image which could be accessible if the code above was in swift.

Similar to Is there a way to access Flutter resources from native code?

Mohammad Amir
  • 352
  • 2
  • 12

1 Answers1

6

So I've found the answer in Swift and it goes like this:

public static func register(with registrar: FlutterPluginRegistrar) {
    let channel = FlutterMethodChannel(name: "image_process_plugin", binaryMessenger: registrar.messenger())
    let instance = SwiftImageProcessPlugin()
    registrar.addMethodCallDelegate(instance, channel: channel)
    //giving access to the plugin registrar and since it's static we can access variables from outer scope:
    instance.registrar = registrar
}

in the outer scope(in the class defined, which in my case was SwiftImageProcessPlugin) I defined the registrar variable used in the scope for the instance variable:

var registrar: FlutterPluginRegistrar? = nil

and then used it to access my asset Image like this:

let key = registrar?.lookupKey(forAsset: "Images/topImage.png")
let topPath = Bundle.main.path(forResource: key, ofType: nil)!
let topImage: UIImage = UIImage(contentsOfFile: topPath)!

Complete example code for this part is like this:

@available(iOS 10.0, *)
public class SwiftImageProcessPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
    let channel = FlutterMethodChannel(name: "image_process_plugin", binaryMessenger: registrar.messenger())
    let instance = SwiftImageProcessPlugin()
    registrar.addMethodCallDelegate(instance, channel: channel)
    //giving access to the plugin registrar and since it's static we can access variables from outer scope:
    instance.registrar = registrar
}

//defining registrar variable:
var registrar: FlutterPluginRegistrar? = nil

//handling the method:
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {

        //MARK: photo sharing
    if call.method == "preparePhotoForSharing2"{
        let values = call.arguments as! NSDictionary
        preparePhotoForSharing2(result: result, values: values)
    }

    else {
        result(FlutterMethodNotImplemented)
        return
    }
}

and the function:

@available(iOS 10.0, *)
func preparePhotoForSharing2(result: @escaping FlutterResult, values: NSDictionary){
    DispatchQueue.global(qos: .userInitiated).async {

        let srcPath: String = values["srcPath"] as! String
        let destPath: String = values["destPath"] as! String
        let assetImagePath: String = values["assetImagePath"] as! String



        // setting source image and getting height and width:
        let srcUrl: URL = URL(fileURLWithPath: srcPath)
        let srcImage: UIImage = UIImage(contentsOfFile: srcUrl.path)!

        let srcheightInPoints = srcImage.size.height
        let srcheightInPixels = srcheightInPoints * srcImage.scale

        let srcwidthInPoints = srcImage.size.width
        let srcwidthInPixels = srcwidthInPoints * srcImage.scale


        // setting asset image and getting height and width:
        let key = self.registrar?.lookupKey(forAsset: assetImagePath)
        let assetPath = Bundle.main.path(forResource: key, ofType: nil)!
        let assetImage: UIImage = UIImage(contentsOfFile: assetPath)!

        let assetheightInPoints = assetImage.size.height
        let assetheightInPixels = assetheightInPoints * assetImage.scale

        let assetwidthInPoints = assetImage.size.width
        let assetwidthInPixels = assetwidthInPoints * assetImage.scale

        let cWidth:Int = Int(assetwidthInPixels)
        let _1Height:Int = Int(Double(assetwidthInPixels / srcwidthInPixels) * Double(srcheightInPixels));
        let cHeight:Int = _1Height + Int(assetheightInPixels)


        //starting to process the image:
        let size = CGSize(width: cWidth, height: cHeight)
        UIGraphicsBeginImageContext(size)

        let areaSize = CGRect(x: 0, y: 0, width: cWidth, height: _1Height)
        srcImage.draw(in: areaSize)

        let areaSize2 = CGRect(x: 0, y: _1Height, width: cWidth, height: Int(assetheightInPixels))
        assetImage.draw(in: areaSize2, blendMode: .normal, alpha: 1)

        let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!

        let newUrl: URL = URL(fileURLWithPath: destPath)

        //saving the new image to the given address
        do{ try newImage.jpegData(compressionQuality: 1.0)?.write(to: newUrl)}
        catch  {
            print(Error.self)
            DispatchQueue.main.sync {
                result("0")
            }
        }
        // ending the image process
        UIGraphicsEndImageContext()
        DispatchQueue.main.sync {
            result(nil)
        }
Mohammad Amir
  • 352
  • 2
  • 12