diff --git a/Example/SDWebImageSVGCoder/SDViewController.m b/Example/SDWebImageSVGCoder/SDViewController.m index bfac528..d33b494 100644 --- a/Example/SDWebImageSVGCoder/SDViewController.m +++ b/Example/SDWebImageSVGCoder/SDViewController.m @@ -25,6 +25,11 @@ - (void)viewDidLoad NSURL *svgURL = [NSURL URLWithString:@"https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/w3c.svg"]; NSURL *svgURL2 = [NSURL URLWithString:@"https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/wikimedia.svg"]; NSURL *svgURL3 = [NSURL URLWithString:@"https://simpleicons.org/icons/github.svg"]; + // Some SVG will fail, this demo check them and the C++/Objc exception should be catched by SDK + NSURL *badSVGURL = [NSURL URLWithString:@"https://openseauserdata.com/files/b809fe0925eb3629bb1d3edb1fafcc88.svg"]; + [SDWebImageManager.sharedManager loadImageWithURL:badSVGURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) { + + }]; CGSize screenSize = self.view.bounds.size; diff --git a/README.md b/README.md index e41b48e..f0c0fb2 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,8 @@ If you still worry about the SPI usage, you can use [SDWebImageSVGKitPlugin](htt There is also another solution: [SVG-Native](https://w3c.github.io/svgwg/specs/svg-native/index.html), a new W3C standard from Adobe, which is a subset of SVG/1.1. Both Apple/Google/Microsoft already join the agreement for this standard, you can try to write your own coder using code from [SVG-native-viewer](https://github.com/adobe/svg-native-viewer/blob/master/svgnative/example/testCocoaCG/SVGNSView.mm) and adopt SVG-native for vector images. +> Warning: Some user report that Apple's CoreSVG has compatible issue for some SVGs (like using non-system Font, gradient), from v1.7.0 we protect some cases, but other exceptions are un-catchable. For these crashes, either use `Render SVG as bitmap image` (see below) or edit your SVG source file to make Apple's CoeSVG compatible. + ## Example To run the example project, clone the repo, and run `pod install` from the Example directory first. diff --git a/SDWebImageSVGCoder/Classes/SDImageSVGCoder.m b/SDWebImageSVGCoder/Classes/SDImageSVGCoder.m index de81cc9..b07c44f 100644 --- a/SDWebImageSVGCoder/Classes/SDImageSVGCoder.m +++ b/SDWebImageSVGCoder/Classes/SDImageSVGCoder.m @@ -49,12 +49,12 @@ + (SDImageSVGCoder *)sharedCoder { } + (void)initialize { - SDCGSVGDocumentRetain = dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dTVkdEb2N1bWVudFJldGFpbg==").UTF8String); - SDCGSVGDocumentRelease = dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dTVkdEb2N1bWVudFJlbGVhc2U=").UTF8String); - SDCGSVGDocumentCreateFromData = dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dTVkdEb2N1bWVudENyZWF0ZUZyb21EYXRh").UTF8String); - SDCGSVGDocumentWriteToData = dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dTVkdEb2N1bWVudFdyaXRlVG9EYXRh").UTF8String); - SDCGContextDrawSVGDocument = dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dDb250ZXh0RHJhd1NWR0RvY3VtZW50").UTF8String); - SDCGSVGDocumentGetCanvasSize = dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dTVkdEb2N1bWVudEdldENhbnZhc1NpemU=").UTF8String); + SDCGSVGDocumentRetain = (CGSVGDocumentRef (*)(CGSVGDocumentRef))dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dTVkdEb2N1bWVudFJldGFpbg==").UTF8String); + SDCGSVGDocumentRelease = (void (*)(CGSVGDocumentRef))dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dTVkdEb2N1bWVudFJlbGVhc2U=").UTF8String); + SDCGSVGDocumentCreateFromData = (CGSVGDocumentRef (*)(CFDataRef data, CFDictionaryRef options))dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dTVkdEb2N1bWVudENyZWF0ZUZyb21EYXRh").UTF8String); + SDCGSVGDocumentWriteToData = (void (*)(CGSVGDocumentRef document, CFDataRef data, CFDictionaryRef options))dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dTVkdEb2N1bWVudFdyaXRlVG9EYXRh").UTF8String); + SDCGContextDrawSVGDocument = (void (*)(CGContextRef context, CGSVGDocumentRef document))dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dDb250ZXh0RHJhd1NWR0RvY3VtZW50").UTF8String); + SDCGSVGDocumentGetCanvasSize = (CGSize (*)(CGSVGDocumentRef document))dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dTVkdEb2N1bWVudEdldENhbnZhc1NpemU=").UTF8String); #if SD_UIKIT || SD_WATCH SDImageWithCGSVGDocumentSEL = NSSelectorFromString(SDBase64DecodedString(@"X2ltYWdlV2l0aENHU1ZHRG9jdW1lbnQ6")); SDCGSVGDocumentSEL = NSSelectorFromString(SDBase64DecodedString(@"X0NHU1ZHRG9jdW1lbnQ=")); @@ -152,7 +152,15 @@ - (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format o return nil; } - SDCGSVGDocumentWriteToData(document, (__bridge CFDataRef)data, NULL); + @try { + // WARNING! Some CoreSVG exceptions can be catched, but not always + // If you finally crash here (un-catchable), you can only workaround (or hope Apple fix this) + // Do not encode vector UIImage into NSData, query `SDImageCache` for the same key and get back SVG Data + SDCGSVGDocumentWriteToData(document, (__bridge CFMutableDataRef)data, NULL); + } @catch (...) { + // CoreSVG export failed + return nil; + } return [data copy]; } @@ -178,6 +186,23 @@ - (UIImage *)createVectorSVGWithData:(nonnull NSData *)data { image = ((UIImage *(*)(id,SEL,CGSVGDocumentRef))[UIImage.class methodForSelector:SDImageWithCGSVGDocumentSEL])(UIImage.class, SDImageWithCGSVGDocumentSEL, document); SDCGSVGDocumentRelease(document); #endif + + // CoreSVG has compatible for some SVG/1.1 format (like Font issue) and may crash when rendering on screen (not here, Core Animation commit time) + // So, we snapshot a 1x1 pixel image and try catch here to check :( + + SDGraphicsImageRenderer *renderer = [[SDGraphicsImageRenderer alloc] initWithSize:CGSizeMake(1, 1)]; + @try { + __unused UIImage *dummyImage = [renderer imageWithActions:^(CGContextRef _Nonnull context) { + // WARNING! Some CoreSVG exceptions can be catched, but not always + // If you finally crash here (un-catchable), you can only workaround (or hope Apple fix this) + // Change your code to use `SDWebImageContextImageThumbnailPixelSize` context option with enough size to render bitmap SVG instead + [image drawInRect:CGRectMake(0, 0, 1, 1)]; + }]; + } @catch (...) { + // CoreSVG decode failed + return nil; + } + return image; }