#import "WKSVGConvert.h"
#import <WebKit/WebKit.h>
@interface WKSVGConvert ()
<WKNavigationDelegate>
@property (nonatomic, strong) WKWebView *webView;
@property (nonatomic, copy) WKSVGConvertDataCallback waitCallback;
@end
@implementation WKSVGConvert
- (instancetype)init {
self = [super init];
if (self) {
self.webView = [WKWebView new];
self.webView.navigationDelegate = self;
}
return self;
}
- (void)doCallback:(NSError *)error imageDataArray:(NSArray<NSData *> *)imageDataArray {
[self callback:self.waitCallback error:error imageDataArray:imageDataArray];
}
- (void)callback:(WKSVGConvertDataCallback)callback error:(NSError *)error imageDataArray:(NSArray<NSData *> *)imageDataArray {
WKSVGConvertDataCallback aCallback = callback;
if (aCallback) {
dispatch_async(dispatch_get_main_queue(), ^{
aCallback(error, imageDataArray);
});
}
}
- (void)convertSvgData2Png:(NSArray<NSData *> *)svgDataArray complete:(WKSVGConvertImageCallback)complete {
[self convertSvgData:svgDataArray complete:complete ? ^(NSError * _Nullable error, NSArray<NSData *> * _Nonnull pictureDataArray) {
if (error) {
complete(error, nil);
} else {
NSMutableArray<UIImage *> *imageArray = [NSMutableArray array];
for (NSData *data in pictureDataArray) {
UIImage *image = [UIImage imageWithData:data];
[imageArray addObject:image ?: [UIImage new]];
}
complete(nil, imageArray);
}
} : nil];
}
- (void)convertSvgData:(NSArray<NSData *> *)svgDataArray complete:(WKSVGConvertDataCallback)complete {
WKSVGConvertDataCallback callback = self.waitCallback;
NSString *htmlString = [self urlStringForLoadingSvgData:svgDataArray];
self.waitCallback = complete;
[self.webView loadHTMLString:htmlString baseURL:nil];
[self callback:callback error:[NSError errorWithDomain:@"Canceled" code:kCFURLErrorCancelled userInfo:nil] imageDataArray:nil];
}
- (NSString *)urlStringForLoadingSvgData:(NSArray<NSData *> *)svgDataArray {
NSMutableString *htmlString = [NSMutableString stringWithString:@" \
<html> \
<head> \
</head> \
<body>"];
for (NSData *svgData in svgDataArray) {
NSString *base64Svg = [svgData base64EncodedStringWithOptions:kNilOptions];
[htmlString appendFormat:@" \
<img src='data:image/svg+xml;base64,%@'> \
", base64Svg];
}
[htmlString appendString:@"\
</body> \
</html> \
"];
return htmlString.copy;
}
- (NSString *)javaScriptForRequestPngData {
return @"\
function imagePngData() { \
var imageArray = document.getElementsByTagName('img'); \
var pngArray = new Array(); \
for (var index =0; index < imageArray.length; index++) { \
var image = imageArray[index]; \
var canvas = document.createElement('canvas'); \
canvas.width = image.width; \
canvas.height = image.height; \
var context = canvas.getContext('2d'); \
context.drawImage(image, 0, 0); \
pngArray.push(canvas.toDataURL('image/png')) \
} \
return pngArray; \
} \
imagePngData()";
}
- (void)requestSvg2PngDataByJavaScript {
__weak typeof(self) weakSelf = self;
[self.webView evaluateJavaScript:[self javaScriptForRequestPngData] completionHandler:^(id _Nullable result, NSError * _Nullable error) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (error) {
[strongSelf doCallback:error imageDataArray:nil];
return;
}
if (!result || ![result isKindOfClass:[NSArray class]]) {
[strongSelf doCallback:[NSError errorWithDomain:@"Bad Response" code:kCFURLErrorBadServerResponse userInfo:nil] imageDataArray:nil];
return;
}
NSString *pngPrefix = @"data:image/png;base64,";
NSMutableArray<NSData *> *pngDataArray = [NSMutableArray array];
for (NSString *pngBase64 in result) {
if (![pngBase64 hasPrefix:pngPrefix]) {
[pngDataArray addObject:[NSData data]];
} else {
NSString *base64String = [pngBase64 stringByReplacingCharactersInRange:NSMakeRange(0, pngPrefix.length) withString:@""];
NSData *data = [[NSData alloc] initWithBase64EncodedString:base64String options:kNilOptions];
[pngDataArray addObject:data ?: [NSData data]];
}
}
[strongSelf doCallback:nil imageDataArray:pngDataArray];
}];
}
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
[self requestSvg2PngDataByJavaScript];
}
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
[self doCallback:error imageDataArray:nil];
}
@end