Add the feature to allows advanced user to provided extended data associarted with image data, used for scale factor saving, rich link metadata saving, etc

This commit is contained in:
DreamPiggy 2019-11-23 18:50:39 +08:00
parent 74526bdde4
commit 892a7ad892
10 changed files with 274 additions and 0 deletions

View File

@ -89,6 +89,12 @@
325C46272233A0A8004CAE11 /* NSBezierPath+RoundedCorners.h in Headers */ = {isa = PBXBuildFile; fileRef = 325C46242233A0A8004CAE11 /* NSBezierPath+RoundedCorners.h */; settings = {ATTRIBUTES = (Private, ); }; };
325C46282233A0A8004CAE11 /* NSBezierPath+RoundedCorners.m in Sources */ = {isa = PBXBuildFile; fileRef = 325C46252233A0A8004CAE11 /* NSBezierPath+RoundedCorners.m */; };
325C46292233A0A8004CAE11 /* NSBezierPath+RoundedCorners.m in Sources */ = {isa = PBXBuildFile; fileRef = 325C46252233A0A8004CAE11 /* NSBezierPath+RoundedCorners.m */; };
325F7CC623893B2E00AEDFCC /* NSFileManager+ExtendedAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = 325F7CC423893B2E00AEDFCC /* NSFileManager+ExtendedAttributes.h */; settings = {ATTRIBUTES = (Private, ); }; };
325F7CC723893B2E00AEDFCC /* NSFileManager+ExtendedAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = 325F7CC523893B2E00AEDFCC /* NSFileManager+ExtendedAttributes.m */; };
325F7CCA238942AB00AEDFCC /* NSData+ExtendedData.h in Headers */ = {isa = PBXBuildFile; fileRef = 325F7CC8238942AB00AEDFCC /* NSData+ExtendedData.h */; settings = {ATTRIBUTES = (Public, ); }; };
325F7CCB238942AB00AEDFCC /* NSData+ExtendedData.m in Sources */ = {isa = PBXBuildFile; fileRef = 325F7CC9238942AB00AEDFCC /* NSData+ExtendedData.m */; };
325F7CCC2389463D00AEDFCC /* NSData+ExtendedData.m in Sources */ = {isa = PBXBuildFile; fileRef = 325F7CC9238942AB00AEDFCC /* NSData+ExtendedData.m */; };
325F7CCD2389467800AEDFCC /* NSData+ExtendedData.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 325F7CC8238942AB00AEDFCC /* NSData+ExtendedData.h */; };
326E2F2E236F0B23006F847F /* SDAnimatedImagePlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 326E2F2C236F0B23006F847F /* SDAnimatedImagePlayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
326E2F2F236F0B23006F847F /* SDAnimatedImagePlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 326E2F2D236F0B23006F847F /* SDAnimatedImagePlayer.m */; };
326E2F30236F0B23006F847F /* SDAnimatedImagePlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 326E2F2D236F0B23006F847F /* SDAnimatedImagePlayer.m */; };
@ -298,6 +304,7 @@
dstPath = include/SDWebImage;
dstSubfolderSpec = 16;
files = (
325F7CCD2389467800AEDFCC /* NSData+ExtendedData.h in Copy Headers */,
326E2F36236F1E30006F847F /* SDAnimatedImagePlayer.h in Copy Headers */,
3250C9F12355E3DF0093A896 /* SDWebImageDownloaderDecryptor.h in Copy Headers */,
325427662355783C0042BAA4 /* SDWebImageDownloaderResponseModifier.h in Copy Headers */,
@ -407,6 +414,10 @@
325C461F2233A02E004CAE11 /* UIColor+HexString.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIColor+HexString.m"; sourceTree = "<group>"; };
325C46242233A0A8004CAE11 /* NSBezierPath+RoundedCorners.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSBezierPath+RoundedCorners.h"; sourceTree = "<group>"; };
325C46252233A0A8004CAE11 /* NSBezierPath+RoundedCorners.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSBezierPath+RoundedCorners.m"; sourceTree = "<group>"; };
325F7CC423893B2E00AEDFCC /* NSFileManager+ExtendedAttributes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSFileManager+ExtendedAttributes.h"; sourceTree = "<group>"; };
325F7CC523893B2E00AEDFCC /* NSFileManager+ExtendedAttributes.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSFileManager+ExtendedAttributes.m"; sourceTree = "<group>"; };
325F7CC8238942AB00AEDFCC /* NSData+ExtendedData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "NSData+ExtendedData.h"; path = "Core/NSData+ExtendedData.h"; sourceTree = "<group>"; };
325F7CC9238942AB00AEDFCC /* NSData+ExtendedData.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "NSData+ExtendedData.m"; path = "Core/NSData+ExtendedData.m"; sourceTree = "<group>"; };
326E2F2C236F0B23006F847F /* SDAnimatedImagePlayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDAnimatedImagePlayer.h; path = Core/SDAnimatedImagePlayer.h; sourceTree = "<group>"; };
326E2F2D236F0B23006F847F /* SDAnimatedImagePlayer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDAnimatedImagePlayer.m; path = Core/SDAnimatedImagePlayer.m; sourceTree = "<group>"; };
326E2F31236F1D58006F847F /* SDDeviceHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDDeviceHelper.h; sourceTree = "<group>"; };
@ -635,6 +646,8 @@
325C461F2233A02E004CAE11 /* UIColor+HexString.m */,
325C46242233A0A8004CAE11 /* NSBezierPath+RoundedCorners.h */,
325C46252233A0A8004CAE11 /* NSBezierPath+RoundedCorners.m */,
325F7CC423893B2E00AEDFCC /* NSFileManager+ExtendedAttributes.h */,
325F7CC523893B2E00AEDFCC /* NSFileManager+ExtendedAttributes.m */,
329F123F223FAD3400B309FD /* SDInternalMacros.h */,
329F123E223FAD3400B309FD /* SDInternalMacros.m */,
329F1235223FAA3B00B309FD /* SDmetamacros.h */,
@ -744,6 +757,8 @@
children = (
5D5B9140188EE8DD006D06BD /* NSData+ImageContentType.h */,
5D5B9141188EE8DD006D06BD /* NSData+ImageContentType.m */,
325F7CC8238942AB00AEDFCC /* NSData+ExtendedData.h */,
325F7CC9238942AB00AEDFCC /* NSData+ExtendedData.m */,
A18A6CC5172DC28500419892 /* UIImage+GIF.h */,
A18A6CC6172DC28500419892 /* UIImage+GIF.m */,
329A18571FFF5DFD008C9A2F /* UIImage+Metadata.h */,
@ -849,6 +864,7 @@
3257EAFA21898AED0097B271 /* SDImageGraphics.h in Headers */,
32D3CDD121DDE87300C4DB49 /* UIImage+MemoryCacheCost.h in Headers */,
328BB6AC2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */,
325F7CCA238942AB00AEDFCC /* NSData+ExtendedData.h in Headers */,
325C46272233A0A8004CAE11 /* NSBezierPath+RoundedCorners.h in Headers */,
321B378F2083290E00C0EA77 /* SDImageLoadersManager.h in Headers */,
329A185B1FFF5DFD008C9A2F /* UIImage+Metadata.h in Headers */,
@ -906,6 +922,7 @@
32C0FDE32013426C001B8F2D /* SDWebImageIndicator.h in Headers */,
32F7C0712030114C00873181 /* SDImageTransformer.h in Headers */,
32E67311235765B500DB4987 /* SDDisplayLink.h in Headers */,
325F7CC623893B2E00AEDFCC /* NSFileManager+ExtendedAttributes.h in Headers */,
4A2CAE2D1AB4BB7500B6BC39 /* UIImage+GIF.h in Headers */,
4A2CAE291AB4BB7500B6BC39 /* NSData+ImageContentType.h in Headers */,
328BB69E2081FED200760D6C /* SDWebImageCacheKeyFilter.h in Headers */,
@ -1098,6 +1115,7 @@
3257EAFD21898AED0097B271 /* SDImageGraphics.m in Sources */,
3290FA0C1FA478AF0047D20C /* SDImageFrame.m in Sources */,
325C46232233A02E004CAE11 /* UIColor+HexString.m in Sources */,
325F7CCB238942AB00AEDFCC /* NSData+ExtendedData.m in Sources */,
321E60C61F38E91700405457 /* UIImage+ForceDecode.m in Sources */,
3244062E2296C5F400A36084 /* SDWebImageOptionsProcessor.m in Sources */,
3250C9F02355D9DA0093A896 /* SDWebImageDownloaderDecryptor.m in Sources */,
@ -1127,6 +1145,7 @@
321E609C1F38E8ED00405457 /* SDImageIOCoder.m in Sources */,
4A2CAE261AB4BB7000B6BC39 /* SDWebImagePrefetcher.m in Sources */,
328BB6C92082581100760D6C /* SDDiskCache.m in Sources */,
325F7CC723893B2E00AEDFCC /* NSFileManager+ExtendedAttributes.m in Sources */,
3248475F201775F600AF9E5A /* SDAnimatedImageView.m in Sources */,
32D1222C2080B2EB003685A3 /* SDImageCachesManager.m in Sources */,
32B9B53F206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */,
@ -1198,6 +1217,7 @@
5376130D155AD0D5005750A4 /* SDWebImagePrefetcher.m in Sources */,
328BB6C72082581100760D6C /* SDDiskCache.m in Sources */,
3248475D201775F600AF9E5A /* SDAnimatedImageView.m in Sources */,
325F7CCC2389463D00AEDFCC /* NSData+ExtendedData.m in Sources */,
32D1222A2080B2EB003685A3 /* SDImageCachesManager.m in Sources */,
32B9B53D206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */,
43A9186B1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */,

View File

@ -0,0 +1,21 @@
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
* (c) Fabrice Aneche
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import <Foundation/Foundation.h>
#import "SDWebImageCompat.h"
@interface NSData (ExtendedData)
/**
Read and Write the extended data to the image data. Which can hold some extra metadata like Image's scale factor, URL rich link, date, etc.
The extended data will be write to disk cache as well as the image data. The disk cache preserve both of the data and extended data with the same cache key.
*/
@property (nonatomic, strong, nullable) NSData *sd_extendedData;
@end

View File

@ -0,0 +1,23 @@
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
* (c) Fabrice Aneche
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "NSData+ExtendedData.h"
#import <objc/runtime.h>
@implementation NSData (ExtendedData)
- (NSData *)sd_extendedData {
return objc_getAssociatedObject(self, @selector(sd_extendedData));
}
- (void)setSd_extendedData:(NSData *)sd_extendedData {
objc_setAssociatedObject(self, @selector(sd_extendedData), sd_extendedData, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end

View File

@ -54,6 +54,26 @@
*/
- (void)setData:(nullable NSData *)data forKey:(nonnull NSString *)key;
/**
Returns the extended data associated with a given key.
This method may blocks the calling thread until file read finished.
@param key A string identifying the data. If nil, just return nil.
@return The value associated with key, or nil if no value is associated with key.
*/
- (nullable NSData *)extendedDataForKey:(nonnull NSString *)key;
/**
Set extended data with a given key.
@discussion You can set any extended data to exist cache key. Without override the exist disk file data.
on UNIX, the common way for this is to use the Extended file attributes (xattr)
@param extendedData The extended data (pass nil to remove).
@param key The key with which to associate the value. If nil, this method has no effect.
*/
- (void)setExtendedData:(nullable NSData *)extendedData forKey:(nonnull NSString *)key;
/**
Removes the value of the specified key in the cache.
This method may blocks the calling thread until file delete finished.

View File

@ -8,8 +8,11 @@
#import "SDDiskCache.h"
#import "SDImageCacheConfig.h"
#import "NSFileManager+ExtendedAttributes.h"
#import <CommonCrypto/CommonDigest.h>
static NSString * const SDDiskCacheExtendedAttributeName = @"com.hackemist.SDDiskCache";
@interface SDDiskCache ()
@property (nonatomic, copy) NSString *diskCachePath;
@ -95,6 +98,31 @@
}
}
- (NSData *)extendedDataForKey:(NSString *)key {
NSParameterAssert(key);
// get cache Path for image key
NSString *cachePathForKey = [self cachePathForKey:key];
NSData *extendedData = [self.fileManager extendedAttribute:SDDiskCacheExtendedAttributeName atPath:cachePathForKey traverseLink:NO error:nil];
return extendedData;
}
- (void)setExtendedData:(NSData *)extendedData forKey:(NSString *)key {
NSParameterAssert(key);
// get cache Path for image key
NSString *cachePathForKey = [self cachePathForKey:key];
if (!extendedData) {
// Remove
[self.fileManager removeExtendedAttribute:SDDiskCacheExtendedAttributeName atPath:cachePathForKey traverseLink:NO error:nil];
} else {
// Override
[self.fileManager setExtendedAttribute:SDDiskCacheExtendedAttributeName value:extendedData atPath:cachePathForKey traverseLink:NO overwrite:YES error:nil];
}
}
- (void)removeDataForKey:(NSString *)key {
NSParameterAssert(key);
NSString *filePath = [self cachePathForKey:key];

View File

@ -14,6 +14,7 @@
#import "SDAnimatedImage.h"
#import "UIImage+MemoryCacheCost.h"
#import "UIImage+Metadata.h"
#import "NSData+ExtendedData.h"
@interface SDImageCache ()
@ -238,6 +239,10 @@
}
[self.diskCache setData:imageData forKey:key];
NSData *extendedData = imageData.sd_extendedData;
if (extendedData) {
[self.diskCache setExtendedData:extendedData forKey:key];
}
}
#pragma mark - Query and Retrieve Ops
@ -320,6 +325,11 @@
NSData *data = [self.diskCache dataForKey:key];
if (data) {
// Check extended data
NSData *extendedData = [self.diskCache extendedDataForKey:key];
if (extendedData) {
data.sd_extendedData = extendedData;
}
return data;
}

View File

@ -17,6 +17,10 @@ typedef NSData * _Nullable(^SDWebImageCacheSerializerBlock)(UIImage * _Nonnull i
*/
@protocol SDWebImageCacheSerializer <NSObject>
/// Provide the image data associated to the image and store to disk cache
/// @param image The loaded image
/// @param data The original loaded image data
/// @param imageURL The image URL
- (nullable NSData *)cacheDataWithImage:(nonnull UIImage *)image originalData:(nullable NSData *)data imageURL:(nullable NSURL *)imageURL;
@end

View File

@ -0,0 +1,19 @@
//
// NSFileManager+ExtendedAttributes.h
// NSFileManager+ExtendedAttributes
//
// Created by Jesús A. Álvarez on 2008-12-17.
// Copyright 2008-2009 namedfork.net. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSFileManager (ExtendedAttributes)
- (NSArray*)extendedAttributeNamesAtPath:(NSString*)path traverseLink:(BOOL)follow error:(NSError**)err;
- (BOOL)hasExtendedAttribute:(NSString*)name atPath:(NSString*)path traverseLink:(BOOL)follow error:(NSError**)err;
- (NSData*)extendedAttribute:(NSString*)name atPath:(NSString*)path traverseLink:(BOOL)follow error:(NSError**)err;
- (BOOL)setExtendedAttribute:(NSString*)name value:(NSData*)value atPath:(NSString*)path traverseLink:(BOOL)follow overwrite:(BOOL)overwrite error:(NSError**)err;
- (BOOL)removeExtendedAttribute:(NSString*)name atPath:(NSString*)path traverseLink:(BOOL)follow error:(NSError**)err;
@end

View File

@ -0,0 +1,128 @@
//
// NSFileManager+ExtendedAttributes.m
// NSFileManager+ExtendedAttributes
//
// Created by Jesús A. Álvarez on 2008-12-17.
// Copyright 2008-2009 namedfork.net. All rights reserved.
//
#import "NSFileManager+ExtendedAttributes.h"
#import <sys/xattr.h>
@implementation NSFileManager (ExtendedAttributes)
- (NSArray*)extendedAttributeNamesAtPath:(NSString*)path traverseLink:(BOOL)follow error:(NSError**)err {
int flags = follow? 0 : XATTR_NOFOLLOW;
// get size of name list
ssize_t nameBuffLen = listxattr([path fileSystemRepresentation], NULL, 0, flags);
if (nameBuffLen == -1) {
if (err) *err = [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:
[NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithUTF8String:strerror(errno)], @"error",
@"listxattr", @"function",
path, @":path",
[NSNumber numberWithBool:follow], @":traverseLink",
nil]
];
return nil;
} else if (nameBuffLen == 0) return [NSArray array];
// get name list
NSMutableData *nameBuff = [NSMutableData dataWithLength:nameBuffLen];
listxattr([path fileSystemRepresentation], [nameBuff mutableBytes], nameBuffLen, flags);
// convert to array
NSMutableArray * names = [NSMutableArray arrayWithCapacity:5];
char *nextName, *endOfNames = [nameBuff mutableBytes] + nameBuffLen;
for(nextName = [nameBuff mutableBytes]; nextName < endOfNames; nextName += 1+strlen(nextName))
[names addObject:[NSString stringWithUTF8String:nextName]];
return [NSArray arrayWithArray:names];
}
- (BOOL)hasExtendedAttribute:(NSString*)name atPath:(NSString*)path traverseLink:(BOOL)follow error:(NSError**)err {
int flags = follow? 0 : XATTR_NOFOLLOW;
// get size of name list
ssize_t nameBuffLen = listxattr([path fileSystemRepresentation], NULL, 0, flags);
if (nameBuffLen == -1) {
if (err) *err = [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:
[NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithUTF8String:strerror(errno)], @"error",
@"listxattr", @"function",
path, @":path",
[NSNumber numberWithBool:follow], @":traverseLink",
nil]
];
return NO;
} else if (nameBuffLen == 0) return NO;
// get name list
NSMutableData *nameBuff = [NSMutableData dataWithLength:nameBuffLen];
listxattr([path fileSystemRepresentation], [nameBuff mutableBytes], nameBuffLen, flags);
// find our name
char *nextName, *endOfNames = [nameBuff mutableBytes] + nameBuffLen;
for(nextName = [nameBuff mutableBytes]; nextName < endOfNames; nextName += 1+strlen(nextName))
if (strcmp(nextName, [name UTF8String]) == 0) return YES;
return NO;
}
- (NSData*)extendedAttribute:(NSString*)name atPath:(NSString*)path traverseLink:(BOOL)follow error:(NSError**)err {
int flags = follow? 0 : XATTR_NOFOLLOW;
// get length
ssize_t attrLen = getxattr([path fileSystemRepresentation], [name UTF8String], NULL, 0, 0, flags);
if (attrLen == -1) {
if (err) *err = [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:
[NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithUTF8String:strerror(errno)], @"error",
@"getxattr", @"function",
name, @":name",
path, @":path",
[NSNumber numberWithBool:follow], @":traverseLink",
nil]
];
return nil;
}
// get attribute data
NSMutableData * attrData = [NSMutableData dataWithLength:attrLen];
getxattr([path fileSystemRepresentation], [name UTF8String], [attrData mutableBytes], attrLen, 0, flags);
return attrData;
}
- (BOOL)setExtendedAttribute:(NSString*)name value:(NSData*)value atPath:(NSString*)path traverseLink:(BOOL)follow overwrite:(BOOL)overwrite error:(NSError**)err {
int flags = (follow? 0 : XATTR_NOFOLLOW) | (overwrite? 0 : XATTR_CREATE);
if (0 == setxattr([path fileSystemRepresentation], [name UTF8String], [value bytes], [value length], 0, flags)) return YES;
// error
if (err) *err = [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:
[NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithUTF8String:strerror(errno)], @"error",
@"setxattr", @"function",
name, @":name",
[NSNumber numberWithUnsignedInteger:[value length]], @":value.length",
path, @":path",
[NSNumber numberWithBool:follow], @":traverseLink",
[NSNumber numberWithBool:overwrite], @":overwrite",
nil]
];
return NO;
}
- (BOOL)removeExtendedAttribute:(NSString*)name atPath:(NSString*)path traverseLink:(BOOL)follow error:(NSError**)err {
int flags = (follow? 0 : XATTR_NOFOLLOW);
if (0 == removexattr([path fileSystemRepresentation], [name UTF8String], flags)) return YES;
// error
if (err) *err = [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:
[NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithUTF8String:strerror(errno)], @"error",
@"removexattr", @"function",
name, @":name",
path, @":path",
[NSNumber numberWithBool:follow], @":traverseLink",
nil]
];
return NO;
}
@end

View File

@ -67,6 +67,7 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[];
#import <SDWebImage/UIImage+GIF.h>
#import <SDWebImage/UIImage+ForceDecode.h>
#import <SDWebImage/NSData+ImageContentType.h>
#import <SDWebImage/NSData+ExtendedData.h>
#import <SDWebImage/SDWebImageDefine.h>
#import <SDWebImage/SDWebImageError.h>
#import <SDWebImage/SDWebImageOptionsProcessor.h>