You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
105 lines
3.7 KiB
105 lines
3.7 KiB
/*
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#import <React/RCTImageEditingManager.h>
|
|
|
|
#import <FBReactNativeSpec/FBReactNativeSpec.h>
|
|
#import <React/RCTConvert.h>
|
|
#import <React/RCTImageLoader.h>
|
|
#import <React/RCTImageStoreManager.h>
|
|
#import <React/RCTImageUtils.h>
|
|
#import <React/RCTImageLoaderProtocol.h>
|
|
#import <React/RCTLog.h>
|
|
#import <React/RCTUtils.h>
|
|
#import <UIKit/UIKit.h>
|
|
|
|
#import "RCTImagePlugins.h"
|
|
|
|
@interface RCTImageEditingManager() <NativeImageEditorSpec>
|
|
@end
|
|
|
|
@implementation RCTImageEditingManager
|
|
|
|
RCT_EXPORT_MODULE()
|
|
|
|
@synthesize moduleRegistry = _moduleRegistry;
|
|
|
|
/**
|
|
* Crops an image and adds the result to the image store.
|
|
*
|
|
* @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).
|
|
*/
|
|
RCT_EXPORT_METHOD(cropImage:(NSURLRequest *)imageRequest
|
|
cropData:(JS::NativeImageEditor::Options &)cropData
|
|
successCallback:(RCTResponseSenderBlock)successCallback
|
|
errorCallback:(RCTResponseSenderBlock)errorCallback)
|
|
{
|
|
CGRect rect = {
|
|
[RCTConvert CGPoint:@{
|
|
@"x": @(cropData.offset().x()),
|
|
@"y": @(cropData.offset().y()),
|
|
}],
|
|
[RCTConvert CGSize:@{
|
|
@"width": @(cropData.size().width()),
|
|
@"height": @(cropData.size().height()),
|
|
}]
|
|
};
|
|
|
|
// We must keep a copy of cropData so that we can access data from it at a later time
|
|
JS::NativeImageEditor::Options cropDataCopy = cropData;
|
|
|
|
[[_moduleRegistry moduleForName:"ImageLoader"]
|
|
loadImageWithURLRequest:imageRequest callback:^(NSError *error, UIImage *image) {
|
|
if (error) {
|
|
errorCallback(@[RCTJSErrorFromNSError(error)]);
|
|
return;
|
|
}
|
|
|
|
// Crop image
|
|
CGSize targetSize = rect.size;
|
|
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 (cropDataCopy.displaySize()) {
|
|
targetSize = [RCTConvert CGSize:@{@"width": @(cropDataCopy.displaySize()->width()), @"height": @(cropDataCopy.displaySize()->height())}]; // in pixels
|
|
RCTResizeMode resizeMode = [RCTConvert RCTResizeMode:cropDataCopy.resizeMode() ?: @"contain"];
|
|
targetRect = RCTTargetRect(croppedImage.size, targetSize, 1, resizeMode);
|
|
transform = RCTTransformFromTargetRect(croppedImage.size, targetRect);
|
|
croppedImage = RCTTransformImage(croppedImage, targetSize, image.scale, transform);
|
|
}
|
|
|
|
// Store image
|
|
[[self->_moduleRegistry moduleForName:"ImageStoreManager"] storeImage:croppedImage withBlock:^(NSString *croppedImageTag) {
|
|
if (!croppedImageTag) {
|
|
NSString *errorMessage = @"Error storing cropped image in RCTImageStoreManager";
|
|
RCTLogWarn(@"%@", errorMessage);
|
|
errorCallback(@[RCTJSErrorFromNSError(RCTErrorWithMessage(errorMessage))]);
|
|
return;
|
|
}
|
|
successCallback(@[croppedImageTag]);
|
|
}];
|
|
}];
|
|
}
|
|
|
|
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params
|
|
{
|
|
return std::make_shared<facebook::react::NativeImageEditorSpecJSI>(params);
|
|
}
|
|
|
|
@end
|
|
|
|
Class RCTImageEditingManagerCls() {
|
|
return RCTImageEditingManager.class;
|
|
}
|