Committed by
GitHub
Merge pull request #2080 from dreampiggy/feature_heif_image_format
Add image format detect of HEIC (One type of HEIF which use HEVC codec). This is supported natively in iOS 11 & macOS 10.13
Showing
4 changed files
with
64 additions
and
12 deletions
@@ -16,7 +16,8 @@ typedef NS_ENUM(NSInteger, SDImageFormat) { | @@ -16,7 +16,8 @@ typedef NS_ENUM(NSInteger, SDImageFormat) { | ||
16 | SDImageFormatPNG, | 16 | SDImageFormatPNG, |
17 | SDImageFormatGIF, | 17 | SDImageFormatGIF, |
18 | SDImageFormatTIFF, | 18 | SDImageFormatTIFF, |
19 | - SDImageFormatWebP | 19 | + SDImageFormatWebP, |
20 | + SDImageFormatHEIC | ||
20 | }; | 21 | }; |
21 | 22 | ||
22 | @interface NSData (ImageContentType) | 23 | @interface NSData (ImageContentType) |
@@ -14,6 +14,11 @@ | @@ -14,6 +14,11 @@ | ||
14 | #import <MobileCoreServices/MobileCoreServices.h> | 14 | #import <MobileCoreServices/MobileCoreServices.h> |
15 | #endif | 15 | #endif |
16 | 16 | ||
17 | +// Currently Image/IO does not support WebP | ||
18 | +#define kSDUTTypeWebP ((__bridge CFStringRef)@"public.webp") | ||
19 | +// AVFileTypeHEIC is defined in AVFoundation via iOS 11, we use this without import AVFoundation | ||
20 | +#define kSDUTTypeHEIC ((__bridge CFStringRef)@"public.heic") | ||
21 | + | ||
17 | @implementation NSData (ImageContentType) | 22 | @implementation NSData (ImageContentType) |
18 | 23 | ||
19 | + (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data { | 24 | + (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data { |
@@ -21,6 +26,7 @@ | @@ -21,6 +26,7 @@ | ||
21 | return SDImageFormatUndefined; | 26 | return SDImageFormatUndefined; |
22 | } | 27 | } |
23 | 28 | ||
29 | + // File signatures table: http://www.garykessler.net/library/file_sigs.html | ||
24 | uint8_t c; | 30 | uint8_t c; |
25 | [data getBytes:&c length:1]; | 31 | [data getBytes:&c length:1]; |
26 | switch (c) { | 32 | switch (c) { |
@@ -33,16 +39,26 @@ | @@ -33,16 +39,26 @@ | ||
33 | case 0x49: | 39 | case 0x49: |
34 | case 0x4D: | 40 | case 0x4D: |
35 | return SDImageFormatTIFF; | 41 | return SDImageFormatTIFF; |
36 | - case 0x52: | ||
37 | - // R as RIFF for WEBP | ||
38 | - if (data.length < 12) { | ||
39 | - return SDImageFormatUndefined; | 42 | + case 0x52: { |
43 | + if (data.length >= 12) { | ||
44 | + //RIFF....WEBP | ||
45 | + NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding]; | ||
46 | + if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) { | ||
47 | + return SDImageFormatWebP; | ||
48 | + } | ||
40 | } | 49 | } |
41 | - | ||
42 | - NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding]; | ||
43 | - if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) { | ||
44 | - return SDImageFormatWebP; | 50 | + break; |
51 | + } | ||
52 | + case 0x00: { | ||
53 | + if (data.length >= 12) { | ||
54 | + //....ftypheic | ||
55 | + NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(4, 8)] encoding:NSASCIIStringEncoding]; | ||
56 | + if ([testString isEqualToString:@"ftypheic"]) { | ||
57 | + return SDImageFormatHEIC; | ||
58 | + } | ||
45 | } | 59 | } |
60 | + break; | ||
61 | + } | ||
46 | } | 62 | } |
47 | return SDImageFormatUndefined; | 63 | return SDImageFormatUndefined; |
48 | } | 64 | } |
@@ -62,6 +78,12 @@ | @@ -62,6 +78,12 @@ | ||
62 | case SDImageFormatTIFF: | 78 | case SDImageFormatTIFF: |
63 | UTType = kUTTypeTIFF; | 79 | UTType = kUTTypeTIFF; |
64 | break; | 80 | break; |
81 | + case SDImageFormatWebP: | ||
82 | + UTType = kSDUTTypeWebP; | ||
83 | + break; | ||
84 | + case SDImageFormatHEIC: | ||
85 | + UTType = kSDUTTypeHEIC; | ||
86 | + break; | ||
65 | default: | 87 | default: |
66 | // default is kUTTypePNG | 88 | // default is kUTTypePNG |
67 | UTType = kUTTypePNG; | 89 | UTType = kUTTypePNG; |
@@ -33,10 +33,12 @@ CG_EXTERN BOOL SDCGImageRefContainsAlpha(_Nullable CGImageRef imageRef); | @@ -33,10 +33,12 @@ CG_EXTERN BOOL SDCGImageRefContainsAlpha(_Nullable CGImageRef imageRef); | ||
33 | 33 | ||
34 | /** | 34 | /** |
35 | This is the image coder protocol to provide custom image decoding/encoding. | 35 | This is the image coder protocol to provide custom image decoding/encoding. |
36 | + These methods are all required to implement. | ||
36 | @note Pay attention that these methods are not called from main queue. | 37 | @note Pay attention that these methods are not called from main queue. |
37 | */ | 38 | */ |
38 | @protocol SDWebImageCoder <NSObject> | 39 | @protocol SDWebImageCoder <NSObject> |
39 | 40 | ||
41 | +@required | ||
40 | #pragma mark - Decoding | 42 | #pragma mark - Decoding |
41 | /** | 43 | /** |
42 | Returns YES if this coder can decode some data. Otherwise, the data should be passed to another coder. | 44 | Returns YES if this coder can decode some data. Otherwise, the data should be passed to another coder. |
@@ -90,10 +92,12 @@ CG_EXTERN BOOL SDCGImageRefContainsAlpha(_Nullable CGImageRef imageRef); | @@ -90,10 +92,12 @@ CG_EXTERN BOOL SDCGImageRefContainsAlpha(_Nullable CGImageRef imageRef); | ||
90 | 92 | ||
91 | /** | 93 | /** |
92 | This is the image coder protocol to provide custom progressive image decoding. | 94 | This is the image coder protocol to provide custom progressive image decoding. |
95 | + These methods are all required to implement. | ||
93 | @note Pay attention that these methods are not called from main queue. | 96 | @note Pay attention that these methods are not called from main queue. |
94 | */ | 97 | */ |
95 | @protocol SDWebImageProgressiveCoder <SDWebImageCoder> | 98 | @protocol SDWebImageProgressiveCoder <SDWebImageCoder> |
96 | 99 | ||
100 | +@required | ||
97 | /** | 101 | /** |
98 | Returns YES if this coder can incremental decode some data. Otherwise, it should be passed to another coder. | 102 | Returns YES if this coder can incremental decode some data. Otherwise, it should be passed to another coder. |
99 | 103 |
@@ -66,8 +66,8 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over | @@ -66,8 +66,8 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over | ||
66 | #pragma mark - Decode | 66 | #pragma mark - Decode |
67 | - (BOOL)canDecodeFromData:(nullable NSData *)data { | 67 | - (BOOL)canDecodeFromData:(nullable NSData *)data { |
68 | switch ([NSData sd_imageFormatForImageData:data]) { | 68 | switch ([NSData sd_imageFormatForImageData:data]) { |
69 | - // Do not support WebP decoding | ||
70 | case SDImageFormatWebP: | 69 | case SDImageFormatWebP: |
70 | + // Do not support WebP decoding | ||
71 | return NO; | 71 | return NO; |
72 | default: | 72 | default: |
73 | return YES; | 73 | return YES; |
@@ -76,8 +76,8 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over | @@ -76,8 +76,8 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over | ||
76 | 76 | ||
77 | - (BOOL)canIncrementallyDecodeFromData:(NSData *)data { | 77 | - (BOOL)canIncrementallyDecodeFromData:(NSData *)data { |
78 | switch ([NSData sd_imageFormatForImageData:data]) { | 78 | switch ([NSData sd_imageFormatForImageData:data]) { |
79 | - // Support static GIF progressive decoding | ||
80 | case SDImageFormatWebP: | 79 | case SDImageFormatWebP: |
80 | + // Do not support WebP progressive decoding | ||
81 | return NO; | 81 | return NO; |
82 | default: | 82 | default: |
83 | return YES; | 83 | return YES; |
@@ -394,9 +394,12 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over | @@ -394,9 +394,12 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over | ||
394 | #pragma mark - Encode | 394 | #pragma mark - Encode |
395 | - (BOOL)canEncodeToFormat:(SDImageFormat)format { | 395 | - (BOOL)canEncodeToFormat:(SDImageFormat)format { |
396 | switch (format) { | 396 | switch (format) { |
397 | - // Do not support WebP encoding | ||
398 | case SDImageFormatWebP: | 397 | case SDImageFormatWebP: |
398 | + // Do not support WebP encoding | ||
399 | return NO; | 399 | return NO; |
400 | + case SDImageFormatHEIC: | ||
401 | + // Check HEIC encoding compatibility | ||
402 | + return [[self class] canEncodeToHEICFormat]; | ||
400 | default: | 403 | default: |
401 | return YES; | 404 | return YES; |
402 | } | 405 | } |
@@ -469,6 +472,28 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over | @@ -469,6 +472,28 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over | ||
469 | return YES; | 472 | return YES; |
470 | } | 473 | } |
471 | 474 | ||
475 | ++ (BOOL)canEncodeToHEICFormat | ||
476 | +{ | ||
477 | + static BOOL canEncode = NO; | ||
478 | + static dispatch_once_t onceToken; | ||
479 | + dispatch_once(&onceToken, ^{ | ||
480 | + NSMutableData *imageData = [NSMutableData data]; | ||
481 | + CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatHEIC]; | ||
482 | + | ||
483 | + // Create an image destination. | ||
484 | + CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, 1, NULL); | ||
485 | + if (!imageDestination) { | ||
486 | + // Can't encode to HEIC | ||
487 | + canEncode = NO; | ||
488 | + } else { | ||
489 | + // Can encode to HEIC | ||
490 | + CFRelease(imageDestination); | ||
491 | + canEncode = YES; | ||
492 | + } | ||
493 | + }); | ||
494 | + return canEncode; | ||
495 | +} | ||
496 | + | ||
472 | #if SD_UIKIT || SD_WATCH | 497 | #if SD_UIKIT || SD_WATCH |
473 | #pragma mark EXIF orientation tag converter | 498 | #pragma mark EXIF orientation tag converter |
474 | + (UIImageOrientation)sd_imageOrientationFromImageData:(nonnull NSData *)imageData { | 499 | + (UIImageOrientation)sd_imageOrientationFromImageData:(nonnull NSData *)imageData { |
-
Please register or login to post a comment