【问题标题】:Flutter image_picker choose videoFlutter image_picker 选择视频
【发布时间】:2017-11-22 12:14:33
【问题描述】:

我已成功使用 Flutter 插件 Image_picker 选择图像,以便我可以将它们用于上传、显示等...我想知道是否有人对如何修改此插件以也查看视频并允许他们有任何指导被选择并用于上传等......

如果有人对如何继续或示例代码有指导,请寻找 iOS 和 Android 修改。我已经取得了一些进展,但仍然需要让相机保存视频并能够呈现。到目前为止,我将发布代码更改。我让它选择一个视频,但它不会显示回应用程序。

// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

@import UIKit;
#import <MobileCoreServices/MobileCoreServices.h>

#import "ImagePickerPlugin.h"

@interface ImagePickerPlugin ()<UINavigationControllerDelegate, UIImagePickerControllerDelegate>
@end

static const int SOURCE_ASK_USER = 0;
static const int SOURCE_CAMERA = 1;
static const int SOURCE_GALLERY = 2;

@implementation ImagePickerPlugin {
  FlutterResult _result;
  NSDictionary *_arguments;
  UIImagePickerController *_imagePickerController;
  UIViewController *_viewController;
}

+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
  FlutterMethodChannel *channel =
      [FlutterMethodChannel methodChannelWithName:@"image_picker"
                                  binaryMessenger:[registrar messenger]];
  UIViewController *viewController =
      [UIApplication sharedApplication].delegate.window.rootViewController;
  ImagePickerPlugin *instance = [[ImagePickerPlugin alloc] initWithViewController:viewController];
  [registrar addMethodCallDelegate:instance channel:channel];
}

- (instancetype)initWithViewController:(UIViewController *)viewController {
  self = [super init];
  if (self) {
    _viewController = viewController;
    _imagePickerController = [[UIImagePickerController alloc] init];
  }
  return self;
}

- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
  if (_result) {
    _result([FlutterError errorWithCode:@"multiple_request"
                                message:@"Cancelled by a second request"
                                details:nil]);
    _result = nil;
  }

  if ([@"pickImage" isEqualToString:call.method]) {
    _imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext;
    _imagePickerController.delegate = self;

    _result = result;
    _arguments = call.arguments;

    int imageSource = [[_arguments objectForKey:@"source"] intValue];

    switch (imageSource) {
      case SOURCE_ASK_USER:
        [self showImageSourceSelector];
        break;
      case SOURCE_CAMERA:
        [self showCamera];
        break;
      case SOURCE_GALLERY:
        [self showPhotoLibrary];
        break;
      default:
        result([FlutterError errorWithCode:@"invalid_source"
                                   message:@"Invalid image source."
                                   details:nil]);
        break;
    }
  } else {
    result(FlutterMethodNotImplemented);
  }
}

- (void)showImageSourceSelector {
  UIAlertControllerStyle style = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad
                                     ? UIAlertControllerStyleAlert
                                     : UIAlertControllerStyleActionSheet;

  UIAlertController *alert =
      [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:style];
  UIAlertAction *camera = [UIAlertAction actionWithTitle:@"Take Photo"
                                                   style:UIAlertActionStyleDefault
                                                 handler:^(UIAlertAction *action) {
                                                   [self showCamera];
                                                 }];
  UIAlertAction *library = [UIAlertAction actionWithTitle:@"Choose Photo"
                                                    style:UIAlertActionStyleDefault
                                                  handler:^(UIAlertAction *action) {
                                                    [self showPhotoLibrary];
                                                  }];


  UIAlertAction *cancel =
      [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
  [alert addAction:camera];
  [alert addAction:library];
  [alert addAction:cancel];
  [_viewController presentViewController:alert animated:YES completion:nil];
}

- (void)showCamera {
  // Camera is not available on simulators
  if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
    _imagePickerController.sourceType = UIImagePickerControllerCameraCaptureModeVideo;
    [_viewController presentViewController:_imagePickerController animated:YES completion:nil];
  } else {
    [[[UIAlertView alloc] initWithTitle:@"Error"
                                message:@"Camera not available."
                               delegate:nil
                      cancelButtonTitle:@"OK"
                      otherButtonTitles:nil] show];
  }
}

