Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,32 @@ let thumbnailWebpData = SDImageWebPCoder.shared.encodedData(with: image, format:

See more documentation in [SDWebImage Wiki - Coders](https://github.com/SDWebImage/SDWebImage/wiki/Advanced-Usage#custom-coder-420)

### Advanced WebP codec options (0.8+)

The WebP codec [libwebp](https://developers.google.com/speed/webp/docs/api) we use, supports some advanced control options for encoding/decoding. You can pass them to libwebp by using the wrapper top level API:

+ Objective-C

```objective-c
UIImage *image;
SDImageCoderOptions *options = @{SDImageCoderEncodeWebPMethod: @(0), SDImageCoderEncodeWebPAlphaCompression: @(100)};
NSData *data = [SDImageWebPCoder.sharedCoder encodedDataWithImage:image format:SDImageFormatWebP options:options];
// Will translate into:
// config->method = 0;
// config->alpha_quality = 100;
```

+ Swift

```swift
let image: UIImage
let options = [.encodeWebPMethod: 0, .encodeWebPAlphaCompression: 100]
let data = SDImageWebPCoder.shared.encodedData(with: image, format: .webP, options: options)
// Will translate into:
// config->method = 0;
// config->alpha_quality = 100;
```

## Example

To run the example project, clone the repo, and run `pod install` from the root directory first. Then open `SDWebImageWebPCoder.xcworkspace`.
Expand Down
2 changes: 1 addition & 1 deletion SDWebImageWebPCoder.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'SDWebImageWebPCoder'
s.version = '0.7.0'
s.version = '0.8.0'
s.summary = 'WebP decoder/encoder for SDWebImage coder plugin.'

s.description = <<-DESC
Expand Down
32 changes: 20 additions & 12 deletions SDWebImageWebPCoder.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@
objects = {

/* Begin PBXBuildFile section */
220A623A257EAFB300262720 /* SDWebImageWebPCoderDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 220A6237257EAFB300262720 /* SDWebImageWebPCoderDefine.m */; };
220A623B257EAFB300262720 /* SDWebImageWebPCoderDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 220A6237257EAFB300262720 /* SDWebImageWebPCoderDefine.m */; };
220A623C257EAFB300262720 /* SDWebImageWebPCoderDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 220A6237257EAFB300262720 /* SDWebImageWebPCoderDefine.m */; };
220A623D257EAFB300262720 /* SDWebImageWebPCoderDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 220A6238257EAFB300262720 /* SDWebImageWebPCoderDefine.h */; settings = {ATTRIBUTES = (Public, ); }; };
220A623E257EAFB300262720 /* SDWebImageWebPCoderDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 220A6238257EAFB300262720 /* SDWebImageWebPCoderDefine.h */; settings = {ATTRIBUTES = (Public, ); }; };
220A623F257EAFB300262720 /* SDWebImageWebPCoderDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 220A6238257EAFB300262720 /* SDWebImageWebPCoderDefine.h */; settings = {ATTRIBUTES = (Public, ); }; };
220A6240257EAFB300262720 /* SDWebImageWebPCoderDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 220A6238257EAFB300262720 /* SDWebImageWebPCoderDefine.h */; settings = {ATTRIBUTES = (Public, ); }; };
228EA36125825A52005903D9 /* SDWebImageWebPCoderDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 220A6237257EAFB300262720 /* SDWebImageWebPCoderDefine.m */; };
806E77B32136A2E900A316D2 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 806E77AA2136A2E900A316D2 /* UIImage+WebP.m */; };
806E77B42136A2E900A316D2 /* SDImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 806E77AB2136A2E900A316D2 /* SDImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; };
806E77B62136A2E900A316D2 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 806E77AD2136A2E900A316D2 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -38,7 +46,8 @@
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
28D8AA3D3015E075692FD3E3 /* Pods-SDWebImageWebPCoderTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImageWebPCoderTests.debug.xcconfig"; path = "Tests/Pods/Target Support Files/Pods-SDWebImageWebPCoderTests/Pods-SDWebImageWebPCoderTests.debug.xcconfig"; sourceTree = "<group>"; };
220A6237257EAFB300262720 /* SDWebImageWebPCoderDefine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageWebPCoderDefine.m; sourceTree = "<group>"; };
220A6238257EAFB300262720 /* SDWebImageWebPCoderDefine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageWebPCoderDefine.h; sourceTree = "<group>"; };
3217BE7B220547EB003D0310 /* SDWebImageWebPCoder.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = SDWebImageWebPCoder.modulemap; sourceTree = "<group>"; };
46F21AD7D1692EBAC4D0FF33 /* Pods_SDWebImageWebPCoderTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SDWebImageWebPCoderTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
806E779D2136A1C000A316D2 /* SDWebImageWebPCoder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImageWebPCoder.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand All @@ -59,7 +68,6 @@
80BFF26E2136BE7900B95470 /* SDWebImageWebPCoder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImageWebPCoder.framework; sourceTree = BUILT_PRODUCTS_DIR; };
80BFF2772136BEE000B95470 /* SDWebImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDWebImage.framework; path = Carthage/Build/watchOS/SDWebImage.framework; sourceTree = "<group>"; };
80BFF2782136BEE000B95470 /* libwebp.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libwebp.framework; path = Carthage/Build/watchOS/libwebp.framework; sourceTree = "<group>"; };
D92E6791BF088D1A101E670E /* Pods-SDWebImageWebPCoderTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImageWebPCoderTests.release.xcconfig"; path = "Tests/Pods/Target Support Files/Pods-SDWebImageWebPCoderTests/Pods-SDWebImageWebPCoderTests.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -102,22 +110,12 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
52FB3B532EE8775B69517E2E /* Pods */ = {
isa = PBXGroup;
children = (
28D8AA3D3015E075692FD3E3 /* Pods-SDWebImageWebPCoderTests.debug.xcconfig */,
D92E6791BF088D1A101E670E /* Pods-SDWebImageWebPCoderTests.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
806E77932136A1C000A316D2 = {
isa = PBXGroup;
children = (
806E77A82136A2E900A316D2 /* SDImageWebPCoder */,
806E779E2136A1C000A316D2 /* Products */,
80BFF2312136AA7D00B95470 /* Frameworks */,
52FB3B532EE8775B69517E2E /* Pods */,
);
sourceTree = "<group>";
};
Expand Down Expand Up @@ -146,6 +144,8 @@
806E77A92136A2E900A316D2 /* Classes */ = {
isa = PBXGroup;
children = (
220A6238257EAFB300262720 /* SDWebImageWebPCoderDefine.h */,
220A6237257EAFB300262720 /* SDWebImageWebPCoderDefine.m */,
806E77AB2136A2E900A316D2 /* SDImageWebPCoder.h */,
806E77AE2136A2E900A316D2 /* SDImageWebPCoder.m */,
806E77AD2136A2E900A316D2 /* UIImage+WebP.h */,
Expand Down Expand Up @@ -228,6 +228,7 @@
files = (
806E77C72136A7AD00A316D2 /* SDWebImageWebPCoder.h in Headers */,
806E77B62136A2E900A316D2 /* UIImage+WebP.h in Headers */,
220A623D257EAFB300262720 /* SDWebImageWebPCoderDefine.h in Headers */,
806E77B42136A2E900A316D2 /* SDImageWebPCoder.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -238,6 +239,7 @@
files = (
80BFF2502136BC1500B95470 /* UIImage+WebP.h in Headers */,
80BFF24D2136BC0600B95470 /* SDWebImageWebPCoder.h in Headers */,
220A623E257EAFB300262720 /* SDWebImageWebPCoderDefine.h in Headers */,
80BFF24E2136BC1000B95470 /* SDImageWebPCoder.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -248,6 +250,7 @@
files = (
80BFF2632136BE2200B95470 /* SDWebImageWebPCoder.h in Headers */,
80BFF2612136BE1C00B95470 /* UIImage+WebP.h in Headers */,
220A623F257EAFB300262720 /* SDWebImageWebPCoderDefine.h in Headers */,
80BFF25F2136BE1700B95470 /* SDImageWebPCoder.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -258,6 +261,7 @@
files = (
80BFF27F2136BEF200B95470 /* SDWebImageWebPCoder.h in Headers */,
80BFF27D2136BEED00B95470 /* UIImage+WebP.h in Headers */,
220A6240257EAFB300262720 /* SDWebImageWebPCoderDefine.h in Headers */,
80BFF27B2136BEE700B95470 /* SDImageWebPCoder.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -416,6 +420,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
228EA36125825A52005903D9 /* SDWebImageWebPCoderDefine.m in Sources */,
806E77B72136A2E900A316D2 /* SDImageWebPCoder.m in Sources */,
806E77B32136A2E900A316D2 /* UIImage+WebP.m in Sources */,
);
Expand All @@ -425,6 +430,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
220A623A257EAFB300262720 /* SDWebImageWebPCoderDefine.m in Sources */,
80BFF24F2136BC1300B95470 /* SDImageWebPCoder.m in Sources */,
80BFF2512136BC1800B95470 /* UIImage+WebP.m in Sources */,
);
Expand All @@ -434,6 +440,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
220A623B257EAFB300262720 /* SDWebImageWebPCoderDefine.m in Sources */,
80BFF2602136BE1A00B95470 /* SDImageWebPCoder.m in Sources */,
80BFF2622136BE1F00B95470 /* UIImage+WebP.m in Sources */,
);
Expand All @@ -443,6 +450,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
220A623C257EAFB300262720 /* SDWebImageWebPCoderDefine.m in Sources */,
80BFF27C2136BEEB00B95470 /* SDImageWebPCoder.m in Sources */,
80BFF27E2136BEF000B95470 /* UIImage+WebP.m in Sources */,
);
Expand Down
159 changes: 148 additions & 11 deletions SDWebImageWebPCoder/Classes/SDImageWebPCoder.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
*/

