From 131ddb6a1adf52e8d5f76890da6b2ab1f7f8cccf Mon Sep 17 00:00:00 2001 From: Mikael Sand Date: Sun, 10 Feb 2019 03:42:18 +0200 Subject: [PATCH] Implement version of toDataURL with width and height options https://github.com/react-native-community/react-native-svg/issues/855 --- .../main/java/com/horcrux/svg/SvgView.java | 14 ++++++++++ .../java/com/horcrux/svg/SvgViewModule.java | 16 ++++++++++++ elements/Svg.js | 13 +++++++--- ios/Elements/RNSVGSvgView.h | 2 ++ ios/Elements/RNSVGSvgView.m | 11 +++++++- ios/ViewManagers/RNSVGSvgViewManager.m | 26 +++++++++++++++++++ 6 files changed, 78 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/horcrux/svg/SvgView.java b/android/src/main/java/com/horcrux/svg/SvgView.java index 90d855db..4252f703 100644 --- a/android/src/main/java/com/horcrux/svg/SvgView.java +++ b/android/src/main/java/com/horcrux/svg/SvgView.java @@ -306,6 +306,20 @@ public class SvgView extends ReactViewGroup implements ReactCompoundView, ReactC return Base64.encodeToString(bitmapBytes, Base64.DEFAULT); } + String toDataURL(int width, int height) { + Bitmap bitmap = Bitmap.createBitmap( + width, + height, + Bitmap.Config.ARGB_8888); + + drawChildren(new Canvas(bitmap)); + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); + bitmap.recycle(); + byte[] bitmapBytes = stream.toByteArray(); + return Base64.encodeToString(bitmapBytes, Base64.DEFAULT); + } + void enableTouchEvents() { if (!mResponsible) { mResponsible = true; diff --git a/android/src/main/java/com/horcrux/svg/SvgViewModule.java b/android/src/main/java/com/horcrux/svg/SvgViewModule.java index b9ef4c03..a7573551 100644 --- a/android/src/main/java/com/horcrux/svg/SvgViewModule.java +++ b/android/src/main/java/com/horcrux/svg/SvgViewModule.java @@ -13,6 +13,7 @@ import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReadableMap; class SvgViewModule extends ReactContextBaseJavaModule { SvgViewModule(ReactApplicationContext reactContext) { @@ -33,4 +34,19 @@ class SvgViewModule extends ReactContextBaseJavaModule { successCallback.invoke(svg.toDataURL()); } } + + + @ReactMethod + public void toDataURL(int tag, ReadableMap options, Callback successCallback) { + SvgView svg = SvgViewManager.getSvgViewByTag(tag); + + if (svg != null) { + successCallback.invoke( + svg.toDataURL( + options.getInt("width"), + options.getInt("height") + ) + ); + } + } } diff --git a/elements/Svg.js b/elements/Svg.js index 1bac2f4a..30f7cbbc 100644 --- a/elements/Svg.js +++ b/elements/Svg.js @@ -49,9 +49,16 @@ export default class Svg extends Shape { this.root.setNativeProps(props); }; - toDataURL = callback => { - callback && - RNSVGSvgViewManager.toDataURL(findNodeHandle(this.root), callback); + toDataURL = (callback, options) => { + if (!callback) { + return; + } + const handle = findNodeHandle(this.root); + if (options) { + RNSVGSvgViewManager.toDataURL(handle, options, callback); + } else { + RNSVGSvgViewManager.toDataURL(handle, callback); + } }; render() { diff --git a/ios/Elements/RNSVGSvgView.h b/ios/Elements/RNSVGSvgView.h index 99112606..9ba992cf 100644 --- a/ios/Elements/RNSVGSvgView.h +++ b/ios/Elements/RNSVGSvgView.h @@ -52,6 +52,8 @@ - (NSString *)getDataURL; +- (NSString *)getDataURLwithBounds:(CGSize)bounds; + - (CGRect)getContextBounds; - (void)drawRect:(CGRect)rect; diff --git a/ios/Elements/RNSVGSvgView.m b/ios/Elements/RNSVGSvgView.m index 8b71ba30..f7c10826 100644 --- a/ios/Elements/RNSVGSvgView.m +++ b/ios/Elements/RNSVGSvgView.m @@ -247,7 +247,6 @@ return nil; } - - (NSString *)getDataURL { UIGraphicsBeginImageContextWithOptions(_boundingBox.size, NO, 0); @@ -258,6 +257,16 @@ return base64; } +- (NSString *)getDataURLwithBounds:(CGSize)bounds +{ + UIGraphicsBeginImageContextWithOptions(bounds, NO, 0); + [self drawRect:_boundingBox]; + NSData *imageData = UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext()); + NSString *base64 = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; + UIGraphicsEndImageContext(); + return base64; +} + - (void)reactSetInheritedBackgroundColor:(UIColor *)inheritedBackgroundColor { self.backgroundColor = inheritedBackgroundColor; diff --git a/ios/ViewManagers/RNSVGSvgViewManager.m b/ios/ViewManagers/RNSVGSvgViewManager.m index ae32ae60..97489a1c 100644 --- a/ios/ViewManagers/RNSVGSvgViewManager.m +++ b/ios/ViewManagers/RNSVGSvgViewManager.m @@ -43,4 +43,30 @@ RCT_EXPORT_METHOD(toDataURL:(nonnull NSNumber *)reactTag callback:(RCTResponseSe }]; } +RCT_EXPORT_METHOD(toDataURL:(nonnull NSNumber *)reactTag options:(NSDictionary *)options callback:(RCTResponseSenderBlock)callback) +{ + [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { + __kindof UIView *view = viewRegistry[reactTag]; + if ([view isKindOfClass:[RNSVGSvgView class]]) { + RNSVGSvgView *svg = view; + id width = [options objectForKey:@"width"]; + id height = [options objectForKey:@"height"]; + if (![width isKindOfClass:NSNumber.class] || + ![height isKindOfClass:NSNumber.class]) { + RCTLogError(@"Invalid width or height given to toDataURL"); + return; + } + NSNumber* w = width; + NSInteger wi = (NSInteger)[w intValue]; + NSNumber* h = height; + NSInteger hi = (NSInteger)[h intValue]; + + CGSize bounds = CGSizeMake(wi, hi); + callback(@[[svg getDataURLwithBounds:bounds]]); + } else { + RCTLogError(@"Invalid svg returned frin registry, expecting RNSVGSvgView, got: %@", view); + } + }]; +} + @end