- (void)showPhotoLibrary {
  // No need to check if SourceType is available. It always is.
  //_imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    _imagePickerController.mediaTypes =[UIImagePickerController availableMediaTypesForSourceType:_imagePickerController.sourceType];
  [_viewController presentViewController:_imagePickerController animated:YES completion:nil];
}

- (void)imagePickerController:(UIImagePickerController *)picker
    didFinishPickingMediaWithInfo:(NSDictionary<NSString *, id> *)info {
  [_imagePickerController dismissViewControllerAnimated:YES completion:nil];
  UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage];
  NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
  if (image == nil) {
    image = [info objectForKey:UIImagePickerControllerOriginalImage];
  } else {
      image = [self normalizedImage:image];
  }
  if (videoURL == nil) {

  } else {
      //image = videoURL;
  }


  NSNumber *maxWidth = [_arguments objectForKey:@"maxWidth"];
  NSNumber *maxHeight = [_arguments objectForKey:@"maxHeight"];

  if (maxWidth != (id)[NSNull null] || maxHeight != (id)[NSNull null]) {
    image = [self scaledImage:image maxWidth:maxWidth maxHeight:maxHeight];
  }

  NSData *data = UIImageJPEGRepresentation(image, 1.0);
  NSString *tmpDirectory = NSTemporaryDirectory();
  NSString *guid = [[NSProcessInfo processInfo] globallyUniqueString];
  // TODO(jackson): Using the cache directory might be better than temporary
  // directory.
  NSString *tmpFile = [NSString stringWithFormat:@"image_picker_%@.jpg", guid];
  NSString *tmpPath = [tmpDirectory stringByAppendingPathComponent:tmpFile];
  if ([[NSFileManager defaultManager] createFileAtPath:tmpPath contents:data attributes:nil]) {
    _result(tmpPath);
  } else {
    _result([FlutterError errorWithCode:@"create_error"
                                message:@"Temporary file could not be created"
                                details:nil]);
  }
  _result = nil;
  _arguments = nil;
}

// The way we save images to the tmp dir currently throws away all EXIF data
// (including the orientation of the image). That means, pics taken in portrait
// will not be orientated correctly as is. To avoid that, we rotate the actual
// image data.
// TODO(goderbauer): investigate how to preserve EXIF data.
- (UIImage *)normalizedImage:(UIImage *)image {
  if (image.imageOrientation == UIImageOrientationUp) return image;

  UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
  [image drawInRect:(CGRect){0, 0, image.size}];
  UIImage *normalizedImage = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();
  return normalizedImage;
}


- (UIImage *)scaledImage:(UIImage *)image
                maxWidth:(NSNumber *)maxWidth
               maxHeight:(NSNumber *)maxHeight {
  double originalWidth = image.size.width;
  double originalHeight = image.size.height;

  bool hasMaxWidth = maxWidth != (id)[NSNull null];
  bool hasMaxHeight = maxHeight != (id)[NSNull null];

  double width = hasMaxWidth ? MIN([maxWidth doubleValue], originalWidth) : originalWidth;
  double height = hasMaxHeight ? MIN([maxHeight doubleValue], originalHeight) : originalHeight;

  bool shouldDownscaleWidth = hasMaxWidth && [maxWidth doubleValue] < originalWidth;
  bool shouldDownscaleHeight = hasMaxHeight && [maxHeight doubleValue] < originalHeight;
  bool shouldDownscale = shouldDownscaleWidth || shouldDownscaleHeight;

  if (shouldDownscale) {
    double downscaledWidth = (height / originalHeight) * originalWidth;
    double downscaledHeight = (width / originalWidth) * originalHeight;

    if (width < height) {
      if (!hasMaxWidth) {
        width = downscaledWidth;
      } else {
        height = downscaledHeight;
      }
    } else if (height < width) {
      if (!hasMaxHeight) {
        height = downscaledHeight;
      } else {
        width = downscaledWidth;
      }
    } else {
      if (originalWidth < originalHeight) {
        width = downscaledWidth;
      } else if (originalHeight < originalWidth) {
        height = downscaledHeight;
      }
    }
  }

  UIGraphicsBeginImageContextWithOptions(CGSizeMake(width, height), NO, 1.0);
  [image drawInRect:CGRectMake(0, 0, width, height)];

  UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();

  return scaledImage;
}

