RNImageToBase64 本机模块崩溃 URL

RNImageToBase64 native module crashes for a URL

我正在尝试将 React Native Asset 转换为 Base64 图像。

有一个在 NativeModules 中实现的 React Native 库,但它会在执行 getBase64String(url, callback).

时崩溃本机 iOS 应用程序

示例 URL 发送至 RNImageToBase64(由 react-native-camera 生成):

/var/mobile/Containers/Data/Application/8BE6DA73-73A6-4E9A-BDF9-431726243667/Documents/F76931EE-E8F6-431F-8FFF-D481DDA8CC6B.jpg

失败的行:

[library assetForURL:url resultBlock:^(ALAsset *asset) {

Xcode中的错误:

libsystem_kernel.dylib`__abort_with_payload:
    0x180640d6c <+0>:  movz   x16, #0x209
    0x180640d70 <+4>:  svc    #0x80
->  0x180640d74 <+8>:  b.lo   0x180640d8c               ; <+32>
    0x180640d78 <+12>: stp    x29, x30, [sp, #-16]!
    0x180640d7c <+16>: mov    x29, sp
    0x180640d80 <+20>: bl     0x1806257b4               ; cerror_nocancel
    0x180640d84 <+24>: mov    sp, x29
    0x180640d88 <+28>: ldp    x29, x30, [sp], #16
    0x180640d8c <+32>: ret    

index.ios.js 调用 NativeModules 的行:

NativeModules.RNImageToBase64.getBase64String(uri, (err, base64) => {
});

RNImageToBase64.m 崩溃的原生模块:

#import "RNImageToBase64.h"
#import <AssetsLibrary/AssetsLibrary.h>
#import <UIKit/UIKit.h>

@implementation RNImageToBase64

RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(getBase64String:(NSString *)input callback:(RCTResponseSenderBlock)callback)
{
  NSURL *url = [[NSURL alloc] initWithString:input];
  ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
  [library assetForURL:url resultBlock:^(ALAsset *asset) {
    ALAssetRepresentation *rep = [asset defaultRepresentation];
    CGImageRef imageRef = [rep fullScreenImage];
    NSData *imageData = UIImagePNGRepresentation([UIImage imageWithCGImage:imageRef]);
    NSString *base64Encoded = [imageData base64EncodedStringWithOptions:0];
    callback(@[[NSNull null], base64Encoded]);
  } failureBlock:^(NSError *error) {
    NSLog(@"that didn't work %@", error);
    callback(@[error]);
  }];
}

@end

问题是它试图访问资产库中的图像。

我的解决方案由 RNImageToBase64 模块的一个修改版本组成,该模块使用磁盘上的文件路径。

#import "RNImageToBase64.h"
#import <AssetsLibrary/AssetsLibrary.h>
#import <UIKit/UIKit.h>
#import <ImageIO/ImageIO.h>

@implementation RNImageToBase64

RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(getBase64String:(NSString *)input callback:(RCTResponseSenderBlock)callback)
{
  CGImageRef image = MyCreateCGImageFromFile(input);
  NSData *imageData = UIImagePNGRepresentation([UIImage imageWithCGImage:image]);
  NSString *base64Encoded = [imageData base64EncodedStringWithOptions:0];
  callback(@[[NSNull null], base64Encoded]);
}

CGImageRef MyCreateCGImageFromFile (NSString* path)
{
    // Get the URL for the pathname passed to the function.
    NSURL *url = [NSURL fileURLWithPath:path];
    CGImageRef        myImage = NULL;
    CGImageSourceRef  myImageSource;
    CFDictionaryRef   myOptions = NULL;
    CFStringRef       myKeys[2];
    CFTypeRef         myValues[2];

    // Set up options if you want them. The options here are for
    // caching the image in a decoded form and for using floating-point
    // values if the image format supports them.
    myKeys[0] = kCGImageSourceShouldCache;
    myValues[0] = (CFTypeRef)kCFBooleanTrue;
    myKeys[1] = kCGImageSourceShouldAllowFloat;
    myValues[1] = (CFTypeRef)kCFBooleanTrue;
    // Create the dictionary
    myOptions = CFDictionaryCreate(NULL, (const void **) myKeys,
                                   (const void **) myValues, 2,
                                   &kCFTypeDictionaryKeyCallBacks,
                                   & kCFTypeDictionaryValueCallBacks);
    // Create an image source from the URL.
    myImageSource = CGImageSourceCreateWithURL((CFURLRef)url, myOptions);
    CFRelease(myOptions);
    // Make sure the image source exists before continuing
    if (myImageSource == NULL){
        fprintf(stderr, "Image source is NULL.");
        return  NULL;
    }
    // Create an image from the first item in the image source.
    myImage = CGImageSourceCreateImageAtIndex(myImageSource,
                                              0,
                                              NULL);

    CFRelease(myImageSource);
    // Make sure the image exists before continuing
    if (myImage == NULL){
        fprintf(stderr, "Image not created from image source.");
        return NULL;
    }

    return myImage;
}

@end