#import "SDImageWebPCoder.h"
#import "SDWebImageWebPCoderDefine.h"
#import <Accelerate/Accelerate.h>
#import <os/lock.h>
#import <libkern/OSAtomic.h>

#if __has_include("webp/decode.h") && __has_include("webp/encode.h") && __has_include("webp/demux.h") && __has_include("webp/mux.h")
#import "webp/decode.h"
Expand All @@ -22,7 +26,47 @@
@import libwebp;
#endif

#import <Accelerate/Accelerate.h>
#define SD_USE_OS_UNFAIR_LOCK TARGET_OS_MACCATALYST ||\
(__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0) ||\
(__MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_12) ||\
(__TV_OS_VERSION_MIN_REQUIRED >= __TVOS_10_0) ||\
(__WATCH_OS_VERSION_MIN_REQUIRED >= __WATCHOS_3_0)

#ifndef SD_LOCK_DECLARE
#if SD_USE_OS_UNFAIR_LOCK
#define SD_LOCK_DECLARE(lock) os_unfair_lock lock
#else
#define SD_LOCK_DECLARE(lock) os_unfair_lock lock API_AVAILABLE(ios(10.0), tvos(10), watchos(3), macos(10.12)); \
OSSpinLock lock##_deprecated;
#endif
#endif