@end

谢谢

【问题讨论】:

    标签: flutter


    【解决方案1】:

    这是我已经完成的IOS代码,如果有人想提供帮助,我还在Android上工作,我会发布我目前的位置。此代码替换了 IOS 文件夹的 .m 文件中的内容,无需进行其他更改即可拾取和捕获视频以及图像。您必须弄清楚如何在您的应用程序中显示选定的视频/图像,但这就是您想要处理的方式。如果您想协助完成他的 Android 方面,请再次告诉我。

    @import UIKit;
    #import <MobileCoreServices/MobileCoreServices.h>
    
    #import "MediaPickerPlugin.h"
    
    @interface MediaPickerPlugin ()<UINavigationControllerDelegate, UIImagePickerControllerDelegate>
    @end
    
    static const int SOURCE_ASK_USER = 0;
    //static const int SOURCE_CAMERA = 0;
    //static const int SOURCE_GALLERY = 0;
    
    @implementation MediaPickerPlugin {
        FlutterResult _result;
        NSDictionary *_arguments;
        UIImagePickerController *_imagePickerController;
        UIViewController *_viewController;
    }
    
    + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
        FlutterMethodChannel *channel =
        [FlutterMethodChannel methodChannelWithName:@"media_picker"
                                    binaryMessenger:[registrar messenger]];
        UIViewController *viewController =
            [UIApplication sharedApplication].delegate.window.rootViewController;
        MediaPickerPlugin *instance =
            [[MediaPickerPlugin alloc] initWithViewController:viewController];
        [registrar addMethodCallDelegate:instance channel:channel];
    }
    
    - (instancetype)initWithViewController:(UIViewController *)viewController {
        self = [super init];
        if (self) {
          _viewController = viewController;
          _imagePickerController = [[UIImagePickerController alloc] init];
        }
        return self;
    }
    
    - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
      if (_result) {
        _result([FlutterError errorWithCode:@"multiple_request"
                                    message:@"Cancelled by a second request"
                                    details:nil]);
        _result = nil;
          _arguments = nil;
    }
    
    if ([@"pickImage" isEqualToString:call.method]) {
      _imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext;
      _imagePickerController.delegate = self;
    
      _result = result;
      _arguments = call.arguments;
    
      int imageSource = [[_arguments objectForKey:@"source"] intValue];
    
        switch (imageSource) {
            case SOURCE_ASK_USER:
                [self showImageSourceSelector];
                break;
            default:
                result([FlutterError errorWithCode:@"invalid_source"
                                           message:@"Invalid image source."
                                           details:nil]);
                break;
            }
        } else {
          result(FlutterMethodNotImplemented);
        }
    }
    
    - (void)showImageSourceSelector {
        UIAlertControllerStyle style = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad
                                            ? UIAlertControllerStyleAlert
                                            : UIAlertControllerStyleActionSheet;
    
        UIAlertController *alert =
            [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:style];
        UIAlertAction *camera = [UIAlertAction actionWithTitle:@"Camera"
                                                         style:UIAlertActionStyleDefault
                                                       handler:^(UIAlertAction *action) {
                                                           [self showCamera];
                                                       }];
        UIAlertAction *library = [UIAlertAction actionWithTitle:@"Gallery"
                                                          style:UIAlertActionStyleDefault
                                                        handler:^(UIAlertAction *action) {
                                                            [self showPhotoLibrary];
                                                        }];
        UIAlertAction *cancel =
        [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
        [alert addAction:camera];
        [alert addAction:library];
        [alert addAction:cancel];
        [_viewController presentViewController:alert animated:YES completion:nil];
    }
    
    - (void)showCamera {
        // Camera is not available on simulators
        if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
            _imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
            _imagePickerController.mediaTypes = [NSArray arrayWithObjects:@"public.movie", @"public.image", nil];
            _imagePickerController.delegate = self;
            _imagePickerController.restoresFocusAfterTransition = false;
            _imagePickerController.allowsEditing = NO;
            _imagePickerController.videoQuality = UIImagePickerControllerQualityTypeLow;
            _imagePickerController.videoMaximumDuration = 30.0f; // 30 seconds
            [_viewController presentViewController:_imagePickerController animated:YES completion:nil];
        } else {
            [[[UIAlertView alloc] initWithTitle:@"Error"
                                        message:@"Camera not available."
                                       delegate:nil
                              cancelButtonTitle:@"OK"
                              otherButtonTitles:nil] show];
        }
    }
    
    - (void)showPhotoLibrary {
    // No need to check if SourceType is available. It always is.
    _imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
        _imagePickerController.mediaTypes = [NSArray arrayWithObjects:@"public.movie", @"public.image", nil];
    //_imagePickerController.mediaTypes =[UIImagePickerController availableMediaTypesForSourceType:_imagePickerController.sourceType];
    [_viewController presentViewController:_imagePickerController animated:YES completion:nil];
    }
    
    - (void)imagePickerController:(UIImagePickerController *)picker
          didFinishPickingMediaWithInfo:(NSDictionary<NSString *, id> *)info {
      [_imagePickerController dismissViewControllerAnimated:YES completion:nil];
      NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
      if ([mediaType isEqualToString:@"public.movie"]) {
        NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
        NSString *videoString = [videoURL absoluteString];
        NSLog(@"Video File:%@", videoString);
        _result(videoString);
      } else {
        UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage];
        if (image == nil) {
          image = [info objectForKey:UIImagePickerControllerOriginalImage];
        }
        image = [self normalizedImage:image];
    
        NSNumber *maxWidth = [_arguments objectForKey:@"maxWidth"];
        NSNumber *maxHeight = [_arguments objectForKey:@"maxHeight"];
    
        if (maxWidth != (id)[NSNull null] || maxHeight != (id)[NSNull null]) {
          image = [self scaledImage:image maxWidth:maxWidth maxHeight:maxHeight];
        }
    
        NSData *data = UIImageJPEGRepresentation(image, 1.0);
        NSString *tmpDirectory = NSTemporaryDirectory();
        NSString *guid = [[NSProcessInfo processInfo] globallyUniqueString];
        // TODO(jackson): Using the cache directory might be better than temporary
        // directory.
        NSString *tmpFile = [NSString stringWithFormat:@"image_picker_%@.jpg", guid];
        NSString *tmpPath = [tmpDirectory stringByAppendingPathComponent:tmpFile];
        NSLog(@"Image File:%@", tmpPath);
        if ([[NSFileManager defaultManager] createFileAtPath:tmpPath contents:data attributes:nil]) {
            _result(tmpPath);
        } else {
            _result([FlutterError errorWithCode:@"create_error"
                                        message:@"Temporary file could not be created"
                                        details:nil]);
        }
          _result = nil;
          _arguments = nil;
      }
      _result = nil;
      _arguments = nil;
    }
    
    // The way we save images to the tmp dir currently throws away all EXIF data
        // (including the orientation of the image). That means, pics taken in portrait
        // will not be orientated correctly as is. To avoid that, we rotate the actual
        // image data.
    // TODO(goderbauer): investigate how to preserve EXIF data.
    - (UIImage *)normalizedImage:(UIImage *)image {
        if (image.imageOrientation == UIImageOrientationUp) return image;
    
        UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
        [image drawInRect:(CGRect){0, 0, image.size}];
        UIImage *normalizedImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return normalizedImage;
    }
    //- (NSString *)normalVideo:(NSURL *)videoURL {
      //    NSString *normalVideo = UIImagePickerControllerMediaURL;
      //    return normalVideo;
    //}
    
    - (UIImage *)scaledImage:(UIImage *)image
        maxWidth:(NSNumber *)maxWidth
        maxHeight:(NSNumber *)maxHeight {
        double originalWidth = image.size.width;
        double originalHeight = image.size.height;
    
        bool hasMaxWidth = maxWidth != (id)[NSNull null];
        bool hasMaxHeight = maxHeight != (id)[NSNull null];
    
        double width = hasMaxWidth ? MIN([maxWidth doubleValue], originalWidth) : originalWidth;
        double height = hasMaxHeight ? MIN([maxHeight doubleValue], originalHeight) : originalHeight;
    
        bool shouldDownscaleWidth = hasMaxWidth && [maxWidth doubleValue] < originalWidth;
        bool shouldDownscaleHeight = hasMaxHeight && [maxHeight doubleValue] < originalHeight;
        bool shouldDownscale = shouldDownscaleWidth || shouldDownscaleHeight;
    
        if (shouldDownscale) {
              double downscaledWidth = (height / originalHeight) * originalWidth;
              double downscaledHeight = (width / originalWidth) * originalHeight;
    
              if (width < height) {
                if (!hasMaxWidth) {
                  width = downscaledWidth;
                } else {
                  height = downscaledHeight;
                }
              } else if (height < width) {
                if (!hasMaxHeight) {
                  height = downscaledHeight;
                } else {
                  width = downscaledWidth;
                }
              } else {
                if (originalWidth < originalHeight) {
                  width = downscaledWidth;
                } else if (originalHeight < originalWidth) {
                  height = downscaledHeight;
                }
              }
        }
    
        UIGraphicsBeginImageContextWithOptions(CGSizeMake(width, height), NO, 1.0);
        [image drawInRect:CGRectMake(0, 0, width, height)];
    
        UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        return scaledImage;
    }
    
    @end
    

    【讨论】:

      【解决方案2】:

      我可能会在image_picker.dart 中添加另一个方法pickVideo,然后在imagePickerPlugin.mImagePickerPlugin.java 中添加相应的Android 和iOS 实现。

      在后两者中,我会使用 iOS 和 Android API 来处理视频,例如在 iOS 上是这样的: Objective c - ios : How to pick video from Camera Roll?

      【讨论】:

      • 有任何代码示例或者你之前为这个插件做过吗?
      • 任何人都有一个代码示例,我试图看看代码如何适合当前的插件,但现在不太精通Objective c。我知道它是如何工作的,但不知道如何修改当前代码来进行更改。任何帮助将不胜感激。
      • 我有它选择视频,但无法弄清楚如何让它呈现回插件,当我选择它时它崩溃或挂起,任何想法或有人做过,需要也可以在相机上捕捉视频。
      • 我添加了一些我一直在处理的代码,但仍在寻求帮助。
      • @Slabo 我刚刚发布了我完成的 ios 代码,android 也快完成了,我可能会在完成后做一个 PR,或者制作一个名为 media_picker 的新的并作为一个包发布。
      【解决方案3】:

      从 0.4.2 版本开始,该插件允许选择视频

      添加了对挑选视频的支持。更新了示例应用以显示视频 预览。

      【讨论】:

        【解决方案4】:

        您现在可以使用 image_picker 中的 pickVideo 来做到这一点

        final _picker = ImagePicker();
        PickedFile video = await _picker.getVideo(...)
        ...
        
        

        参考 - https://pub.dev/packages/image_picker

        【讨论】:

          【解决方案5】:

          您可以使用图像选择器来录制视频,并使用咀嚼库通过视频控制器显示视频。 如需更多参考,请使用此视频链接 - https://www.youtube.com/watch?time_continue=17&v=XSn5EwWBG-4&feature=emb_logo

          【讨论】:

            猜你喜欢
            • 2020-05-05
            • 1970-01-01
            • 2020-03-06
            • 1970-01-01
            • 1970-01-01
            • 2021-02-19
            • 1970-01-01
            • 1970-01-01
            • 2015-04-02
            相关资源
            最近更新 更多