-
Notifications
You must be signed in to change notification settings - Fork 118
Expand file tree
/
Copy pathRNCImageEditor.mm
More file actions
143 lines (124 loc) · 5.12 KB
/
Copy pathRNCImageEditor.mm
File metadata and controls
143 lines (124 loc) · 5.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RNCImageEditor.h"
#import <UIKit/UIKit.h>
#import <React/RCTConvert.h>
#import <React/RCTLog.h>
#import <React/RCTUtils.h>
#import <React/RCTImageLoader.h>
#import <React/RCTImageStoreManager.h>
#import "RNCFileSystem.h"
#import "RNCImageUtils.h"
#if __has_include(<RCTImage/RCTImageUtils.h>)
#import <RCTImage/RCTImageUtils.h>
#else
#import "RCTImageUtils.h"
#endif
@implementation RNCImageEditor
RCT_EXPORT_MODULE()
@synthesize bridge = _bridge;
/**
* Crops an image and saves the result to temporary file. Consider using
* CameraRoll API or other third-party module to save it in gallery.
*
* @param imageRequest An image URL
* @param cropData Dictionary with `offset`, `size` and `displaySize`.
* `offset` and `size` are relative to the full-resolution image size.
* `displaySize` is an optimization - if specified, the image will
* be scaled down to `displaySize` rather than `size`.
* All units are in px (not points).
*/
#ifdef RCT_NEW_ARCH_ENABLED
- (void) cropImage:(NSString *)uri
cropData:(JS::NativeRNCImageEditor::SpecCropImageCropData &)data
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject
{
CGSize size = [RCTConvert CGSize:@{ @"width": @(data.size().width()), @"height": @(data.size().height()) }];
CGPoint offset = [RCTConvert CGPoint:@{ @"x": @(data.offset().x()), @"y": @(data.offset().y()) }];
CGSize targetSize = size;
if (data.displaySize().has_value()) {
JS::NativeRNCImageEditor::SpecCropImageCropDataDisplaySize displaySize = *data.displaySize(); // Extract the value from the optional
// in pixels
targetSize = [RCTConvert CGSize:@{ @"width": @(displaySize.width()), @"height": @(displaySize.height()) }];
}
NSString *displaySize = data.resizeMode();
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:[NSURL URLWithString: uri]];
CGFloat compressionQuality = 1;
if (data.quality().has_value()) {
compressionQuality = *data.quality();
}
#else
RCT_EXPORT_METHOD(cropImage:(NSURLRequest *)imageRequest
cropData:(NSDictionary *)cropData
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject)
{
CGSize size = [RCTConvert CGSize:cropData[@"size"]];
CGPoint offset = [RCTConvert CGPoint:cropData[@"offset"]];
CGSize targetSize = size;
NSString *displaySize = cropData[@"resizeMode"];
if(displaySize){
targetSize = [RCTConvert CGSize:cropData[@"displaySize"]];
}
CGFloat compressionQuality = 1;
if(cropData[@"quality"]){
compressionQuality = [RCTConvert CGFloat:cropData[@"quality"]];
}
#endif
CGRect rect = {offset,size};
NSURL *url = [imageRequest URL];
NSString *urlPath = [url path];
NSString *extension = [urlPath pathExtension];
[[_bridge moduleForName:@"ImageLoader" lazilyLoadIfNecessary:YES] loadImageWithURLRequest:imageRequest callback:^(NSError *error, UIImage *image) {
if (error) {
reject(@(error.code).stringValue, error.description, error);
return;
}
if (compressionQuality > 1 || compressionQuality < 0) {
reject(RCTErrorUnspecified, @("quality must be a number between 0 and 1"), nil);
return;
}
// Crop image
CGRect targetRect = {{-rect.origin.x, -rect.origin.y}, image.size};
CGAffineTransform transform = RCTTransformFromTargetRect(image.size, targetRect);
UIImage *croppedImage = RCTTransformImage(image, targetSize, image.scale, transform);
// Scale image
if (displaySize) {
RCTResizeMode resizeMode = [RCTConvert RCTResizeMode:displaySize ?: @"contain"];
targetRect = RCTTargetRect(croppedImage.size, targetSize, 1, resizeMode);
transform = RCTTransformFromTargetRect(croppedImage.size, targetRect);
croppedImage = RCTTransformImage(croppedImage, targetSize, image.scale, transform);
}
// Store image
NSString *path = NULL;
NSData *imageData = NULL;
if([extension isEqualToString:@"png"]){
imageData = UIImagePNGRepresentation(croppedImage);
path = [RNCFileSystem generatePathInDirectory:[[RNCFileSystem cacheDirectoryPath] stringByAppendingPathComponent:@"ReactNative_cropped_image_"] withExtension:@".png"];
}
else{
imageData = UIImageJPEGRepresentation(croppedImage, compressionQuality);
path = [RNCFileSystem generatePathInDirectory:[[RNCFileSystem cacheDirectoryPath] stringByAppendingPathComponent:@"ReactNative_cropped_image_"] withExtension:@".jpg"];
}
NSError *writeError;
NSString *uri = [RNCImageUtils writeImage:imageData toPath:path error:&writeError];
if (writeError != nil) {
reject(@(writeError.code).stringValue, writeError.description, writeError);
return;
}
resolve(uri);
}];
}
#ifdef RCT_NEW_ARCH_ENABLED
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
return std::make_shared<facebook::react::NativeRNCImageEditorSpecJSI>(params);
}
#endif
@end