#ifndef SD_LOCK_INIT
#if SD_USE_OS_UNFAIR_LOCK
#define SD_LOCK_INIT(lock) lock = OS_UNFAIR_LOCK_INIT
#else
#define SD_LOCK_INIT(lock) if (@available(iOS 10, tvOS 10, watchOS 3, macOS 10.12, *)) lock = OS_UNFAIR_LOCK_INIT; \
else lock##_deprecated = OS_SPINLOCK_INIT;
#endif
#endif

#ifndef SD_LOCK
#if SD_USE_OS_UNFAIR_LOCK
#define SD_LOCK(lock) os_unfair_lock_lock(&lock)
#else
#define SD_LOCK(lock) if (@available(iOS 10, tvOS 10, watchOS 3, macOS 10.12, *)) os_unfair_lock_lock(&lock); \
else OSSpinLockLock(&lock##_deprecated);
#endif
#endif

#ifndef SD_UNLOCK
#if SD_USE_OS_UNFAIR_LOCK
#define SD_UNLOCK(lock) os_unfair_lock_unlock(&lock)
#else
#define SD_UNLOCK(lock) if (@available(iOS 10, tvOS 10, watchOS 3, macOS 10.12, *)) os_unfair_lock_unlock(&lock); \
else OSSpinLockUnlock(&lock##_deprecated);
#endif
#endif

/// Calculate the actual thumnail pixel size
static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio, CGSize thumbnailSize) {
Expand Down Expand Up @@ -98,7 +142,7 @@ @implementation SDImageWebPCoder {
BOOL _finished;
CGFloat _canvasWidth;
CGFloat _canvasHeight;
dispatch_semaphore_t _lock;
SD_LOCK_DECLARE(_lock);
NSUInteger _currentBlendIndex;
BOOL _preserveAspectRatio;
CGSize _thumbnailSize;
Expand Down Expand Up @@ -291,7 +335,7 @@ - (instancetype)initIncrementalWithOptions:(nullable SDImageCoderOptions *)optio
}
_preserveAspectRatio = preserveAspectRatio;
_currentBlendIndex = NSNotFound;
_lock = dispatch_semaphore_create(1);
SD_LOCK_INIT(_lock);
}
return self;
}
Expand Down Expand Up @@ -617,7 +661,11 @@ - (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format o
BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue];
if (encodeFirstFrame || frames.count == 0) {
// for static single webp image
data = [self sd_encodedWebpDataWithImage:image.CGImage quality:compressionQuality maxPixelSize:maxPixelSize maxFileSize:maxFileSize];
data = [self sd_encodedWebpDataWithImage:image.CGImage
quality:compressionQuality
maxPixelSize:maxPixelSize
maxFileSize:maxFileSize
options:options];
} else {
// for animated webp image
WebPMux *mux = WebPMuxNew();
Expand All @@ -626,7 +674,11 @@ - (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format o
}
for (size_t i = 0; i < frames.count; i++) {
SDImageFrame *currentFrame = frames[i];
NSData *webpData = [self sd_encodedWebpDataWithImage:currentFrame.image.CGImage quality:compressionQuality maxPixelSize:maxPixelSize maxFileSize:maxFileSize];
NSData *webpData = [self sd_encodedWebpDataWithImage:currentFrame.image.CGImage
quality:compressionQuality
maxPixelSize:maxPixelSize
maxFileSize:maxFileSize
options:options];
int duration = currentFrame.duration * 1000;
WebPMuxFrameInfo frame = { .bitstream.bytes = webpData.bytes,
.bitstream.size = webpData.length,
Expand Down Expand Up @@ -663,7 +715,12 @@ - (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format o
return data;
}

- (nullable NSData *)sd_encodedWebpDataWithImage:(nullable CGImageRef)imageRef quality:(double)quality maxPixelSize:(CGSize)maxPixelSize maxFileSize:(NSUInteger)maxFileSize {
- (nullable NSData *)sd_encodedWebpDataWithImage:(nullable CGImageRef)imageRef
quality:(double)quality
maxPixelSize:(CGSize)maxPixelSize
maxFileSize:(NSUInteger)maxFileSize
options:(nullable SDImageCoderOptions *)options
{
NSData *webpData;
if (!imageRef) {
return nil;
Expand Down Expand Up @@ -779,10 +836,7 @@ - (nullable NSData *)sd_encodedWebpDataWithImage:(nullable CGImageRef)imageRef q
return nil;
}

config.target_size = (int)maxFileSize; // Max filesize for output, 0 means use quality instead
config.pass = maxFileSize > 0 ? 6 : 1; // Use 6 passes for file size limited encoding, which is the default value of `cwebp` command line
config.thread_level = 1; // Thread encoding for fast
config.lossless = 0; // Disable lossless encoding (If we need, can add new Encoding Options in future version)
[self updateWebPOptionsToConfig:&config maxFileSize:maxFileSize options:options];
picture.use_argb = 0; // Lossy encoding use YUV for internel bitstream
picture.width = (int)width;
picture.height = (int)height;
Expand Down Expand Up @@ -830,6 +884,89 @@ - (nullable NSData *)sd_encodedWebpDataWithImage:(nullable CGImageRef)imageRef q
return webpData;
}

- (void) updateWebPOptionsToConfig:(WebPConfig * _Nonnull)config
maxFileSize:(NSUInteger)maxFileSize
options:(nullable SDImageCoderOptions *)options {

config->target_size = (int)maxFileSize; // Max filesize for output, 0 means use quality instead
config->pass = maxFileSize > 0 ? 6 : 1; // Use 6 passes for file size limited encoding, which is the default value of `cwebp` command line
config->lossless = 0; // Disable lossless encoding (If we need, can add new Encoding Options in future version)

if ([options[SDImageCoderEncodeWebPMethod] intValue]) {
config->method = [options[SDImageCoderEncodeWebPMethod] intValue];
}
if ([options[SDImageCoderEncodeWebPPass] intValue]) {
config->pass = [options[SDImageCoderEncodeWebPPass] intValue];
}
if ([options[SDImageCoderEncodeWebPPreprocessing] intValue]) {
config->preprocessing = [options[SDImageCoderEncodeWebPPreprocessing] intValue];
}
if ([options[SDImageCoderEncodeWebPThreadLevel] intValue]) {
config->thread_level = [options[SDImageCoderEncodeWebPThreadLevel] intValue];
} else {
config->thread_level = 1;
}
if ([options[SDImageCoderEncodeWebPLowMemory] intValue]) {
config->low_memory = [options[SDImageCoderEncodeWebPLowMemory] intValue];
}

if ([options[SDImageCoderEncodeWebPTargetPSNR] floatValue]) {
config->target_PSNR = [options[SDImageCoderEncodeWebPTargetPSNR] floatValue];
}

if ([options[SDImageCoderEncodeWebPSegments] intValue]) {
config->segments = [options[SDImageCoderEncodeWebPSegments] intValue];
}

if ([options[SDImageCoderEncodeWebPSnsStrength] intValue]) {
config->sns_strength = [options[SDImageCoderEncodeWebPSnsStrength] intValue];
}

if ([options[SDImageCoderEncodeWebPFilterStrength] intValue]) {
config->filter_strength = [options[SDImageCoderEncodeWebPFilterStrength] intValue];
}

if ([options[SDImageCoderEncodeWebPFilterSharpness] intValue]) {
config->filter_sharpness = [options[SDImageCoderEncodeWebPFilterSharpness] intValue];
}

if ([options[SDImageCoderEncodeWebPFilterType] intValue]) {
config->filter_type = [options[SDImageCoderEncodeWebPFilterType] intValue];
}

if ([options[SDImageCoderEncodeWebPAutofilter] intValue]) {
config->autofilter = [options[SDImageCoderEncodeWebPAutofilter] intValue];
}

if ([options[SDImageCoderEncodeWebPAlphaCompression] intValue]) {
config->alpha_compression = [options[SDImageCoderEncodeWebPAlphaCompression] intValue];
}

if ([options[SDImageCoderEncodeWebPAlphaFiltering] intValue]) {
config->alpha_filtering = [options[SDImageCoderEncodeWebPAlphaFiltering] intValue];
}

if ([options[SDImageCoderEncodeWebPAlphaQuality] intValue]) {
config->alpha_quality = [options[SDImageCoderEncodeWebPAlphaQuality] intValue];
}

if ([options[SDImageCoderEncodeWebPShowCompressed] intValue]) {
config->show_compressed = [options[SDImageCoderEncodeWebPShowCompressed] intValue];
}

if ([options[SDImageCoderEncodeWebPPartitions] intValue]) {
config->partitions = [options[SDImageCoderEncodeWebPPartitions] intValue];
}

if ([options[SDImageCoderEncodeWebPPartitionLimit] intValue]) {
config->partition_limit = [options[SDImageCoderEncodeWebPPartitionLimit] intValue];
}

if ([options[SDImageCoderEncodeWebPUseSharpYuv] intValue]) {
config->use_sharp_yuv = [options[SDImageCoderEncodeWebPUseSharpYuv] intValue];
}
}

static void FreeImageData(void *info, const void *data, size_t size) {
free((void *)data);
}
Expand Down Expand Up @@ -881,7 +1018,7 @@ - (instancetype)initWithAnimatedImageData:(NSData *)data options:(nullable SDIma
_demux = demuxer;
_imageData = data;
_currentBlendIndex = NSNotFound;
_lock = dispatch_semaphore_create(1);
SD_LOCK_INIT(_lock);
}
return self;
}
Expand Down
Loading