mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-06-05 16:04:38 +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) {
|
||||
mBitmap = drawOutput();
|
||||
}
|
||||
if (mBitmap != null)
|
||||
if (mBitmap != 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
|
||||
@@ -138,6 +149,10 @@ public class SvgView extends ReactViewGroup implements ReactCompoundView, ReactC
|
||||
private boolean mRendered = false;
|
||||
int mTintColor = 0;
|
||||
|
||||
boolean isRendered() {
|
||||
return mRendered;
|
||||
}
|
||||
|
||||
private void clearChildCache() {
|
||||
if (!mRendered) {
|
||||
return;
|
||||
@@ -298,7 +313,10 @@ public class SvgView extends ReactViewGroup implements ReactCompoundView, ReactC
|
||||
getHeight(),
|
||||
Bitmap.Config.ARGB_8888);
|
||||
|
||||
clearChildCache();
|
||||
drawChildren(new Canvas(bitmap));
|
||||
clearChildCache();
|
||||
this.invalidate();
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
||||
bitmap.recycle();
|
||||
@@ -312,7 +330,10 @@ public class SvgView extends ReactViewGroup implements ReactCompoundView, ReactC
|
||||
height,
|
||||
Bitmap.Config.ARGB_8888);
|
||||
|
||||
clearChildCache();
|
||||
drawChildren(new Canvas(bitmap));
|
||||
clearChildCache();
|
||||
this.invalidate();
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
||||
bitmap.recycle();
|
||||
|
||||
@@ -28,9 +28,19 @@ class SvgViewManager extends ReactViewManager {
|
||||
private static final String REACT_CLASS = "RNSVGSvgView";
|
||||
|
||||
private static final SparseArray<SvgView> mTagToSvgView = new SparseArray<>();
|
||||
private static final SparseArray<Runnable> mTagToRunnable = new SparseArray<>();
|
||||
|
||||
static void setSvgView(int tag, SvgView 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) {
|
||||
|
||||
@@ -25,12 +25,33 @@ class SvgViewModule extends ReactContextBaseJavaModule {
|
||||
return "RNSVGSvgViewManager";
|
||||
}
|
||||
|
||||
|
||||
@ReactMethod
|
||||
public void toDataURL(int tag, ReadableMap options, Callback successCallback) {
|
||||
static public void toDataURL(final int tag, final ReadableMap options, final Callback successCallback, final int attempt) {
|
||||
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) {
|
||||
successCallback.invoke(
|
||||
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 *)getDataURLwithBounds:(CGSize)bounds;
|
||||
- (NSString *)getDataURLwithBounds:(CGRect)bounds;
|
||||
|
||||
- (CGRect)getContextBounds;
|
||||
|
||||
|
||||
@@ -250,17 +250,23 @@
|
||||
- (NSString *)getDataURL
|
||||
{
|
||||
UIGraphicsBeginImageContextWithOptions(_boundingBox.size, NO, 0);
|
||||
[self clearChildCache];
|
||||
[self drawRect:_boundingBox];
|
||||
[self clearChildCache];
|
||||
[self invalidate];
|
||||
NSData *imageData = UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext());
|
||||
NSString *base64 = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
|
||||
UIGraphicsEndImageContext();
|
||||
return base64;
|
||||
}
|
||||
|
||||
- (NSString *)getDataURLwithBounds:(CGSize)bounds
|
||||
- (NSString *)getDataURLwithBounds:(CGRect)bounds
|
||||
{
|
||||
UIGraphicsBeginImageContextWithOptions(bounds, NO, 0);
|
||||
[self drawRect:_boundingBox];
|
||||
UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 0);
|
||||
[self clearChildCache];
|
||||
[self drawRect:bounds];
|
||||
[self clearChildCache];
|
||||
[self invalidate];
|
||||
NSData *imageData = UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext());
|
||||
NSString *base64 = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
@@ -251,6 +251,7 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@@ -463,6 +464,7 @@
|
||||
1039D29A1CE7212C001E90A8 /* Utils */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
94696EE92235A7F200C1D558 /* RNSVGVectorEffect.h */,
|
||||
B56895A920352B36004DBF1E /* RNSVGBezierElement.h */,
|
||||
B56895A820352B35004DBF1E /* RNSVGBezierElement.m */,
|
||||
7F69160D1E3703D800DA6EDC /* RNSVGUnits.h */,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTUIManager.h>
|
||||
#import <React/RCTUIManagerUtils.h>
|
||||
#import "RNSVGSvgViewManager.h"
|
||||
#import "RNSVGSvgView.h"
|
||||
|
||||
@@ -30,15 +31,15 @@ RCT_EXPORT_VIEW_PROPERTY(align, NSString)
|
||||
RCT_EXPORT_VIEW_PROPERTY(meetOrSlice, RNSVGVBMOS)
|
||||
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) {
|
||||
__kindof UIView *view = viewRegistry[reactTag];
|
||||
NSString * b64;
|
||||
if ([view isKindOfClass:[RNSVGSvgView class]]) {
|
||||
RNSVGSvgView *svg = view;
|
||||
if (options == nil) {
|
||||
RNSVGSvgView *svg = view;
|
||||
callback(@[[svg getDataURL]]);
|
||||
b64 = [svg getDataURL];
|
||||
} else {
|
||||
id width = [options objectForKey:@"width"];
|
||||
id height = [options objectForKey:@"height"];
|
||||
@@ -52,13 +53,30 @@ RCT_EXPORT_METHOD(toDataURL:(nonnull NSNumber *)reactTag options:(NSDictionary *
|
||||
NSNumber* h = height;
|
||||
NSInteger hi = (NSInteger)[h intValue];
|
||||
|
||||
CGSize bounds = CGSizeMake(wi, hi);
|
||||
callback(@[[svg getDataURLwithBounds:bounds]]);
|
||||
CGRect bounds = CGRectMake(0, 0, wi, hi);
|
||||
b64 = [svg getDataURLwithBounds:bounds];
|
||||
}
|
||||
} else {
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user