Flutter 圖片裁剪旋轉翻轉編輯器

extended_image 相關文章ios

圖片編輯這個功能很早以前就想把它給作了,畢竟是作的全家桶,少一個功能都以爲不舒服。最近本身一我的在家,週末瘋狂寫了2天代碼,睡覺都在思考,git

恰巧今天Google大會,聽說如今掘金Flutter相關 約2萬粉絲,2600多篇相關文章。我晚上回家擼到半夜總算是完成,嗯,文章+1了

實現

這部分我以爲不太好講,全是數學幾何相關的計算。當初開始寫的extended_image的時候,就留意了一下可能會擴展的功能實現的可能性,代碼之間也作好了鋪墊。你們都問,功能能抽離出來嗎? 我說不能,從開始基礎就決定它將會擁有這些功能。簡單提一下,圖片的顯示區域不等於圖片的layout區域,它受BoxFix等參數的影響。而Flutter裏面的 Transform是對整個layout區域起做用的,明顯不符合咱們的需求。因此從一開始我就放棄直接使用Transform對圖片進行處理,直接經過算法在繪製圖片的時候進行縮放,平移,旋轉,翻轉等操做。github

Rome is not built in one day,extended_image從今年2月份開始編寫的,到9月份最終成爲各類經常使用實用功能的圖片全家桶。 若是對實現感興趣的小夥伴,能夠先看看源碼,若是有不清楚的,能夠加羣(QQ羣:181398081)詢問。算法

使用

ExtendedImage.network(
      imageTestUrl,
      fit: BoxFit.contain,
      mode: ExtendedImageMode.editor,
      extendedImageEditorKey: editorKey,
      initEditorConfigHandler: (state) {
        return EditorConfig(
            maxScale: 8.0,
            cropRectPadding: EdgeInsets.all(20.0),
            hitTestSize: 20.0,
            cropAspectRatio: _aspectRatio.aspectRatio);
      },
    );
複製代碼

ExtendedImage 相關參數設置微信

參數 描述 默認
mode 圖片模式,默認/手勢/編輯 (none,gestrue,editor) none
initGestureConfigHandler 編輯器配置的回調(圖片加載完成時).你能夠根據圖片的信息好比寬高,來初始化 -
extendedImageEditorKey key of ExtendedImageEditorState 用於裁剪旋轉翻轉 -

EditorConfig 參數markdown

參數 描述 默認
maxScale 最大的縮放倍數 5.0
cropRectPadding 裁剪框跟圖片layout區域之間的距離。最好是保持必定距離,否則裁剪框邊界很難進行拖拽 EdgeInsets.all(20.0)
cornerSize 裁剪框四角圖形的大小 Size(30.0, 5.0)
cornerColor 裁剪框四角圖形的顏色 primaryColor
lineColor 裁剪框線的顏色 scaffoldBackgroundColor.withOpacity(0.7)
lineHeight 裁剪框線的高度 0.6
eidtorMaskColorHandler 蒙層的顏色回調,你能夠根據是否手指按下來設置不一樣的蒙層顏色 scaffoldBackgroundColor.withOpacity(pointerdown ? 0.4 : 0.8)
hitTestSize 裁剪框四角以及邊線可以拖拽的區域的大小 20.0
animationDuration 當裁剪框拖拽變化結束以後,自動適應到中間的動畫的時長 Duration(milliseconds: 200)
tickerDuration 當裁剪框拖拽變化結束以後,多少時間才觸發自動適應到中間的動畫 Duration(milliseconds: 400)
cropAspectRatio 裁剪框的寬高比 null(無寬高比))
initCropRectType 剪切框的初始化類型(根據圖片初始化區域或者圖片的layout區域) imageRect

裁剪框的寬高比

這是一個double類型,你能夠自定義裁剪框的寬高比。 若是爲null,那就沒有寬高比限制。 若是小於等於0,寬高比等於圖片的寬高比。 下面是一些定義好了的寬高比編輯器

class CropAspectRatios {
  /// no aspect ratio for crop
  static const double custom = null;

  /// the same as aspect ratio of image
  /// [cropAspectRatio] is not more than 0.0, it's original
  static const double original = 0.0;

  /// ratio of width and height is 1 : 1
  static const double ratio1_1 = 1.0;

  /// ratio of width and height is 3 : 4
  static const double ratio3_4 = 3.0 / 4.0;

