SDImageSVGKCoder.m 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. //
  2. // SDImageSVGKCoder.m
  3. // SDWebImageSVGPlugin
  4. //
  5. // Created by DreamPiggy on 2018/9/27.
  6. //
  7. #import "SDImageSVGKCoder.h"
  8. #import "SDSVGKImage.h"
  9. #import "SDWebImageSVGKitDefine.h"
  10. #if __has_include(<SVGKit/SVGKit.h>)
  11. #import <SVGKit/SVGKit.h>
  12. #else
  13. @import SVGKit;
  14. #endif
  15. #define kSVGTagEnd @"</svg>"
  16. @implementation SDImageSVGKCoder
  17. + (SDImageSVGKCoder *)sharedCoder {
  18. static dispatch_once_t onceToken;
  19. static SDImageSVGKCoder *coder;
  20. dispatch_once(&onceToken, ^{
  21. coder = [[SDImageSVGKCoder alloc] init];
  22. });
  23. return coder;
  24. }
  25. #pragma mark - Decode
  26. - (BOOL)canDecodeFromData:(NSData *)data {
  27. return [self.class isSVGFormatForData:data];
  28. }
  29. - (UIImage *)decodedImageWithData:(NSData *)data options:(SDImageCoderOptions *)options {
  30. if (!data) {
  31. return nil;
  32. }
  33. // Parse SVG
  34. SVGKImage *svgImage = [[SVGKImage alloc] initWithData:data];
  35. if (!svgImage) {
  36. return nil;
  37. }
  38. CGSize imageSize = CGSizeZero;
  39. BOOL preserveAspectRatio = YES;
  40. #pragma clang diagnostic push
  41. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  42. // Parse args
  43. SDWebImageContext *context = options[SDImageCoderWebImageContext];
  44. if (context[SDWebImageContextSVGKImageSize]) {
  45. NSValue *sizeValue = context[SDWebImageContextSVGKImageSize];
  46. #if SD_UIKIT
  47. imageSize = sizeValue.CGSizeValue;
  48. #else
  49. imageSize = sizeValue.sizeValue;
  50. #endif
  51. } else if (options[SDImageCoderDecodeThumbnailPixelSize]) {
  52. NSValue *sizeValue = options[SDImageCoderDecodeThumbnailPixelSize];
  53. #if SD_UIKIT
  54. imageSize = sizeValue.CGSizeValue;
  55. #else
  56. imageSize = sizeValue.sizeValue;
  57. #endif
  58. }
  59. if (context[SDWebImageContextSVGKImagePreserveAspectRatio]) {
  60. preserveAspectRatio = [context[SDWebImageContextSVGKImagePreserveAspectRatio] boolValue];
  61. } else if (options[SDImageCoderDecodePreserveAspectRatio]) {
  62. preserveAspectRatio = [options[SDImageCoderDecodePreserveAspectRatio] boolValue];
  63. }
  64. #pragma clang diagnostic pop
  65. if (!CGSizeEqualToSize(imageSize, CGSizeZero)) {
  66. if (preserveAspectRatio) {
  67. [svgImage scaleToFitInside:imageSize];
  68. } else {
  69. svgImage.size = imageSize;
  70. }
  71. }
  72. UIImage *image = svgImage.UIImage;
  73. if (!image) {
  74. return nil;
  75. }
  76. // SVG is vector image, so no need scale factor
  77. image.sd_imageFormat = SDImageFormatSVG;
  78. return image;
  79. }
  80. #pragma mark - Encode
  81. - (BOOL)canEncodeToFormat:(SDImageFormat)format {
  82. return format == SDImageFormatSVG;
  83. }
  84. - (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(SDImageCoderOptions *)options {
  85. // Only support SVGKImage wrapper
  86. if (![image isKindOfClass:SDSVGKImage.class]) {
  87. return nil;
  88. }
  89. SVGKImage *svgImage = ((SDSVGKImage *)image).SVGKImage;
  90. if (!svgImage) {
  91. return nil;
  92. }
  93. SVGKSource *source = svgImage.source;
  94. // Should be NSData type source
  95. if (![source isKindOfClass:SVGKSourceNSData.class]) {
  96. return nil;
  97. }
  98. return ((SVGKSourceNSData *)source).rawData;
  99. }
  100. #pragma mark - Helper
  101. + (BOOL)isSVGFormatForData:(NSData *)data {
  102. if (!data) {
  103. return NO;
  104. }
  105. if (data.length <= 100) {
  106. return NO;
  107. }
  108. // Check end with SVG tag
  109. NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(data.length - 100, 100)] encoding:NSASCIIStringEncoding];
  110. if (![testString containsString:kSVGTagEnd]) {
  111. return NO;
  112. }
  113. return YES;
  114. }
  115. @end