Files
react-native/packages/rn-tester/NativeModuleExample/Screenshot.m
T
Chaoshuai Lu d70d7fd0b3 Adopt UIGraphicsImageRenderer API
Summary:
Apple suggested to this new API on iOS 10+.

> // Any new bitmap drawing code is encouraged to use UIGraphicsImageRenderer in lieu of this API.

WWDC18 Reference: https://developer.apple.com/videos/play/wwdc2018/219/
> Use UIGraphicsImageRenderer to create and draw to an image buffer
Supports Wide Color, unlike UIGraphicsBeginImageContext()
Combine with UIImageView for efficient offscreen rendering

Per https://nshipster.com/image-resizing/#performance-benchmarks, the new API runs even faster than the C version, probably due to more smart context reuses/management.

Changelog:
[iOS][Changed] - Adopt UIGraphicsImageRenderer API

Reviewed By: philIip

Differential Revision: D35699584

fbshipit-source-id: 7a1e2109d5e121fb396c1014f4ed0a892211b0cc
2022-04-22 17:02:51 -07:00

88 lines
2.8 KiB
Objective-C

/*
* 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 "Screenshot.h"
#import <React/RCTUIManager.h>
@implementation ScreenshotManager
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(takeScreenshot
: (id /* NSString or NSNumber */)target withOptions
: (NSDictionary *)options resolve
: (RCTPromiseResolveBlock)resolve reject
: (RCTPromiseRejectBlock)reject)
{
[self.bridge.uiManager addUIBlock:^(
__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
// Get view
UIView *view;
if (target == nil || [target isEqual:@"window"]) {
view = RCTKeyWindow();
} else if ([target isKindOfClass:[NSNumber class]]) {
view = viewRegistry[target];
if (!view) {
RCTLogError(@"No view found with reactTag: %@", target);
return;
}
}
// Get options
CGSize size = [RCTConvert CGSize:options];
NSString *format = [RCTConvert NSString:options[@"format"] ?: @"png"];
// Capture image
if (size.width < 0.1 || size.height < 0.1) {
size = view.bounds.size;
}
UIGraphicsImageRendererFormat *const rendererFormat = [UIGraphicsImageRendererFormat defaultFormat];
UIGraphicsImageRenderer *const renderer = [[UIGraphicsImageRenderer alloc] initWithSize:size format:rendererFormat];
__block BOOL success = NO;
UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull context) {
success = [view drawViewHierarchyInRect:(CGRect){CGPointZero, size} afterScreenUpdates:YES];
}];
if (!success || !image) {
reject(RCTErrorUnspecified, @"Failed to capture view snapshot.", nil);
return;
}
// Convert image to data (on a background thread)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data;
if ([format isEqualToString:@"png"]) {
data = UIImagePNGRepresentation(image);
} else if ([format isEqualToString:@"jpeg"]) {
CGFloat quality = [RCTConvert CGFloat:options[@"quality"] ?: @1];
data = UIImageJPEGRepresentation(image, quality);
} else {
RCTLogError(@"Unsupported image format: %@", format);
return;
}
// Save to a temp file
NSError *error = nil;
NSString *tempFilePath = RCTTempFilePath(format, &error);
if (tempFilePath) {
if ([data writeToFile:tempFilePath options:(NSDataWritingOptions)0 error:&error]) {
resolve(tempFilePath);
return;
}
}
// If we reached here, something went wrong
reject(RCTErrorUnspecified, error.localizedDescription, error);
});
}];
}
@end