mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-10 18:07:59 -06:00
feat: Add document scanner package
This commit is contained in:
38
packages/paperless_document_scanner/ios/.gitignore
vendored
Normal file
38
packages/paperless_document_scanner/ios/.gitignore
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
.idea/
|
||||
.vagrant/
|
||||
.sconsign.dblite
|
||||
.svn/
|
||||
|
||||
.DS_Store
|
||||
*.swp
|
||||
profile
|
||||
|
||||
DerivedData/
|
||||
build/
|
||||
GeneratedPluginRegistrant.h
|
||||
GeneratedPluginRegistrant.m
|
||||
|
||||
.generated/
|
||||
|
||||
*.pbxuser
|
||||
*.mode1v3
|
||||
*.mode2v3
|
||||
*.perspectivev3
|
||||
|
||||
!default.pbxuser
|
||||
!default.mode1v3
|
||||
!default.mode2v3
|
||||
!default.perspectivev3
|
||||
|
||||
xcuserdata
|
||||
|
||||
*.moved-aside
|
||||
|
||||
*.pyc
|
||||
*sync/
|
||||
Icon?
|
||||
.tags*
|
||||
|
||||
/Flutter/Generated.xcconfig
|
||||
/Flutter/ephemeral/
|
||||
/Flutter/flutter_export_environment.sh
|
||||
@@ -0,0 +1,4 @@
|
||||
#import <Flutter/Flutter.h>
|
||||
|
||||
@interface PaperlessDocumentScannerPlugin : NSObject<FlutterPlugin>
|
||||
@end
|
||||
@@ -0,0 +1,15 @@
|
||||
#import "SimpleEdgeDetectionPlugin.h"
|
||||
#if __has_include(<paperless_document_scanner/paperless_document_scanner-Swift.h>)
|
||||
#import <paperless_document_scanner/paperless_document_scanner-Swift.h>
|
||||
#else
|
||||
// Support project import fallback if the generated compatibility header
|
||||
// is not copied when this plugin is created as a library.
|
||||
// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816
|
||||
#import "paperless_document_scanner-Swift.h"
|
||||
#endif
|
||||
|
||||
@implementation SimpleEdgeDetectionPlugin
|
||||
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
|
||||
[SwiftSimpleEdgeDetectionPlugin registerWithRegistrar:registrar];
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,14 @@
|
||||
import Flutter
|
||||
import UIKit
|
||||
|
||||
public class PaperlessDocumentScannerPlugin: NSObject, FlutterPlugin {
|
||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||
let channel = FlutterMethodChannel(name: "paperless_document_scanner", binaryMessenger: registrar.messenger())
|
||||
let instance = PaperlessDocumentScannerPlugin()
|
||||
registrar.addMethodCallDelegate(instance, channel: channel)
|
||||
}
|
||||
|
||||
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||
result("iOS " + UIDevice.current.systemVersion)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#include "conversion_utils.hpp"
|
||||
using namespace cv;
|
||||
uint8_t * ConversionUtils::matrix_to_bytearray(Mat mat)
|
||||
{
|
||||
int size = mat.total() * mat.elemSize();
|
||||
uint8_t *bytes = (uint8_t *)malloc(size);
|
||||
std::memcpy(bytes, mat.data, size * sizeof(uint8_t));
|
||||
return bytes;
|
||||
}
|
||||
|
||||
Mat ConversionUtils::bytearray_to_matrix(uint8_t *bytes, int byteCount)
|
||||
{
|
||||
std::vector<uint8_t> buf(bytes, bytes + byteCount);
|
||||
return imdecode(buf, IMREAD_COLOR);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
class ConversionUtils {
|
||||
public:
|
||||
static uint8_t *matrix_to_bytearray(Mat mat);
|
||||
static Mat bytearray_to_matrix(uint8_t *bytes, int byteCount);
|
||||
};
|
||||
@@ -0,0 +1,163 @@
|
||||
#include "edge_detector.hpp"
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <opencv2/imgproc/types_c.h>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
// helper function:
|
||||
// finds a cosine of angle between vectors
|
||||
// from pt0->pt1 and from pt0->pt2
|
||||
double EdgeDetector::get_cosine_angle_between_vectors(cv::Point pt1, cv::Point pt2, cv::Point pt0)
|
||||
{
|
||||
double dx1 = pt1.x - pt0.x;
|
||||
double dy1 = pt1.y - pt0.y;
|
||||
double dx2 = pt2.x - pt0.x;
|
||||
double dy2 = pt2.y - pt0.y;
|
||||
return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
|
||||
}
|
||||
|
||||
vector<cv::Point> image_to_vector(Mat& image)
|
||||
{
|
||||
int imageWidth = image.size().width;
|
||||
int imageHeight = image.size().height;
|
||||
|
||||
return {
|
||||
cv::Point(0, 0),
|
||||
cv::Point(imageWidth, 0),
|
||||
cv::Point(0, imageHeight),
|
||||
cv::Point(imageWidth, imageHeight)
|
||||
};
|
||||
}
|
||||
|
||||
vector<cv::Point> EdgeDetector::detect_edges(Mat& image)
|
||||
{
|
||||
vector<vector<cv::Point>> squares = find_squares(image);
|
||||
vector<cv::Point>* biggestSquare = NULL;
|
||||
|
||||
// Sort so that the points are ordered clockwise
|
||||
|
||||
struct sortY {
|
||||
bool operator() (cv::Point pt1, cv::Point pt2) { return (pt1.y < pt2.y);}
|
||||
} orderRectangleY;
|
||||
struct sortX {
|
||||
bool operator() (cv::Point pt1, cv::Point pt2) { return (pt1.x < pt2.x);}
|
||||
} orderRectangleX;
|
||||
|
||||
for (int i = 0; i < squares.size(); i++) {
|
||||
vector<cv::Point>* currentSquare = &squares[i];
|
||||
|
||||
std::sort(currentSquare->begin(),currentSquare->end(), orderRectangleY);
|
||||
std::sort(currentSquare->begin(),currentSquare->begin()+2, orderRectangleX);
|
||||
std::sort(currentSquare->begin()+2,currentSquare->end(), orderRectangleX);
|
||||
|
||||
float currentSquareWidth = get_width(*currentSquare);
|
||||
float currentSquareHeight = get_height(*currentSquare);
|
||||
|
||||
if (currentSquareWidth < image.size().width / 5 || currentSquareHeight < image.size().height / 5) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentSquareWidth > image.size().width * 0.99 || currentSquareHeight > image.size().height * 0.99) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (biggestSquare == NULL) {
|
||||
biggestSquare = currentSquare;
|
||||
continue;
|
||||
}
|
||||
|
||||
float biggestSquareWidth = get_width(*biggestSquare);
|
||||
float biggestSquareHeight = get_height(*biggestSquare);
|
||||
|
||||
if (currentSquareWidth * currentSquareHeight >= biggestSquareWidth * biggestSquareHeight) {
|
||||
biggestSquare = currentSquare;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (biggestSquare == NULL) {
|
||||
return image_to_vector(image);
|
||||
}
|
||||
|
||||
std::sort(biggestSquare->begin(),biggestSquare->end(), orderRectangleY);
|
||||
std::sort(biggestSquare->begin(),biggestSquare->begin()+2, orderRectangleX);
|
||||
std::sort(biggestSquare->begin()+2,biggestSquare->end(), orderRectangleX);
|
||||
|
||||
return *biggestSquare;
|
||||
}
|
||||
|
||||
float EdgeDetector::get_height(vector<cv::Point>& square) {
|
||||
float upperLeftToLowerRight = square[3].y - square[0].y;
|
||||
float upperRightToLowerLeft = square[1].y - square[2].y;
|
||||
|
||||
return max(upperLeftToLowerRight, upperRightToLowerLeft);
|
||||
}
|
||||
|
||||
float EdgeDetector::get_width(vector<cv::Point>& square) {
|
||||
float upperLeftToLowerRight = square[3].x - square[0].x;
|
||||
float upperRightToLowerLeft = square[1].x - square[2].x;
|
||||
|
||||
return max(upperLeftToLowerRight, upperRightToLowerLeft);
|
||||
}
|
||||
|
||||
cv::Mat EdgeDetector::debug_squares( cv::Mat image )
|
||||
{
|
||||
vector<vector<cv::Point> > squares = find_squares(image);
|
||||
|
||||
for (const auto & square : squares) {
|
||||
// draw rotated rect
|
||||
cv::RotatedRect minRect = minAreaRect(cv::Mat(square));
|
||||
cv::Point2f rect_points[4];
|
||||
minRect.points( rect_points );
|
||||
for ( int j = 0; j < 4; j++ ) {
|
||||
cv::line( image, rect_points[j], rect_points[(j+1)%4], cv::Scalar(0,0,255), 1, 8 ); // blue
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
vector<vector<cv::Point> > EdgeDetector::find_squares(Mat& image)
|
||||
{
|
||||
vector<int> usedThresholdLevel;
|
||||
vector<vector<Point> > squares;
|
||||
|
||||
Mat gray0(image.size(), CV_8U), gray;
|
||||
|
||||
cvtColor(image , gray, COLOR_BGR2GRAY);
|
||||
medianBlur(gray, gray, 3); // blur will enhance edge detection
|
||||
vector<vector<cv::Point> > contours;
|
||||
|
||||
int thresholdLevels[] = {10, 30, 50, 70};
|
||||
for(int thresholdLevel : thresholdLevels) {
|
||||
Canny(gray, gray0, thresholdLevel, thresholdLevel*3, 3);
|
||||
|
||||
dilate(gray0, gray0, Mat(), Point(-1, -1));
|
||||
|
||||
findContours(gray0, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
|
||||
|
||||
vector<Point> approx;
|
||||
for (const auto & contour : contours) {
|
||||
approxPolyDP(Mat(contour), approx, arcLength(Mat(contour), true) * 0.02, true);
|
||||
|
||||
if (approx.size() == 4 && fabs(contourArea(Mat(approx))) > 1000 &&
|
||||
isContourConvex(Mat(approx))) {
|
||||
double maxCosine = 0;
|
||||
|
||||
for (int j = 2; j < 5; j++) {
|
||||
double cosine = fabs(get_cosine_angle_between_vectors(approx[j % 4], approx[j - 2], approx[j - 1]));
|
||||
maxCosine = MAX(maxCosine, cosine);
|
||||
}
|
||||
|
||||
if (maxCosine < 0.3) {
|
||||
squares.push_back(approx);
|
||||
usedThresholdLevel.push_back(thresholdLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return squares;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
|
||||
class EdgeDetector {
|
||||
public:
|
||||
static vector<cv::Point> detect_edges( Mat& image);
|
||||
static Mat debug_squares( Mat image );
|
||||
|
||||
private:
|
||||
static double get_cosine_angle_between_vectors( cv::Point pt1, cv::Point pt2, cv::Point pt0 );
|
||||
static vector<vector<cv::Point> > find_squares(Mat& image);
|
||||
static float get_width(vector<cv::Point>& square);
|
||||
static float get_height(vector<cv::Point>& square);
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
#include "image_processor.hpp"
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
using namespace cv;
|
||||
|
||||
Point2f computePoint(int p1, int p2)
|
||||
{
|
||||
Point2f pt;
|
||||
pt.x = p1;
|
||||
pt.y = p2;
|
||||
return pt;
|
||||
}
|
||||
|
||||
Mat ImageProcessor::process_image(Mat img, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4)
|
||||
{
|
||||
cvtColor(img, img, COLOR_BGR2GRAY);
|
||||
Mat dst = ImageProcessor::crop_and_transform(img, x1, y1, x2, y2, x3, y3, x4, y4);
|
||||
adaptiveThreshold(dst, dst, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, 53, 10);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
Mat ImageProcessor::crop_and_transform(Mat img, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4)
|
||||
{
|
||||
float w1 = sqrt(pow(x4 - x3, 2) + pow(x4 - x3, 2));
|
||||
float w2 = sqrt(pow(x2 - x1, 2) + pow(x2 - x1, 2));
|
||||
float h1 = sqrt(pow(y2 - y4, 2) + pow(y2 - y4, 2));
|
||||
float h2 = sqrt(pow(y1 - y3, 2) + pow(y1 - y3, 2));
|
||||
|
||||
float maxWidth = (w1 < w2) ? w1 : w2;
|
||||
float maxHeight = (h1 < h2) ? h1 : h2;
|
||||
|
||||
Mat dst = Mat::zeros(maxHeight, maxWidth, CV_8UC1);
|
||||
|
||||
vector<Point2f> dst_pts;
|
||||
vector<Point2f> img_pts;
|
||||
dst_pts.push_back(Point(0, 0));
|
||||
dst_pts.push_back(Point(maxWidth - 1, 0));
|
||||
dst_pts.push_back(Point(0, maxHeight - 1));
|
||||
dst_pts.push_back(Point(maxWidth - 1, maxHeight - 1));
|
||||
|
||||
img_pts.push_back(computePoint(x1, y1));
|
||||
img_pts.push_back(computePoint(x2, y2));
|
||||
img_pts.push_back(computePoint(x3, y3));
|
||||
img_pts.push_back(computePoint(x4, y4));
|
||||
|
||||
Mat transformation_matrix = getPerspectiveTransform(img_pts, dst_pts);
|
||||
warpPerspective(img, dst, transformation_matrix, dst.size());
|
||||
|
||||
return dst;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
|
||||
class ImageProcessor {
|
||||
public:
|
||||
static Mat process_image(Mat img, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4);
|
||||
|
||||
private:
|
||||
static Mat crop_and_transform(Mat img, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4);
|
||||
};
|
||||
@@ -0,0 +1,130 @@
|
||||
#include "native_edge_detection.hpp"
|
||||
#include "edge_detector.hpp"
|
||||
#include "image_processor.hpp"
|
||||
#include "conversion_utils.hpp"
|
||||
#include <stdlib.h>
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
extern "C" __attribute__((visibility("default"))) __attribute__((used)) struct Coordinate *create_coordinate(double x, double y)
|
||||
{
|
||||
struct Coordinate *coordinate = (struct Coordinate *)malloc(sizeof(struct Coordinate));
|
||||
coordinate->x = x;
|
||||
coordinate->y = y;
|
||||
return coordinate;
|
||||
}
|
||||
|
||||
extern "C" __attribute__((visibility("default"))) __attribute__((used)) struct DetectionResult *create_detection_result(
|
||||
Coordinate *topLeft,
|
||||
Coordinate *topRight,
|
||||
Coordinate *bottomLeft,
|
||||
Coordinate *bottomRight)
|
||||
{
|
||||
struct DetectionResult *detectionResult = (struct DetectionResult *)malloc(sizeof(struct DetectionResult));
|
||||
detectionResult->topLeft = topLeft;
|
||||
detectionResult->topRight = topRight;
|
||||
detectionResult->bottomLeft = bottomLeft;
|
||||
detectionResult->bottomRight = bottomRight;
|
||||
return detectionResult;
|
||||
}
|
||||
|
||||
extern "C" __attribute__((visibility("default"))) __attribute__((used)) struct DetectionResult *detect_edges_from_file(char *str)
|
||||
{
|
||||
struct DetectionResult *coordinate = (struct DetectionResult *)malloc(sizeof(struct DetectionResult));
|
||||
cv::Mat mat = cv::imread(str);
|
||||
|
||||
if (mat.size().width == 0 || mat.size().height == 0)
|
||||
{
|
||||
return create_detection_result(
|
||||
create_coordinate(0, 0),
|
||||
create_coordinate(1, 0),
|
||||
create_coordinate(0, 1),
|
||||
create_coordinate(1, 1));
|
||||
}
|
||||
|
||||
vector<cv::Point> points = EdgeDetector::detect_edges(mat);
|
||||
|
||||
return create_detection_result(
|
||||
create_coordinate((double)points[0].x / mat.size().width, (double)points[0].y / mat.size().height),
|
||||
create_coordinate((double)points[1].x / mat.size().width, (double)points[1].y / mat.size().height),
|
||||
create_coordinate((double)points[2].x / mat.size().width, (double)points[2].y / mat.size().height),
|
||||
create_coordinate((double)points[3].x / mat.size().width, (double)points[3].y / mat.size().height));
|
||||
}
|
||||
|
||||
extern "C" __attribute__((visibility("default"))) __attribute__((used)) struct DetectionResult *detect_edges(uint8_t *bytes, int byteCount)
|
||||
{
|
||||
struct DetectionResult *coordinate = (struct DetectionResult *)malloc(sizeof(struct DetectionResult));
|
||||
Mat mat = ConversionUtils::bytearray_to_matrix(bytes, byteCount);
|
||||
|
||||
if (mat.size().width == 0 || mat.size().height == 0)
|
||||
{
|
||||
return create_detection_result(
|
||||
create_coordinate(0, 0),
|
||||
create_coordinate(1, 0),
|
||||
create_coordinate(0, 1),
|
||||
create_coordinate(1, 1));
|
||||
}
|
||||
|
||||
vector<cv::Point> points = EdgeDetector::detect_edges(mat);
|
||||
|
||||
return create_detection_result(
|
||||
create_coordinate((double)points[0].x / mat.size().width, (double)points[0].y / mat.size().height),
|
||||
create_coordinate((double)points[1].x / mat.size().width, (double)points[1].y / mat.size().height),
|
||||
create_coordinate((double)points[2].x / mat.size().width, (double)points[2].y / mat.size().height),
|
||||
create_coordinate((double)points[3].x / mat.size().width, (double)points[3].y / mat.size().height));
|
||||
}
|
||||
|
||||
extern "C" __attribute__((visibility("default"))) __attribute__((used)) bool process_image_from_file(
|
||||
char *path,
|
||||
double topLeftX,
|
||||
double topLeftY,
|
||||
double topRightX,
|
||||
double topRightY,
|
||||
double bottomLeftX,
|
||||
double bottomLeftY,
|
||||
double bottomRightX,
|
||||
double bottomRightY)
|
||||
{
|
||||
cv::Mat mat = cv::imread(path);
|
||||
|
||||
cv::Mat resizedMat = ImageProcessor::process_image(
|
||||
mat,
|
||||
topLeftX * mat.size().width,
|
||||
topLeftY * mat.size().height,
|
||||
topRightX * mat.size().width,
|
||||
topRightY * mat.size().height,
|
||||
bottomLeftX * mat.size().width,
|
||||
bottomLeftY * mat.size().height,
|
||||
bottomRightX * mat.size().width,
|
||||
bottomRightY * mat.size().height);
|
||||
|
||||
return cv::imwrite(path, resizedMat);
|
||||
}
|
||||
|
||||
extern "C" __attribute__((visibility("default"))) __attribute__((used))
|
||||
uint8_t *
|
||||
process_image(
|
||||
uint8_t *bytes,
|
||||
int byteCount,
|
||||
double topLeftX,
|
||||
double topLeftY,
|
||||
double topRightX,
|
||||
double topRightY,
|
||||
double bottomLeftX,
|
||||
double bottomLeftY,
|
||||
double bottomRightX,
|
||||
double bottomRightY)
|
||||
{
|
||||
cv::Mat mat = ConversionUtils::bytearray_to_matrix(bytes, byteCount);
|
||||
cv::Mat resizedMat = ImageProcessor::process_image(
|
||||
mat,
|
||||
topLeftX * mat.size().width,
|
||||
topLeftY * mat.size().height,
|
||||
topRightX * mat.size().width,
|
||||
topRightY * mat.size().height,
|
||||
bottomLeftX * mat.size().width,
|
||||
bottomLeftY * mat.size().height,
|
||||
bottomRightX * mat.size().width,
|
||||
bottomRightY * mat.size().height);
|
||||
|
||||
return ConversionUtils::matrix_to_bytearray(resizedMat);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#include <iostream>
|
||||
struct Coordinate
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
};
|
||||
|
||||
struct DetectionResult
|
||||
{
|
||||
Coordinate *topLeft;
|
||||
Coordinate *topRight;
|
||||
Coordinate *bottomLeft;
|
||||
Coordinate *bottomRight;
|
||||
};
|
||||
|
||||
extern "C" struct ProcessingInput
|
||||
{
|
||||
char *path;
|
||||
DetectionResult detectionResult;
|
||||
};
|
||||
|
||||
extern "C" struct DetectionResult *detect_edges_from_file(char *str);
|
||||
|
||||
extern "C" struct DetectionResult *detect_edges(uint8_t *bytes, int byteCount);
|
||||
|
||||
extern "C" uint8_t *process_image(
|
||||
uint8_t *bytes,
|
||||
int byteCount,
|
||||
double topLeftX,
|
||||
double topLeftY,
|
||||
double topRightX,
|
||||
double topRightY,
|
||||
double bottomLeftX,
|
||||
double bottomLeftY,
|
||||
double bottomRightX,
|
||||
double bottomRightY);
|
||||
|
||||
extern "C" bool process_image_from_file(
|
||||
char *path,
|
||||
double topLeftX,
|
||||
double topLeftY,
|
||||
double topRightX,
|
||||
double topRightY,
|
||||
double bottomLeftX,
|
||||
double bottomLeftY,
|
||||
double bottomRightX,
|
||||
double bottomRightY);
|
||||
@@ -0,0 +1,29 @@
|
||||
#
|
||||
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
|
||||
# Run `pod lib lint paperless_document_scanner.podspec` to validate before publishing.
|
||||
#
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'paperless_document_scanner'
|
||||
s.version = '0.0.1'
|
||||
s.summary = 'A new Flutter plugin project.'
|
||||
s.description = <<-DESC
|
||||
A new Flutter plugin project.
|
||||
DESC
|
||||
s.homepage = 'http://example.com'
|
||||
s.license = { :file => '../LICENSE' }
|
||||
s.author = { 'Your Company' => 'email@example.com' }
|
||||
s.source = { :path => '.' }
|
||||
s.source_files = 'Classes/**/*.{swift,c,m,h,mm,cpp,plist}'
|
||||
s.dependency 'Flutter'
|
||||
s.platform = :ios, '9.0'
|
||||
|
||||
# Flutter.framework does not contain a i386 slice.
|
||||
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
|
||||
s.swift_version = '5.0'
|
||||
|
||||
s.preserve_paths = 'opencv2.framework'
|
||||
s.xcconfig = { 'OTHER_LDFLAGS' => '-framework opencv2' }
|
||||
s.vendored_frameworks = 'opencv2.framework'
|
||||
s.frameworks = 'AVFoundation'
|
||||
s.library = 'c++'
|
||||
end
|
||||
Reference in New Issue
Block a user