  /// ratio of width and height is 4 : 3
  static const double ratio4_3 = 4.0 / 3.0;

  /// ratio of width and height is 9 : 16
  static const double ratio9_16 = 9.0 / 16.0;

  /// ratio of width and height is 16 : 9
  static const double ratio16_9 = 16.0 / 9.0;
}
複製代碼

旋轉,翻轉,重置

  • 定義key,以方便操做ExtendedImageEditorState

final GlobalKey<ExtendedImageEditorState> editorKey =GlobalKey<ExtendedImageEditorState>();post

  • 順時針旋轉90°

editorKey.currentState.rotate(right: true);學習

  • 逆時針旋轉90°

editorKey.currentState.rotate(right: false);動畫

  • 翻轉(鏡像)

editorKey.currentState.flip();

  • 重置

editorKey.currentState.reset();

使用dart庫(穩定)

  • 添加 Image 庫到 pubspec.yaml, 它是用來裁剪/旋轉/翻轉圖片數據的
dependencies:
 image: any
複製代碼
  • 從ExtendedImageEditorState中獲取裁剪區域以及圖片數據
///crop rect base on raw image
  final Rect cropRect = state.getCropRect();

  var data = state.rawImageData;
複製代碼
  • 將flutter的圖片數據轉換爲image庫的數據
/// it costs much time and blocks ui.
  //Image src = decodeImage(data);

  /// it will not block ui with using isolate.
  //Image src = await compute(decodeImage, data);
  //Image src = await isolateDecodeImage(data);
  final lb = await loadBalancer;
  Image src = await lb.run<Image, List<int>>(decodeImage, data);
複製代碼
  • 翻轉,旋轉,裁剪數據
//相機拍照的圖片帶有旋轉,處理以前須要去掉
  src = bakeOrientation(src);

  if (editAction.needCrop)
    src = copyCrop(src, cropRect.left.toInt(), cropRect.top.toInt(),
        cropRect.width.toInt(), cropRect.height.toInt());

  if (editAction.needFlip) {
    Flip mode;
    if (editAction.flipY && editAction.flipX) {
      mode = Flip.both;
    } else if (editAction.flipY) {
      mode = Flip.horizontal;
    } else if (editAction.flipX) {
      mode = Flip.vertical;
    }
    src = flip(src, mode);
  }

  if (editAction.hasRotateAngle) src = copyRotate(src, editAction.rotateAngle);
複製代碼
  • 將數據轉爲爲圖片的元數據

獲取到的將是圖片的元數據,你可使用它來保存或者其餘的一些用途

/// you can encode your image
  ///
  /// it costs much time and blocks ui.
  //var fileData = encodeJpg(src);

  /// it will not block ui with using isolate.
  //var fileData = await compute(encodeJpg, src);
  //var fileData = await isolateEncodeImage(src);
  var fileData = await lb.run<List<int>, Image>(encodeJpg, src);
複製代碼

使用原生庫(快速)

  • 添加 ImageEditor 庫到 pubspec.yaml, 它是用來裁剪/旋轉/翻轉圖片數據的。
dependencies:
 image_editor: any
複製代碼
  • 從ExtendedImageEditorState中獲取裁剪區域以及圖片數據
///crop rect base on raw image
  final Rect cropRect = state.getCropRect();

  final img = state.rawImageData;
複製代碼
  • 準備裁剪選項
final rotateAngle = action.rotateAngle.toInt();
  final flipHorizontal = action.flipY;
  final flipVertical = action.flipX;

  ImageEditorOption option = ImageEditorOption();

  if (action.needCrop) option.addOption(ClipOption.fromRect(cropRect));

  if (action.needFlip)
    option.addOption(
        FlipOption(horizontal: flipHorizontal, vertical: flipVertical));

  if (action.hasRotateAngle) option.addOption(RotateOption(rotateAngle));
複製代碼
  • 使用editImage方法進行裁剪

獲取到的將是圖片的元數據,你可使用它來保存或者其餘的一些用途

final result = await ImageEditor.editImage(
    image: img,
    imageEditorOption: option,
  );
複製代碼

更多細節

結語

時間過得真快,搞弄flutter也快要1年了,認識很多朋友,你們在一塊兒互相學習,促進的感受真好。歡迎加入Flutter Candies,一塊兒生產可愛的Flutter小糖果(QQ羣:181398081)

最最後放上Flutter Candies全家桶,真香。

相關文章
相關標籤/搜索