RCTImageEditingManager.mm 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #import <React/RCTImageEditingManager.h>
  8. #import <FBReactNativeSpec/FBReactNativeSpec.h>
  9. #import <React/RCTConvert.h>
  10. #import <React/RCTImageLoader.h>
  11. #import <React/RCTImageStoreManager.h>
  12. #import <React/RCTImageUtils.h>
  13. #import <React/RCTImageLoaderProtocol.h>
  14. #import <React/RCTLog.h>
  15. #import <React/RCTUtils.h>
  16. #import <UIKit/UIKit.h>
  17. #import "RCTImagePlugins.h"
  18. @interface RCTImageEditingManager() <NativeImageEditorSpec>
  19. @end
  20. @implementation RCTImageEditingManager
  21. RCT_EXPORT_MODULE()
  22. @synthesize bridge = _bridge;
  23. /**
  24. * Crops an image and adds the result to the image store.
  25. *
  26. * @param imageRequest An image URL
  27. * @param cropData Dictionary with `offset`, `size` and `displaySize`.
  28. * `offset` and `size` are relative to the full-resolution image size.
  29. * `displaySize` is an optimization - if specified, the image will
  30. * be scaled down to `displaySize` rather than `size`.
  31. * All units are in px (not points).
  32. */
  33. RCT_EXPORT_METHOD(cropImage:(NSURLRequest *)imageRequest
  34. cropData:(JS::NativeImageEditor::Options &)cropData
  35. successCallback:(RCTResponseSenderBlock)successCallback
  36. errorCallback:(RCTResponseSenderBlock)errorCallback)
  37. {
  38. CGRect rect = {
  39. [RCTConvert CGPoint:@{
  40. @"x": @(cropData.offset().x()),
  41. @"y": @(cropData.offset().y()),
  42. }],
  43. [RCTConvert CGSize:@{
  44. @"width": @(cropData.size().width()),
  45. @"height": @(cropData.size().height()),
  46. }]
  47. };
  48. // We must keep a copy of cropData so that we can access data from it at a later time
  49. JS::NativeImageEditor::Options cropDataCopy = cropData;
  50. [[_bridge moduleForName:@"ImageLoader" lazilyLoadIfNecessary:YES]
  51. loadImageWithURLRequest:imageRequest callback:^(NSError *error, UIImage *image) {
  52. if (error) {
  53. errorCallback(@[RCTJSErrorFromNSError(error)]);
  54. return;
  55. }
  56. // Crop image
  57. CGSize targetSize = rect.size;
  58. CGRect targetRect = {{-rect.origin.x, -rect.origin.y}, image.size};
  59. CGAffineTransform transform = RCTTransformFromTargetRect(image.size, targetRect);
  60. UIImage *croppedImage = RCTTransformImage(image, targetSize, image.scale, transform);
  61. // Scale image
  62. if (cropDataCopy.displaySize()) {
  63. targetSize = [RCTConvert CGSize:@{@"width": @(cropDataCopy.displaySize()->width()), @"height": @(cropDataCopy.displaySize()->height())}]; // in pixels
  64. RCTResizeMode resizeMode = [RCTConvert RCTResizeMode:cropDataCopy.resizeMode() ?: @"contain"];
  65. targetRect = RCTTargetRect(croppedImage.size, targetSize, 1, resizeMode);
  66. transform = RCTTransformFromTargetRect(croppedImage.size, targetRect);
  67. croppedImage = RCTTransformImage(croppedImage, targetSize, image.scale, transform);
  68. }
  69. // Store image
  70. [self->_bridge.imageStoreManager storeImage:croppedImage withBlock:^(NSString *croppedImageTag) {
  71. if (!croppedImageTag) {
  72. NSString *errorMessage = @"Error storing cropped image in RCTImageStoreManager";
  73. RCTLogWarn(@"%@", errorMessage);
  74. errorCallback(@[RCTJSErrorFromNSError(RCTErrorWithMessage(errorMessage))]);
  75. return;
  76. }
  77. successCallback(@[croppedImageTag]);
  78. }];
  79. }];
  80. }
  81. - (std::shared_ptr<facebook::react::TurboModule>)
  82. getTurboModuleWithJsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
  83. nativeInvoker:(std::shared_ptr<facebook::react::CallInvoker>)nativeInvoker
  84. perfLogger:(id<RCTTurboModulePerformanceLogger>)perfLogger
  85. {
  86. return std::make_shared<facebook::react::NativeImageEditorSpecJSI>(self, jsInvoker, nativeInvoker, perfLogger);
  87. }
  88. @end
  89. Class RCTImageEditingManagerCls() {
  90. return RCTImageEditingManager.class;
  91. }