mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-06-06 16:32:24 +00:00
[bugfix] Fix calling toDataUrl early and with options
Enable calling toDataUrl as soon as you get a ref to the svg root. Fix invalidation and rendering with options for width and height.
This commit is contained in:
@@ -101,8 +101,19 @@ public class SvgView extends ReactViewGroup implements ReactCompoundView, ReactC
|
|||||||
if (mBitmap == null) {
|
if (mBitmap == null) {
|
||||||
mBitmap = drawOutput();
|
mBitmap = drawOutput();
|
||||||
}
|
}
|
||||||
if (mBitmap != null)
|
if (mBitmap != null) {
|
||||||
canvas.drawBitmap(mBitmap, 0, 0, null);
|
canvas.drawBitmap(mBitmap, 0, 0, null);
|
||||||
|
if (toDataUrlTask != null) {
|
||||||
|
toDataUrlTask.run();
|
||||||
|
toDataUrlTask = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Runnable toDataUrlTask = null;
|
||||||
|
|
||||||
|
void setToDataUrlTask(Runnable task) {
|
||||||
|
toDataUrlTask = task;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -138,6 +149,10 @@ public class SvgView extends ReactViewGroup implements ReactCompoundView, ReactC
|
|||||||
private boolean mRendered = false;
|
private boolean mRendered = false;
|
||||||
int mTintColor = 0;
|
int mTintColor = 0;
|
||||||
|
|
||||||
|
boolean isRendered() {
|
||||||
|
return mRendered;
|
||||||
|
}
|
||||||
|
|
||||||
private void clearChildCache() {
|
private void clearChildCache() {
|
||||||
if (!mRendered) {
|
if (!mRendered) {
|
||||||
return;
|
return;
|
||||||
@@ -298,7 +313,10 @@ public class SvgView extends ReactViewGroup implements ReactCompoundView, ReactC
|
|||||||
getHeight(),
|
getHeight(),
|
||||||
Bitmap.Config.ARGB_8888);
|
Bitmap.Config.ARGB_8888);
|
||||||
|
|
||||||
|
clearChildCache();
|
||||||
drawChildren(new Canvas(bitmap));
|
drawChildren(new Canvas(bitmap));
|
||||||
|
clearChildCache();
|
||||||
|
this.invalidate();
|
||||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
||||||
bitmap.recycle();
|
bitmap.recycle();
|
||||||
@@ -312,7 +330,10 @@ public class SvgView extends ReactViewGroup implements ReactCompoundView, ReactC
|
|||||||
height,
|
height,
|
||||||
Bitmap.Config.ARGB_8888);
|
Bitmap.Config.ARGB_8888);
|
||||||
|
|
||||||
|
clearChildCache();
|
||||||
drawChildren(new Canvas(bitmap));
|
drawChildren(new Canvas(bitmap));
|
||||||
|
clearChildCache();
|
||||||
|
this.invalidate();
|
||||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
||||||
bitmap.recycle();
|
bitmap.recycle();
|
||||||
|
|||||||
@@ -28,9 +28,19 @@ class SvgViewManager extends ReactViewManager {
|
|||||||
private static final String REACT_CLASS = "RNSVGSvgView";
|
private static final String REACT_CLASS = "RNSVGSvgView";
|
||||||
|
|
||||||
private static final SparseArray<SvgView> mTagToSvgView = new SparseArray<>();
|
private static final SparseArray<SvgView> mTagToSvgView = new SparseArray<>();
|
||||||
|
private static final SparseArray<Runnable> mTagToRunnable = new SparseArray<>();
|
||||||
|
|
||||||
static void setSvgView(int tag, SvgView svg) {
|
static void setSvgView(int tag, SvgView svg) {
|
||||||
mTagToSvgView.put(tag, svg);
|
mTagToSvgView.put(tag, svg);
|
||||||
|
Runnable task = mTagToRunnable.get(tag);
|
||||||
|
if (task != null) {
|
||||||
|
task.run();
|
||||||
|
mTagToRunnable.delete(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void runWhenViewIsAvailable(int tag, Runnable task) {
|
||||||
|
mTagToRunnable.put(tag, task);
|
||||||
}
|
}
|
||||||
|
|
||||||
static @Nullable SvgView getSvgViewByTag(int tag) {
|
static @Nullable SvgView getSvgViewByTag(int tag) {
|
||||||
|
|||||||
@@ -25,12 +25,33 @@ class SvgViewModule extends ReactContextBaseJavaModule {
|
|||||||
return "RNSVGSvgViewManager";
|
return "RNSVGSvgViewManager";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static public void toDataURL(final int tag, final ReadableMap options, final Callback successCallback, final int attempt) {
|
||||||
@ReactMethod
|
|
||||||
public void toDataURL(int tag, ReadableMap options, Callback successCallback) {
|
|
||||||
SvgView svg = SvgViewManager.getSvgViewByTag(tag);
|
SvgView svg = SvgViewManager.getSvgViewByTag(tag);
|
||||||
|
|
||||||
if (svg != null) {
|
if (svg == null) {
|
||||||
|
SvgViewManager.runWhenViewIsAvailable(tag, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
SvgView svg = SvgViewManager.getSvgViewByTag(tag);
|
||||||
|
if (svg == null) { // Should never happen
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
svg.setToDataUrlTask(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
toDataURL(tag, options, successCallback, attempt + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (!svg.isRendered()) {
|
||||||
|
svg.setToDataUrlTask(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
toDataURL(tag, options, successCallback, attempt + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
if (options != null) {
|
if (options != null) {
|
||||||
successCallback.invoke(
|
successCallback.invoke(
|
||||||
svg.toDataURL(
|
svg.toDataURL(
|
||||||
@@ -43,4 +64,9 @@ class SvgViewModule extends ReactContextBaseJavaModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void toDataURL(int tag, ReadableMap options, Callback successCallback) {
|
||||||
|
toDataURL(tag, options, successCallback, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
|
|
||||||
- (NSString *)getDataURL;
|
- (NSString *)getDataURL;
|
||||||
|
|
||||||
- (NSString *)getDataURLwithBounds:(CGSize)bounds;
|
- (NSString *)getDataURLwithBounds:(CGRect)bounds;
|
||||||
|
|
||||||
- (CGRect)getContextBounds;
|
- (CGRect)getContextBounds;
|
||||||
|
|
||||||
|
|||||||
@@ -250,17 +250,23 @@
|
|||||||
- (NSString *)getDataURL
|
- (NSString *)getDataURL
|
||||||
{
|
{
|
||||||
UIGraphicsBeginImageContextWithOptions(_boundingBox.size, NO, 0);
|
UIGraphicsBeginImageContextWithOptions(_boundingBox.size, NO, 0);
|
||||||
|
[self clearChildCache];
|
||||||
[self drawRect:_boundingBox];
|
[self drawRect:_boundingBox];
|
||||||
|
[self clearChildCache];
|
||||||
|
[self invalidate];
|
||||||
NSData *imageData = UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext());
|
NSData *imageData = UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext());
|
||||||
NSString *base64 = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
|
NSString *base64 = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
|
||||||
UIGraphicsEndImageContext();
|
UIGraphicsEndImageContext();
|
||||||
return base64;
|
return base64;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)getDataURLwithBounds:(CGSize)bounds
|
- (NSString *)getDataURLwithBounds:(CGRect)bounds
|
||||||
{
|
{
|
||||||
UIGraphicsBeginImageContextWithOptions(bounds, NO, 0);
|
UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 0);
|
||||||
[self drawRect:_boundingBox];
|
[self clearChildCache];
|
||||||
|
[self drawRect:bounds];
|
||||||
|
[self clearChildCache];
|
||||||
|
[self invalidate];
|
||||||
NSData *imageData = UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext());
|
NSData *imageData = UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext());
|
||||||
NSString *base64 = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
|
NSString *base64 = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
|
||||||
UIGraphicsEndImageContext();
|
UIGraphicsEndImageContext();
|
||||||
|
|||||||
@@ -251,6 +251,7 @@
|
|||||||
94241669213B0DB800088E93 /* RNSVGPattern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNSVGPattern.h; sourceTree = "<group>"; };
|
94241669213B0DB800088E93 /* RNSVGPattern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNSVGPattern.h; sourceTree = "<group>"; };
|
||||||
9424166A213B2FF100088E93 /* RNSVGPatternManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNSVGPatternManager.h; sourceTree = "<group>"; };
|
9424166A213B2FF100088E93 /* RNSVGPatternManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNSVGPatternManager.h; sourceTree = "<group>"; };
|
||||||
9424166C213B302600088E93 /* RNSVGPatternManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNSVGPatternManager.m; sourceTree = "<group>"; };
|
9424166C213B302600088E93 /* RNSVGPatternManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNSVGPatternManager.m; sourceTree = "<group>"; };
|
||||||
|
94696EE92235A7F200C1D558 /* RNSVGVectorEffect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGVectorEffect.h; path = Utils/RNSVGVectorEffect.h; sourceTree = "<group>"; };
|
||||||
947F3809214810B800677F2A /* RNSVGMask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGMask.h; path = Elements/RNSVGMask.h; sourceTree = "<group>"; };
|
947F3809214810B800677F2A /* RNSVGMask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGMask.h; path = Elements/RNSVGMask.h; sourceTree = "<group>"; };
|
||||||
947F380A214810DC00677F2A /* RNSVGMask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGMask.m; path = Elements/RNSVGMask.m; sourceTree = "<group>"; };
|
947F380A214810DC00677F2A /* RNSVGMask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGMask.m; path = Elements/RNSVGMask.m; sourceTree = "<group>"; };
|
||||||
947F380D2148118300677F2A /* RNSVGMaskManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGMaskManager.h; sourceTree = "<group>"; };
|
947F380D2148118300677F2A /* RNSVGMaskManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGMaskManager.h; sourceTree = "<group>"; };
|
||||||
@@ -463,6 +464,7 @@
|
|||||||
1039D29A1CE7212C001E90A8 /* Utils */ = {
|
1039D29A1CE7212C001E90A8 /* Utils */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
94696EE92235A7F200C1D558 /* RNSVGVectorEffect.h */,
|
||||||
B56895A920352B36004DBF1E /* RNSVGBezierElement.h */,
|
B56895A920352B36004DBF1E /* RNSVGBezierElement.h */,
|
||||||
B56895A820352B35004DBF1E /* RNSVGBezierElement.m */,
|
B56895A820352B35004DBF1E /* RNSVGBezierElement.m */,
|
||||||
7F69160D1E3703D800DA6EDC /* RNSVGUnits.h */,
|
7F69160D1E3703D800DA6EDC /* RNSVGUnits.h */,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#import <React/RCTBridge.h>
|
#import <React/RCTBridge.h>
|
||||||
#import <React/RCTUIManager.h>
|
#import <React/RCTUIManager.h>
|
||||||
|
#import <React/RCTUIManagerUtils.h>
|
||||||
#import "RNSVGSvgViewManager.h"
|
#import "RNSVGSvgViewManager.h"
|
||||||
#import "RNSVGSvgView.h"
|
#import "RNSVGSvgView.h"
|
||||||
|
|
||||||
@@ -30,15 +31,15 @@ RCT_EXPORT_VIEW_PROPERTY(align, NSString)
|
|||||||
RCT_EXPORT_VIEW_PROPERTY(meetOrSlice, RNSVGVBMOS)
|
RCT_EXPORT_VIEW_PROPERTY(meetOrSlice, RNSVGVBMOS)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
|
RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(toDataURL:(nonnull NSNumber *)reactTag options:(NSDictionary *)options callback:(RCTResponseSenderBlock)callback)
|
|
||||||
{
|
- (void)toDataURL:(nonnull NSNumber *)reactTag options:(NSDictionary *)options callback:(RCTResponseSenderBlock)callback attempt:(int)attempt {
|
||||||
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
|
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
|
||||||
__kindof UIView *view = viewRegistry[reactTag];
|
__kindof UIView *view = viewRegistry[reactTag];
|
||||||
|
NSString * b64;
|
||||||
if ([view isKindOfClass:[RNSVGSvgView class]]) {
|
if ([view isKindOfClass:[RNSVGSvgView class]]) {
|
||||||
RNSVGSvgView *svg = view;
|
RNSVGSvgView *svg = view;
|
||||||
if (options == nil) {
|
if (options == nil) {
|
||||||
RNSVGSvgView *svg = view;
|
b64 = [svg getDataURL];
|
||||||
callback(@[[svg getDataURL]]);
|
|
||||||
} else {
|
} else {
|
||||||
id width = [options objectForKey:@"width"];
|
id width = [options objectForKey:@"width"];
|
||||||
id height = [options objectForKey:@"height"];
|
id height = [options objectForKey:@"height"];
|
||||||
@@ -52,13 +53,30 @@ RCT_EXPORT_METHOD(toDataURL:(nonnull NSNumber *)reactTag options:(NSDictionary *
|
|||||||
NSNumber* h = height;
|
NSNumber* h = height;
|
||||||
NSInteger hi = (NSInteger)[h intValue];
|
NSInteger hi = (NSInteger)[h intValue];
|
||||||
|
|
||||||
CGSize bounds = CGSizeMake(wi, hi);
|
CGRect bounds = CGRectMake(0, 0, wi, hi);
|
||||||
callback(@[[svg getDataURLwithBounds:bounds]]);
|
b64 = [svg getDataURLwithBounds:bounds];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
RCTLogError(@"Invalid svg returned frin registry, expecting RNSVGSvgView, got: %@", view);
|
RCTLogError(@"Invalid svg returned frin registry, expecting RNSVGSvgView, got: %@", view);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (b64) {
|
||||||
|
callback(@[b64]);
|
||||||
|
} else if (attempt < 1) {
|
||||||
|
void (^retryBlock)(void) = ^{
|
||||||
|
[self toDataURL:reactTag options:options callback:callback attempt:(attempt + 1)];
|
||||||
|
};
|
||||||
|
|
||||||
|
RCTExecuteOnUIManagerQueue(retryBlock);
|
||||||
|
} else {
|
||||||
|
callback(@[]);
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RCT_EXPORT_METHOD(toDataURL:(nonnull NSNumber *)reactTag options:(NSDictionary *)options callback:(RCTResponseSenderBlock)callback)
|
||||||
|
{
|
||||||
|
[self toDataURL:reactTag options:options callback:callback attempt:0];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
Reference in New Issue
Block a user