6
6
//
7
7
8
8
#import " SDImageSVGCoder.h"
9
- #import " SDSVGImage.h"
10
9
#import " SDWebImageSVGCoderDefine.h"
11
- #import < SVGKit/SVGKit.h>
12
10
#import < dlfcn.h>
11
+ #import < objc/runtime.h>
13
12
14
13
#define kSVGTagEnd @" </svg>"
15
14
16
15
typedef struct CF_BRIDGED_TYPE (id ) CGSVGDocument *CGSVGDocumentRef;
17
16
static CGSVGDocumentRef (*CGSVGDocumentCreateFromDataProvider)(CGDataProviderRef provider, CFDictionaryRef options);
18
17
static CGSVGDocumentRef (*CGSVGDocumentRetain)(CGSVGDocumentRef);
19
18
static void (*CGSVGDocumentRelease)(CGSVGDocumentRef);
19
+ static void (*CGSVGDocumentWriteToData)(CGSVGDocumentRef document, CFDataRef data, CFDictionaryRef options);
20
20
21
21
#if SD_UIKIT
22
22
@@ -32,6 +32,20 @@ - (CGSVGDocumentRef)_CGSVGDocument;
32
32
33
33
#endif
34
34
35
+ #if SD_MAC
36
+
37
+ #define NSSVGImageRepClass @" _NSSVGImageRep"
38
+
39
+ @protocol NSSVGImageRepProtocol <NSObject >
40
+
41
+ - (instancetype )initWithSVGDocument : (CGSVGDocumentRef)document ;
42
+ - (instancetype )initWithData : (NSData *)data ;
43
+ - (CGSVGDocumentRef)_document ;
44
+
45
+ @end
46
+
47
+ #endif
48
+
35
49
@implementation SDImageSVGCoder
36
50
37
51
+ (SDImageSVGCoder *)sharedCoder {
@@ -47,6 +61,7 @@ + (void)initialize {
47
61
CGSVGDocumentCreateFromDataProvider = dlsym (RTLD_DEFAULT, " CGSVGDocumentCreateFromDataProvider" );
48
62
CGSVGDocumentRetain = dlsym (RTLD_DEFAULT, " CGSVGDocumentRetain" );
49
63
CGSVGDocumentRelease = dlsym (RTLD_DEFAULT, " CGSVGDocumentRelease" );
64
+ CGSVGDocumentWriteToData = dlsym (RTLD_DEFAULT, " CGSVGDocumentWriteToData" );
50
65
}
51
66
52
67
#pragma mark - Decode
@@ -59,20 +74,27 @@ - (UIImage *)decodedImageWithData:(NSData *)data options:(SDImageCoderOptions *)
59
74
if (!data) {
60
75
return nil ;
61
76
}
62
- #if SD_UIKIT
63
- if ([self .class supportsVectorSVGImage ]) {
64
- return [self createVectorSVGWithData: data options: options];
65
- } else {
66
- return [self createBitmapSVGWithData: data options: options];
77
+ if (![self .class supportsVectorSVGImage ]) {
78
+ return nil ;
67
79
}
80
+ // Parse args
81
+ SDWebImageContext *context = options[SDImageCoderWebImageContext];
82
+ NSValue *sizeValue = context[SDWebImageContextSVGImageSize];
83
+ #if SD_MAC
84
+ CGSize imageSize = sizeValue.sizeValue ;
85
+ #else
86
+ CGSize imageSize = sizeValue.CGSizeValue ;
87
+ #endif
88
+
89
+ #if SD_MAC
90
+ Class imageRepClass = NSClassFromString (NSSVGImageRepClass);
91
+ NSImageRep *imageRep = [[imageRepClass alloc ] initWithData: data];
92
+ if (!imageRep) {
93
+ return nil ;
94
+ }
95
+ NSImage *image = [[NSImage alloc ] initWithSize: imageSize];
96
+ [image addRepresentation: imageRep];
68
97
#else
69
- return [self createBitmapSVGWithData: data options: options];
70
- #endif
71
- }
72
-
73
- #if SD_UIKIT
74
- - (UIImage *)createVectorSVGWithData : (NSData *)data options : (SDImageCoderOptions *)options {
75
- NSParameterAssert (data);
76
98
CGDataProviderRef provider = CGDataProviderCreateWithCFData ((__bridge CFDataRef)data);
77
99
if (!provider) {
78
100
return nil ;
@@ -83,51 +105,7 @@ - (UIImage *)createVectorSVGWithData:(NSData *)data options:(SDImageCoderOptions
83
105
}
84
106
UIImage *image = [UIImage _imageWithCGSVGDocument: document];
85
107
CGSVGDocumentRelease (document);
86
-
87
- return image;
88
- }
89
108
#endif
90
-
91
- - (UIImage *)createBitmapSVGWithData : (NSData *)data options : (SDImageCoderOptions *)options {
92
- NSParameterAssert (data);
93
- // Parse SVG
94
- SVGKImage *svgImage = [[SVGKImage alloc ] initWithData: data];
95
- if (!svgImage) {
96
- return nil ;
97
- }
98
-
99
- CGSize imageSize = CGSizeZero;
100
- BOOL preserveAspectRatio = YES ;
101
- // Parse args
102
- SDWebImageContext *context = options[SDImageCoderWebImageContext];
103
- if (context[SDWebImageContextSVGImageSize]) {
104
- NSValue *sizeValue = context[SDWebImageContextSVGImageSize];
105
- #if SD_UIKIT
106
- imageSize = sizeValue.CGSizeValue ;
107
- #else
108
- imageSize = sizeValue.sizeValue ;
109
- #endif
110
- }
111
- if (context[SDWebImageContextSVGImagePreserveAspectRatio]) {
112
- preserveAspectRatio = [context[SDWebImageContextSVGImagePreserveAspectRatio] boolValue ];
113
- }
114
-
115
- if (!CGSizeEqualToSize (imageSize, CGSizeZero)) {
116
- if (preserveAspectRatio) {
117
- [svgImage scaleToFitInside: imageSize];
118
- } else {
119
- svgImage.size = imageSize;
120
- }
121
- }
122
-
123
- UIImage *image = svgImage.UIImage ;
124
- if (!image) {
125
- return nil ;
126
- }
127
-
128
- // SVG is vector image, so no need scale factor
129
- image.sd_imageFormat = SDImageFormatSVG;
130
-
131
109
return image;
132
110
}
133
111
@@ -137,41 +115,54 @@ - (BOOL)canEncodeToFormat:(SDImageFormat)format {
137
115
return format == SDImageFormatSVG;
138
116
}
139
117
140
- - (NSData *)encodedDataWithImage : (UIImage *)image format : (SDImageFormat)format options : (SDImageCoderOptions *)options {
141
- // Only support SVGKImage wrapper
142
- if (![image isKindOfClass: SDSVGImage.class]) {
118
+ - (NSData *)encodedDataWithImage : (UIImage *)image format : (SDImageFormat)format options : (SDImageCoderOptions *)options { // SVGKImage wrapper
119
+ if (![self .class supportsVectorSVGImage ]) {
143
120
return nil ;
144
121
}
145
- SVGKImage *svgImage = ((SDSVGImage *)image).SVGImage ;
146
- if (!svgImage) {
147
- return nil ;
122
+ NSMutableData *data = [NSMutableData data ];
123
+ CGSVGDocumentRef document = NULL ;
124
+ #if SD_MAC
125
+ NSRect imageRect = NSMakeRect (0 , 0 , image.size .width , image.size .height );
126
+ NSImageRep *imageRep = [image bestRepresentationForRect: imageRect context: nil hints: nil ];
127
+ if ([imageRep isKindOfClass: NSClassFromString (NSSVGImageRepClass)]) {
128
+ Ivar ivar = class_getInstanceVariable (imageRep.class , " _document" );
129
+ document = (__bridge CGSVGDocumentRef)(object_getIvar (imageRep, ivar));
148
130
}
149
- SVGKSource *source = svgImage.source ;
150
- // Should be NSData type source
151
- if (![source isKindOfClass: SVGKSourceNSData.class]) {
131
+ #else
132
+ document = [image _CGSVGDocument ];
133
+ #endif
134
+ if (!document) {
152
135
return nil ;
153
136
}
154
- return ((SVGKSourceNSData *)source).rawData ;
137
+
138
+ CGSVGDocumentWriteToData (document, (__bridge CFDataRef)data, NULL );
139
+
140
+ return [data copy ];
155
141
}
156
142
157
143
#pragma mark - Helper
158
144
159
145
+ (BOOL )supportsVectorSVGImage {
160
- #if SD_MAC
161
- return NO ;
162
- #else
163
146
static dispatch_once_t onceToken;
164
147
static BOOL supports;
165
148
dispatch_once (&onceToken, ^{
149
+ #if SD_MAC
150
+ // macOS 10.15+ supports SVG built-in rendering, use selector to check is more accurate
151
+ if (NSClassFromString (NSSVGImageRepClass)) {
152
+ supports = YES ;
153
+ } else {
154
+ supports = NO ;
155
+ }
156
+ #else
166
157
// iOS 13+ supports SVG built-in rendering, use selector to check is more accurate
167
158
if ([UIImage respondsToSelector: @selector (_imageWithCGSVGDocument: )]) {
168
159
supports = YES ;
169
160
} else {
170
161
supports = NO ;
171
162
}
163
+ #endif
172
164
});
173
165
return supports;
174
- #endif
175
166
}
176
167
177
168
+ (BOOL )isSVGFormatForData : (NSData *)data {
0 commit comments